diff --git a/tests/test_optimize.py b/tests/test_optimize.py index 99390df9..35c1943b 100644 --- a/tests/test_optimize.py +++ b/tests/test_optimize.py @@ -1,23 +1,15 @@ """Tests for the zipline.finance package""" -import unittest from unittest2 import TestCase, skip from nose.tools import timed from collections import defaultdict -from datetime import datetime, timedelta import logging import numpy as np -from zipline.optimize.factory import create_updown_trade_source -import zipline.utils.factory as factory from zipline.utils.logger import configure_logging -from zipline.core.devsimulator import AddressAllocator, Simulator -from zipline.optimize.algorithms import BuySellAlgorithm +from zipline.core.devsimulator import AddressAllocator from zipline.optimize.factory import create_predictable_zipline -from zipline.finance.trading import TradingEnvironment -from zipline.lines import SimulatedTrading -from zipline.finance.trading import SIMULATION_STYLE DEFAULT_TIMEOUT = 15 # seconds EXTENDED_TIMEOUT = 90 @@ -37,7 +29,10 @@ class TestUpDown(TestCase): configure_logging() self.zipline_test_config = { 'allocator':allocator, - 'sid':133 + 'sid':133, + 'trade_count':5, + 'amplitude':30, + 'base_price':50 } @timed(DEFAULT_TIMEOUT) @@ -48,23 +43,16 @@ class TestUpDown(TestCase): UpDownSource and BuySellAlgorithm interact correctly." """ - #generate events - trade_count = 5 - sid = 133 - base_price = 50 - amplitude = 6 - offset = 0 - zipline, config = create_predictable_zipline( self.zipline_test_config, - sid=sid, - amplitude=amplitude, - base_price=base_price, - offset=offset, - trade_count=5, + offset=0, simulate=False ) + #extract arguments + base_price = self.zipline_test_config['base_price'] + amplitude = self.zipline_test_config['amplitude'] + prices = np.array([event.price for event in config['trade_source'].event_list]) max_price_idx = np.where(prices==prices.max())[0] min_price_idx = np.where(prices==prices.min())[0] @@ -109,14 +97,9 @@ class TestUpDown(TestCase): (i.e. 0). """ - #generate events - trade_count = 6 - sid = 133 - amplitude = 30 - base_price = 50 - - #test whether return-function is concave wrt repeats. test_offsets = np.arange(-9, 9, 1.) + #maximum value is expect to be at center, create boolean mask + #for later extraction supposed_max = np.zeros(len(test_offsets), dtype=bool) supposed_max[len(test_offsets) // 2] = True @@ -125,12 +108,7 @@ class TestUpDown(TestCase): for i, offset in enumerate(test_offsets): zipline, config = create_predictable_zipline( self.zipline_test_config, - sid=sid, - amplitude=amplitude, - base_price=base_price, offset=offset, - trade_count=trade_count, - simulate=True ) ziplines.append(zipline) compound_returns[i] = zipline.get_cumulative_performance()['returns'] @@ -153,7 +131,7 @@ class TestUpDown(TestCase): idx[0] -= 1 idx[1] += 1 - #@skip + @skip def test_optimize(self): """verify that gradient descent (Powell's method) can find the optimal free parameter under which the BuySellAlgorithm produces @@ -163,12 +141,7 @@ class TestUpDown(TestCase): def simulate(offset): zipline, config = create_predictable_zipline( self.zipline_test_config, - sid=133, - amplitude=10, - base_price=50, offset=offset, - trade_count=5, - simulate=True ) #function is getting minimized, so have to return negative cum returns. return -zipline.get_cumulative_performance()['returns'] diff --git a/zipline/optimize/algorithms.py b/zipline/optimize/algorithms.py index d0c84b60..c4e3fb9d 100644 --- a/zipline/optimize/algorithms.py +++ b/zipline/optimize/algorithms.py @@ -1,4 +1,4 @@ -class BuySellAlgorithm(): +class BuySellAlgorithm(object): """Algorithm that buys and sells alternatingly. The amount for each order can be specified. In addition, an offset that will quadratically reduce the amount that will be bought can be @@ -40,7 +40,6 @@ class BuySellAlgorithm(): self.buy_or_sell *= -1 self.orders.append(order_size) - #self.prices.append(frame['price']) self.frame_count += 1 self.incr += 1 diff --git a/zipline/optimize/factory.py b/zipline/optimize/factory.py index a752a013..d9776a9c 100644 --- a/zipline/optimize/factory.py +++ b/zipline/optimize/factory.py @@ -3,7 +3,7 @@ Factory functions to prepare useful data for optimize tests. Author: Thomas V. Wiecki (thomas.wiecki@gmail.com), 2012 """ -from datetime import datetime, timedelta +from datetime import timedelta import zipline.protocol as zp @@ -13,13 +13,34 @@ from zipline.optimize.algorithms import BuySellAlgorithm from zipline.lines import SimulatedTrading from zipline.finance.trading import SIMULATION_STYLE -from copy import deepcopy +from copy import copy from itertools import cycle -def create_updown_trade_source(sid, trade_count, trading_environment, start_price, amplitude): +def create_updown_trade_source(sid, trade_count, trading_environment, base_price, amplitude): + """Create the updown trade source. This source emits events with + the price going up and down by the same amount in each + iteration. The trade source is thus perfectly predictable. This is + used for a test case for the optimization code. + + :Arguments: + sid : int + SID of stock to create. + trade_count : int + How many trade events to create (will also influence order count) + trading_environment : TradeEnvironment object + The trading environment to use (see zipline.factory.create_trading_environment) + base_price : int + The average price that each iteration will hover around. + amplitude : int + How much the price will go up and down each iteration. + + :Returns: + source : SpecificEquityTrades + The trade source emitting up down events. + """ volume = 1000 events = [] - price = start_price-amplitude/2. + price = base_price-amplitude/2. cur = trading_environment.first_open one_day = timedelta(days = 1) @@ -49,8 +70,49 @@ def create_updown_trade_source(sid, trade_count, trading_environment, start_pric return source -def create_predictable_zipline(config, sid=133, amplitude=10, base_price=50, offset=0, trade_count=3, simulate=True): - #config = deepcopy(config) +def create_predictable_zipline(config, offset=0, simulate=True): + """Create a test zipline object as specified by config. The + zipline will use the UpDown tradesource which is perfectly + predictable. + + Trade source parameters can be specified inside the config object. + + :Trade source arguments: + config['sid'] : int + SID of stock to create. + config['amplitude'] : int (default 10) + How much the price will go up and down each iteration. + config['base_price'] : int (default 50) + The average price that each iteration will hover around. + config['trade_count'] : int (default 3) + How many trade events to create (will also influence order count) + + If not specified, the BuySellAlgorithm is used by default. This + can be changed by setting config['algorithm']. + + :Arguments: + offset : int (default 0) + The offset parameter specifies how much the BuySellAlgorithm will + order each iteration and is a negative quadratic centered around + 0. Thus, any deviations from 0 will lead to less buy and sell + orders each iteration and ultimately to less compound returns. + simulate : bool (default True) + Whether to call .simulate(blocking=True) on the created zipline + argument. + + :Returns: + zipline : class zipline + created zipline object + config : dict + the config dict used to create the zipline + """ + config = copy(config) + sid = config['sid'] + # remove + amplitude = config.pop('amplitude', 10) + base_price = config.pop('base_price', 50) + trade_count = config.pop('trade_count', 3) + trading_environment = create_trading_environment() source = create_updown_trade_source(sid, trade_count,