def _add_legs_to_ib_contract(ibcontract: Contract, trade_list_for_multiple_legs: tradeQuantity, resolved_legs: list) -> ibcontractWithLegs: ratio_list = list_of_ints_with_highest_common_factor_positive_first( trade_list_for_multiple_legs ) ibcontract_legs = [ _get_ib_combo_leg(ratio, resolved_leg) for ratio, resolved_leg in zip(ratio_list, resolved_legs) ] ibcontract.comboLegs = ibcontract_legs ibcontract_with_legs = ibcontractWithLegs(ibcontract, resolved_legs) return ibcontract_with_legs
def ib_futures_contract( self, futures_contract_with_ib_data, always_return_single_leg=False, trade_list_for_multiple_legs=None, return_leg_data=False, ): """ Return a complete and unique IB contract that matches contract_object_with_ib_data Doesn't actually get the data from IB, tries to get from cache :param futures_contract_with_ib_data: contract, containing instrument metadata suitable for IB :return: a single ib contract object """ contract_object_to_use = copy(futures_contract_with_ib_data) if always_return_single_leg and contract_object_to_use.is_spread_contract( ): contract_object_to_use = contract_object_to_use.new_contract_with_first_contract_date( ) if getattr(self, "_futures_contract_cache", None) is None: self._futures_contract_cache = {} if not contract_object_to_use.is_spread_contract(): trade_list_suffix = "" else: # WANT TO TREAT EG -2,2 AND -4,4 AS THE SAME BUT DIFFERENT FROM # -2,1 OR -1,2,-1... trade_list_suffix = str( list_of_ints_with_highest_common_factor_positive_first( trade_list_for_multiple_legs)) cache = self._futures_contract_cache key = contract_object_to_use.key + trade_list_suffix ibcontract_with_legs = cache.get(key, missing_contract) if ibcontract_with_legs is missing_contract: ibcontract_with_legs = self._get_ib_futures_contract( contract_object_to_use, trade_list_for_multiple_legs=trade_list_for_multiple_legs, ) cache[key] = ibcontract_with_legs if return_leg_data: return ibcontract_with_legs else: return ibcontract_with_legs.ibcontract
def _get_spread_ib_futures_contract( self, futures_instrument_with_ib_data: futuresInstrumentWithIBConfigData, contract_date, trade_list_for_multiple_legs=[-1, 1], ): """ Return a complete and unique IB contract that matches contract_object_with_ib_data This is expensive so not called directly, only by ib_futures_contract which does caching :param contract_object_with_ib_data: contract, containing instrument metadata suitable for IB :return: a single ib contract object """ # Convert to IB world ibcontract = ib_futures_instrument(futures_instrument_with_ib_data) ibcontract.secType = "BAG" list_of_contract_dates = contract_date.list_of_single_contract_dates resolved_legs = [ self._get_vanilla_ib_futures_contract( futures_instrument_with_ib_data, contract_date) for contract_date in list_of_contract_dates ] ratio_list = list_of_ints_with_highest_common_factor_positive_first( trade_list_for_multiple_legs) def _get_ib_combo_leg(ratio, resolved_leg): leg = ComboLeg() leg.conId = int(resolved_leg.conId) leg.exchange = str(resolved_leg.exchange) action, size = resolveBS(ratio) leg.ratio = int(size) leg.action = str(action) return leg ibcontract.comboLegs = [ _get_ib_combo_leg(ratio, resolved_leg) for ratio, resolved_leg in zip(ratio_list, resolved_legs) ] return ibcontract, resolved_legs
def _get_contract_cache_key( self, contract_object_to_use: futuresContract, trade_list_for_multiple_legs: tradeQuantity = None) -> str: if not contract_object_to_use.is_spread_contract(): trade_list_suffix = "" else: # WANT TO TREAT EG -2,2 AND -4,4 AS THE SAME BUT DIFFERENT FROM # -2,1 OR -1,2,-1... trade_list_suffix = str( list_of_ints_with_highest_common_factor_positive_first( trade_list_for_multiple_legs)) key = contract_object_to_use.key + trade_list_suffix return key
def resolve_multi_leg_price_to_single_price(trade_list: tradeQuantity, price_list: list) -> float: if len(price_list) == 0: return None if len(price_list) == 1: return price_list[0] assert len(price_list) == len(trade_list) trade_list_as_common_factor = list_of_ints_with_highest_common_factor_positive_first( trade_list) fill_price = [ x * y for x, y in zip(trade_list_as_common_factor, price_list) ] fill_price = sum(fill_price) if np.isnan(fill_price): return None return fill_price
def resolve_multi_leg_price_to_single_price( trade_list: tradeQuantity, price_list: list ) -> float: if len(price_list) == 0: ## This will be the case when an order is first created or has no fills return None if len(price_list) == 1: return price_list[0] assert len(price_list) == len(trade_list) trade_list_as_common_factor = ( list_of_ints_with_highest_common_factor_positive_first(trade_list) ) fill_price = [x * y for x, y in zip(trade_list_as_common_factor, price_list)] fill_price = sum(fill_price) if np.isnan(fill_price): return None return fill_price