mirror of
https://github.com/wassname/catalyst.git
synced 2026-06-28 23:24:02 +08:00
211 lines
7.7 KiB
Python
211 lines
7.7 KiB
Python
"""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.finance.trading import TradingEnvironment
|
|
from zipline.lines import SimulatedTrading
|
|
from zipline.finance.trading import SIMULATION_STYLE
|
|
|
|
DEFAULT_TIMEOUT = 15 # seconds
|
|
EXTENDED_TIMEOUT = 90
|
|
|
|
allocator = AddressAllocator(1000)
|
|
LOGGER = logging.getLogger('ZiplineLogger')
|
|
|
|
class TestUpDown(TestCase):
|
|
"""This unittest verifies that the BuySellAlgorithm in
|
|
combination with the UpDownSource are suitable for usage in an
|
|
optimization framework.
|
|
|
|
"""
|
|
leased_sockets = defaultdict(list)
|
|
|
|
def setUp(self):
|
|
configure_logging()
|
|
self.zipline_test_config = {
|
|
'allocator':allocator,
|
|
'sid':133
|
|
}
|
|
|
|
@skip
|
|
@timed(DEFAULT_TIMEOUT)
|
|
def test_source_and_orders(self):
|
|
"""verify that UpDownSource is having the correct
|
|
behavior and that BuySellAlgorithm places the buy/sell
|
|
orders at the right time. Moreover, establishes that
|
|
UpDownSource and BuySellAlgorithm interact correctly."
|
|
|
|
"""
|
|
#generate events
|
|
trade_count = 5
|
|
sid = 133
|
|
base_price = 50
|
|
amplitude = 6
|
|
offset = 0
|
|
self.zipline_test_config['order_count'] = trade_count - 1
|
|
self.zipline_test_config['trade_count'] = trade_count
|
|
self.zipline_test_config['simulation_style'] = \
|
|
SIMULATION_STYLE.FIXED_SLIPPAGE
|
|
|
|
trading_environment = factory.create_trading_environment()
|
|
source = create_updown_trade_source(sid,
|
|
trade_count,
|
|
trading_environment,
|
|
base_price,
|
|
amplitude
|
|
)
|
|
|
|
prices = np.array([event.price for event in source.event_list])
|
|
max_price_idx = np.where(prices==prices.max())[0]
|
|
min_price_idx = np.where(prices==prices.min())[0]
|
|
self.assertTrue(np.all(max_price_idx % 2 == 1),
|
|
"Maximum prices are not periodic."
|
|
)
|
|
self.assertTrue(np.all(min_price_idx % 2 == 0),
|
|
"Minimum prices are not periodic."
|
|
)
|
|
self.assertEqual(prices.max(), base_price+amplitude/2.,
|
|
"Maximum price does not equal expected maximum price."
|
|
)
|
|
self.assertEqual(prices.min(), base_price-amplitude/2.,
|
|
"Minimum price does not equal expected maximum price."
|
|
)
|
|
|
|
algo = BuySellAlgorithm(sid, 100, 0)
|
|
|
|
self.zipline_test_config['trade_source'] = source
|
|
self.zipline_test_config['algorithm'] = algo
|
|
self.zipline_test_config['environment'] = trading_environment
|
|
|
|
zipline = SimulatedTrading.create_test_zipline(**self.zipline_test_config)
|
|
zipline.simulate(blocking=True)
|
|
|
|
orders = np.asarray(algo.orders)
|
|
max_order_idx = np.where(orders==orders.max())[0]
|
|
min_order_idx = np.where(orders==orders.min())[0]
|
|
|
|
self.assertTrue(np.all(max_order_idx % 2 == 1),
|
|
"Maximum orders are not periodic."
|
|
)
|
|
self.assertTrue(np.all(min_order_idx % 2 == 0),
|
|
"Minimum orders are not periodic."
|
|
)
|
|
self.assertTrue(np.all(max_order_idx == max_price_idx),
|
|
"Algorithm did not buy when price was going to drop."
|
|
)
|
|
self.assertTrue(np.all(min_order_idx == min_price_idx),
|
|
"Algorithm did not sell when price was going to increase."
|
|
)
|
|
|
|
@skip
|
|
def test_concavity_of_returns(self):
|
|
"""verify concave relationship between of free parameter and
|
|
returns in certain region around the max. Moreover,
|
|
establishes that the max returns is at the correct value
|
|
(i.e. 0).
|
|
|
|
"""
|
|
#generate events
|
|
trade_count = 6
|
|
sid = 133
|
|
amplitude = 30
|
|
base_price = 50
|
|
self.zipline_test_config['order_count'] = trade_count - 1
|
|
self.zipline_test_config['trade_count'] = trade_count
|
|
self.zipline_test_config['simulation_style'] = \
|
|
SIMULATION_STYLE.FIXED_SLIPPAGE
|
|
|
|
#test whether return-function is concave wrt repeats.
|
|
test_offsets = np.arange(-9, 9, 1.)
|
|
supposed_max = np.zeros(len(test_offsets), dtype=bool)
|
|
supposed_max[len(test_offsets) // 2] = True
|
|
|
|
compound_returns = np.empty(len(test_offsets))
|
|
ziplines = []
|
|
for i, test_offset in enumerate(test_offsets):
|
|
trading_environment = factory.create_trading_environment()
|
|
source = create_updown_trade_source(sid,
|
|
trade_count,
|
|
trading_environment,
|
|
base_price,
|
|
amplitude
|
|
)
|
|
|
|
algo = BuySellAlgorithm(sid, 100, test_offset)
|
|
self.zipline_test_config['algorithm'] = algo
|
|
self.zipline_test_config['trade_source'] = source
|
|
self.zipline_test_config['environment'] = trading_environment
|
|
zipline = SimulatedTrading.create_test_zipline(**self.zipline_test_config)
|
|
zipline.simulate(blocking=True)
|
|
ziplines.append(zipline)
|
|
compound_returns[i] = zipline.get_cumulative_performance()['returns']
|
|
|
|
self.assertTrue(np.all(compound_returns[supposed_max] > compound_returns[np.logical_not(supposed_max)]),
|
|
"Maximum compound returns are not where they are supposed to be."
|
|
)
|
|
|
|
# test for concavity
|
|
max_idx = np.where(supposed_max)[0][0]
|
|
idx = np.array([max_idx, max_idx])
|
|
for i in range((len(test_offsets)-1)/2):
|
|
# going outwards, returns must decrease
|
|
self.assertTrue(compound_returns[idx[0]-1] < compound_returns[idx[0]],
|
|
"Compound returns are not convex."
|
|
)
|
|
self.assertTrue(compound_returns[idx[1]+1] < compound_returns[idx[1]],
|
|
"Compound returns are not convex."
|
|
)
|
|
idx[0] -= 1
|
|
idx[1] += 1
|
|
|
|
@skip
|
|
def test_optimize(self):
|
|
"""verify that gradient descent (Powell's method) can find
|
|
the optimal free parameter under which the BuySellAlgorithm produces
|
|
maximum returns.
|
|
|
|
"""
|
|
def simulate(offset):
|
|
#generate events
|
|
trade_count = 3
|
|
sid = 133
|
|
amplitude = 10
|
|
base_price = 50
|
|
self.zipline_test_config['order_count'] = trade_count - 1
|
|
self.zipline_test_config['trade_count'] = trade_count
|
|
self.zipline_test_config['simulation_style'] = \
|
|
SIMULATION_STYLE.FIXED_SLIPPAGE
|
|
trading_environment = factory.create_trading_environment()
|
|
source = create_updown_trade_source(sid,
|
|
trade_count,
|
|
trading_environment,
|
|
base_price,
|
|
amplitude
|
|
)
|
|
|
|
algo = BuySellAlgorithm(sid, 100, offset)
|
|
self.zipline_test_config['algorithm'] = algo
|
|
self.zipline_test_config['trade_source'] = source
|
|
self.zipline_test_config['environment'] = trading_environment
|
|
zipline = SimulatedTrading.create_test_zipline(**self.zipline_test_config)
|
|
zipline.simulate(blocking=True)
|
|
zipline.shutdown()
|
|
#function is getting minimized, so have to return negative cum returns.
|
|
return -zipline.get_cumulative_performance()['returns']
|
|
|
|
from scipy import optimize
|
|
opt = optimize.fmin_powell(simulate, 1.5)
|
|
np.testing.assert_almost_equal(opt, 0, 5)
|