def __init__(self, data_frequency, equity_slippage=None, future_slippage=None, equity_commission=None, future_commission=None, cancel_policy=None): # these orders are aggregated by asset self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # holding orders that have come in since the last event. self.new_orders = [] self.current_dt = None self.max_shares = int(1e+11) self.slippage_models = { Equity: equity_slippage or VolumeShareSlippage(), Future: future_slippage or VolumeShareSlippage(), } self.commission_models = { Equity: equity_commission or PerShare(), Future: future_commission or PerTrade(cost=DEFAULT_FUTURE_COST_PER_TRADE, ), } self.data_frequency = data_frequency self.cancel_policy = cancel_policy if cancel_policy else NeverCancel()
def test_orders_stop(self, name, order_data, event_data, expected): data = order_data data['asset'] = self.ASSET133 order = Order(**data) if expected['transaction']: expected['transaction']['asset'] = self.ASSET133 event_data['asset'] = self.ASSET133 assets = ( (133, pd.DataFrame( { 'open': [event_data['open']], 'high': [event_data['high']], 'low': [event_data['low']], 'close': [event_data['close']], 'volume': [event_data['volume']], }, index=[pd.Timestamp('2006-01-05 14:31', tz='UTC')], )), ) days = pd.date_range( start=normalize_date(self.minutes[0]), end=normalize_date(self.minutes[-1]) ) with tmp_bcolz_equity_minute_bar_reader( self.trading_calendar, days, assets) as reader: data_portal = DataPortal( self.env.asset_finder, self.trading_calendar, first_trading_day=reader.first_trading_day, equity_minute_reader=reader, ) slippage_model = VolumeShareSlippage() try: dt = pd.Timestamp('2006-01-05 14:31', tz='UTC') bar_data = BarData( data_portal, lambda: dt, self.sim_params.data_frequency, self.trading_calendar, NoRestrictions(), ) _, txn = next(slippage_model.simulate( bar_data, self.ASSET133, [order], )) except StopIteration: txn = None if expected['transaction'] is None: self.assertIsNone(txn) else: self.assertIsNotNone(txn) for key, value in expected['transaction'].items(): self.assertEquals(value, txn[key])
def test_volume_share_slippage(self): slippage_model = VolumeShareSlippage() open_orders = [ Order(dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list( slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.0001875), 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(5), 'sid': int(133), 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__) open_orders = [ Order(dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133) ] # Set bar_data to be a minute ahead of last trade. # Volume share slippage should not execute when there is no trade. bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list( slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0)
def test_orders_stop(self, name, order_data, event_data, expected): tempdir = TempDirectory() try: data = order_data data['sid'] = self.ASSET133 order = Order(**data) assets = { 133: pd.DataFrame({ "open": [event_data["open"]], "high": [event_data["high"]], "low": [event_data["low"]], "close": [event_data["close"]], "volume": [event_data["volume"]], "dt": [pd.Timestamp('2006-01-05 14:31', tz='UTC')] }).set_index("dt") } write_bcolz_minute_data( self.env, pd.date_range( start=normalize_date(self.minutes[0]), end=normalize_date(self.minutes[-1]) ), tempdir.path, assets ) equity_minute_reader = BcolzMinuteBarReader(tempdir.path) data_portal = DataPortal( self.env, equity_minute_reader=equity_minute_reader, ) slippage_model = VolumeShareSlippage() try: dt = pd.Timestamp('2006-01-05 14:31', tz='UTC') bar_data = BarData(data_portal, lambda: dt, 'minute') _, txn = next(slippage_model.simulate( bar_data, self.ASSET133, [order], )) except StopIteration: txn = None if expected['transaction'] is None: self.assertIsNone(txn) else: self.assertIsNotNone(txn) for key, value in expected['transaction'].items(): self.assertEquals(value, txn[key]) finally: tempdir.cleanup()
def test_orders_stop(self, name, order_data, event_data, expected): data = order_data data['asset'] = self.ASSET133 order = Order(**data) if expected['transaction']: expected['transaction']['asset'] = self.ASSET133 event_data['asset'] = self.ASSET133 assets = ( (133, pd.DataFrame( { 'open': [event_data['open']], 'high': [event_data['high']], 'low': [event_data['low']], 'close': [event_data['close']], 'volume': [event_data['volume']], }, index=[pd.Timestamp('2006-01-05 14:31', tz='UTC')], )), ) days = pd.date_range( start=normalize_date(self.minutes[0]), end=normalize_date(self.minutes[-1]) ) with tmp_bcolz_equity_minute_bar_reader( self.trading_calendar, days, assets) as reader: data_portal = DataPortal( self.env.asset_finder, self.trading_calendar, first_trading_day=reader.first_trading_day, equity_minute_reader=reader, ) slippage_model = VolumeShareSlippage() try: dt = pd.Timestamp('2006-01-05 14:31', tz='UTC') bar_data = BarData( data_portal, lambda: dt, self.sim_params.data_frequency, self.trading_calendar, NoRestrictions(), ) _, txn = next(slippage_model.simulate( bar_data, self.ASSET133, [order], )) except StopIteration: txn = None if expected['transaction'] is None: self.assertIsNone(txn) else: self.assertIsNotNone(txn) for key, value in expected['transaction'].items(): self.assertEquals(value, txn[key])
def test_volume_share_slippage(self): event = ndict({ 'volume': 200, 'TRANSACTION': None, 'type': 4, 'price': 3.0, 'datetime': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'high': 3.15, 'low': 2.85, 'sid': 133, 'source_id': 'test_source', 'close': 3.0, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'open': 3.0 }) slippage_model = VolumeShareSlippage() open_orders = { 133: [ ndict({ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133 }) ] } txn = slippage_model.simulate(event, open_orders) expected_txn = { 'price': float(3.01875), 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_volume_share_slippage(self): event = Event({ 'volume': 200, 'type': 4, 'price': 3.0, 'datetime': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'high': 3.15, 'low': 2.85, 'sid': 133, 'source_id': 'test_source', 'close': 3.0, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'open': 3.0 }) slippage_model = VolumeShareSlippage() open_orders = [ Order( **{ 'dt': datetime.datetime( 2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133 }) ] orders_txns = list(slippage_model.simulate(event, open_orders)) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.01875), 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133), 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__)
def test_equality_and_comparison(self): vol1 = VolumeShareSlippage(volume_limit=0.2) vol2 = VolumeShareSlippage(volume_limit=0.2) self.assertEqual(vol1, vol2) self.assertEqual(hash(vol1), hash(vol2)) self.assertEqual(vol1.__dict__, vol1.asdict()) self.assertEqual(vol2.__dict__, vol2.asdict())
def test_volume_share_slippage(self): event = Event( {'volume': 200, 'type': 4, 'price': 3.0, 'datetime': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'high': 3.15, 'low': 2.85, 'sid': 133, 'source_id': 'test_source', 'close': 3.0, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'open': 3.0} ) slippage_model = VolumeShareSlippage() open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133}) ] orders_txns = list(slippage_model.simulate( event, open_orders )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.01875), 'dt': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133), 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__)
def __init__(self, *args, **kwargs): """ Initialize sids and other state variables. """ self.done = False self.order = None self.frame_count = 0 self._portfolio = None self.datetime = None self.registered_transforms = {} self.transforms = [] self.sources = [] self.logger = None # default components for transact self.slippage = VolumeShareSlippage() self.commission = PerShare() # an algorithm subclass needs to set initialized to True # when it is fully initialized. self.initialized = False # call to user-defined constructor method self.initialize(*args, **kwargs)
def __init__(self, data_frequency, asset_finder, slippage_func=None, commission=None, cancel_policy=None): # these orders are aggregated by sid self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # all our legacy order management code works with integer sids. # this lets us convert those to assets when needed. ideally, we'd just # revamp all the legacy code to work with assets. self.asset_finder = asset_finder # holding orders that have come in since the last event. self.new_orders = [] self.current_dt = None self.max_shares = int(1e+11) self.slippage_func = slippage_func or VolumeShareSlippage() self.commission = commission or PerShare() self.data_frequency = data_frequency self.cancel_policy = cancel_policy if cancel_policy else NeverCancel()
def initialize(context): """ Initialization and trading logic """ # Set comission and slippage if enable_commission: comm_model = PerDollar(cost=commission_pct) else: comm_model = PerDollar(cost=0.0) set_commission(comm_model) if enable_slippage: slippage_model = VolumeShareSlippage( volume_limit=slippage_volume_limit, price_impact=slippage_impact) else: slippage_model = FixedSlippage(spread=0.0) # Used only for progress output context.last_month = initial_portfolio # Store index membership context.index_members = pd.read_csv('./data/sp500_members.csv', index_col=0, parse_dates=[0]) # Schedule rebalance monthly schedule_function(func=rebalance, date_rule=date_rules.month_start(), time_rule=time_rules.market_open())
def test_volume_share_slippage(self): event = ndict( {'volume': 200, 'TRANSACTION': None, 'type': 4, 'price': 3.0, 'datetime': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'high': 3.15, 'low': 2.85, 'sid': 133, 'source_id': 'test_source', 'close': 3.0, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'open': 3.0} ) slippage_model = VolumeShareSlippage() open_orders = {133: [ ndict( {'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133}) ]} txn = slippage_model.simulate( event, open_orders ) expected_txn = { 'price': float(3.01875), 'dt': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def __init__(self, *args, **kwargs): """Initialize sids and other state variables. :Arguments: data_frequency : str (daily, hourly or minutely) The duration of the bars. annualizer : int <optional> Which constant to use for annualizing risk metrics. If not provided, will extract from data_frequency. capital_base : float <default: 1.0e5> How much capital to start with. """ self._portfolio = None self.datetime = None self.registered_transforms = {} self.transforms = [] self.sources = [] self._recorded_vars = {} self.logger = None self.benchmark_return_source = None # default components for transact self.slippage = VolumeShareSlippage() self.commission = PerShare() if 'data_frequency' in kwargs: self.set_data_frequency(kwargs.pop('data_frequency')) else: self.data_frequency = None self.instant_fill = kwargs.pop('instant_fill', False) # Override annualizer if set if 'annualizer' in kwargs: self.annualizer = kwargs['annualizer'] # set the capital base self.capital_base = kwargs.pop('capital_base', DEFAULT_CAPITAL_BASE) self.sim_params = kwargs.pop('sim_params', None) if self.sim_params: self.sim_params.data_frequency = self.data_frequency self.blotter = kwargs.pop('blotter', None) if not self.blotter: self.blotter = Blotter() # an algorithm subclass needs to set initialized to True when # it is fully initialized. self.initialized = False # call to user-defined constructor method self.initialize(*args, **kwargs)
def test_orders_stop(self, name, order_data, event_data, expected): order = Order(**order_data) event = Event(initial_values=event_data) slippage_model = VolumeShareSlippage() try: _, txn = slippage_model.simulate(event, [order]).next() except StopIteration: txn = None if expected['transaction'] is None: self.assertIsNone(txn) else: self.assertIsNotNone(txn) for key, value in expected['transaction'].items(): self.assertEquals(value, txn[key])
def __init__(self): self.transact = transact_partial(VolumeShareSlippage(), PerShare()) # these orders are aggregated by sid self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # holding orders that have come in since the last # event. self.new_orders = []
def initialize_testing_algo(self, context): set_commission(PerShare()) set_slippage(VolumeShareSlippage()) if self.syms is None: self.syms = self.__validate_symbols__(self.ticker_syms) self.portfolio_memory = PortfolioMemory(len(self.syms), self.config.n_history) schedule_function(self.testing_rebalance, date_rule=date_rules.month_start(), time_rule=time_rules.market_open(minutes=1))
def __init__(self): self.transact = transact_partial(VolumeShareSlippage(), OrderCost()) # these orders are aggregated by sid self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # holding orders that have come in since the last # event. self.new_orders = [] self.current_dt = None self.max_shares = int(1e+11)
def test_volume_share_slippage_with_future(self): slippage_model = VolumeShareSlippage(volume_limit=1, price_impact=0.3) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=10, filled=0, asset=self.ASSET1000, ), ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list( slippage_model.simulate(bar_data, self.ASSET1000, open_orders) ) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] # We expect to fill the order for all 10 contracts. The volume for the # futures contract in this bar is 100, so our volume share is: # 10.0 / 100 = 0.1 # The current price is 5.0 and the price impact is 0.3, so the expected # impacted price is: # 5.0 + (5.0 * (0.1 ** 2) * 0.3) = 5.015 expected_txn = { 'price': 5.015, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': 10, 'asset': self.ASSET1000, 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id, } self.assertIsNotNone(txn) self.assertEquals(expected_txn, txn.__dict__)
def test_volume_share_slippage_with_future(self): slippage_model = VolumeShareSlippage(volume_limit=1, price_impact=0.3) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=10, filled=0, asset=self.ASSET1000, ), ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list( slippage_model.simulate(bar_data, self.ASSET1000, open_orders) ) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] # We expect to fill the order for all 10 contracts. The volume for the # futures contract in this bar is 100, so our volume share is: # 10.0 / 100 = 0.1 # The current price is 5.0 and the price impact is 0.3, so the expected # impacted price is: # 5.0 + (5.0 * (0.1 ** 2) * 0.3) = 5.015 expected_txn = { 'price': 5.015, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': 10, 'asset': self.ASSET1000, 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id, } self.assertIsNotNone(txn) self.assertEquals(expected_txn, txn.__dict__)
def __init__(self, data_frequency, asset_finder, equity_slippage=None, future_slippage=None, equity_commission=None, future_commission=None, cancel_policy=None): # these orders are aggregated by sid self.open_orders = defaultdict(list) # keep a dict of orders by their own id self.orders = {} # all our legacy order management code works with integer sids. # this lets us convert those to assets when needed. ideally, we'd just # revamp all the legacy code to work with assets. self.asset_finder = asset_finder # holding orders that have come in since the last event. self.new_orders = [] self.current_dt = None self.max_shares = int(1e+11) self.slippage_models = { Equity: equity_slippage or VolumeShareSlippage(), Future: future_slippage or VolumeShareSlippage(), } self.commission_models = { Equity: equity_commission or PerShare(), Future: future_commission or PerTrade(cost=DEFAULT_FUTURE_COST_PER_TRADE, ), } self.data_frequency = data_frequency self.cancel_policy = cancel_policy if cancel_policy else NeverCancel()
def get_blotter(self): slippage_func = VolumeShareSlippage( volume_limit=1, price_impact=0 ) blotter = MyBlotter( data_frequency=self.sim_params.data_frequency, asset_finder=self.env.asset_finder, slippage_func=slippage_func, # https://github.com/quantopian/zipline/blob/3350227f44dcf36b6fe3c509dcc35fe512965183/tests/test_blotter.py#L136 cancel_policy=NeverCancel() ) return blotter
def test_volume_share_slippage_with_future(self): slippage_model = VolumeShareSlippage(volume_limit=1, price_impact=0.3) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=10, filled=0, asset=self.ASSET1000, ), ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list( slippage_model.simulate(bar_data, self.ASSET1000, open_orders)) assert len(orders_txns) == 1 _, txn = orders_txns[0] # We expect to fill the order for all 10 contracts. The volume for the # futures contract in this bar is 100, so our volume share is: # 10.0 / 100 = 0.1 # The current price is 5.0 and the price impact is 0.3, so the expected # impacted price is: # 5.0 + (5.0 * (0.1 ** 2) * 0.3) = 5.015 expected_txn = { "price": 5.015, "dt": datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), "amount": 10, "asset": self.ASSET1000, "type": DATASOURCE_TYPE.TRANSACTION, "order_id": open_orders[0].id, } assert txn is not None assert expected_txn == txn.__dict__
def test_equality_and_comparison(self): vol1 = VolumeShareSlippage(volume_limit=0.2) vol2 = VolumeShareSlippage(volume_limit=0.2) self.assertEqual(vol1, vol2) self.assertEqual(hash(vol1), hash(vol2)) self.assertEqual(vol1.__dict__, vol1.asdict()) self.assertEqual(vol2.__dict__, vol2.asdict())
def initialize(context): set_slippage(VolumeShareSlippage(volume_limit=0.025,price_impact=0.1)) tickers = ['AYI','APA','AMZN','LNT','CTL','ALB','ABBV','AMT','ADM','AON','ORCL'] context.tick_list = tickers context.tickers = [ symbol(x) for x in tickers ] context.long= False context.short= False start = datetime.datetime(2013,1,3) end = datetime.datetime(2017,8,1) sec_list = SecurityList(tickers=tickers) sec_list.downloadQuandl(start,end) ts = sec_list.genTimeSeries() context.adjDiv = sec_list.adjDividends() context.adjHedge = sec_list.adjSplits() context.divFactors = sec_list.getAdjFactors() context.splits = sec_list.getSplits() context.avg = ts.mean() context.std = ts.std() context.leverage = 1 context.share_num = 0 context.diff_thresh = 100 schedule_function(adjust_splits_dividends, date_rules.every_day(), time_rules.market_open()) schedule_function(place_orders, date_rules.every_day(), time_rules.market_open(hours=1, minutes=30))
def initialize(context): set_slippage(VolumeShareSlippage(volume_limit=0.025, price_impact=0.1)) tickers = [ 'AYI', 'APA', 'AMZN', 'LNT', 'CTL', 'ALB', 'ABBV', 'AMT', 'ADM', 'AON', 'ORCL' ] context.tick_list = tickers context.tickers = [symbol(x) for x in tickers] context.long = False context.short = False start = datetime.datetime(2013, 1, 3) end = datetime.datetime(2017, 8, 1) sec_list = SecurityList(tickers=tickers) sec_list.downloadQuandl(start, end) ts, context.hedgeRatio, context.df_close = sec_list.genTimeSeries() context.adjustedHedge = np.copy(context.hedgeRatio) context.adjustedHedge[3] = context.adjustedHedge[3] / 2 context.avg = ts.mean() context.std = ts.std() context.volume = sec_list.getVolume() context.share_num = 0 context.diff_thresh = 100 schedule_function(place_orders, date_rules.every_day())
def __init__(self, *args, **kwargs): """Initialize sids and other state variables. :Arguments: :Optional: initialize : function Function that is called with a single argument at the begninning of the simulation. handle_data : function Function that is called with 2 arguments (context and data) on every bar. script : str Algoscript that contains initialize and handle_data function definition. data_frequency : str (daily, hourly or minutely) The duration of the bars. capital_base : float <default: 1.0e5> How much capital to start with. instant_fill : bool <default: False> Whether to fill orders immediately or on next bar. """ self.datetime = None self.registered_transforms = {} self.transforms = [] self.sources = [] # List of trading controls to be used to validate orders. self.trading_controls = [] self._recorded_vars = {} self.namespace = kwargs.get('namespace', {}) self.logger = None self.benchmark_return_source = None # default components for transact self.slippage = VolumeShareSlippage() self.commission = PerShare() self.instant_fill = kwargs.pop('instant_fill', False) # set the capital base self.capital_base = kwargs.pop('capital_base', DEFAULT_CAPITAL_BASE) self.sim_params = kwargs.pop('sim_params', None) if self.sim_params is None: self.sim_params = create_simulation_parameters( capital_base=self.capital_base ) self.perf_tracker = PerformanceTracker(self.sim_params) self.blotter = kwargs.pop('blotter', None) if not self.blotter: self.blotter = Blotter() self.portfolio_needs_update = True self._portfolio = None self.history_container = None self.history_specs = {} # If string is passed in, execute and get reference to # functions. self.algoscript = kwargs.pop('script', None) self._initialize = None self._analyze = None if self.algoscript is not None: exec_(self.algoscript, self.namespace) self._initialize = self.namespace.get('initialize', None) if 'handle_data' not in self.namespace: raise ValueError('You must define a handle_data function.') else: self._handle_data = self.namespace['handle_data'] # Optional analyze function, gets called after run self._analyze = self.namespace.get('analyze', None) elif kwargs.get('initialize', False) and kwargs.get('handle_data'): if self.algoscript is not None: raise ValueError('You can not set script and \ initialize/handle_data.') self._initialize = kwargs.pop('initialize') self._handle_data = kwargs.pop('handle_data') # If method not defined, NOOP if self._initialize is None: self._initialize = lambda x: None # Alternative way of setting data_frequency for backwards # compatibility. if 'data_frequency' in kwargs: self.data_frequency = kwargs.pop('data_frequency') # Subclasses that override initialize should only worry about # setting self.initialized = True if AUTO_INITIALIZE is # is manually set to False. self.initialized = False self.initialize(*args, **kwargs) if self.AUTO_INITIALIZE: self.initialized = True
def __init__(self, *args, **kwargs): """Initialize sids and other state variables. :Arguments: :Optional: initialize : function Function that is called with a single argument at the begninning of the simulation. handle_data : function Function that is called with 2 arguments (context and data) on every bar. script : str Algoscript that contains initialize and handle_data function definition. data_frequency : {'daily', 'minute'} The duration of the bars. capital_base : float <default: 1.0e5> How much capital to start with. instant_fill : bool <default: False> Whether to fill orders immediately or on next bar. asset_finder : An AssetFinder object A new AssetFinder object to be used in this TradingEnvironment asset_metadata: can be either: - dict - pandas.DataFrame - object with 'read' property If dict is provided, it must have the following structure: * keys are the identifiers * values are dicts containing the metadata, with the metadata field name as the key If pandas.DataFrame is provided, it must have the following structure: * column names must be the metadata fields * index must be the different asset identifiers * array contents should be the metadata value If an object with a 'read' property is provided, 'read' must return rows containing at least one of 'sid' or 'symbol' along with the other metadata fields. identifiers : List Any asset identifiers that are not provided in the asset_metadata, but will be traded by this TradingAlgorithm """ self.sources = [] # List of trading controls to be used to validate orders. self.trading_controls = [] # List of account controls to be checked on each bar. self.account_controls = [] self._recorded_vars = {} self.namespace = kwargs.get('namespace', {}) self._platform = kwargs.pop('platform', 'zipline') self.logger = None self.benchmark_return_source = None # default components for transact self.slippage = VolumeShareSlippage() self.commission = PerShare() self.instant_fill = kwargs.pop('instant_fill', False) # set the capital base self.capital_base = kwargs.pop('capital_base', DEFAULT_CAPITAL_BASE) self.sim_params = kwargs.pop('sim_params', None) if self.sim_params is None: self.sim_params = create_simulation_parameters( capital_base=self.capital_base, start=kwargs.pop('start', None), end=kwargs.pop('end', None)) self.perf_tracker = PerformanceTracker(self.sim_params) # Update the TradingEnvironment with the provided asset metadata self.trading_environment = kwargs.pop('env', TradingEnvironment.instance()) self.trading_environment.update_asset_finder( asset_finder=kwargs.pop('asset_finder', None), asset_metadata=kwargs.pop('asset_metadata', None), identifiers=kwargs.pop('identifiers', None)) # Pull in the environment's new AssetFinder for quick reference self.asset_finder = self.trading_environment.asset_finder self.init_engine(kwargs.pop('ffc_loader', None)) # Maps from name to Term self._filters = {} self._factors = {} self._classifiers = {} self.blotter = kwargs.pop('blotter', None) if not self.blotter: self.blotter = Blotter() # Set the dt initally to the period start by forcing it to change self.on_dt_changed(self.sim_params.period_start) self.portfolio_needs_update = True self.account_needs_update = True self.performance_needs_update = True self._portfolio = None self._account = None self.history_container_class = kwargs.pop( 'history_container_class', HistoryContainer, ) self.history_container = None self.history_specs = {} # If string is passed in, execute and get reference to # functions. self.algoscript = kwargs.pop('script', None) self._initialize = None self._before_trading_start = None self._analyze = None self.event_manager = EventManager() if self.algoscript is not None: filename = kwargs.pop('algo_filename', None) if filename is None: filename = '<string>' code = compile(self.algoscript, filename, 'exec') exec_(code, self.namespace) self._initialize = self.namespace.get('initialize') if 'handle_data' not in self.namespace: raise ValueError('You must define a handle_data function.') else: self._handle_data = self.namespace['handle_data'] self._before_trading_start = \ self.namespace.get('before_trading_start') # Optional analyze function, gets called after run self._analyze = self.namespace.get('analyze') elif kwargs.get('initialize') and kwargs.get('handle_data'): if self.algoscript is not None: raise ValueError('You can not set script and \ initialize/handle_data.') self._initialize = kwargs.pop('initialize') self._handle_data = kwargs.pop('handle_data') self._before_trading_start = kwargs.pop('before_trading_start', None) self.event_manager.add_event( zipline.utils.events.Event( zipline.utils.events.Always(), # We pass handle_data.__func__ to get the unbound method. # We will explicitly pass the algorithm to bind it again. self.handle_data.__func__, ), prepend=True, ) # If method not defined, NOOP if self._initialize is None: self._initialize = lambda x: None # Alternative way of setting data_frequency for backwards # compatibility. if 'data_frequency' in kwargs: self.data_frequency = kwargs.pop('data_frequency') self._most_recent_data = None # Prepare the algo for initialization self.initialized = False self.initialize_args = args self.initialize_kwargs = kwargs
def test_orders_stop_limit(self): slippage_model = VolumeShareSlippage() slippage_model.data_portal = self.data_portal # long, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.0}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[2], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[2], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.6}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[2], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.50021875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 4.0}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 3.4}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.49978125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-50), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_orders_limit(self): slippage_model = VolumeShareSlippage() slippage_model.data_portal = self.data_portal # long, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.6}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[3], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) txn = orders_txns[0][1] expected_txn = { 'price': float(3.50021875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), # we ordered 100 shares, but default volume slippage only allows # for 2.5% of the volume. 2.5% * 2000 = 50 shares 'amount': int(50), 'sid': int(133), 'order_id': open_orders[0].id } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.4}) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.49978125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-50), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def __init__(self, *args, **kwargs): """Initialize sids and other state variables. :Arguments: :Optional: initialize : function Function that is called with a single argument at the begninning of the simulation. handle_data : function Function that is called with 2 arguments (context and data) on every bar. script : str Algoscript that contains initialize and handle_data function definition. data_frequency : str (daily, hourly or minutely) The duration of the bars. annualizer : int <optional> Which constant to use for annualizing risk metrics. If not provided, will extract from data_frequency. capital_base : float <default: 1.0e5> How much capital to start with. instant_fill : bool <default: False> Whether to fill orders immediately or on next bar. """ self.datetime = None self.registered_transforms = {} self.transforms = [] self.sources = [] self._recorded_vars = {} self.logger = None self.benchmark_return_source = None self.perf_tracker = None # default components for transact self.slippage = VolumeShareSlippage() self.commission = PerShare() if 'data_frequency' in kwargs: self.set_data_frequency(kwargs.pop('data_frequency')) else: self.data_frequency = None self.instant_fill = kwargs.pop('instant_fill', False) # Override annualizer if set if 'annualizer' in kwargs: self.annualizer = kwargs['annualizer'] # set the capital base self.capital_base = kwargs.pop('capital_base', DEFAULT_CAPITAL_BASE) self.sim_params = kwargs.pop('sim_params', None) if self.sim_params: if self.data_frequency is None: self.data_frequency = self.sim_params.data_frequency else: self.sim_params.data_frequency = self.data_frequency self.perf_tracker = PerformanceTracker(self.sim_params) self.blotter = kwargs.pop('blotter', None) if not self.blotter: self.blotter = Blotter() self.portfolio_needs_update = True self._portfolio = None # If string is passed in, execute and get reference to # functions. self.algoscript = kwargs.pop('script', None) self._initialize = None if self.algoscript is not None: self.ns = {} exec_(self.algoscript, self.ns) if 'initialize' not in self.ns: raise ValueError('You must define an initialze function.') if 'handle_data' not in self.ns: raise ValueError('You must define a handle_data function.') self._initialize = self.ns['initialize'] self._handle_data = self.ns['handle_data'] # If two functions are passed in assume initialize and # handle_data are passed in. elif kwargs.get('initialize', False) and kwargs.get('handle_data'): if self.algoscript is not None: raise ValueError('You can not set script and \ initialize/handle_data.') self._initialize = kwargs.pop('initialize') self._handle_data = kwargs.pop('handle_data') if self._initialize is None: self._initialize = lambda x: None # an algorithm subclass needs to set initialized to True when # it is fully initialized. self.initialized = False self.initialize(*args, **kwargs)
def test_volume_share_slippage(self): slippage_model = VolumeShareSlippage() open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, asset=self.ASSET133 ) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[0], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.0001875), 'dt': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(5), 'asset': self.ASSET133, 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, asset=self.ASSET133 ) ] # Set bar_data to be a minute ahead of last trade. # Volume share slippage should not execute when there is no trade. bar_data = self.create_bardata( simulation_dt_func=lambda: self.minutes[1], ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0)
def test_orders_stop_limit(self): events = self.genTrades() slippage_model = VolumeShareSlippage() ''' long, does not trade ''' open_orders = {133: [ # ndict( # this causes the nosetest to fail Order( {'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'stop': 4.0, 'limit': 3.0}) ]} txn = slippage_model.simulate( events[2], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None txn = slippage_model.simulate( events[3], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None ''' long, does trade ''' open_orders = {133: [ # ndict( # this causes the nosetest to fail Order( {'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'stop': 4.0, 'limit': 3.6}) ]} txn = slippage_model.simulate( events[2], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None txn = slippage_model.simulate( events[3], open_orders ) expected_txn = { 'price': float(3.500875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), 'amount': int(100), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) ''' short, does not trade ''' open_orders = {133: [ # ndict( # this causes the nosetest to fail Order( {'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'stop': 3.0, 'limit': 4.0}) ]} txn = slippage_model.simulate( events[0], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None txn = slippage_model.simulate( events[1], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None ''' short, does trade ''' open_orders = {133: [ # ndict( # this causes the nosetest to fail Order( {'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'stop': 3.0, 'limit': 3.4}) ]} txn = slippage_model.simulate( events[0], open_orders ) expected_txn = {} for key, value in expected_txn.items(): print( key, txn[key]) # self.assertEquals(value, txn[key]) assert txn == None txn = slippage_model.simulate( events[1], open_orders ) expected_txn = { 'price': float(3.499125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-100), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_orders_limit(self): events = self.gen_trades() slippage_model = VolumeShareSlippage() # long, does not trade open_orders = {133: [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'limit': 3.5}) ]} txn = slippage_model.simulate( events[2], open_orders ) expected_txn = {} self.assertIsNone(txn) # long, does trade open_orders = {133: [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'limit': 3.5}) ]} txn = slippage_model.simulate( events[3], open_orders ) expected_txn = { 'price': float(3.500875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), 'amount': int(100), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = {133: [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'limit': 3.5}) ]} txn = slippage_model.simulate( events[0], open_orders ) expected_txn = {} self.assertIsNone(txn) # short, does trade open_orders = {133: [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'limit': 3.5}) ]} txn = slippage_model.simulate( events[1], open_orders ) expected_txn = { 'price': float(3.499125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-100), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_orders_limit(self): slippage_model = VolumeShareSlippage() slippage_model.data_portal = self.data_portal # long, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.6}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) txn = orders_txns[0][1] expected_txn = { 'price': float(3.50021875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), # we ordered 100 shares, but default volume slippage only allows # for 2.5% of the volume. 2.5% * 2000 = 50 shares 'amount': int(50), 'sid': int(133), 'order_id': open_orders[0].id } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[0], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[0], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'limit': 3.4}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[1], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.49978125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-50), 'sid': int(133) } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_volume_share_slippage(self): assets = ( (133, pd.DataFrame( { 'open': [3.00], 'high': [3.15], 'low': [2.85], 'close': [3.00], 'volume': [200], }, index=[self.minutes[0]], )), ) days = pd.date_range( start=normalize_date(self.minutes[0]), end=normalize_date(self.minutes[-1]) ) with tmp_bcolz_minute_bar_reader(self.env, days, assets) as reader: data_portal = DataPortal( self.env, first_trading_day=reader.first_trading_day, equity_minute_reader=reader, ) slippage_model = VolumeShareSlippage() open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133 ) ] bar_data = BarData(data_portal, lambda: self.minutes[0], 'minute') orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.0001875), 'dt': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(5), 'sid': int(133), 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133 ) ] # Set bar_data to be a minute ahead of last trade. # Volume share slippage should not execute when there is no trade. bar_data = BarData(data_portal, lambda: self.minutes[1], 'minute') orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0)
def test_volume_share_slippage(self): tempdir = TempDirectory() try: assets = { 133: pd.DataFrame({ "open": [3.00], "high": [3.15], "low": [2.85], "close": [3.00], "volume": [200], "dt": [self.minutes[0]] }).set_index("dt") } write_bcolz_minute_data( self.env, pd.date_range( start=normalize_date(self.minutes[0]), end=normalize_date(self.minutes[-1]) ), tempdir.path, assets ) equity_minute_reader = BcolzMinuteBarReader(tempdir.path) data_portal = DataPortal( self.env, equity_minute_reader=equity_minute_reader, ) slippage_model = VolumeShareSlippage() open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133 ) ] bar_data = BarData(data_portal, lambda: self.minutes[0], 'minute') orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.0001875), 'dt': datetime.datetime( 2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': int(5), 'sid': int(133), 'commission': None, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. self.assertEquals(expected_txn, txn.__dict__) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=100, filled=0, sid=self.ASSET133 ) ] # Set bar_data to be a minute ahead of last trade. # Volume share slippage should not execute when there is no trade. bar_data = BarData(data_portal, lambda: self.minutes[1], 'minute') orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) finally: tempdir.cleanup()
def test_orders_stop_limit(self): slippage_model = VolumeShareSlippage() slippage_model.data_portal = self.data_portal # long, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.0}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[2], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[2], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # long, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': self.ASSET133, 'stop': 4.0, 'limit': 3.6}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[2], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[3], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.50021875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), 'amount': int(50), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 4.0}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[0], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[1], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does not trade - impacted price worse than limit price open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 3.5}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[0], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[1], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) # short, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': self.ASSET133, 'stop': 3.0, 'limit': 3.4}) ] bar_data = BarData(self.data_portal, lambda: self.minutes[0], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 0) bar_data = BarData(self.data_portal, lambda: self.minutes[1], self.sim_params.data_frequency) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.49978125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-50), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_orders_stop_limit(self): events = self.gen_trades() slippage_model = VolumeShareSlippage() # long, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'stop': 4.0, 'limit': 3.0}) ] orders_txns = list(slippage_model.simulate( events[2], open_orders )) self.assertEquals(len(orders_txns), 0) orders_txns = list(slippage_model.simulate( events[3], open_orders )) self.assertEquals(len(orders_txns), 0) # long, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': 100, 'filled': 0, 'sid': 133, 'stop': 4.0, 'limit': 3.5}) ] orders_txns = list(slippage_model.simulate( events[2], open_orders )) self.assertEquals(len(orders_txns), 0) orders_txns = list(slippage_model.simulate( events[3], open_orders )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.500875), 'dt': datetime.datetime( 2006, 1, 5, 14, 34, tzinfo=pytz.utc), 'amount': int(100), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key]) # short, does not trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'stop': 3.0, 'limit': 4.0}) ] orders_txns = list(slippage_model.simulate( events[0], open_orders )) self.assertEquals(len(orders_txns), 0) orders_txns = list(slippage_model.simulate( events[1], open_orders )) self.assertEquals(len(orders_txns), 0) # short, does trade open_orders = [ Order(**{ 'dt': datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), 'amount': -100, 'filled': 0, 'sid': 133, 'stop': 3.0, 'limit': 3.5}) ] orders_txns = list(slippage_model.simulate( events[0], open_orders )) self.assertEquals(len(orders_txns), 0) orders_txns = list(slippage_model.simulate( events[1], open_orders )) self.assertEquals(len(orders_txns), 1) _, txn = orders_txns[0] expected_txn = { 'price': float(3.499125), 'dt': datetime.datetime( 2006, 1, 5, 14, 32, tzinfo=pytz.utc), 'amount': int(-100), 'sid': int(133) } for key, value in expected_txn.items(): self.assertEquals(value, txn[key])
def test_order_hold(self): """ Held orders act almost identically to open orders, except for the status indication. When a fill happens, the order should switch status to OPEN/FILLED as necessary """ blotter = SimulationBlotter(self.sim_params, equity_slippage=VolumeShareSlippage()) # Nothing happens on held of a non-existent order blotter.hold(56) self.assertEqual(blotter.new_orders, []) open_id = blotter.order(self.asset_24, 100, MarketOrder()) open_order = blotter.open_orders[self.asset_24][0] self.assertEqual(open_order.id, open_id) blotter.hold(open_id) self.assertEqual(len(blotter.new_orders), 1) self.assertEqual(len(blotter.open_orders[self.asset_24]), 1) held_order = blotter.new_orders[0] self.assertEqual(held_order.status, ORDER_STATUS.HELD) self.assertEqual(held_order.reason, '') blotter.cancel(held_order.id) self.assertEqual(len(blotter.new_orders), 1) self.assertEqual(len(blotter.open_orders[self.asset_24]), 0) cancelled_order = blotter.new_orders[0] self.assertEqual(cancelled_order.id, held_order.id) self.assertEqual(cancelled_order.status, ORDER_STATUS.CANCELLED) for data in ([100, self.sim_params.sessions[0]], [400, self.sim_params.sessions[1]]): # Verify that incoming fills will change the order status. trade_amt = data[0] dt = data[1] order_size = 100 expected_filled = int(trade_amt * DEFAULT_EQUITY_VOLUME_SLIPPAGE_BAR_LIMIT) expected_open = order_size - expected_filled expected_status = ORDER_STATUS.OPEN if expected_open else \ ORDER_STATUS.FILLED blotter = SimulationBlotter(self.sim_params, equity_slippage=VolumeShareSlippage()) open_id = blotter.order(self.asset_24, order_size, MarketOrder()) open_order = blotter.open_orders[self.asset_24][0] self.assertEqual(open_id, open_order.id) blotter.hold(open_id) held_order = blotter.new_orders[0] filled_order = None blotter.current_dt = dt bar_data = self.create_bardata(simulation_dt_func=lambda: dt, ) txns, _, _ = blotter.get_transactions(bar_data) for txn in txns: filled_order = blotter.orders[txn.order_id] self.assertEqual(filled_order.id, held_order.id) self.assertEqual(filled_order.status, expected_status) self.assertEqual(filled_order.filled, expected_filled) self.assertEqual(filled_order.open_amount, expected_open)
def __init__(self): self.transact = transact_partial(VolumeShareSlippage(), PerShare()) self.open_orders = defaultdict(list)