def ib_resolve_unique_contract(self, ibcontract_pattern, log: logger = None): """ Returns the 'resolved' IB contract based on a pattern. We expect a unique contract. This is used for FX only, since for futures things are potentially funkier :param ibcontract_pattern: ibContract :param log: log object :return: ibContract or missing_contract """ if log is None: log = self.log contract_chain = self.ib_get_contract_chain(ibcontract_pattern) if len(contract_chain) > 1: log.warn( "Got multiple contracts for %s when only expected a single contract: Check contract date" % str(ibcontract_pattern)) return missing_contract if len(contract_chain) == 0: log.warn("Failed to resolve contract %s" % str(ibcontract_pattern)) return missing_contract resolved_contract = contract_chain[0] return resolved_contract
def _get_generic_data_for_contract( self, ibcontract: ibContract, log: logger = None, bar_freq: Frequency = DAILY_PRICE_FREQ, whatToShow: str = "TRADES") -> pd.DataFrame: """ Get historical daily data :param contract_object_with_ib_data: contract where instrument has ib metadata :param freq: str; one of D, H, 5M, M, 10S, S :return: futuresContractPriceData """ if log is None: log = self.log try: barSizeSetting, durationStr = _get_barsize_and_duration_from_frequency( bar_freq) except Exception as exception: log.warn(exception) return missing_data price_data_raw = self._ib_get_historical_data_of_duration_and_barSize( ibcontract, durationStr=durationStr, barSizeSetting=barSizeSetting, whatToShow=whatToShow, log=log, ) price_data_as_df = self._raw_ib_data_to_df( price_data_raw=price_data_raw, log=log) return price_data_as_df
def _avoid_pacing_violation(last_call_datetime: datetime.datetime, log: logger = logtoscreen("")): printed_warning_already = False while _pause_for_pacing(last_call_datetime): if not printed_warning_already: log.msg( "Pausing %f seconds to avoid pacing violation" % (datetime.datetime.now() - last_call_datetime).total_seconds()) printed_warning_already = True pass
def calculate_buffers(instrument_code: str, position: pd.Series, config: Config, vol_scalar: pd.Series, instr_weights: pd.DataFrame = arg_not_supplied, idm: pd.Series = arg_not_supplied, log: logger = logtoscreen("")) -> pd.Series: log.msg( "Calculating buffers for %s" % instrument_code, instrument_code=instrument_code, ) buffer_method = config.buffer_method if buffer_method == "forecast": log.msg( "Calculating forecast method buffers for %s" % instrument_code, instrument_code=instrument_code, ) if instr_weights is arg_not_supplied: instr_weight_this_code = arg_not_supplied else: instr_weight_this_code = instr_weights[instrument_code] buffer = get_forecast_method_buffer(instr_weight_this_code=instr_weight_this_code, vol_scalar=vol_scalar, idm=idm, position=position, config=config) elif buffer_method == "position": log.msg( "Calculating position method buffer for %s" % instrument_code, instrument_code=instrument_code, ) buffer = get_position_method_buffer(config=config, position=position) elif buffer_method == "none": log.msg( "None method, no buffering for %s" % instrument_code, instrument_code=instrument_code, ) buffer = get_buffer_if_not_buffering( position=position) else: log.critical( "Buffer method %s not recognised - not buffering" % buffer_method ) buffer = get_buffer_if_not_buffering( position=position) return buffer
def _avoid_pacing_violation(last_call_datetime: datetime.datetime, log: logger = logtoscreen("")): printed_warning_already = False while _pause_for_pacing(last_call_datetime): if not printed_warning_already: log.msg("Pausing %f seconds to avoid pacing violation" % (last_call_datetime + datetime.timedelta(seconds=PACING_INTERVAL_SECONDS) - datetime.datetime.now()).total_seconds()) printed_warning_already = True pass
def _is_imbalance_ratio_exceeded(current_tick_analysis: analysisTick, log: logger) -> bool: latest_imbalance_ratio = current_tick_analysis.imbalance_ratio latest_imbalance_ratio_exceeded = latest_imbalance_ratio > IMBALANCE_THRESHOLD if latest_imbalance_ratio_exceeded: log.msg("Imbalance ratio for ticker %s %f exceeds threshold %f" % (str(current_tick_analysis), latest_imbalance_ratio, IMBALANCE_THRESHOLD)) return latest_imbalance_ratio_exceeded
def _is_insufficient_size_on_our_preferred_side( ticker_object: tickerObject, current_tick_analysis: analysisTick, log: logger) -> bool: abs_size_we_wish_to_trade = abs(ticker_object.qty) size_we_require_to_trade_limit = IMBALANCE_ADJ_FACTOR * abs_size_we_wish_to_trade available_size_on_our_preferred_side = abs(current_tick_analysis.side_qty) insufficient_size_on_our_preferred_side = ( available_size_on_our_preferred_side < size_we_require_to_trade_limit) if insufficient_size_on_our_preferred_side: log.msg( "On ticker %s we require size of %f (our trade %f * adjustment %f) for a limit order but only %f available" % (str(current_tick_analysis), size_we_require_to_trade_limit, abs_size_we_wish_to_trade, IMBALANCE_ADJ_FACTOR, available_size_on_our_preferred_side)) return insufficient_size_on_our_preferred_side
def _raw_ib_data_to_df( self, price_data_raw: pd.DataFrame, log: logger ) -> pd.DataFrame: if price_data_raw is None: log.warn("No price data from IB") return missing_data price_data_as_df = price_data_raw[["open", "high", "low", "close", "volume"]] price_data_as_df.columns = ["OPEN", "HIGH", "LOW", "FINAL", "VOLUME"] date_index = [ self._ib_timestamp_to_datetime(price_row) for price_row in price_data_raw["date"] ] price_data_as_df.index = date_index return price_data_as_df
def log(self, log: logger): return log.setup(instrument_code=self.instrument_code, contract_date=self.date_str)