def cancel_market_data_for_contract_object( self, contract_object: futuresContract, trade_list_for_multiple_legs=None ): """ Returns my encapsulation of a ticker object :param contract_object: :param trade_list_for_multiple_legs: :return: """ new_log = contract_object.log(self.log) contract_object_with_ib_data = ( self.futures_contract_data.get_contract_object_with_IB_data( contract_object ) ) if contract_object_with_ib_data is missing_contract: new_log.warn("Can't get data for %s" % str(contract_object)) return futuresContractPrices.create_empty() self.ibconnection.cancel_market_data_for_contract_object( contract_object_with_ib_data, trade_list_for_multiple_legs=trade_list_for_multiple_legs, )
def write_prices_for_contract_object( self, futures_contract_object: futuresContract, futures_price_data: futuresContractPrices, ignore_duplication=False): """ Write some prices :param futures_contract_object: :param futures_price_data: :param ignore_duplication: bool, to stop us overwriting existing prices :return: None """ if self.has_data_for_contract(futures_contract_object): if ignore_duplication: pass else: log = futures_contract_object.log(self.log) log.warn("There is already existing data for %s" % futures_contract_object.key) return None self._write_prices_for_contract_object_no_checking( futures_contract_object, futures_price_data)
def _get_prices_at_frequency_for_contract_object_no_checking( self, contract_object: futuresContract, freq: Frequency, allow_expired=False, ) -> futuresContractPrices: """ Get historical prices at a particular frequency We override this method, rather than _get_prices_at_frequency_for_contract_object_no_checking Because the list of dates returned by contracts_with_price_data is likely to not match (expiries) :param contract_object: futuresContract :param freq: str; one of D, H, 15M, 5M, M, 10S, S :return: data """ new_log = contract_object.log(self.log) contract_object_with_ib_broker_config = ( self.futures_contract_data.get_contract_object_with_IB_data( contract_object, allow_expired=allow_expired)) if contract_object_with_ib_broker_config is missing_contract: new_log.warn("Can't get data for %s" % str(contract_object)) return futuresContractPrices.create_empty() price_data = self._get_prices_at_frequency_for_ibcontract_object_no_checking( contract_object_with_ib_broker_config, freq=freq, allow_expired=allow_expired, ) return price_data
def get_recent_bid_ask_tick_data_for_contract_object( self, contract_object: futuresContract) -> dataFrameOfRecentTicks: """ Get last few price ticks :param contract_object: futuresContract :return: """ new_log = contract_object.log(self.log) contract_object_with_ib_data = ( self.futures_contract_data.get_contract_object_with_IB_data( contract_object)) if contract_object_with_ib_data is missing_contract: new_log.warn("Can't get data for %s" % str(contract_object)) return dataFrameOfRecentTicks.create_empty() tick_data = self.ib_client.ib_get_recent_bid_ask_tick_data( contract_object_with_ib_data) if tick_data is missing_contract: return missing_data tick_data_as_df = from_ib_bid_ask_tick_data_to_dataframe(tick_data) return tick_data_as_df
def is_contract_okay_to_trade(self, futures_contract: futuresContract) -> bool: new_log = futures_contract.log(self.log) trading_hours = self.get_trading_hours_for_contract(futures_contract) if trading_hours is missing_contract: new_log.critical( "Error! Cannot find active contract! Expired? interactive_update_roll_status.py not executed?" ) return False return trading_hours.okay_to_trade_now()
def update_prices_for_contract( self, contract_object: futuresContract, new_futures_per_contract_prices: futuresContractPrices, check_for_spike: bool = True, max_price_spike: float = VERY_BIG_NUMBER) -> int: """ Reads existing data, merges with new_futures_prices, writes merged data :param new_futures_prices: :return: int, number of rows """ new_log = contract_object.log(self.log) if len(new_futures_per_contract_prices) == 0: new_log.msg("No new data") return 0 old_prices = self.get_prices_for_contract_object(contract_object) merged_prices = old_prices.add_rows_to_existing_data( new_futures_per_contract_prices, check_for_spike=check_for_spike, max_price_spike=max_price_spike) if merged_prices is spike_in_data: new_log.msg( "Price has moved too much - will need to manually check - no price update done" ) return spike_in_data rows_added = len(merged_prices) - len(old_prices) if rows_added < 0: new_log.critical("Can't remove prices something gone wrong!") return failure elif rows_added == 0: if len(old_prices) == 0: new_log.msg("No existing or additional data") return 0 else: new_log.msg("No additional data since %s " % str(old_prices.index[-1])) return 0 # We have guaranteed no duplication self.write_prices_for_contract_object(contract_object, merged_prices, ignore_duplication=True) new_log.msg("Added %d additional rows of data" % rows_added) return rows_added
def _get_actual_expiry_date_given_contract_with_ib_metadata( self, contract_object_with_ib_data: futuresContract) -> expiryDate: expiry_date = self.ibconnection.broker_get_contract_expiry_date( contract_object_with_ib_data) if expiry_date is missing_contract: log = contract_object_with_ib_data.log(self.log) log.msg("No IB expiry date found") return missing_contract else: expiry_date = expiryDate.from_str(expiry_date) return expiry_date
def _get_prices_at_frequency_for_contract_object_no_checking(self, contract_object: futuresContract, freq: str ) -> futuresContractPrices: """ Get historical prices at a particular frequency We override this method, rather than _get_prices_at_frequency_for_contract_object_no_checking Because the list of dates returned by contracts_with_price_data is likely to not match (expiries) :param contract_object: futuresContract :param freq: str; one of D, H, 15M, 5M, M, 10S, S :return: data """ new_log = contract_object.log(self.log) contract_object_with_ib_broker_config = ( self.futures_contract_data.get_contract_object_with_IB_data( contract_object ) ) if contract_object_with_ib_broker_config is missing_contract: new_log.warn("Can't get data for %s" % str(contract_object)) return futuresContractPrices.create_empty() price_data = self.ib_client.broker_get_historical_futures_data_for_contract( contract_object_with_ib_broker_config, bar_freq=freq) if price_data is missing_data: new_log.warn( "Something went wrong getting IB price data for %s" % str(contract_object)) price_data = futuresContractPrices.create_empty() elif len(price_data) == 0: new_log.warn( "No IB price data found for %s" % str(contract_object)) price_data = futuresContractPrices.create_empty() else: price_data = futuresContractPrices(price_data) ## It's important that the data is in local time zone so that this works price_data = price_data.remove_future_data() ## Some contract data is marked to model, don't want this price_data = price_data.remove_zero_volumes() return price_data
def _delete_prices_for_contract_object_with_no_checks_be_careful( self, futures_contract_object: futuresContract): """ Delete prices for a given contract object without performing any checks WILL THIS WORK IF DOESN'T EXIST? :param futures_contract_object: :return: None """ log = futures_contract_object.log(self.log) ident = from_contract_to_key(futures_contract_object) self.arctic_connection.delete(ident) log.msg("Deleted all prices for %s from %s" % (futures_contract_object.key, str(self)))
def get_min_tick_size_for_contract(self, contract_object: futuresContract) -> float: new_log = contract_object.log(self.log) contract_object_with_ib_data = self.get_contract_object_with_IB_data(contract_object) if contract_object_with_ib_data is missing_contract: new_log.msg("Can't resolve contract so can't find tick size") return missing_contract min_tick_size = self.ibconnection.ib_get_min_tick_size( contract_object_with_ib_data ) if min_tick_size is missing_contract: new_log.msg("No tick size found") return missing_contract return min_tick_size
def _get_prices_for_contract_object_no_checking( self, futures_contract_object: futuresContract ) -> futuresContractPrices: """ Read back the prices for a given contract object :param contract_object: futuresContract :return: data """ keyname = self._keyname_given_contract_object(futures_contract_object) filename = self._filename_given_key_name(keyname) config = self.config date_format = config.input_date_format date_time_column = config.input_date_index_name input_column_mapping = config.input_column_mapping skiprows = config.input_skiprows skipfooter = config.input_skipfooter multiplier = config.apply_multiplier inverse = config.apply_inverse try: instrpricedata = pd_readcsv( filename, date_index_name=date_time_column, date_format=date_format, input_column_mapping=input_column_mapping, skiprows=skiprows, skipfooter=skipfooter, ) except OSError: log = futures_contract_object.log(self.log) log.warn("Can't find adjusted price file %s" % filename) return futuresContractPrices.create_empty() instrpricedata = instrpricedata.groupby(level=0).last() for col_name in ["OPEN", "HIGH", "LOW", "FINAL"]: column_series = instrpricedata[col_name] if inverse: column_series = 1 / column_series column_series *= multiplier instrpricedata[col_name] = column_series.round(2) instrpricedata = futuresContractPrices(instrpricedata) return instrpricedata
def delete_prices_for_contract_object( self, futures_contract_object: futuresContract, areyousure=False): """ :param futures_contract_object: :return: """ if not areyousure: raise Exception( "You have to be sure to delete prices_for_contract_object!") if self.has_data_for_contract(futures_contract_object): self._delete_prices_for_contract_object_with_no_checks_be_careful( futures_contract_object) else: log = futures_contract_object.log(self.log) log.warn("Tried to delete non existent contract")
def update_prices_for_contract( self, contract_object: futuresContract, new_futures_per_contract_prices: futuresContractPrices, check_for_spike: bool = True, ) -> int: """ Reads existing data, merges with new_futures_prices, writes merged data :param new_futures_prices: :return: int, number of rows """ new_log = contract_object.log(self.log) old_prices = self.get_prices_for_contract_object(contract_object) merged_prices = old_prices.add_rows_to_existing_data( new_futures_per_contract_prices, check_for_spike=check_for_spike) if merged_prices is data_error: new_log.msg( "Price has moved too much - will need to manually check - no price updated done" ) return data_error rows_added = len(merged_prices) - len(old_prices) if rows_added == 0: if len(old_prices) == 0: new_log.msg("No existing or additional data") return 0 else: new_log.msg("No additional data since %s " % str(old_prices.index[-1])) return 0 # We have guaranteed no duplication self.write_prices_for_contract_object(contract_object, merged_prices, ignore_duplication=True) new_log.msg("Added %d additional rows of data" % rows_added) return rows_added
def _get_actual_expiry_date_given_single_contract_with_ib_metadata(self, futures_contract_with_ib_data: futuresContract) -> expiryDate: log = futures_contract_with_ib_data.specific_log(self.log) if futures_contract_with_ib_data.is_spread_contract(): log.warn("Can't find expiry for multiple leg contract here") return missing_contract expiry_date = self.ibconnection.broker_get_single_contract_expiry_date( futures_contract_with_ib_data ) if expiry_date is missing_contract: log = futures_contract_with_ib_data.log(self.log) log.msg("No IB expiry date found") return missing_contract else: expiry_date = expiryDate.from_str( expiry_date) return expiry_date
def add_contract_data(self, contract_object: futuresContract, ignore_duplication: bool = False): instrument_code = contract_object.instrument_code contract_date = contract_object.date_str log = contract_object.log(self.log) if self.is_contract_in_data(instrument_code, contract_date): if ignore_duplication: pass else: log.warn( "There is already %s in the data, you have to delete it first" % (contract_object.key)) return None self._add_contract_object_without_checking_for_existing_entry( contract_object) log.terse("Added contract %s %s" % (instrument_code, contract_date))
def _write_prices_for_contract_object_no_checking( self, futures_contract_object: futuresContract, futures_price_data: futuresContractPrices): """ Write prices CHECK prices are overriden on second write :param futures_contract_object: futuresContract :param futures_price_data: futuresContractPriceData :return: None """ log = futures_contract_object.log(self.log) ident = from_contract_to_key(futures_contract_object) futures_price_data_as_pd = pd.DataFrame(futures_price_data) self.arctic_connection.write(ident, futures_price_data_as_pd) log.msg("Wrote %s lines of prices for %s to %s" % (len(futures_price_data), str( futures_contract_object.key), str(self)))
def get_actual_expiry_date_for_contract( self, contract_object: futuresContract) -> expiryDate: """ FIXME CONSIDER USE OF get_contract_object_with_IB_data INSTEAD Get the actual expiry date of a contract from IB :param contract_object: type futuresContract :return: YYYYMMDD or None """ log = contract_object.log(self.log) contract_object_with_ib_data = self._get_contract_object_with_IB_metadata( contract_object) if contract_object_with_ib_data is missing_contract: log.msg("Can't resolve contract so can't find expiry date") return missing_contract expiry_date = self._get_actual_expiry_date_given_contract_with_ib_metadata( contract_object_with_ib_data) return expiry_date
def get_trading_hours_for_contract(self, futures_contract: futuresContract) : """ :param futures_contract: :return: list of paired date times """ new_log = futures_contract.log(self.log) contract_object_with_ib_data = self.get_contract_object_with_IB_data(futures_contract) if contract_object_with_ib_data is missing_contract: new_log.msg("Can't resolve contract") return missing_contract trading_hours = self.ibconnection.ib_get_trading_hours( contract_object_with_ib_data ) if trading_hours is missing_contract: new_log.msg("No IB expiry date found") trading_hours = [] return trading_hours
def _get_prices_for_contract_object_no_checking( self, futures_contract_object: futuresContract) -> futuresContractPrices: """ Read back the prices for a given contract object :param contract_object: futuresContract :return: data """ keyname = self._keyname_given_contract_object(futures_contract_object) filename = self._filename_given_key_name(keyname) config = self.config date_format = config.input_date_format date_time_column = config.input_date_index_name input_column_mapping = config.input_column_mapping skiprows = config.input_skiprows skipfooter = config.input_skipfooter try: instrpricedata = pd_readcsv( filename, date_index_name=date_time_column, date_format=date_format, input_column_mapping=input_column_mapping, skiprows=skiprows, skipfooter=skipfooter, ) except OSError: log = futures_contract_object.log(self.log) log.warning("Can't find adjusted price file %s" % filename) return futuresContractPrices.create_empty() instrpricedata = instrpricedata.groupby(level=0).last() instrpricedata = futuresContractPrices(instrpricedata) return instrpricedata