diff --git a/zipline/lines.py b/zipline/lines.py index d3eceb6e..f9773fd7 100644 --- a/zipline/lines.py +++ b/zipline/lines.py @@ -205,9 +205,18 @@ class SimulatedTrading(object): to :py:class:`zipline.test.client.TestAlgorithm` """ assert isinstance(config, dict) - trading_environment = config['environment'] + allocator = config['allocator'] sid = config['sid'] + + #-------------------- + # Trading Environment + #-------------------- + if config.has_key('environment'): + trading_environment = config['environment'] + else: + trading_environment = factory.create_trading_environment() + if config.has_key('order_count'): order_count = config['order_count'] else: @@ -222,7 +231,7 @@ class SimulatedTrading(object): simulator_class = config['simulator_class'] else: simulator_class = Simulator - + #------------------- # Trade Source #------------------- @@ -279,7 +288,7 @@ class SimulatedTrading(object): after the simulation has begun.") def get_cumulative_performance(self): - self.trading_client.perf.cumulative_performance.to_dict() + return self.trading_client.perf.cumulative_performance.to_dict() def allocate_sockets(self, n): """ diff --git a/zipline/test/factory.py b/zipline/test/factory.py index 2fd61f06..31f6b3af 100644 --- a/zipline/test/factory.py +++ b/zipline/test/factory.py @@ -1,18 +1,23 @@ -import datetime +""" +Factory functions to prepare useful data for tests. +""" import pytz import msgpack import random + +from datetime import datetime, timedelta import zipline.util as qutil import zipline.finance.risk as risk import zipline.protocol as zp from zipline.sources import SpecificEquityTrades +from zipline.finance.trading import TradingEnvironment def load_market_data(): fp_bm = open("./zipline/test/benchmark.msgpack", "rb") bm_map = msgpack.loads(fp_bm.read()) bm_returns = [] for epoch, returns in bm_map.iteritems(): - event_dt = datetime.datetime.fromtimestamp(epoch) + event_dt = datetime.fromtimestamp(epoch) event_dt = event_dt.replace( hour=0, minute=0, @@ -27,13 +32,26 @@ def load_market_data(): tr_map = msgpack.loads(fp_tr.read()) tr_curves = {} for epoch, curve in tr_map.iteritems(): - tr_dt = datetime.datetime.fromtimestamp(epoch) + tr_dt = datetime.fromtimestamp(epoch) tr_dt = tr_dt.replace(hour=0, minute=0, second=0, tzinfo=pytz.utc) tr_curves[tr_dt] = curve return bm_returns, tr_curves +def create_trading_environment(): + """Construct a complete environment with reasonable defaults""" + benchmark_returns, treasury_curves = load_market_data() + start = datetime.strptime("01/01/2006","%m/%d/%Y") + start = start.replace(tzinfo=pytz.utc) + trading_environment = TradingEnvironment( + benchmark_returns, + treasury_curves, + period_start = start, + capital_base = 100000.0 + ) + + return trading_environment def create_trade(sid, price, amount, datetime): row = zp.namedict({ 'source_id' : "test_factory", @@ -58,7 +76,7 @@ def create_trade_history(sid, prices, amounts, start_time, interval, trading_cal current = current + interval else: - current = current + datetime.timedelta(days=1) + current = current + timedelta(days=1) return trades @@ -82,7 +100,7 @@ def create_txn_history(sid, priceList, amtList, startTime, interval, trading_cal current = current + interval else: - current = current + datetime.timedelta(days=1) + current = current + timedelta(days=1) return txns @@ -91,7 +109,7 @@ def create_returns(daycount, start, trading_calendar): i = 0 test_range = [] current = start.replace(tzinfo=pytz.utc) - one_day = datetime.timedelta(days = 1) + one_day = timedelta(days = 1) while i < daycount: i += 1 r = risk.DailyReturn(current, random.random()) @@ -103,7 +121,7 @@ def create_returns(daycount, start, trading_calendar): def create_returns_from_range(start, end, trading_calendar): current = start.replace(tzinfo=pytz.utc) end = end.replace(tzinfo=pytz.utc) - one_day = datetime.timedelta(days = 1) + one_day = timedelta(days = 1) test_range = [] i = 0 while current <= end: @@ -118,7 +136,7 @@ def create_returns_from_range(start, end, trading_calendar): def create_returns_from_list(returns, start, trading_calendar): current = start.replace(tzinfo=pytz.utc) - one_day = datetime.timedelta(days = 1) + one_day = timedelta(days = 1) test_range = [] i = 0 while len(test_range) < len(returns): @@ -144,7 +162,7 @@ def create_daily_trade_source(sids, trade_count, trading_environment): price = [10.1] * trade_count volume = [100] * trade_count start_date = trading_environment.period_start - trade_time_increment = datetime.timedelta(days=1) + trade_time_increment = timedelta(days=1) generated_trades = create_trade_history( sid, diff --git a/zipline/test/test_finance.py b/zipline/test/test_finance.py index 0e2bce14..ea080d8b 100644 --- a/zipline/test/test_finance.py +++ b/zipline/test/test_finance.py @@ -32,129 +32,11 @@ class FinanceTestCase(TestCase): def setUp(self): qutil.configure_logging() - self.benchmark_returns, self.treasury_curves = \ - factory.load_market_data() - - start = datetime.strptime("01/1/2006","%m/%d/%Y") - start = start.replace(tzinfo=pytz.utc) - self.trading_environment = TradingEnvironment( - self.benchmark_returns, - self.treasury_curves, - period_start = start, - capital_base = 100000.0 - ) - - self.allocator = allocator - self.zipline_test_config = { - 'allocator':self.allocator, - 'sid':133, - 'environment':self.trading_environment + 'allocator':allocator, + 'sid':133 } - @timed(DEFAULT_TIMEOUT) - def test_trade_feed_protocol(self): - - sid = 133 - price = [10.0] * 4 - volume = [100] * 4 - - start_date = datetime.strptime("02/15/2012","%m/%d/%Y") - one_day_td = timedelta(days=1) - - trades = factory.create_trade_history( - sid, - price, - volume, - start_date, - one_day_td, - self.trading_environment - ) - - for trade in trades: - #simulate data source sending frame - msg = zp.DATASOURCE_FRAME(zp.namedict(trade)) - #feed unpacking frame - recovered_trade = zp.DATASOURCE_UNFRAME(msg) - #feed sending frame - feed_msg = zp.FEED_FRAME(recovered_trade) - #transform unframing - recovered_feed = zp.FEED_UNFRAME(feed_msg) - #do a transform - trans_msg = zp.TRANSFORM_FRAME('helloworld', 2345.6) - #simulate passthrough transform -- passthrough shouldn't even - # unpack the msg, just resend. - - passthrough_msg = zp.TRANSFORM_FRAME(zp.TRANSFORM_TYPE.PASSTHROUGH,\ - feed_msg) - - #merge unframes transform and passthrough - trans_recovered = zp.TRANSFORM_UNFRAME(trans_msg) - pt_recovered = zp.TRANSFORM_UNFRAME(passthrough_msg) - #simulated merge - pt_recovered.PASSTHROUGH.merge(trans_recovered) - #frame the merged event - merged_msg = zp.MERGE_FRAME(pt_recovered.PASSTHROUGH) - #unframe the merge and validate values - event = zp.MERGE_UNFRAME(merged_msg) - - #check the transformed value, should only be in event, not trade. - self.assertTrue(event.helloworld == 2345.6) - event.delete('helloworld') - - self.assertEqual(zp.namedict(trade), event) - - @timed(DEFAULT_TIMEOUT) - def test_order_protocol(self): - #client places an order - now = datetime.utcnow().replace(tzinfo=pytz.utc) - order = zp.namedict({ - 'dt':now, - 'sid':133, - 'amount':100 - }) - order_msg = zp.ORDER_FRAME(order) - - #order datasource receives - order = zp.ORDER_UNFRAME(order_msg) - self.assertEqual(order.sid, 133) - self.assertEqual(order.amount, 100) - self.assertEqual(order.dt, now) - - #order datasource datasource frames the order - order_event = zp.namedict({ - "sid" : order.sid, - "amount" : order.amount, - "dt" : order.dt, - "source_id" : zp.FINANCE_COMPONENT.ORDER_SOURCE, - "type" : zp.DATASOURCE_TYPE.ORDER - }) - - - order_ds_msg = zp.DATASOURCE_FRAME(order_event) - - #transaction transform unframes - recovered_order = zp.DATASOURCE_UNFRAME(order_ds_msg) - - self.assertEqual(now, recovered_order.dt) - - #create a transaction from the order - txn = zp.namedict({ - 'sid' : recovered_order.sid, - 'amount' : recovered_order.amount, - 'dt' : recovered_order.dt, - 'price' : 10.0, - 'commission' : 0.50 - }) - - #frame that transaction - txn_msg = zp.TRANSFORM_FRAME(zp.TRANSFORM_TYPE.TRANSACTION, txn) - - #unframe - recovered_tx = zp.TRANSFORM_UNFRAME(txn_msg).TRANSACTION - self.assertEqual(recovered_tx.sid, 133) - self.assertEqual(recovered_tx.amount, 100) - @timed(DEFAULT_TIMEOUT) def test_orders(self): # Simulation diff --git a/zipline/test/test_protocol.py b/zipline/test/test_protocol.py new file mode 100644 index 00000000..aaa470f7 --- /dev/null +++ b/zipline/test/test_protocol.py @@ -0,0 +1,130 @@ +""" +Test the FRAME/UNFRAME functions in the sequence expected from ziplines. +""" +import pytz + +from unittest2 import TestCase +from datetime import datetime, timedelta +from collections import defaultdict + +from nose.tools import timed + +import zipline.test.factory as factory +import zipline.util as qutil +import zipline.protocol as zp + +from zipline.sources import SpecificEquityTrades + +DEFAULT_TIMEOUT = 5 # seconds + +class ProtocolTestCase(TestCase): + + leased_sockets = defaultdict(list) + + def setUp(self): + qutil.configure_logging() + self.trading_environment = factory.create_trading_environment() + + @timed(DEFAULT_TIMEOUT) + def test_trade_feed_protocol(self): + + sid = 133 + price = [10.0] * 4 + volume = [100] * 4 + + start_date = datetime.strptime("02/15/2012","%m/%d/%Y") + one_day_td = timedelta(days=1) + + trades = factory.create_trade_history( + sid, + price, + volume, + start_date, + one_day_td, + self.trading_environment + ) + + for trade in trades: + #simulate data source sending frame + msg = zp.DATASOURCE_FRAME(zp.namedict(trade)) + #feed unpacking frame + recovered_trade = zp.DATASOURCE_UNFRAME(msg) + #feed sending frame + feed_msg = zp.FEED_FRAME(recovered_trade) + #transform unframing + recovered_feed = zp.FEED_UNFRAME(feed_msg) + #do a transform + trans_msg = zp.TRANSFORM_FRAME('helloworld', 2345.6) + #simulate passthrough transform -- passthrough shouldn't even + # unpack the msg, just resend. + + passthrough_msg = zp.TRANSFORM_FRAME(zp.TRANSFORM_TYPE.PASSTHROUGH,\ + feed_msg) + + #merge unframes transform and passthrough + trans_recovered = zp.TRANSFORM_UNFRAME(trans_msg) + pt_recovered = zp.TRANSFORM_UNFRAME(passthrough_msg) + #simulated merge + pt_recovered.PASSTHROUGH.merge(trans_recovered) + #frame the merged event + merged_msg = zp.MERGE_FRAME(pt_recovered.PASSTHROUGH) + #unframe the merge and validate values + event = zp.MERGE_UNFRAME(merged_msg) + + #check the transformed value, should only be in event, not trade. + self.assertTrue(event.helloworld == 2345.6) + event.delete('helloworld') + + self.assertEqual(zp.namedict(trade), event) + + @timed(DEFAULT_TIMEOUT) + def test_order_protocol(self): + #client places an order + now = datetime.utcnow().replace(tzinfo=pytz.utc) + order = zp.namedict({ + 'dt':now, + 'sid':133, + 'amount':100 + }) + order_msg = zp.ORDER_FRAME(order) + + #order datasource receives + order = zp.ORDER_UNFRAME(order_msg) + self.assertEqual(order.sid, 133) + self.assertEqual(order.amount, 100) + self.assertEqual(order.dt, now) + + #order datasource datasource frames the order + order_event = zp.namedict({ + "sid" : order.sid, + "amount" : order.amount, + "dt" : order.dt, + "source_id" : zp.FINANCE_COMPONENT.ORDER_SOURCE, + "type" : zp.DATASOURCE_TYPE.ORDER + }) + + + order_ds_msg = zp.DATASOURCE_FRAME(order_event) + + #transaction transform unframes + recovered_order = zp.DATASOURCE_UNFRAME(order_ds_msg) + + self.assertEqual(now, recovered_order.dt) + + #create a transaction from the order + txn = zp.namedict({ + 'sid' : recovered_order.sid, + 'amount' : recovered_order.amount, + 'dt' : recovered_order.dt, + 'price' : 10.0, + 'commission' : 0.50 + }) + + #frame that transaction + txn_msg = zp.TRANSFORM_FRAME(zp.TRANSFORM_TYPE.TRANSACTION, txn) + + #unframe + recovered_tx = zp.TRANSFORM_UNFRAME(txn_msg).TRANSACTION + self.assertEqual(recovered_tx.sid, 133) + self.assertEqual(recovered_tx.amount, 100) +