def test_transactions_not_created_for_incompl_orders(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') broker._tws.nextValidId(0) asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset amount = -4 limit_price = 43.1 stop_price = 6 style = StopLimitOrder(limit_price=limit_price, stop_price=stop_price) order = broker.order(asset, amount, style) assert not broker.transactions assert len(broker.orders) == 1 assert broker.orders[order.id].open ib_order_id = order.broker_order_id ib_contract = self._create_contract(str(asset.symbol)) action, qty, order_type, limit_price, stop_price = \ 'SELL', 4, 'STP LMT', 4.3, 2 ib_order = self._create_order(action, qty, order_type, limit_price, stop_price) ib_state = self._create_order_state('PreSubmitted') broker._tws.openOrder(ib_order_id, ib_contract, ib_order, ib_state) broker._tws.orderStatus(ib_order_id, status='Cancelled', filled=0, remaining=4, avg_fill_price=0.0, perm_id=4, parent_id=4, last_fill_price=0.0, client_id=32, why_held='') assert not broker.transactions assert len(broker.orders) == 1 assert not broker.orders[order.id].open broker._tws.orderStatus(ib_order_id, status='Inactive', filled=0, remaining=4, avg_fill_price=0.0, perm_id=4, parent_id=4, last_fill_price=0.0, client_id=1111, why_held='') assert not broker.transactions assert len(broker.orders) == 1 assert not broker.orders[order.id].open
def test_order_ref_serdes(self): # Even though _creater_order_ref and _parse_order_ref is private # it is helpful to test as it plays a key role to re-create orders order = self._create_order("BUY", 66, "STP LMT", 13.4, 44.2) serialized = IBBroker._create_order_ref(order) deserialized = IBBroker._parse_order_ref(serialized) assert deserialized['action'] == order.action assert deserialized['qty'] == order.totalQuantity assert deserialized['order_type'] == order.orderType assert deserialized['limit_price'] == order.lmtPrice assert deserialized['stop_price'] == order.auxPrice assert (deserialized['dt'] - pd.to_datetime('now', utc=True) < pd.Timedelta('10s'))
def test_transactions_created_for_complete_orders(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') broker._tws.nextValidId(0) asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset order_count = 0 for amount, order_style in [(-112, StopLimitOrder(limit_price=9, stop_price=1)), (43, LimitOrder(limit_price=10)), (-99, StopOrder(stop_price=8)), (-32, MarketOrder())]: order = broker.order(asset, amount, order_style) broker._tws.orderStatus(order.broker_order_id, 'Filled', filled=int(fabs(amount)), remaining=0, avg_fill_price=111, perm_id=0, parent_id=1, last_fill_price=112, client_id=1111, why_held='') contract = self._create_contract(str(asset.symbol)) (shares, cum_qty, price, avg_price, exec_time, exec_id) = \ (int(fabs(amount)), int(fabs(amount)), 12.3, 12.31, pd.to_datetime('now', utc=True), order_count) exec_detail = self._create_exec_detail(order.broker_order_id, shares, cum_qty, price, avg_price, exec_time, exec_id) broker._tws.execDetails(0, contract, exec_detail) order_count += 1 assert len(broker.transactions) == order_count transactions = [ tx for tx in broker.transactions.values() if tx.order_id == order.id ] assert len(transactions) == 1 assert broker.transactions[exec_id].asset == asset assert broker.transactions[exec_id].amount == order.amount assert (broker.transactions[exec_id].dt - pd.to_datetime('now', utc=True) < pd.Timedelta('10s')) assert broker.transactions[exec_id].price == price assert broker.orders[order.id].commission == 0
def test_orders_loaded_from_exec_details(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset (req_id, ib_order_id, shares, cum_qty, price, avg_price, exec_time, exec_id) = (7, 3, 12, 40, 12.43, 12.50, '20160101 14:20', 4) ib_contract = self._create_contract(str(asset.symbol)) exec_detail = self._create_exec_detail(ib_order_id, shares, cum_qty, price, avg_price, exec_time, exec_id) broker._tws.execDetails(req_id, ib_contract, exec_detail) assert len(broker.orders) == 1 zp_order = list(broker.orders.values())[-1] assert zp_order.broker_order_id == ib_order_id assert zp_order.open assert zp_order.asset == asset assert zp_order.amount == -40 assert zp_order.limit == limit_price assert zp_order.stop == stop_price assert (zp_order.dt - pd.to_datetime('now', utc=True) < pd.Timedelta('10s'))
def test_orders_updated_from_order_status(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') broker._tws.nextValidId(0) # orderStatus calls only work if a respective order has been created asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset amount = -4 limit_price = 43.1 stop_price = 6 style = StopLimitOrder(limit_price=limit_price, stop_price=stop_price) order = broker.order(asset, amount, style) ib_order_id = order.broker_order_id status = 'Filled' filled = 14 remaining = 9 avg_fill_price = 12.4 perm_id = 99 parent_id = 88 last_fill_price = 12.3 client_id = 1111 why_held = '' broker._tws.orderStatus(ib_order_id, status, filled, remaining, avg_fill_price, perm_id, parent_id, last_fill_price, client_id, why_held) assert len(broker.orders) == 1 zp_order = list(broker.orders.values())[-1] assert zp_order.broker_order_id == ib_order_id assert zp_order.status == ORDER_STATUS.FILLED assert not zp_order.open assert zp_order.asset == asset assert zp_order.amount == amount assert zp_order.limit == limit_price assert zp_order.stop == stop_price assert (zp_order.dt - pd.to_datetime('now', utc=True) < pd.Timedelta('10s'))
def test_new_order_appears_in_orders(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') broker._tws.nextValidId(0) asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset amount = -4 limit_price = 43.1 stop_price = 6 style = StopLimitOrder(limit_price=limit_price, stop_price=stop_price) order = broker.order(asset, amount, style) assert len(broker.orders) == 1 assert broker.orders[order.id] == order assert order.open assert order.asset == asset assert order.amount == amount assert order.limit == limit_price assert order.stop == stop_price assert (order.dt - pd.to_datetime('now', utc=True) < pd.Timedelta('10s'))
def test_multiple_orders(self, symbol_lookup): with patch('sharadar.live.brokers.ib_broker.TWSConnection.start'): broker = IBBroker("localhost:9999:1111", account_id='TEST-123') broker._tws.nextValidId(0) asset = self.asset_finder.retrieve_asset(1) symbol_lookup.return_value = asset order_count = 0 for amount, order_style in [(-112, StopLimitOrder(limit_price=9, stop_price=1)), (43, LimitOrder(limit_price=10)), (-99, StopOrder(stop_price=8)), (-32, MarketOrder())]: order = broker.order(asset, amount, order_style) order_count += 1 assert order_count == len(broker.orders) assert broker.orders[order.id] == order is_buy = amount > 0 assert order.stop == order_style.get_stop_price(is_buy) assert order.limit == order_style.get_limit_price(is_buy)
def test_get_spot_value(self, tws): dt = None # dt is not used in real broker data_freq = 'minute' asset = self.asset_finder.retrieve_asset(1) bars = { 'last_trade_price': [12, 10, 11, 14], 'last_trade_size': [1, 2, 3, 4], 'total_volume': [10, 10, 10, 10], 'vwap': [12.1, 10.1, 11.1, 14.1], 'single_trade_flag': [0, 1, 0, 1] } last_trade_times = [ pd.to_datetime('2017-06-16 10:30:00', utc=True), pd.to_datetime('2017-06-16 10:30:11', utc=True), pd.to_datetime('2017-06-16 10:30:30', utc=True), pd.to_datetime('2017-06-17 10:31:9', utc=True) ] index = pd.DatetimeIndex(last_trade_times) broker = IBBroker(sentinel.tws_uri) tws.return_value.bars = { asset.symbol: pd.DataFrame(index=index, data=bars) } price = broker.get_spot_value(asset, 'price', dt, data_freq) last_trade = broker.get_spot_value(asset, 'last_traded', dt, data_freq) open_ = broker.get_spot_value(asset, 'open', dt, data_freq) high = broker.get_spot_value(asset, 'high', dt, data_freq) low = broker.get_spot_value(asset, 'low', dt, data_freq) close = broker.get_spot_value(asset, 'close', dt, data_freq) volume = broker.get_spot_value(asset, 'volume', dt, data_freq) # Only the last minute is taken into account, therefore # the first bar is ignored assert price == bars['last_trade_price'][-1] assert last_trade == last_trade_times[-1] assert open_ == bars['last_trade_price'][1] assert high == max(bars['last_trade_price'][1:]) assert low == min(bars['last_trade_price'][1:]) assert close == bars['last_trade_price'][-1] assert volume == sum(bars['last_trade_size'][1:])
def test_get_realtime_bars_produces_correct_df(self): bars = self._tws_bars() with patch('sharadar.live.brokers.ib_broker.TWSConnection'): broker = IBBroker(sentinel.tws_uri) broker._tws.bars = bars assets = (self.asset_finder.retrieve_asset(1), self.asset_finder.retrieve_asset(2)) realtime_history = broker.get_realtime_bars(assets, '1m') asset_spy = self.asset_finder.retrieve_asset(1) asset_xiv = self.asset_finder.retrieve_asset(2) assert asset_spy in realtime_history assert asset_xiv in realtime_history spy = realtime_history[asset_spy] xiv = realtime_history[asset_xiv] assert list(spy.columns) == ['open', 'high', 'low', 'close', 'volume'] assert list(xiv.columns) == ['open', 'high', 'low', 'close', 'volume'] # There are 159 minutes between the first (XIV @ 2017-09-27 9:32:00) # and the last bar (SPY @ 2017-09-27 12:10:00) assert len(realtime_history) == 159 spy_non_na = spy.dropna() xiv_non_na = xiv.dropna() assert len(spy_non_na) == 4 assert len(xiv_non_na) == 3 assert spy_non_na.iloc[0].name == pd.to_datetime('2017-09-27 10:30:00', utc=True) assert spy_non_na.iloc[0].open == 12.40 assert spy_non_na.iloc[0].high == 12.41 assert spy_non_na.iloc[0].low == 12.40 assert spy_non_na.iloc[0].close == 12.41 assert spy_non_na.iloc[0].volume == 20 assert spy_non_na.iloc[1].name == pd.to_datetime('2017-09-27 10:31:00', utc=True) assert spy_non_na.iloc[1].open == 12.44 assert spy_non_na.iloc[1].high == 12.44 assert spy_non_na.iloc[1].low == 12.44 assert spy_non_na.iloc[1].close == 12.44 assert spy_non_na.iloc[1].volume == 20 assert spy_non_na.iloc[-1].name == pd.to_datetime( '2017-09-27 12:10:00', utc=True) assert spy_non_na.iloc[-1].open == 12.99 assert spy_non_na.iloc[-1].high == 12.99 assert spy_non_na.iloc[-1].low == 12.99 assert spy_non_na.iloc[-1].close == 12.99 assert spy_non_na.iloc[-1].volume == 15 assert xiv_non_na.iloc[0].name == pd.to_datetime('2017-09-27 9:32:00', utc=True) assert xiv_non_na.iloc[0].open == 100.4 assert xiv_non_na.iloc[0].high == 100.41 assert xiv_non_na.iloc[0].low == 100.4 assert xiv_non_na.iloc[0].close == 100.41 assert xiv_non_na.iloc[0].volume == 200