mirror of
https://github.com/wassname/catalyst.git
synced 2026-08-14 12:10:24 +08:00
ENH: Add support for splits in zipline.
When a split is encountered, open positions and open orders are updated accordingly.
This commit is contained in:
committed by
Eddie Hebert
parent
9ff588e7fc
commit
6fc077a573
@@ -390,3 +390,38 @@ class FinanceTestCase(TestCase):
|
||||
self.assertTrue(sid in oo)
|
||||
order_list = oo[sid]
|
||||
self.assertEqual(0, len(order_list))
|
||||
|
||||
def test_blotter_processes_splits(self):
|
||||
sim_params = factory.create_simulation_parameters()
|
||||
blotter = Blotter()
|
||||
blotter.set_date(sim_params.period_start)
|
||||
|
||||
# set up two open limit orders with very low limit prices,
|
||||
# one for sid 1 and one for sid 2
|
||||
blotter.order(1, 100, 10, None, None)
|
||||
blotter.order(2, 100, 10, None, None)
|
||||
|
||||
# send in a split for sid 2
|
||||
split_event = factory.create_split(2, 0.33333,
|
||||
sim_params.period_start +
|
||||
timedelta(days=1))
|
||||
|
||||
blotter.process_split(split_event)
|
||||
|
||||
for sid in [1, 2]:
|
||||
order_lists = blotter.open_orders[sid]
|
||||
self.assertIsNotNone(order_lists)
|
||||
self.assertEqual(1, len(order_lists))
|
||||
|
||||
aapl_order = blotter.open_orders[1][0].to_dict()
|
||||
fls_order = blotter.open_orders[2][0].to_dict()
|
||||
|
||||
# make sure the aapl order didn't change
|
||||
self.assertEqual(100, aapl_order['amount'])
|
||||
self.assertEqual(10, aapl_order['limit'])
|
||||
self.assertEqual(1, aapl_order['sid'])
|
||||
|
||||
# make sure the fls order did change
|
||||
self.assertEqual(33, fls_order['amount'])
|
||||
self.assertEqual(30, fls_order['limit'])
|
||||
self.assertEqual(2, fls_order['sid'])
|
||||
|
||||
@@ -26,6 +26,7 @@ import itertools
|
||||
import zipline.utils.factory as factory
|
||||
import zipline.finance.performance as perf
|
||||
from zipline.finance.slippage import Transaction, create_transaction
|
||||
import zipline.utils.math_utils as zp_math
|
||||
|
||||
from zipline.gens.composites import date_sorted_sources
|
||||
from zipline.finance.trading import SimulationParameters
|
||||
@@ -86,6 +87,62 @@ def calculate_results(host, events):
|
||||
return results
|
||||
|
||||
|
||||
class TestSplitPerformance(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.sim_params, self.dt, self.end_dt = \
|
||||
create_random_simulation_parameters()
|
||||
|
||||
# start with $10,000
|
||||
self.sim_params.capital_base = 10e3
|
||||
|
||||
self.benchmark_events = benchmark_events_in_range(self.sim_params)
|
||||
|
||||
def test_split_long_position(self):
|
||||
with trading.TradingEnvironment() as env:
|
||||
events = factory.create_trade_history(
|
||||
1,
|
||||
[20, 20],
|
||||
[100, 100],
|
||||
oneday,
|
||||
self.sim_params
|
||||
)
|
||||
|
||||
# set up a long position in sid 1
|
||||
# 100 shares at $20 apiece = $2000 position
|
||||
events.insert(0, create_txn(events[0], 20, 100))
|
||||
events.append(factory.create_split(1, 0.33333,
|
||||
env.next_trading_day(events[1].dt)))
|
||||
|
||||
results = calculate_results(self, events)
|
||||
|
||||
# should have 33 shares (at $60 apiece) and $20 in cash
|
||||
self.assertEqual(2, len(results))
|
||||
|
||||
latest_positions = results[1]['daily_perf']['positions']
|
||||
self.assertEqual(1, len(latest_positions))
|
||||
|
||||
# check the last position to make sure it's been updated
|
||||
position = latest_positions[0]
|
||||
|
||||
self.assertEqual(1, position['sid'])
|
||||
self.assertEqual(33, position['amount'])
|
||||
self.assertEqual(60, position['cost_basis'])
|
||||
self.assertEqual(60, position['last_sale_price'])
|
||||
|
||||
# since we started with $10000, and we spent $2000 on the
|
||||
# position, but then got $20 back, we should have $8020
|
||||
# (or close to it) in cash.
|
||||
|
||||
# we won't get exactly 8020 because sometimes a split is
|
||||
# denoted as a ratio like 0.3333, and we lose some digits
|
||||
# of precision. thus, make sure we're pretty close.
|
||||
daily_perf = results[1]['daily_perf']
|
||||
|
||||
self.assertTrue(
|
||||
zp_math.tolerant_equals(8020,
|
||||
daily_perf['ending_cash'], 1))
|
||||
|
||||
|
||||
class TestDividendPerformance(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
Reference in New Issue
Block a user