From b8b21b347f1ae26926ea3118f3d492ff0768a077 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Thu, 25 Apr 2013 13:36:42 -0400 Subject: [PATCH 1/5] TST: Added unittest that runs all examples. --- tests/test_examples.py | 54 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/test_examples.py diff --git a/tests/test_examples.py b/tests/test_examples.py new file mode 100644 index 00000000..1bbbd4ab --- /dev/null +++ b/tests/test_examples.py @@ -0,0 +1,54 @@ +# +# Copyright 2013 Quantopian, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# This code is based on a unittest written by John Salvatier: +# https://github.com/pymc-devs/pymc/blob/pymc3/tests/test_examples.py + +# Disable plotting +# +import matplotlib +matplotlib.use('Agg') + +from os import path +import os +import fnmatch +import imp + + +def test_examples(): + os.chdir(example_dir()) + for fname in all_matching_files('.', '*.py'): + yield check_example, fname + + +def all_matching_files(d, pattern): + def addfiles(fls, dir, nfiles): + nfiles = fnmatch.filter(nfiles, pattern) + nfiles = [path.join(dir, f) for f in nfiles] + fls.extend(nfiles) + + files = [] + path.walk(d, addfiles, files) + return files + + +def example_dir(): + import zipline + d = path.dirname(zipline.__file__) + return path.join(path.abspath(d), 'examples/') + + +def check_example(p): + imp.load_source('__main__', path.basename(p)) From d56f1b73f85147d11c888be139f38798dac19e3a Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Thu, 25 Apr 2013 13:37:04 -0400 Subject: [PATCH 2/5] BUG: Removed SlippageModel from olmar example. Fix crash due to 'delay' was no longer supported. But removing SlippageModel override, since current configs should be functionally equivalent to FixedSlippage. --- zipline/examples/olmar.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/zipline/examples/olmar.py b/zipline/examples/olmar.py index af88cfb8..99db9264 100644 --- a/zipline/examples/olmar.py +++ b/zipline/examples/olmar.py @@ -1,12 +1,11 @@ import sys import logbook -import datetime import numpy as np from zipline.algorithm import TradingAlgorithm from zipline.transforms import MovingAverage from zipline.utils.factory import load_bars_from_yahoo -from zipline.finance import slippage, commission +from zipline.finance import commission zipline_logging = logbook.NestedSetup([ logbook.NullHandler(level=logbook.DEBUG, bubble=True), @@ -38,11 +37,6 @@ class OLMAR(TradingAlgorithm): self.add_transform(MovingAverage, 'mavg', ['price'], window_length=window_length) - no_delay = datetime.timedelta(minutes=0) - slip = slippage.VolumeShareSlippage(volume_limit=0.25, - price_impact=0, - delay=no_delay) - self.set_slippage(slip) self.set_commission(commission.PerShare(cost=0)) def handle_data(self, data): From f5a8d76a91bedcb6253748730f68642ce6ed4bcf Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Thu, 2 May 2013 15:28:37 -0400 Subject: [PATCH 3/5] BUG: Do not update last price if price is nan. --- zipline/finance/performance.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/zipline/finance/performance.py b/zipline/finance/performance.py index 02e7785f..adfb5d11 100644 --- a/zipline/finance/performance.py +++ b/zipline/finance/performance.py @@ -622,7 +622,9 @@ class PerformancePeriod(object): def update_last_sale(self, event): is_trade = event.type == zp.DATASOURCE_TYPE.TRADE - if event.sid in self.positions and is_trade: + has_price = not np.isnan(event.price) + # isnan check will keep the last price if its not present + if (event.sid in self.positions) and is_trade and has_price: self.positions[event.sid].last_sale_price = event.price index = self.index_for_position(event.sid) self._position_last_sale_prices[index] = event.price From b748ba62e0d2f35c18923a386f38b6c0e7865222 Mon Sep 17 00:00:00 2001 From: Thomas Wiecki Date: Thu, 2 May 2013 15:55:44 -0400 Subject: [PATCH 4/5] MAINT: Shortened time frame over which examples are run to speed up tests. Minor fix pairtrade to now use record. --- zipline/examples/buyapple.py | 13 +++++++++++-- zipline/examples/dual_moving_average.py | 17 ++++++++++++----- zipline/examples/olmar.py | 10 ++++++++-- zipline/examples/pairtrade.py | 19 +++++++++++-------- 4 files changed, 42 insertions(+), 17 deletions(-) diff --git a/zipline/examples/buyapple.py b/zipline/examples/buyapple.py index e7bea18a..7c6814f8 100755 --- a/zipline/examples/buyapple.py +++ b/zipline/examples/buyapple.py @@ -15,6 +15,8 @@ # limitations under the License. import matplotlib.pyplot as plt +from datetime import datetime +import pytz from zipline.algorithm import TradingAlgorithm from zipline.utils.factory import load_from_yahoo @@ -29,8 +31,15 @@ class BuyApple(TradingAlgorithm): # inherit from TradingAlgorithm if __name__ == '__main__': - data = load_from_yahoo(stocks=['AAPL'], indexes={}) + start = datetime(2008, 1, 1, 0, 0, 0, 0, pytz.utc) + end = datetime(2010, 1, 1, 0, 0, 0, 0, pytz.utc) + data = load_from_yahoo(stocks=['AAPL'], indexes={}, start=start, + end=end) simple_algo = BuyApple() results = simple_algo.run(data) - results.portfolio_value.plot() + + ax1 = plt.subplot(211) + results.portfolio_value.plot(ax=ax1) + ax2 = plt.subplot(212, sharex=ax1) + data.AAPL.plot(ax=ax2) plt.show() diff --git a/zipline/examples/dual_moving_average.py b/zipline/examples/dual_moving_average.py index e00a95ed..eb645f83 100755 --- a/zipline/examples/dual_moving_average.py +++ b/zipline/examples/dual_moving_average.py @@ -20,6 +20,9 @@ from zipline.algorithm import TradingAlgorithm from zipline.transforms import MovingAverage from zipline.utils.factory import load_from_yahoo +from datetime import datetime +import pytz + class DualMovingAverage(TradingAlgorithm): """Dual Moving Average Crossover algorithm. @@ -30,7 +33,7 @@ class DualMovingAverage(TradingAlgorithm): momentum). """ - def initialize(self, short_window=200, long_window=400): + def initialize(self, short_window=20, long_window=40): # Add 2 mavg transforms, one with a long window, one # with a short window. self.add_transform(MovingAverage, 'short_mavg', ['price'], @@ -63,16 +66,20 @@ class DualMovingAverage(TradingAlgorithm): sell=self.sell) if __name__ == '__main__': - data = load_from_yahoo(stocks=['AAPL'], indexes={}) + start = datetime(1990, 1, 1, 0, 0, 0, 0, pytz.utc) + end = datetime(1991, 1, 1, 0, 0, 0, 0, pytz.utc) + data = load_from_yahoo(stocks=['AAPL'], indexes={}, start=start, + end=end) + dma = DualMovingAverage() results = dma.run(data) - print results.short_mavg + fig = plt.figure() - ax1 = fig.add_subplot(211) + ax1 = fig.add_subplot(211, ylabel='portfolio value') results.portfolio_value.plot(ax=ax1) ax2 = fig.add_subplot(212) - data['AAPL'].plot(ax=ax2) + data['AAPL'].plot(ax=ax2, color='r') results[['short_mavg', 'long_mavg']].plot(ax=ax2) ax2.plot(results.ix[results.buy].index, results.short_mavg[results.buy], diff --git a/zipline/examples/olmar.py b/zipline/examples/olmar.py index 99db9264..9d05579c 100644 --- a/zipline/examples/olmar.py +++ b/zipline/examples/olmar.py @@ -1,10 +1,12 @@ import sys import logbook import numpy as np +from datetime import datetime +import pytz from zipline.algorithm import TradingAlgorithm from zipline.transforms import MovingAverage -from zipline.utils.factory import load_bars_from_yahoo +from zipline.utils.factory import load_from_yahoo from zipline.finance import commission zipline_logging = logbook.NestedSetup([ @@ -151,7 +153,11 @@ def simplex_projection(v, b=1): if __name__ == '__main__': import pylab as pl - data = load_bars_from_yahoo(stocks=STOCKS, indexes={}) + start = datetime(2004, 1, 1, 0, 0, 0, 0, pytz.utc) + end = datetime(2008, 1, 1, 0, 0, 0, 0, pytz.utc) + data = load_from_yahoo(stocks=STOCKS, indexes={}, start=start, + end=end) + data = data.dropna() olmar = OLMAR() results = olmar.run(data) results.portfolio_value.plot() diff --git a/zipline/examples/pairtrade.py b/zipline/examples/pairtrade.py index 0786bc94..41b7566e 100755 --- a/zipline/examples/pairtrade.py +++ b/zipline/examples/pairtrade.py @@ -17,6 +17,8 @@ import matplotlib.pyplot as plt import numpy as np import statsmodels.api as sm +from datetime import datetime +import pytz from zipline.algorithm import TradingAlgorithm from zipline.transforms import batch_transform @@ -29,7 +31,7 @@ def ols_transform(data, sid1, sid2): via Ordinary Least Squares between two SIDs. """ p0 = data.price[sid1] - p1 = sm.add_constant(data.price[sid2]) + p1 = sm.add_constant(data.price[sid2], prepend=True) slope, intercept = sm.OLS(p0, p1).fit().params return slope, intercept @@ -53,7 +55,6 @@ class Pairtrade(TradingAlgorithm): def initialize(self, window_length=100): self.spreads = [] - self.zscores = [] self.invested = 0 self.window_length = window_length self.ols_transform = ols_transform(refresh_period=self.window_length, @@ -65,12 +66,12 @@ class Pairtrade(TradingAlgorithm): params = self.ols_transform.handle_data(data, 'PEP', 'KO') if params is None: return - slope, intercept = params + intercept, slope = params ###################################################### # 2. Compute spread and zscore zscore = self.compute_zscore(data, slope, intercept) - self.zscores.append(zscore) + self.record(zscores=zscore) ###################################################### # 3. Place orders @@ -112,12 +113,14 @@ class Pairtrade(TradingAlgorithm): self.order('PEP', -1 * pep_amount) if __name__ == '__main__': - data = load_from_yahoo(stocks=['PEP', 'KO'], indexes={}) + start = datetime(2000, 1, 1, 0, 0, 0, 0, pytz.utc) + end = datetime(2002, 1, 1, 0, 0, 0, 0, pytz.utc) + data = load_from_yahoo(stocks=['PEP', 'KO'], indexes={}, + start=start, end=end) pairtrade = Pairtrade() results = pairtrade.run(data) data['spreads'] = np.nan - data.spreads[pairtrade.window_length:] = pairtrade.spreads ax1 = plt.subplot(211) data[['PEP', 'KO']].plot(ax=ax1) @@ -125,7 +128,7 @@ if __name__ == '__main__': plt.setp(ax1.get_xticklabels(), visible=False) ax2 = plt.subplot(212, sharex=ax1) - data.spreads.plot(ax=ax2, color='r') - plt.ylabel('spread') + results.zscores.plot(ax=ax2, color='r') + plt.ylabel('zscored spread') plt.show() From 7bc20639da2a1ed22814ff84d957a66d834e28ee Mon Sep 17 00:00:00 2001 From: Eddie Hebert Date: Thu, 2 May 2013 16:48:53 -0400 Subject: [PATCH 5/5] BLD: Add matplotlib to test requirements. Example scripts use matplotlib, so add to requirements_dev.txt so that CI will include matplotlib. --- etc/requirements_dev.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etc/requirements_dev.txt b/etc/requirements_dev.txt index 0654e92e..7c9b402b 100644 --- a/etc/requirements_dev.txt +++ b/etc/requirements_dev.txt @@ -12,3 +12,7 @@ pyflakes==0.6.1 # Documentation Conversion pyandoc==0.0.1 + +# Example scripts that are run during unit tests use the following: + +matplotlib==1.2.1