mirror of
https://github.com/wassname/catalyst.git
synced 2026-06-28 13:17:43 +08:00
fixes to the calculation of transactions and associated tests for long and short orders.
This commit is contained in:
@@ -357,13 +357,13 @@ for order:
|
||||
order=str(order)
|
||||
)
|
||||
qutil.LOGGER.warn(warning)
|
||||
|
||||
|
||||
orders = [ x for x in orders if x.amount - x.filled > 0 and x.dt.day >= event.dt.day]
|
||||
|
||||
orders = [ x for x in orders if abs(x.amount - x.filled) > 0 and x.dt.day >= event.dt.day]
|
||||
|
||||
self.open_orders[event.sid] = orders
|
||||
|
||||
|
||||
if simulated_amount > 0:
|
||||
if simulated_amount != 0:
|
||||
return self.create_transaction(
|
||||
event.sid,
|
||||
simulated_amount,
|
||||
|
||||
+11
-11
@@ -191,16 +191,16 @@ class SimulatedTrading(object):
|
||||
- sid - an integer, which will be used as the security ID.
|
||||
- order_count - the number of orders the test algo will place,
|
||||
defaults to 100
|
||||
- order_amount - the number of shares per order, defaults to 100
|
||||
- trade_count - the number of trades to simulate, defaults to 100
|
||||
- simulator_class - optional parameter that provides an alternative
|
||||
subclass of ComponentHost to hold the whole zipline. Defaults to
|
||||
:py:class:`zipline.simulator.Simulator`
|
||||
- algorithm - optional parameter providing an algorithm. defaults
|
||||
to :py:class:`zipline.test.algorithms.TestAlgorithm`
|
||||
- random - optional parameter to request random trades. if present
|
||||
:py:class:`zipline.sources.RandomEquityTrades` is the source. If
|
||||
not :py:class:`ziplien.sources.SpecificEquityTrades` is the
|
||||
source
|
||||
- trade_source - optional parameter to specify trades, if present.
|
||||
If not present :py:class:`ziplien.sources.SpecificEquityTrades`
|
||||
is the source, with daily frequency in trades.
|
||||
"""
|
||||
assert isinstance(config, dict)
|
||||
|
||||
@@ -219,6 +219,11 @@ class SimulatedTrading(object):
|
||||
order_count = config['order_count']
|
||||
else:
|
||||
order_count = 100
|
||||
|
||||
if config.has_key('order_amount'):
|
||||
order_amount = config['order_amount']
|
||||
else:
|
||||
order_amount = 100
|
||||
|
||||
if config.has_key('trade_count'):
|
||||
trade_count = config['trade_count']
|
||||
@@ -235,12 +240,8 @@ class SimulatedTrading(object):
|
||||
#-------------------
|
||||
sids = [sid]
|
||||
#-------------------
|
||||
if config.has_key('random'):
|
||||
trade_source = factory.create_random_trade_source(
|
||||
sids,
|
||||
trade_count,
|
||||
trading_environment
|
||||
)
|
||||
if config.has_key('trade_source'):
|
||||
trade_source = config['trade_source']
|
||||
else:
|
||||
trade_source = factory.create_daily_trade_source(
|
||||
sids,
|
||||
@@ -253,7 +254,6 @@ class SimulatedTrading(object):
|
||||
if config.has_key('algorithm'):
|
||||
test_algo = config['algorithm']
|
||||
else:
|
||||
order_amount = 100
|
||||
test_algo = TestAlgorithm(
|
||||
sid,
|
||||
order_amount,
|
||||
|
||||
@@ -76,8 +76,8 @@ class TestAlgorithm():
|
||||
self.incr += 1
|
||||
|
||||
def get_sid_filter(self):
|
||||
return [self.sid]
|
||||
|
||||
return [self.sid]
|
||||
|
||||
class NoopAlgorithm(object):
|
||||
"""
|
||||
Dolce fa niente.
|
||||
|
||||
+28
-1
@@ -167,6 +167,7 @@ def create_random_trade_source(sid, trade_count, trading_environment):
|
||||
return source
|
||||
|
||||
def create_daily_trade_source(sids, trade_count, trading_environment):
|
||||
|
||||
"""
|
||||
creates trade_count trades for each sid in sids list.
|
||||
first trade will be on trading_environment.period_start, and daily
|
||||
@@ -176,12 +177,38 @@ def create_daily_trade_source(sids, trade_count, trading_environment):
|
||||
Important side-effect: trading_environment.period_end will be modified
|
||||
to match the day of the final trade.
|
||||
"""
|
||||
return create_trade_source(
|
||||
sids,
|
||||
trade_count,
|
||||
timedelta(days=1),
|
||||
trading_environment
|
||||
)
|
||||
|
||||
|
||||
def create_minutely_trade_source(sids, trade_count, trading_environment):
|
||||
|
||||
"""
|
||||
creates trade_count trades for each sid in sids list.
|
||||
first trade will be on trading_environment.period_start, and every minute
|
||||
thereafter for each sid. Thus, two sids should result in two trades per
|
||||
minute.
|
||||
|
||||
Important side-effect: trading_environment.period_end will be modified
|
||||
to match the day of the final trade.
|
||||
"""
|
||||
return create_trade_source(
|
||||
sids,
|
||||
trade_count,
|
||||
timedelta(minutes=1),
|
||||
trading_environment
|
||||
)
|
||||
|
||||
def create_trade_source(sids, trade_count, trade_time_increment, trading_environment):
|
||||
trade_history = []
|
||||
for sid in sids:
|
||||
price = [10.1] * trade_count
|
||||
volume = [100] * trade_count
|
||||
start_date = trading_environment.first_open
|
||||
trade_time_increment = timedelta(days=1)
|
||||
|
||||
generated_trades = create_trade_history(
|
||||
sid,
|
||||
|
||||
@@ -24,6 +24,7 @@ from zipline.lines import SimulatedTrading
|
||||
from zipline.protocol_utils import namedict
|
||||
|
||||
DEFAULT_TIMEOUT = 15 # seconds
|
||||
EXTENDED_TIMEOUT = 90
|
||||
|
||||
allocator = AddressAllocator(1000)
|
||||
|
||||
@@ -121,6 +122,38 @@ class FinanceTestCase(TestCase):
|
||||
.format(n=zipline.sim.feed.pending_messages()))
|
||||
|
||||
|
||||
|
||||
@timed(EXTENDED_TIMEOUT)
|
||||
def test_aggressive_buying(self):
|
||||
|
||||
# Simulation
|
||||
# ----------
|
||||
trade_count = 10 * 1000
|
||||
self.zipline_test_config['order_count'] = 5 * 1000
|
||||
self.zipline_test_config['trade_count'] = trade_count
|
||||
self.zipline_test_config['order_amount'] = 100
|
||||
self.zipline_test_config['environment'] = factory.create_trading_environment()
|
||||
|
||||
sid_list = [self.zipline_test_config['sid']]
|
||||
|
||||
self.zipline_test_config['trade_source'] = factory.create_minutely_trade_source(
|
||||
sid_list,
|
||||
trade_count,
|
||||
self.zipline_test_config['environment']
|
||||
)
|
||||
|
||||
zipline = SimulatedTrading.create_test_zipline(**self.zipline_test_config)
|
||||
zipline.simulate(blocking=True)
|
||||
|
||||
self.assertTrue(zipline.sim.ready())
|
||||
self.assertFalse(zipline.sim.exception)
|
||||
|
||||
# TODO: Make more assertions about the final state of the components.
|
||||
self.assertEqual(zipline.sim.feed.pending_messages(), 0, \
|
||||
"The feed should be drained of all messages, found {n} remaining." \
|
||||
.format(n=zipline.sim.feed.pending_messages()))
|
||||
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_performance(self):
|
||||
#provide enough trades to ensure all orders are filled.
|
||||
@@ -218,9 +251,11 @@ class FinanceTestCase(TestCase):
|
||||
)
|
||||
|
||||
|
||||
# TODO: write a test that proves orders expire without being filled.
|
||||
# TODO: write tests for short sales
|
||||
# TODO: write a test to do massive buying or shorting.
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_transaction_sim(self):
|
||||
def test_partially_filled_orders(self):
|
||||
|
||||
# create a scenario where order size and trade size are equal
|
||||
# so that orders must be spread out over several trades.
|
||||
@@ -240,9 +275,25 @@ class FinanceTestCase(TestCase):
|
||||
|
||||
self.transaction_sim(**params)
|
||||
|
||||
# same scenario, but with short sales
|
||||
params2 ={
|
||||
'trade_count':360,
|
||||
'trade_amount':100,
|
||||
'trade_interval': timedelta(minutes=1),
|
||||
'order_count':2,
|
||||
'order_amount':-100,
|
||||
'order_interval': timedelta(minutes=1),
|
||||
'expected_txn_count':8,
|
||||
'expected_txn_volume':2 * -100
|
||||
}
|
||||
|
||||
self.transaction_sim(**params2)
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_collapsing_orders(self):
|
||||
# create a scenario where order.amount <<< trade.volume
|
||||
# to test that several orders can be covered properly by one trade.
|
||||
params2 ={
|
||||
params1 ={
|
||||
'trade_count':6,
|
||||
'trade_amount':100,
|
||||
'trade_interval': timedelta(hours=1),
|
||||
@@ -254,11 +305,26 @@ class FinanceTestCase(TestCase):
|
||||
'expected_txn_count':1,
|
||||
'expected_txn_volume':24 * 1
|
||||
}
|
||||
self.transaction_sim(**params2)
|
||||
self.transaction_sim(**params1)
|
||||
|
||||
# second verse, same as the first. except short!
|
||||
params2 ={
|
||||
'trade_count':6,
|
||||
'trade_amount':100,
|
||||
'trade_interval': timedelta(hours=1),
|
||||
'order_count':24,
|
||||
'order_amount':-1,
|
||||
'order_interval': timedelta(minutes=1),
|
||||
'expected_txn_count':1,
|
||||
'expected_txn_volume':24 * -1
|
||||
}
|
||||
self.transaction_sim(**params2)
|
||||
|
||||
@timed(DEFAULT_TIMEOUT)
|
||||
def test_partial_expiration_orders(self):
|
||||
# create a scenario where orders expire without being filled
|
||||
# entirely
|
||||
params3 = {
|
||||
params1 = {
|
||||
'trade_count':100,
|
||||
'trade_amount':100,
|
||||
'trade_delay': timedelta(minutes=5),
|
||||
@@ -271,7 +337,25 @@ class FinanceTestCase(TestCase):
|
||||
'expected_txn_count' : 1,
|
||||
'expected_txn_volume' : 25
|
||||
}
|
||||
self.transaction_sim(**params3)
|
||||
self.transaction_sim(**params1)
|
||||
|
||||
# same scenario, but short sales.
|
||||
params2 = {
|
||||
'trade_count':100,
|
||||
'trade_amount':100,
|
||||
'trade_delay': timedelta(minutes=5),
|
||||
'trade_interval': timedelta(days=1),
|
||||
'order_count':3,
|
||||
'order_amount':1000,
|
||||
'order_interval': timedelta(minutes=30),
|
||||
# because we placed an orders totaling less than 25% of one trade
|
||||
# the simulator should produce just one transaction.
|
||||
'expected_txn_count' : 1,
|
||||
'expected_txn_volume' : 25
|
||||
}
|
||||
self.transaction_sim(**params2)
|
||||
|
||||
|
||||
|
||||
def transaction_sim(self, **params):
|
||||
trade_count = params['trade_count']
|
||||
|
||||
@@ -22,8 +22,15 @@ class PerformanceTestCase(unittest.TestCase):
|
||||
0,
|
||||
len(self.treasury_curves)
|
||||
)
|
||||
self.dt = self.treasury_curves.keys()[random_index]
|
||||
self.end_dt = self.dt + datetime.timedelta(days=365)
|
||||
for n in range(100):
|
||||
self.dt = self.treasury_curves.keys()[random_index]
|
||||
self.end_dt = self.dt + datetime.timedelta(days=365)
|
||||
|
||||
now = datetime.datetime.utcnow().replace(tzinfo=pytz.utc)
|
||||
|
||||
if self.end_dt <= now:
|
||||
break
|
||||
|
||||
self.trading_environment = TradingEnvironment(
|
||||
self.benchmark_returns,
|
||||
self.treasury_curves,
|
||||
@@ -505,8 +512,6 @@ shares in position"
|
||||
price = 10.1
|
||||
price_list = [price] * trade_count
|
||||
volume = [100] * trade_count
|
||||
#start_date = datetime.datetime.strptime("01/01/2011","%m/%d/%Y")
|
||||
#start_date = start_date.replace(tzinfo=pytz.utc)
|
||||
trade_time_increment = datetime.timedelta(days=1)
|
||||
trade_history = factory.create_trade_history(
|
||||
sid,
|
||||
|
||||
Reference in New Issue
Block a user