def resolve_inputs_to_order(trade, fill) -> (tradeQuantity, tradeQuantity): resolved_trade = tradeQuantity(trade) if fill is None: resolved_fill = resolved_trade.zero_version() else: resolved_fill = tradeQuantity(fill) return resolved_trade, resolved_fill
def resolve_trade_fill_fillprice(trade, fill, filled_price): resolved_trade = tradeQuantity(trade) if fill is None: resolved_fill = resolved_trade.zero_version() else: resolved_fill = tradeQuantity(fill) if filled_price is None: resolved_filled_price = fillPrice.nan_from_trade_qty(resolved_trade) else: resolved_filled_price = fillPrice(filled_price) return resolved_trade, resolved_fill, resolved_filled_price
def _apply_float_override(override_as_float: float, original_position_no_override: int, proposed_trade: Order) -> Order: """ Works if override value is float, or override_close (float value is 0.0) or override_none (float value is 1.0) :param original_position_no_override: :param proposed_trade: :return: """ if override_as_float == 1.0: return proposed_trade desired_new_position = original_position_no_override + proposed_trade.trade.as_single_trade_qty_or_error() override_new_position = int( np.floor( desired_new_position * override_as_float)) new_trade_value = override_new_position - original_position_no_override proposed_trade.replace_required_trade_size_only_use_for_unsubmitted_trades( tradeQuantity(new_trade_value)) return proposed_trade
def cut_down_proposed_instrument_trade_okay(self, instrument_trade): strategy_name = instrument_trade.strategy_name instrument_code = instrument_trade.instrument_code proposed_trade = instrument_trade.as_single_trade_qty_or_error() ## want to CUT DOWN rather than bool possible trades ## FIXME: ## underneath should be using tradeQuantity and position objects ## these will handle abs cases plus legs if required in future # :FIXME instrument_strategy = instrumentStrategy( strategy_name=strategy_name, instrument_code=instrument_code) max_trade_ok_against_instrument_strategy = \ self.check_if_proposed_trade_okay_against_instrument_strategy_constraint(instrument_strategy, proposed_trade) max_trade_ok_against_instrument = \ self.check_if_proposed_trade_okay_against_instrument_constraint(instrument_code, proposed_trade) ## FIXME THIS IS UGLY WOULD BE BETTER IF DONE INSIDE TRADE SIZE OBJECT mini_max_trade = sign(proposed_trade) * \ min([abs(max_trade_ok_against_instrument), abs(max_trade_ok_against_instrument_strategy)]) mini_max_trade = tradeQuantity(mini_max_trade) instrument_trade = instrument_trade.replace_required_trade_size_only_use_for_unsubmitted_trades( mini_max_trade) return instrument_trade
def replace_trade_only_use_for_unsubmitted_trades(self, new_trade): # if this is a single leg trade, does a straight replacement # otherwise new_order = copy(self) new_order._trade = tradeQuantity(new_trade) return new_order
def what_trade_is_possible(position: int, position_limit: int, order: Order) -> Order: ## POSIITON LIMITS CAN ONLY BE APPLIED TO SINGLE LEG TRADES, EG INSTRUMENT ORDERS proposed_trade = order.as_single_trade_qty_or_error() possible_trade = what_trade_is_possible_single_leg_trade(position=position, position_limit=position_limit, proposed_trade=proposed_trade) possible_trade_as_trade_qty = tradeQuantity(possible_trade) order = order.replace_required_trade_size_only_use_for_unsubmitted_trades(possible_trade_as_trade_qty) return order
def fill_order(self, fill_qty, filled_price=None, fill_datetime=None): # Fill qty is cumulative, eg this is the new amount filled fill_qty = tradeQuantity(fill_qty) assert self.trade.fill_less_than_or_equal_to_desired_trade( fill_qty ), "Can't fill order for more than trade quantity" self._fill = fill_qty if filled_price is not None: self._filled_price = fillPrice(filled_price) if fill_datetime is None: fill_datetime = datetime.datetime.now() self._fill_datetime = fill_datetime
def _apply_reduce_only(original_position_no_override: int, proposed_trade: Order) -> Order: proposed_trade_value = proposed_trade.trade.as_single_trade_qty_or_error() desired_new_position = original_position_no_override + proposed_trade_value if sign(desired_new_position) != sign(original_position_no_override): # Wants sign to change, we convert into a pure closing trade new_trade_value = -original_position_no_override elif abs(desired_new_position) > abs(original_position_no_override): # Increasing trade not allowed, zero trade new_trade_value = 0 else: # Reducing trade and sign not changing, we'll allow new_trade_value = proposed_trade_value proposed_trade.replace_required_trade_size_only_use_for_unsubmitted_trades( tradeQuantity(new_trade_value)) return proposed_trade
def fill(self): return tradeQuantity(self._fill)
def trade(self): return tradeQuantity(self._trade)
def from_broker_trade_object(ibBrokerOrder, extracted_trade_data, instrument_code=arg_not_supplied): sec_type = extracted_trade_data.contract.ib_sectype if sec_type not in ["FUT", "BAG"]: # Doesn't handle non futures trades, just ignores them return missing_order strategy_name = "" if instrument_code is arg_not_supplied: instrument_code = extracted_trade_data.contract.ib_instrument_code contract_id_list = extracted_trade_data.contract.ib_contract_id algo_comment = extracted_trade_data.algo_msg order_type = extracted_trade_data.order.type limit_price = extracted_trade_data.order.limit_price broker_account = extracted_trade_data.order.account broker_permid = extracted_trade_data.order.perm_id broker_objects = dict( order=extracted_trade_data.order.order_object, trade=extracted_trade_data.trade_object, contract=extracted_trade_data.contract.contract_object, ) leg_ratios = extracted_trade_data.contract.leg_ratios # sometimes this is negative unsigned_remain_qty_scalar = extracted_trade_data.order.remain_qty # when it's negative this is often zero unsigned_total_qty_scalar = extracted_trade_data.order.total_qty if unsigned_remain_qty_scalar < 0: total_qty = None else: # remain is not used... but the option is here # remain_qty_scalar = unsigned_remain_qty_scalar * extracted_trade_data.order.order_sign # remain_qty_list = [int(remain_qty_scalar * ratio) for ratio in leg_ratios] # remain_qty = tradeQuantity(remain_qty_list) total_qty_scalar = (unsigned_total_qty_scalar * extracted_trade_data.order.order_sign) total_qty_list = [ int(total_qty_scalar * ratio) for ratio in leg_ratios ] total_qty = tradeQuantity(total_qty_list) fill_totals = extract_totals_from_fill_data(extracted_trade_data.fills) if fill_totals is missing_data: fill_datetime = None fill = total_qty.zero_version() filled_price_list = [] commission = None broker_tempid = extracted_trade_data.order.order_id broker_clientid = extracted_trade_data.order.client_id else: ( broker_clientid, broker_tempid, filled_price_dict, fill_datetime, commission, signed_qty_dict, ) = fill_totals filled_price_list = [ filled_price_dict.get(contractid, None) for contractid in contract_id_list ] fill_list = [ signed_qty_dict.get(contractid, None) for contractid in contract_id_list ] missing_fill = [ fill_price_item is None or fill is None for fill_price_item, fill in zip(filled_price_list, fill_list) ] if any(missing_fill): fill = None filled_price_list = [] else: fill_list = [int(fill) for fill in fill_list] fill = tradeQuantity(fill_list) if total_qty is None: total_qty = fill fill_price = resolve_multi_leg_price_to_single_price( trade_list=total_qty, price_list=filled_price_list) broker_order = ibBrokerOrder( strategy_name, instrument_code, contract_id_list, total_qty, fill=fill, order_type=order_type, limit_price=limit_price, filled_price=fill_price, algo_comment=algo_comment, fill_datetime=fill_datetime, broker_account=broker_account, commission=commission, leg_filled_price=filled_price_list, broker_permid=broker_permid, broker_tempid=broker_tempid, broker_clientid=broker_clientid, ) broker_order.broker_objects = broker_objects return broker_order
def _apply_no_trading(proposed_trade: Order): new_trade = proposed_trade.replace_required_trade_size_only_use_for_unsubmitted_trades( tradeQuantity(0)) return new_trade