def test_volume_limit(self, name, first_order_amount, second_order_amount, first_order_fill_amount, second_order_fill_amount): slippage_model = FixedBasisPointsSlippage(basis_points=5, volume_limit=0.1) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=order_amount, filled=0, asset=self.ASSET133 ) for order_amount in [first_order_amount, second_order_amount] ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.first_minute, ) orders_txns = list(slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) self.assertEquals(len(orders_txns), 2) _, first_txn = orders_txns[0] _, second_txn = orders_txns[1] self.assertEquals(first_txn['amount'], first_order_fill_amount) self.assertEquals(second_txn['amount'], second_order_fill_amount)
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.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 generate_order_and_txns(self, sid, order_amount, fill_amounts): asset1 = self.asset_finder.retrieve_asset(sid) # one order order = Order(dt=None, asset=asset1, amount=order_amount) # three fills txn1 = Transaction(asset=asset1, amount=fill_amounts[0], dt=None, price=100, order_id=order.id) txn2 = Transaction(asset=asset1, amount=fill_amounts[1], dt=None, price=101, order_id=order.id) txn3 = Transaction(asset=asset1, amount=fill_amounts[2], dt=None, price=102, order_id=order.id) return order, [txn1, txn2, txn3]
def order(self, sid, amount, style, order_id=None): """Place an order. Parameters ---------- asset : zipline.assets.Asset The asset that this order is for. amount : int The amount of shares to order. If ``amount`` is positive, this is the number of shares to buy or cover. If ``amount`` is negative, this is the number of shares to sell or short. style : zipline.finance.execution.ExecutionStyle The execution style for the order. order_id : str, optional The unique identifier for this order. Returns ------- order_id : str or None The unique identifier for this order, or None if no order was placed. Notes ----- amount > 0 :: Buy/Cover amount < 0 :: Sell/Short Market order: order(sid, amount) Limit order: order(sid, amount, style=LimitOrder(limit_price)) Stop order: order(sid, amount, style=StopOrder(stop_price)) StopLimit order: order(sid, amount, style=StopLimitOrder(limit_price, stop_price)) """ # something could be done with amount to further divide # between buy by share count OR buy shares up to a dollar amount # numeric == share count AND "$dollar.cents" == cost amount if amount == 0: # Don't bother placing orders for 0 shares. return None elif amount > self.max_shares: # Arbitrary limit of 100 billion (US) shares will never be # exceeded except by a buggy algorithm. raise OverflowError("Can't order more than %d shares" % self.max_shares) is_buy = (amount > 0) order = Order(dt=self.current_dt, sid=sid, amount=amount, stop=style.get_stop_price(is_buy), limit=style.get_limit_price(is_buy), id=order_id) self.open_orders[order.sid].append(order) self.orders[order.id] = order self.new_orders.append(order) return order.id
def test_fill_zero_shares(self): slippage_model = FixedBasisPointsSlippage(basis_points=5, volume_limit=0.1) # since the volume limit for the bar is 20, the first order will be # filled and there will be a transaction for it, and the second order # will order zero shares so there should not be a transaction for it. open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=20, filled=0, asset=self.ASSET133, ) ] * 2 bar_data = self.create_bardata( simulation_dt_func=lambda: self.first_minute) orders_txns = list( slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) assert 1 == len(orders_txns) # ordering zero shares should result in zero transactions open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=0, filled=0, asset=self.ASSET133, ) ] orders_txns = list( slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) assert 0 == len(orders_txns)
def order(self, asset, amount, limit_price, stop_price, style): is_buy = (amount > 0) zp_order = ZPOrder( dt=pd.to_datetime('now', utc=True), asset=asset, amount=amount, stop=style.get_stop_price(is_buy), limit=style.get_limit_price(is_buy)) contract = Contract() contract.m_symbol = str(asset.symbol) contract.m_currency = self.currency contract.m_exchange = 'SMART' contract.m_secType = 'STK' order = Order() order.m_totalQuantity = int(fabs(amount)) order.m_action = "BUY" if amount > 0 else "SELL" order.m_lmtPrice = 0 order.m_auxPrice = 0 if isinstance(style, MarketOrder): order.m_orderType = "MKT" elif isinstance(style, LimitOrder): order.m_orderType = "LMT" order.m_lmtPrice = limit_price elif isinstance(style, StopOrder): order.m_orderType = "STP" order.m_auxPrice = stop_price elif isinstance(style, StopLimitOrder): order.m_orderType = "STP LMT" order.m_auxPrice = stop_price order.m_lmtPrice = limit_price order.m_tif = "DAY" ib_order_id = self._tws.next_order_id zp_order.broker_order_id = ib_order_id self.orders[zp_order.id] = zp_order self._tws.placeOrder(ib_order_id, contract, order) return zp_order.id
def order( self, sid, amount, style, commission, order_id=None, give_price=None, ): # something could be done with amount to further divide # between buy by share count OR buy shares up to a dollar amount # numeric == share count AND "$dollar.cents" == cost amount # sid 为stock_id 股票代码,他么的。 """ amount > 0 :: Buy/Cover amount < 0 :: Sell/Short Market order: order(sid, amount) Limit order: order(sid, amount, style=LimitOrder(limit_price)) Stop order: order(sid, amount, style=StopOrder(stop_price)) StopLimit order: order(sid, amount, style=StopLimitOrder(limit_price, stop_price)) """ if amount == 0: # Don't bother placing orders for 0 shares. return elif amount > self.max_shares: # Arbitrary limit of 100 billion (US) shares will never be # exceeded except by a buggy algorithm. raise OverflowError("Can't order more than %d shares" % self.max_shares) ''' elif amount%100 !=0: original=amount n=amount%100 amount=amount-n print (u"%s:买入股票数目应该为100倍数, 从 %d 调整为 %d"%(self.current_dt,original,amount)) ''' is_buy = (amount > 0) order = Order(dt=self.current_dt, sid=sid, amount=amount, give_price=give_price, stop=style.get_stop_price(is_buy), limit=style.get_limit_price(is_buy), id=order_id) #print u'这里的情况啊啊啊啊啊' self.open_orders[order.sid].append(order) self.orders[order.id] = order self.new_orders.append(order) return order.id
def tdx_order_to_zipline_order(self, order): """ status 0 已报 1 部分成交 2 全部成交 3 部分撤单 4 全部撤单 5 交易所拒单 6 柜台未接受 :param order: :return: """ if order.status == "3" or '4' == order.status: zp_status = ZP_ORDER_STATUS.CANCELLED elif order.status == "0": zp_status = ZP_ORDER_STATUS.OPEN elif order.status == "1": zp_status = ZP_ORDER_STATUS.FILLED elif order.status == "2": zp_status = ZP_ORDER_STATUS.HELD elif order.status == "5" or order.status == "6": zp_status = ZP_ORDER_STATUS.REJECTED zp_order_id = self._tdx_to_zp_order_id(order.order_id) od = ZPOrder( dt=order.dt, asset=symbol(order.symbol), amount=order.amount, filled=order.filled, stop=None, limit=order.price, # TODO 市价单和限价单 id=zp_order_id, ) od.broker_order_id = order.order_id od.status = zp_status return od
def test_calculate_impact_sell(self): answer_key = [ # We ordered -10 contracts, but are capped at -(100 * 0.05) = -5 (91485.499914831875, -5), (91486.499914830943, -5), (None, None), ] order = Order( dt=pd.Timestamp.now(tz='utc').round('min'), asset=self.ASSET, amount=-10, ) self._calculate_impact(order, answer_key)
def test_calculate_impact_buy(self): answer_key = [ # We ordered 10 contracts, but are capped at 100 * 0.05 = 5 (91485.500085168125, 5), (91486.500085169057, 5), (None, None), ] order = Order( dt=pd.Timestamp.now(tz='utc').round('min'), asset=self.ASSET, amount=10, ) self._calculate_impact(order, answer_key)
def test_low_transaction_volume(self): # With a volume limit of 0.001, and a bar volume of 100, we should # compute a transaction volume of 100 * 0.001 = 0.1, which gets rounded # down to zero. In this case we expect no amount to be transacted. model = VolatilityVolumeShare(volume_limit=0.001) minute = pd.Timestamp('2006-03-01 11:35AM', tz='UTC') data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order(dt=data.current_dt, asset=self.ASSET, amount=10) price, amount = model.process_order(data, order) self.assertIsNone(price) self.assertIsNone(amount)
def tdx_order_to_zipline_order(self, order): if order.status is not None and 'CANCEL' == order.status: zp_status = ZP_ORDER_STATUS.CANCELLED elif order.filled == 0: zp_status = ZP_ORDER_STATUS.OPEN else: zp_status = ZP_ORDER_STATUS.FILLED zp_order_id = self._tdx_to_zp_order_id(order.order_id) od = ZPOrder( dt=pd.to_datetime(order.dt), asset=symbol(order.symbol), amount=order.amount, filled=order.filled, stop=None, limit=order.price, # TODO 市价单和限价单 id=zp_order_id, ) od.broker_order_id = order.order_id od.status = zp_status return od
def order(self, sid, amount, style, order_id=None, base_price=None, open_price=None, close_price=None, when=None, current_volume=None): # something could be done with amount to further divide # between buy by share count OR buy shares up to a dollar amount # numeric == share count AND "$dollar.cents" == cost amount """ amount > 0 :: Buy/Cover amount < 0 :: Sell/Short Market order: order(sid, amount) Limit order: order(sid, amount, style=LimitOrder(limit_price)) Stop order: order(sid, amount, style=StopOrder(stop_price)) StopLimit order: order(sid, amount, style=StopLimitOrder(limit_price, stop_price)) """ if amount == 0: # Don't bother placing orders for 0 shares. return elif amount > self.max_shares: # Arbitrary limit of 100 billion (US) shares will never be # exceeded except by a buggy algorithm. raise OverflowError("Can't order more than %d shares" % self.max_shares) is_buy = (amount > 0) order = Order(dt=self.current_dt, sid=sid, amount=amount, stop=style.get_stop_price(is_buy), limit=style.get_limit_price(is_buy), id=order_id, base_price=base_price, close_price=close_price, open_price=open_price, when=when, current_volume=current_volume) self.open_orders[order.sid].append(order) self.orders[order.id] = order self.new_orders.append(order) return order.id
def tdx_order_to_zipline_order(self, order): if order.status == '已撤': zp_status = ZP_ORDER_STATUS.CANCELLED elif order.filled == 0: zp_status = ZP_ORDER_STATUS.OPEN else: zp_status = ZP_ORDER_STATUS.FILLED zp_order_id = self._tdx_to_zp_order_id(order.order_id) od = ZPOrder( dt=pd.to_datetime(order.dt), asset=symbol(order.symbol), amount=order.amount, filled=order.filled, stop=None, limit=order.price, # TODO 市价单和限价单 id=zp_order_id, ) od.broker_order_id = order.order_id od.status = zp_status return od
def test_impacted_price_worse_than_limit(self): model = VolatilityVolumeShare(volume_limit=0.05) # Use all the same numbers from the 'calculate_impact' tests. Since the # impacted price is 59805.5, which is worse than the limit price of # 59800, the model should return None. minute = pd.Timestamp('2006-03-01 11:35AM', tz='UTC') data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order( dt=data.current_dt, asset=self.ASSET, amount=10, limit=59800, ) price, amount = model.process_order(data, order) self.assertIsNone(price) self.assertIsNone(amount)
def generate_order_and_txns(self): asset1 = self.asset_finder.retrieve_asset(1) # one order order = Order(dt=None, sid=asset1, amount=500) # three fills txn1 = Transaction(sid=asset1, amount=230, dt=None, price=100, order_id=order.id) txn2 = Transaction(sid=asset1, amount=170, dt=None, price=101, order_id=order.id) txn3 = Transaction(sid=asset1, amount=100, dt=None, price=102, order_id=order.id) return order, [txn1, txn2, txn3]
def test_fixed_bps_slippage( self, name, basis_points, volume_limit, order_amount, expected_price, expected_amount, ): slippage_model = FixedBasisPointsSlippage(basis_points=basis_points, volume_limit=volume_limit) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=order_amount, filled=0, asset=self.ASSET133, ) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.first_minute) orders_txns = list( slippage_model.simulate( bar_data, self.ASSET133, open_orders, )) assert len(orders_txns) == 1 _, txn = orders_txns[0] expected_txn = { "price": expected_price, "dt": datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), "amount": expected_amount, "asset": self.ASSET133, "type": DATASOURCE_TYPE.TRANSACTION, "order_id": open_orders[0].id, } assert txn is not None assert expected_txn == txn.__dict__
def test_prune_orders(self): blotter = Blotter(self.sim_params.data_frequency, self.asset_finder) blotter.order(self.asset_24, 100, MarketOrder()) open_order = blotter.open_orders[self.asset_24][0] blotter.prune_orders([]) self.assertEqual(1, len(blotter.open_orders[self.asset_24])) blotter.prune_orders([open_order]) self.assertEqual(0, len(blotter.open_orders[self.asset_24])) # prune an order that isn't in our our open orders list, make sure # nothing blows up other_order = Order(dt=blotter.current_dt, sid=self.asset_25, amount=1) blotter.prune_orders([other_order])
def test_fixed_bps_slippage(self, name, basis_points, volume_limit, order_amount, expected_price, expected_amount): slippage_model = FixedBasisPointsSlippage(basis_points=basis_points, volume_limit=volume_limit) open_orders = [ Order( dt=datetime.datetime(2006, 1, 5, 14, 30, tzinfo=pytz.utc), amount=order_amount, filled=0, asset=self.ASSET133 ) ] bar_data = self.create_bardata( simulation_dt_func=lambda: self.first_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': expected_price, 'dt': datetime.datetime(2006, 1, 5, 14, 31, tzinfo=pytz.utc), 'amount': expected_amount, 'asset': self.ASSET133, 'type': DATASOURCE_TYPE.TRANSACTION, 'order_id': open_orders[0].id } self.assertIsNotNone(txn) self.assertEquals(expected_txn, txn.__dict__)
def test_prune_orders(self): blotter = SimulationBlotter() blotter.order(self.asset_24, 100, MarketOrder()) open_order = blotter.open_orders[self.asset_24][0] blotter.prune_orders([]) self.assertEqual(1, len(blotter.open_orders[self.asset_24])) blotter.prune_orders([open_order]) self.assertEqual(0, len(blotter.open_orders[self.asset_24])) # prune an order that isn't in our our open orders list, make sure # nothing blows up other_order = Order(dt=blotter.current_dt, asset=self.asset_25, amount=1) blotter.prune_orders([other_order])
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 _calculate_impact(self, test_order, answer_key): model = VolatilityVolumeShare(volume_limit=0.05) first_minute = pd.Timestamp('2006-03-31 11:35AM', tz='UTC') next_3_minutes = self.trading_calendar.minutes_window(first_minute, 3) remaining_shares = test_order.open_amount for i, minute in enumerate(next_3_minutes): data = self.create_bardata(simulation_dt_func=lambda: minute) new_order = Order( dt=data.current_dt, asset=self.ASSET, amount=remaining_shares, ) price, amount = model.process_order(data, new_order) self.assertEqual(price, answer_key[i][0]) self.assertEqual(amount, answer_key[i][1]) amount = amount or 0 if remaining_shares < 0: remaining_shares = min(0, remaining_shares - amount) else: remaining_shares = max(0, remaining_shares - amount)
def test_calculate_impact_without_history(self): model = VolatilityVolumeShare(volume_limit=1) minutes = [ # Start day of the futures contract; no history yet. pd.Timestamp('2006-02-10 11:35AM', tz='UTC'), # Only a week's worth of history data. pd.Timestamp('2006-02-17 11:35AM', tz='UTC'), ] for minute in minutes: data = self.create_bardata(simulation_dt_func=lambda: minute) order = Order(dt=data.current_dt, asset=self.ASSET, amount=10) price, amount = model.process_order(data, order) avg_price = (data.current(self.ASSET, 'high') + data.current(self.ASSET, 'low')) / 2 expected_price = \ avg_price + (avg_price * NO_DATA_VOLATILITY_SLIPPAGE_IMPACT) self.assertEqual(price, expected_price) self.assertEqual(amount, 10)
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 _order2zp(self, order): zp_order = ZPOrder( id=order.client_order_id, asset=symbol_lookup(order.symbol), amount=int(order.qty) if order.side == 'buy' else -int(order.qty), stop=float(order.stop_price) if order.stop_price else None, limit=float(order.limit_price) if order.limit_price else None, dt=order.submitted_at, commission=0, ) zp_order.status = ZP_ORDER_STATUS.OPEN if order.canceled_at: zp_order.status = ZP_ORDER_STATUS.CANCELLED if order.failed_at: zp_order.status = ZP_ORDER_STATUS.REJECTED if order.filled_at: zp_order.status = ZP_ORDER_STATUS.FILLED zp_order.filled = int(order.filled_qty) return zp_order
def make_order(self, amount): return Order( self.minute, self.asset, amount, )
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, "asset": 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, )) assert 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, "asset": 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, )) assert 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, "asset": 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, )) assert 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), "asset": self.ASSET133, "order_id": open_orders[0].id, } assert txn is not None for key, value in expected_txn.items(): assert 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, "asset": 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, )) assert 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, "asset": 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, )) assert 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, "asset": 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, )) assert 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), "asset": self.ASSET133, } assert txn is not None for key, value in expected_txn.items(): assert value == txn[key]
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, "asset": 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, )) assert 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, )) assert 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, "asset": 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, )) assert 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, )) assert 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, "asset": 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, )) assert 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, )) assert 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), "asset": self.ASSET133, } for key, value in expected_txn.items(): assert 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, "asset": 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, )) assert 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, )) assert 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, "asset": 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, )) assert 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, )) assert 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, "asset": 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, )) assert 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, )) assert 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), "asset": self.ASSET133, } for key, value in expected_txn.items(): assert 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, 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, )) assert 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, "type": DATASOURCE_TYPE.TRANSACTION, "order_id": open_orders[0].id, } assert txn is not None # TODO: Make expected_txn an Transaction object and ensure there # is a __eq__ for that class. assert 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, )) assert len(orders_txns) == 0
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, 'asset': 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, 'asset': 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, 'asset': 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), 'asset': self.ASSET133 } 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, 'asset': 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, 'asset': 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, 'asset': 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), 'asset': self.ASSET133, } 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, 'asset': 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, 'asset': 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, 'asset': 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), 'asset': self.ASSET133, '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, 'asset': 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, 'asset': 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, 'asset': 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), 'asset': self.ASSET133, } self.assertIsNotNone(txn) for key, value in expected_txn.items(): self.assertEquals(value, txn[key])