def test_future_ticker_to_contract_mapping(self): """ Test mapping of future tickers onto IB contracts. """ mapping = { BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), } contract_ticker_mapper = IBContractTickerMapper( mapping, self.data_provider) # Map a specific ticker to contract ticker = BloombergTicker("HGH20 Comdty", SecurityType.FUTURE, 250) actual_contract = contract_ticker_mapper.ticker_to_contract(ticker) expected_contract = IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD", str_to_date("2020-03-20")) self.assertEqual(actual_contract, expected_contract) # Map a future ticker to contract future_ticker = Mock(spec=BloombergFutureTicker) future_ticker.get_current_specific_ticker.return_value = BloombergTicker( "HGN20 Comdty", SecurityType.FUTURE, 250) actual_contract = contract_ticker_mapper.ticker_to_contract( future_ticker) expected_contract = IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD", str_to_date("2020-06-20")) self.assertEqual(actual_contract, expected_contract)
def test_duplicate_stock_tickers(self): bbg_ib_symbols_mapping = { BloombergTicker("Example Index"): IBContract("EXAMPLE", SecurityType.STOCK, "EXAMPLE_EXCHANGE"), BloombergTicker("Example 2 Index"): IBContract("EXAMPLE", SecurityType.STOCK, "EXAMPLE_EXCHANGE"), } with self.assertRaises(Exception): IBContractTickerMapper(bbg_ib_symbols_mapping)
def test_contract_ticker_mapping_multiple_tickers_matching_contract(self): """ Test contract to ticker mapping in case if many tickers correspond to the same contract. """ mapping = { BloombergFutureTicker('Copper1', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), BloombergFutureTicker('Copper2', 'HG{} Comdty', 1, 2, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), } with self.assertRaises(AssertionError): IBContractTickerMapper(mapping, self.data_provider)
def test_invalid_contract_to_specific_future_ticker_mapping(self): """ Test futures contract to ticker mapping in case if the last trade date is invalid. """ mapping = { BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), } contract_ticker_mapper = IBContractTickerMapper( mapping, self.data_provider) contract = IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD", str_to_date("2020-06-25")) with self.assertRaises(ValueError): contract_ticker_mapper.contract_to_ticker(contract)
def test_contract_to_specific_future_ticker_mapping(self): mapping = { BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), } contract_ticker_mapper = IBContractTickerMapper( mapping, self.data_provider) contract = IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD", str_to_date("2020-06-20")) actual_ticker = contract_ticker_mapper.contract_to_ticker(contract) expected_ticker = BloombergTicker("HGN20 Comdty", SecurityType.FUTURE, 250) self.assertEqual(actual_ticker, expected_ticker)
def test_futures_contract_to_ticker_invalid_last_trade_date(self): """ Test contract to ticker mapping, in case if the last trade date in the IBContract is invalid. """ mapping = { BloombergTicker("PAH20 Comdty", SecurityType.FUTURE, 100): IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) } contract_ticker_mapper = IBContractTickerMapper(mapping) contract = IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-10")) with self.assertRaises(ValueError): contract_ticker_mapper.contract_to_ticker(contract)
def test_contract_ticker_mapping_many_future_tickers(self): """ Test futures contract to ticker mapping in case if many future tickers correspond to the given ticker. """ mapping = { BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 17, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "250", "USD"), } contract_ticker_mapper = IBContractTickerMapper( mapping, self.data_provider) with self.assertRaises(ValueError): ticker = BloombergTicker("HGH20 Comdty", SecurityType.FUTURE, 250) contract_ticker_mapper.ticker_to_contract(ticker)
def test_no_data_provider(self): fut_ticker = BloombergFutureTicker("Copper", "HG{} Comdty", 1, 4) bbg_ib_symbols_mapping = { fut_ticker: IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000") } with self.assertRaises(ValueError): contract_ticker_mapper = IBContractTickerMapper( bbg_ib_symbols_mapping, data_provider=None) contract_ticker_mapper.contract_to_ticker( IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", last_trade_date=datetime(2021, 9, 9)))
def test_ticker_to_futures_contract_mapping(self): """ Test contract to ticker mapping, in case of a futures contract when the mapping between a specific futures ticker and an IBContract was provided. """ mapping = { BloombergTicker("PAH20 Comdty", SecurityType.FUTURE, 100): IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) } contract_ticker_mapper = IBContractTickerMapper(mapping) ticker = BloombergTicker("PAH20 Comdty", SecurityType.FUTURE, 100) actual_contract = contract_ticker_mapper.ticker_to_contract(ticker) expected_contract = IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) self.assertEqual(expected_contract, actual_contract)
def test_duplicate_future_tickers(self): future_ticker_1 = BloombergFutureTicker("Copper", "HG{} Comdty", 1, 4) future_ticker_2 = BloombergFutureTicker("Example", "Example{} Comdty", 1, 4) bbg_ib_symbols_mapping = { future_ticker_1: IBContract("EXAMPLE", SecurityType.FUTURE, "DIFFERENT_EXCHANGE", "25000"), future_ticker_2: IBContract("EXAMPLE", SecurityType.FUTURE, "EXAMPLE_EXCHANGE", "25000"), } with self.assertRaises(Exception): IBContractTickerMapper(bbg_ib_symbols_mapping, self.data_provider)
def test_contract_to_ticker_no_valid_mapping(self): """ Test contract to ticker mapping if no mapping for the ticker exists. """ contract_ticker_mapper = IBContractTickerMapper({}) contract = IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) with self.assertRaises(ValueError): contract_ticker_mapper.contract_to_ticker(contract)
def _create_futures_contract(self, specific_ticker: Ticker): """ Creates an IBContract instance for a given specific future ticker. """ future_ticker = self._get_matching_future_ticker(specific_ticker) mapped_contract = self._ticker_to_contract_dict.get( future_ticker, None) if not mapped_contract: raise ValueError( f"Could not map the ticker {specific_ticker} onto Interactive Brokers contract." ) elif self._data_provider is None: raise ValueError( f"In order to map ticker {specific_ticker} onto a corresponding IBContract, it is " f"necessary to set the data_provider to obtain the last trade date value." ) chain_tickers = self._data_provider.get_futures_chain_tickers( future_ticker, ExpirationDateField.LastTradeableDate)[future_ticker] try: last_trade_date = chain_tickers.loc[specific_ticker].to_pydatetime( ) contract = IBContract.from_ib_contract(mapped_contract) contract.last_trade_date = last_trade_date return contract except KeyError: raise ValueError( f"Cannot map the future ticker {specific_ticker} as it doesn't have a corresponding " f"last trade date returned by the DataProvider.") from None
def contract_to_ticker(self, contract: IBContract) -> Ticker: """ It always maps to the specific ticker. """ # Create a new instance of the IBContract, with the last_trade_date parameter removed contract_without_last_trade_date = IBContract.from_ib_contract( contract) contract_without_last_trade_date.last_trade_date = None # Search for the contract in the ticker to contract dictionary, ignoring last_trade_date if necessary ticker = self._contract_to_ticker_dict.get(contract, None) or \ self._contract_to_ticker_dict.get(contract_without_last_trade_date, None) # Get the specific ticker for the given last trade date if isinstance(ticker, FutureTicker): if self._data_provider is None: raise ValueError( f"In order to map contract {contract} onto a corresponding ticker, it is necessary " f"to set the data_provider to obtain the ticker for the given last trade date." ) chain_tickers = self._data_provider.get_futures_chain_tickers( ticker, ExpirationDateField.LastTradeableDate)[ticker] chain_tickers = chain_tickers.index[chain_tickers == contract.last_trade_date] ticker = chain_tickers[0] if not chain_tickers.empty else None if ticker is None: raise ValueError( f"Could not map Interactive Brokers contract {contract} onto a Ticker object." ) return ticker
def test_futures_ibcontract_from_string_2(self): contract_string = "0,,FUT,,0.0,,,GLOBEX,,USD,ESU6,,False,,combo:" ibcontract = IBContract.from_string(contract_string) self.assertEqual(ibcontract.secType, "FUT") self.assertEqual(ibcontract.security_type, SecurityType.FUTURE) self.assertEqual(ibcontract.exchange, "GLOBEX") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.localSymbol, "ESU6")
def test_duplicate_future_and_equity_tickers(self): future_ticker_1 = BloombergFutureTicker("Copper", "HG{} Comdty", 1, 4) bbg_ib_symbols_mapping = { future_ticker_1: IBContract("EXAMPLE", SecurityType.FUTURE, "DIFFERENT_EXCHANGE", "25000"), BloombergTicker("Example Index"): IBContract("EXAMPLE", SecurityType.STOCK, "EXAMPLE_EXCHANGE"), } contract_ticker_mapper = IBContractTickerMapper( bbg_ib_symbols_mapping, self.data_provider) contract = IBContract("EXAMPLE", SecurityType.STOCK, "EXAMPLE_EXCHANGE") ticker = contract_ticker_mapper.contract_to_ticker(contract) self.assertEqual(ticker.as_string(), "Example Index")
def test_index_ibcontract_from_string(self): contract_string = "0,DAX,IND,,0.0,,,DTB,,EUR,,,False,,combo:" ibcontract = IBContract.from_string(contract_string) self.assertEqual(ibcontract.symbol, "DAX") self.assertEqual(ibcontract.secType, "IND") self.assertEqual(ibcontract.security_type, SecurityType.INDEX) self.assertEqual(ibcontract.exchange, "DTB") self.assertEqual(ibcontract.currency, "EUR")
def test_stock_ibcontract_from_string(self): contract_string = "0,MSFT,STK,,0.0,,,SMART,ISLAND,USD,,,False,,combo:" ibcontract = IBContract.from_string(contract_string) self.assertEqual(ibcontract.symbol, "MSFT") self.assertEqual(ibcontract.secType, "STK") self.assertEqual(ibcontract.security_type, SecurityType.STOCK) self.assertEqual(ibcontract.exchange, "SMART") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.primaryExchange, "ISLAND")
def test_futures_ibcontract_from_string(self): contract_string = "0,ES,FUT,20190307,0.0,,5,GLOBEX,,USD,,,False,,combo:" ibcontract = IBContract.from_string(contract_string) self.assertEqual(ibcontract.symbol, "ES") self.assertEqual(ibcontract.secType, "FUT") self.assertEqual(ibcontract.security_type, SecurityType.FUTURE) self.assertEqual(ibcontract.exchange, "GLOBEX") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.lastTradeDateOrContractMonth, "20190307") self.assertEqual(ibcontract.last_trade_date, datetime(2019, 3, 7)) self.assertEqual(ibcontract.multiplier, "5")
def map_future_ticker_to_contract(): mapping = { BloombergFutureTicker('Copper', 'HG{} Comdty', 1, 1, 250): IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD"), BloombergTicker("PAH20 Comdty", SecurityType.FUTURE, 100): IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) } data_provider = container.resolve(BloombergDataProvider) contract_ticker_mapper = IBContractTickerMapper(mapping, data_provider) current_time = str_to_date("2020-12-01") for future_ticker in mapping.keys(): if isinstance(future_ticker, BloombergFutureTicker): future_ticker.initialize_data_provider(SettableTimer(current_time), data_provider) print("\nMapping PAH20 Comdty ticker to IB contract") ticker = BloombergTicker("PAH20 Comdty", SecurityType.FUTURE, 100) contract = contract_ticker_mapper.ticker_to_contract(ticker) print(f"Ticker mapped onto the following contract: {contract}") print("\nMapping IBContract onto ticker") contract = IBContract("PA", SecurityType.FUTURE, "NYMEX", "100", "", str_to_date("2020-03-27")) ticker = contract_ticker_mapper.contract_to_ticker(contract) print(f"Contract mapped onto the following ticker: {ticker}") print( "\nMapping HGH20 Comdty ticker - Copper, March 2020 futures contracts") ticker = BloombergTicker("HGH20 Comdty", SecurityType.FUTURE, 250) contract = contract_ticker_mapper.ticker_to_contract(ticker) print(f"Ticker mapped onto the following contract: {contract}") print("\nMapping IBContract onto ticker") contract = IBContract("HG", SecurityType.FUTURE, "NYMEX", "25000", "USD", str_to_date("2021-01-27")) ticker = contract_ticker_mapper.contract_to_ticker(contract) print(f"Contract mapped onto the following ticker: {ticker}")
def openOrder(self, orderId: OrderId, ib_contract: Contract, ib_order: IBOrder, orderState: OrderState): super().openOrder(orderId, ib_contract, ib_order, orderState) if ib_order.orderType.upper() == 'STP': execution_style = StopOrder(ib_order.auxPrice) elif ib_order.orderType.upper() == 'MKT': execution_style = MarketOrder() else: error_message = "Order Type is not supported: {}".format( ib_order.orderType) self.logger.error(error_message) raise ValueError(error_message) if ib_order.action.upper() == 'SELL': quantity = -ib_order.totalQuantity elif ib_order.action.upper() == 'BUY': quantity = ib_order.totalQuantity else: error_message = "Order Action is not supported: {}".format( ib_order.action) self.logger.error(error_message) raise ValueError(error_message) if ib_order.tif.upper() == 'DAY': time_in_force = TimeInForce.DAY elif ib_order.tif.upper() == 'GTC': time_in_force = TimeInForce.GTC elif ib_order.tif.upper() == 'OPG': time_in_force = TimeInForce.OPG else: error_message = "Time in Force is not supported: {}".format( ib_order.tif) self.logger.error(error_message) raise ValueError(error_message) try: ticker = self.contract_ticker_mapper.contract_to_ticker( IBContract.from_ib_contract(ib_contract)) order = Order(ticker=ticker, quantity=quantity, execution_style=execution_style, time_in_force=time_in_force, order_state=orderState.status) order.id = int(orderId) self.order_list.append(order) except ValueError as e: self.logger.error( f"Open Order for contract {ib_contract} will be skipped due to the following error " f"during parsing: \n{e}")
def test_futures_ibcontract_from_ib_contract_2(self): contract = Contract() contract.secType = "FUT" contract.exchange = "GLOBEX" contract.currency = "USD" contract.localSymbol = "ESU6" ibcontract = IBContract.from_ib_contract(contract) self.assertEqual(ibcontract.secType, "FUT") self.assertEqual(ibcontract.security_type, SecurityType.FUTURE) self.assertEqual(ibcontract.exchange, "GLOBEX") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.localSymbol, "ESU6")
def test_index_ibcontract_from_ib_contract(self): contract = Contract() contract.symbol = "DAX" contract.secType = "IND" contract.currency = "EUR" contract.exchange = "DTB" ibcontract = IBContract.from_ib_contract(contract) self.assertEqual(ibcontract.symbol, "DAX") self.assertEqual(ibcontract.secType, "IND") self.assertEqual(ibcontract.security_type, SecurityType.INDEX) self.assertEqual(ibcontract.exchange, "DTB") self.assertEqual(ibcontract.currency, "EUR")
def test_stock_ibcontract_from_ib_contract(self): contract = Contract() contract.symbol = "MSFT" contract.secType = "STK" contract.currency = "USD" contract.exchange = "SMART" contract.primaryExchange = "ISLAND" ibcontract = IBContract.from_ib_contract(contract) self.assertEqual(ibcontract.symbol, "MSFT") self.assertEqual(ibcontract.secType, "STK") self.assertEqual(ibcontract.security_type, SecurityType.STOCK) self.assertEqual(ibcontract.exchange, "SMART") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.primaryExchange, "ISLAND")
def test_futures_ibcontract_from_ib_contract(self): contract = Contract() contract.symbol = "ES" contract.secType = "FUT" contract.exchange = "GLOBEX" contract.currency = "USD" contract.lastTradeDateOrContractMonth = "20190307" contract.multiplier = "5" ibcontract = IBContract.from_ib_contract(contract) self.assertEqual(ibcontract.symbol, "ES") self.assertEqual(ibcontract.secType, "FUT") self.assertEqual(ibcontract.security_type, SecurityType.FUTURE) self.assertEqual(ibcontract.exchange, "GLOBEX") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.lastTradeDateOrContractMonth, "20190307") self.assertEqual(ibcontract.last_trade_date, datetime(2019, 3, 7)) self.assertEqual(ibcontract.multiplier, "5")
def test_futures_spread_ibcontract_from_string(self): string = "0,VIX,BAG,,0.0,,,CFE,,USD,,,False,,combo:;326501438,1,BUY,CFE,0,0,,-1;323072528,1,SELL,CFE,0,0,,-1" ibcontract = IBContract.from_string(string) self.assertEqual(ibcontract.symbol, "VIX") self.assertEqual(ibcontract.security_type, SecurityType.SPREAD) self.assertEqual(ibcontract.secType, "BAG") self.assertEqual(ibcontract.currency, "USD") self.assertEqual(ibcontract.exchange, "CFE") self.assertEqual(len(ibcontract.comboLegs), 2) self.assertEqual(ibcontract.comboLegs[0].conId, 326501438) self.assertEqual(ibcontract.comboLegs[0].ratio, 1) self.assertEqual(ibcontract.comboLegs[0].action, "BUY") self.assertEqual(ibcontract.comboLegs[0].exchange, "CFE") self.assertEqual(ibcontract.comboLegs[1].conId, 323072528) self.assertEqual(ibcontract.comboLegs[1].ratio, 1) self.assertEqual(ibcontract.comboLegs[1].action, "SELL") self.assertEqual(ibcontract.comboLegs[1].exchange, "CFE")
def position(self, account: str, ib_contract: Contract, position: float, avgCost: float): """ Important note: For futures, the exchange field will not be populated in the position callback as some futures trade on multiple exchanges. """ if not position.is_integer(): self.logger.warning( f"Position {ib_contract} has non-integer quantity = {position}" ) if int(position) != 0: try: ticker = self.contract_ticker_mapper.contract_to_ticker( IBContract.from_ib_contract(ib_contract)) position_info = BrokerPosition(ticker, int(position), avgCost) self.position_list.append(position_info) except ValueError as e: self.logger.error( f"Position for contract {ib_contract} will be skipped due to the following error " f"during parsing: \n{e}")