def update_historical_prices_with_checks_for_instrument( instrument_code, data, log=logger("")): """ Do a daily update for futures contract prices, using IB historical data Any 'spikes' are manually checked :param instrument_code: str :param data: dataBlob :param log: logger :return: None """ diag_contracts = diagContracts(data) all_contracts_list = diag_contracts.get_all_contract_objects_for_instrument_code( instrument_code) contract_list = all_contracts_list.currently_sampling() if len(contract_list) == 0: log.warn("No contracts marked for sampling for %s" % instrument_code) return failure for contract_object in contract_list: update_historical_prices_with_checks_for_instrument_and_contract( contract_object, data, log=log.setup(contract_date=contract_object.date)) return success
def create_force_roll_orders(data, instrument_code): """ :param data: :param instrument_code: :return: tuple; instrument_order (or missing_order), contract_orders """ diag_positions = diagPositions(data) roll_state = diag_positions.get_roll_state(instrument_code) if roll_state not in ['Force', 'Force_Outright']: return missing_order, [] strategy = ROLL_PSEUDO_STRATEGY trade = 0 instrument_order = instrumentOrder(strategy, instrument_code, trade, roll_order=True, order_type="Zero-roll-order") diag_contracts = diagContracts(data) priced_contract_id = diag_contracts.get_priced_contract_id(instrument_code) forward_contract_id = diag_contracts.get_forward_contract_id(instrument_code) position_in_priced = diag_positions.get_position_for_instrument_and_contract_date(instrument_code, priced_contract_id) if roll_state=='Force_Outright': contract_orders = create_contract_orders_outright(data, instrument_code, priced_contract_id, forward_contract_id, position_in_priced) elif roll_state=='Force': contract_orders = create_contract_orders_spread(data, instrument_code, priced_contract_id, forward_contract_id, position_in_priced) else: raise Exception("Roll state %s not recognised" % roll_state) return instrument_order, contract_orders
def passive_roll_child_order( data: dataBlob, trade: int, instrument_order: instrumentOrder, ) -> list: log = instrument_order.log_with_attributes(data.log) diag_positions = diagPositions(data) instrument_code = instrument_order.instrument_code diag_contracts = diagContracts(data) current_contract = diag_contracts.get_priced_contract_id(instrument_code) next_contract = diag_contracts.get_forward_contract_id(instrument_code) position_current_contract = ( diag_positions.get_position_for_instrument_and_contract_date( instrument_code, current_contract)) # Break out because so darn complicated if position_current_contract == 0: # Passive roll and no position in the current contract, start trading # the next contract log.msg( "Passive roll handling order %s, no position in current contract, entire trade in next contract %s" % (str(instrument_order), next_contract)) return [contractIdAndTrade(next_contract, trade)] # ok still have a position in the current contract increasing_trade = sign(trade) == sign(position_current_contract) if increasing_trade: # Passive roll and increasing trade # Do it all in next contract log.msg( "Passive roll handling order %s, increasing trade, entire trade in next contract %s" % (str(instrument_order), next_contract)) return [contractIdAndTrade(next_contract, trade)] # ok a reducing trade new_position = position_current_contract + trade sign_of_position_is_unchanged = sign(position_current_contract) == sign( new_position) if new_position == 0 or sign_of_position_is_unchanged: # A reducing trade that we can do entirely in the current contract log.msg( "Passive roll handling order %s, reducing trade, entire trade in next contract %s" % (str(instrument_order), next_contract)) return [contractIdAndTrade(current_contract, trade)] # OKAY to recap: it's a passive roll, but the trade will be split between # current and next list_of_child_contract_dates_and_trades = \ passive_trade_split_over_two_contracts(trade=trade, current_contract=current_contract, next_contract=next_contract, position_current_contract=position_current_contract) log.msg( "Passive roll handling order %s, reducing trade, split trade between contract %s and %s" % (str(instrument_order), current_contract, next_contract)) return list_of_child_contract_dates_and_trades
def update_contract_database_with_contract_chain( instrument_code, required_contract_chain, data, log=logtoscreen("")): """ :param required_contract_chain: list of contract dates 'yyyymm' :param instrument_code: str :param data: dataBlob :return: None """ diag_contracts = diagContracts(data) # Get list of contracts in the database all_contracts_in_db = diag_contracts.get_all_contract_objects_for_instrument_code(instrument_code) current_contract_chain = all_contracts_in_db.currently_sampling() #Is something in required_contract_chain, but not in the database? missing_from_db = required_contract_chain.difference(current_contract_chain) #They have probably been added as the result of a recent roll # Let's add them add_missing_contracts_to_database(instrument_code, missing_from_db, data, log=log) #Is something in the database, but not in required_contract_chain? #Then it's eithier expired or weirdly very far in the future (maybe we changed the roll parameters) #Eithier way, we stop sampling it (if it hasn't expired, will be added in the future) contracts_not_sampling = current_contract_chain.difference(required_contract_chain) mark_contracts_as_stopped_sampling(instrument_code, contracts_not_sampling, data, log=log) return None
def add_missing_contracts_to_database(instrument_code, missing_from_db, data, log=logtoscreen("")): """ :param instrument_code: str :param missing_from_db: list of contract_date objects :param data: dataBlob :return: None """ diag_contracts = diagContracts(data) update_contracts = updateContracts(data) for contract_to_add in missing_from_db: contract_date = contract_to_add.date if diag_contracts.is_contract_in_data(instrument_code, contract_date): contract_to_add = diag_contracts.get_contract_data( instrument_code, contract_date) # Mark it as sampling contract_to_add.sampling_on() # Add it to the database # We are happy to overwrite update_contracts.add_contract_data(contract_to_add, ignore_duplication=True) log.msg("Contract %s now added to database and sampling" % str(contract_to_add)) return None
def get_roll_spread_information(data: dataBlob, instrument_code: str) -> rollSpreadInformation: diag_positions = diagPositions(data) diag_contracts = diagContracts(data) diag_prices = diagPrices(data) priced_contract_id = diag_contracts.get_priced_contract_id(instrument_code) forward_contract_id = diag_contracts.get_forward_contract_id( instrument_code) position_in_priced = diag_positions.get_position_for_instrument_and_contract_date( instrument_code, priced_contract_id) reference_date, last_matched_prices = tuple( diag_prices.get_last_matched_date_and_prices_for_contract_list( instrument_code, [priced_contract_id, forward_contract_id])) reference_price_priced_contract, reference_price_forward_contract = last_matched_prices return rollSpreadInformation( priced_contract_id=priced_contract_id, forward_contract_id=forward_contract_id, reference_price_forward_contract=reference_price_forward_contract, reference_price_priced_contract=reference_price_priced_contract, position_in_priced=int(position_in_priced), reference_date=reference_date, instrument_code=instrument_code)
def get_contract_chain(instrument_code, data): diag_contracts = diagContracts(data) diag_prices = diagPrices(data) roll_parameters = diag_contracts.get_roll_parameters(instrument_code) # Get the last contract currently being used multiple_prices = diag_prices.get_multiple_prices(instrument_code) current_contract_dict = multiple_prices.current_contract_dict() current_contract_list = list(current_contract_dict.values()) furthest_out_contract_date = max(current_contract_list) furthest_out_contract = contractDateWithRollParameters( roll_parameters, furthest_out_contract_date) # To give us wiggle room, and ensure we start collecting the new forward a # little in advance final_contract = furthest_out_contract.next_priced_contract() contract_date_chain = ( final_contract.get_unexpired_contracts_from_now_to_contract_date()) # We have a list of contract_date objects, need futureContracts # create a 'bare' instrument object instrument_object = futuresInstrument(instrument_code) contract_object_chain_as_list = [ futuresContract(instrument_object, contract_date_object) for contract_date_object in contract_date_chain ] contract_object_chain = listOfFuturesContracts( contract_object_chain_as_list) return contract_object_chain
def add_missing_contract_to_database(data: dataBlob, contract_to_add: futuresContract): diag_contracts = diagContracts(data) update_contracts = updateContracts(data) instrument_code = contract_to_add.instrument_code contract_date_str = contract_to_add.date_str if diag_contracts.is_contract_in_data(instrument_code, contract_date_str): contract_to_add = diag_contracts.get_contract_object( instrument_code, contract_date_str ) # Mark it as sampling contract_to_add.sampling_on() # Add it to the database # We are happy to overwrite update_contracts.add_contract_data( contract_to_add, ignore_duplication=True) log = data.log.setup(instrument_code=instrument_code) log.msg( "Contract %s now added to database and sampling" % str(contract_to_add))
def update_historical_prices_for_instrument(instrument_code: str, data: dataBlob): """ Do a daily update for futures contract prices, using IB historical data :param instrument_code: str :param data: dataBlob :return: None """ diag_contracts = diagContracts(data) all_contracts_list = diag_contracts.get_all_contract_objects_for_instrument_code( instrument_code) contract_list = all_contracts_list.currently_sampling() if len(contract_list) == 0: data.log.warn("No contracts marked for sampling for %s" % instrument_code) return failure for contract_object in contract_list: data.log.label(contract_date=contract_object.date_str) update_historical_prices_for_instrument_and_contract( contract_object, data) return success
def mark_contracts_as_stopped_sampling(instrument_code, contracts_not_sampling, data, log=logtoscreen("")): """ :param instrument_code: str :param contracts_not_sampling: list of contractDate objects :param data: dataBlobg :return: None """ diag_contracts = diagContracts(data) update_contracts = updateContracts(data) for contract_date_object in contracts_not_sampling: contract_date = contract_date_object.date # Mark it as stop sampling in the database contract = diag_contracts.get_contract_data(instrument_code, contract_date) if contract.currently_sampling: contract.sampling_off() update_contracts.add_contract_data(contract, ignore_duplication=True) log.msg( "Contract %s has now stopped sampling" % str(contract), contract_date=contract.date, ) else: # nothing to do pass return None
def update_expiry_for_contract(contract_object, data): """ Get an expiry from IB, check if same as database, otherwise update the database :param contract_object: contract object :param data: dataBlob :param log: log :return: None """ log = data.log diag_contracts = diagContracts(data) data_broker = dataBroker(data) update_contracts = updateContracts(data) contract_date = contract_object.date instrument_code = contract_object.instrument_code log = log.setup( instrument_code=instrument_code, contract_date=contract_date) db_contract = diag_contracts.get_contract_data( instrument_code, contract_date) # Both should be in format expiryDate(yyyy,mm,dd) db_expiry_date = db_contract.date.expiry_date try: ib_expiry_date = ( data_broker.get_actual_expiry_date_for_instrument_code_and_contract_date( instrument_code, contract_date)) if ib_expiry_date is missing_contract: raise Exception() except Exception as e: # We can do nothing with that... log.warn( "%s so couldn't get expiry date for %s" % (e, str(contract_object))) return None # Will they be same format? if ib_expiry_date == db_expiry_date: log.msg( "No change to contract expiry %s to %s" % (str(contract_object), str(ib_expiry_date)) ) return None # Different! contract_object.date.update_expiry_date(ib_expiry_date) update_contracts.add_contract_data( contract_object, ignore_duplication=True) log.msg( "Updated expiry of contract %s to %s" % (str(contract_object), str(ib_expiry_date)) ) return None
def get_current_contract_chain_in_db(data: dataBlob, instrument_code:str) -> listOfFuturesContracts: diag_contracts = diagContracts(data) # Get list of contracts in the database all_contracts_in_db = diag_contracts.get_all_contract_objects_for_instrument_code( instrument_code) current_contract_chain = all_contracts_in_db.currently_sampling() return current_contract_chain
def get_trading_hours_for_instrument(data, instrument_code): diag_contracts = diagContracts(data) contract_id = diag_contracts.get_priced_contract_id(instrument_code) data_broker = dataBroker(data) trading_hours = data_broker.get_trading_hours_for_instrument_code_and_contract_date(instrument_code, contract_id) return trading_hours
def view_contract_config(data): instrument_code, contract_id = get_valid_instrument_code_and_contractid_from_user(data) diag_contracts = diagContracts(data) contract_object = diag_contracts.get_contract_object(instrument_code, contract_id) contract_date = diag_contracts.get_contract_date_object_with_roll_parameters(instrument_code, contract_id) print(contract_object.as_dict()) print(contract_date.roll_parameters) return None
def get_required_contract_trade_for_instrument( data: dataBlob, instrument_order: instrumentOrder) -> list: """ Return the contract to trade for a given instrument Depends on roll status and trade vs position: - roll_states = ['No_Roll', 'Passive', 'Force', 'Force_Outright', 'Roll_Adjusted'] If 'No Roll' then trade current contract If 'Passive', and no position in current contract: trade next contract If 'Passive', and reducing trade which leaves zero or something in current contract: trade current contract If 'Passive', and reducing trade which is larger than current contract position: trade current and next contract If 'Passive', and increasing trade: trade next contract If 'Force' or 'Force Outright' or 'Roll_Adjusted': don't trade :param instrument_order: :param data: dataBlog :return: tuple: list of child orders: each is a tuple: contract str or missing_contract, trade int """ instrument_code = instrument_order.instrument_code log = instrument_order.log_with_attributes(data.log) trade = instrument_order.as_single_trade_qty_or_error() if trade is missing_order: log.critical("Instrument order can't be a spread order") return [] diag_positions = diagPositions(data) if diag_positions.is_roll_state_no_roll(instrument_code): diag_contracts = diagContracts(data) current_contract = diag_contracts.get_priced_contract_id( instrument_code) log.msg("No roll, allocating entire order %s to current contract %s" % (str(instrument_order), current_contract)) return [contractIdAndTrade(current_contract, trade)] elif diag_positions.is_roll_state_passive(instrument_code): # no log as function does it list_of_child_contract_dates_and_trades = passive_roll_child_order( data=data, instrument_order=instrument_order, trade=trade) return list_of_child_contract_dates_and_trades elif diag_positions.is_type_of_active_rolling_roll_state(instrument_code): log.msg( "Roll state is active rolling, not going to generate trade for order %s" % (str(instrument_order))) return [] else: log.critical( "Roll state %s not understood: can't generate trade for %s" % (diag_positions.get_name_of_roll_state(instrument_code), str(instrument_order))) return []
def get_roll_data_for_instrument(instrument_code, data): """ Get roll data for an individual instrument :param instrument_code: str :param data: dataBlob :return: """ c_data = diagContracts(data) relevant_contract_dict = c_data.get_labelled_list_of_relevant_contracts( instrument_code) relevant_contracts = relevant_contract_dict['contracts'] contract_labels = relevant_contract_dict['labels'] current_contracts = relevant_contract_dict['current_contracts'] v_data = diagVolumes(data) volumes = v_data.get_normalised_smoothed_volumes_of_contract_list( instrument_code, relevant_contracts) # price curve p_data = diagPrices(data) contracts_to_match = [current_contracts[k] for k in ('PRICE', 'FORWARD')] last_matched_prices = p_data.get_last_matched_prices_for_contract_list( instrument_code, relevant_contracts, contracts_to_match=contracts_to_match) # length to expiries / length to suggested roll price_expiry = c_data.get_priced_expiry(instrument_code) carry_expiry = c_data.get_carry_expiry(instrument_code) when_to_roll = c_data.when_to_roll_priced_contract(instrument_code) now = datetime.datetime.now() price_expiry_days = (price_expiry - now).days carry_expiry_days = (carry_expiry - now).days when_to_roll_days = (when_to_roll - now).days # roll status s_data = diagPositions(data) roll_status = s_data.get_roll_state(instrument_code) # Positions positions = s_data.get_positions_for_instrument_and_contract_list( instrument_code, relevant_contracts) results_dict_code = dict(code=instrument_code, status=roll_status, roll_expiry=when_to_roll_days, price_expiry=price_expiry_days, carry_expiry=carry_expiry_days, contract_labels=contract_labels, volumes=volumes, curve=last_matched_prices, positions=positions) return results_dict_code
def create_furthest_out_contract_with_roll_parameters_from_contract_date( data: dataBlob, instrument_code: str, furthest_out_contract_date: str): diag_contracts = diagContracts(data) roll_parameters = diag_contracts.get_roll_parameters(instrument_code) furthest_out_contract = contractDateWithRollParameters( contractDate(furthest_out_contract_date), roll_parameters) return furthest_out_contract
def construct_position_entry(data, system, instrument_code, lower_buffer, upper_buffer): diag_contracts = diagContracts(data) reference_price = system.rawdata.get_daily_prices(instrument_code).iloc[-1] reference_contract = diag_contracts.get_priced_contract_id(instrument_code) position_entry = bufferedOptimalPositions(lower_buffer, upper_buffer, reference_price, reference_contract) return position_entry
def create_force_roll_orders(data, instrument_code): """ :param data: :param instrument_code: :return: tuple; instrument_order (or missing_order), contract_orders """ diag_positions = diagPositions(data) strategy = ROLL_PSEUDO_STRATEGY trade = 0 instrument_order = instrumentOrder( strategy, instrument_code, trade, roll_order=True, order_type="Zero-roll-order") diag_contracts = diagContracts(data) priced_contract_id = diag_contracts.get_priced_contract_id(instrument_code) forward_contract_id = diag_contracts.get_forward_contract_id( instrument_code) position_in_priced = diag_positions.get_position_for_instrument_and_contract_date( instrument_code, priced_contract_id) if position_in_priced == 0: return missing_order, [] if diag_positions.is_roll_state_force(instrument_code): contract_orders = create_contract_orders_outright( data, instrument_code, priced_contract_id, forward_contract_id, position_in_priced, ) elif diag_positions.is_roll_state_force_outright(instrument_code): contract_orders = create_contract_orders_spread( data, instrument_code, priced_contract_id, forward_contract_id, position_in_priced, ) else: log = instrument_order.log_with_attributes(data.log) log.warn("Roll state %s is unexpected, might have changed" % str(roll_state)) return missing_order, [] contract_orders = allocate_algo_to_list_of_contract_orders( data, contract_orders, instrument_order=instrument_order ) return instrument_order, contract_orders
def get_required_contract_trade_for_instrument(data, instrument_order): """ Return the contract to trade for a given instrument Depends on roll status and trade vs position: - roll_states = ['No_Roll', 'Passive', 'Force', 'Force_Outright', 'Roll_Adjusted'] If 'No Roll' then trade current contract If 'Passive', and no position in current contract: trade next contract If 'Passive', and reducing trade which leaves zero or something in current contract: trade current contract If 'Passive', and reducing trade which is larger than current contract position: trade current and next contract If 'Passive', and increasing trade: trade next contract If 'Force' or 'Force Outright' or 'Roll_Adjusted': don't trade :param instrument_order: :param data: dataBlog :return: tuple: list of child orders: each is a tuple: contract str or missing_contract, trade int """ instrument_code = instrument_order.instrument_code log = instrument_order.log_with_attributes(data.log) trade = instrument_order.trade.as_int() if trade is missing_order: log.critical("Instrument order can't be a spread order") return missing_contract diag_contracts = diagContracts(data) current_contract = diag_contracts.get_priced_contract_id(instrument_code) next_contract = diag_contracts.get_forward_contract_id(instrument_code) diag_positions = diagPositions(data) roll_state = diag_positions.get_roll_state(instrument_code) position_current_contract = diag_positions.get_position_for_instrument_and_contract_date( instrument_code, current_contract) if roll_state == 'No_Roll': log.msg("No roll, allocating entire order %s to current contract %s" % (str(instrument_order), current_contract)) return [(current_contract, trade)] elif roll_state in ['Force', 'Force_Outright', 'Roll_Adjusted']: log.msg( "Roll state %s is rolling, not going to generate trade for order %s" % (roll_state, str(instrument_order))) return rolling_cant_trade elif roll_state == "Passive": return passive_roll_child_order(position_current_contract, current_contract, next_contract, trade, log, instrument_order) else: log.critical( "Roll state %s not understood: can't generate trade for %s" % (roll_state, str(instrument_order))) return missing_contract
def get_required_roll_state(data: dataBlob, instrument_code: str): diag_positions = diagPositions(data) diag_contracts = diagContracts(data) current_roll_status = diag_positions.get_roll_state(instrument_code) priced_contract_date = diag_contracts.get_priced_contract_id( instrument_code) position_priced_contract = ( diag_positions.get_position_for_instrument_and_contract_date( instrument_code, priced_contract_date)) allowable_roll_states = allowable_roll_state_from_current_and_position( current_roll_status, position_priced_contract) max_possible_states = len(allowable_roll_states) - 1 roll_state_required = no_state_available while roll_state_required is no_state_available: display_roll_query_banner(current_roll_status, position_priced_contract, allowable_roll_states) number_of_state_required = input("Which state do you want? [0-%d] " % max_possible_states) try: number_of_state_required = int(number_of_state_required) assert number_of_state_required >= 0 # avoid weird behaviour roll_state_required = allowable_roll_states[ number_of_state_required] except BaseException: print( "State %s is not an integer specifying a possible roll state\n" % number_of_state_required) roll_state_required = no_state_available # will try again continue # Update roll state if roll_state_required != current_roll_status: # check if changing print("") check = input( "Changing roll state for %s from %s to %s, are you sure y/n: " % (instrument_code, current_roll_status, roll_state_required)) print("") if check == "y": # happy break else: print("OK. Choose again.") roll_state_required = no_state_available # back to top of loop continue return current_roll_status, roll_state_required
def get_roll_data_for_instrument(instrument_code, data): """ Get roll data for an individual instrument :param instrument_code: str :param data: dataBlob :return: """ c_data = diagContracts(data) relevant_contract_dict = c_data.get_labelled_list_of_relevant_contracts( instrument_code) list_of_relevant_contract_date_str = relevant_contract_dict["contracts"] contract_labels = relevant_contract_dict["labels"] current_contracts = relevant_contract_dict["current_contracts"] v_data = diagVolumes(data) volumes = v_data.get_normalised_smoothed_volumes_of_contract_list( instrument_code, list_of_relevant_contract_date_str) # length to expiries / length to suggested roll price_expiry = c_data.get_priced_expiry(instrument_code) carry_expiry = c_data.get_carry_expiry(instrument_code) when_to_roll = c_data.when_to_roll_priced_contract(instrument_code) now = datetime.datetime.now() price_expiry_days = (price_expiry - now).days carry_expiry_days = (carry_expiry - now).days when_to_roll_days = (when_to_roll - now).days # roll status diag_positions = diagPositions(data) roll_status = diag_positions.get_name_of_roll_state(instrument_code) # Positions positions = diag_positions.get_positions_for_instrument_and_contract_list( instrument_code, list_of_relevant_contract_date_str) results_dict_code = dict( code=instrument_code, status=roll_status, roll_expiry=when_to_roll_days, price_expiry=price_expiry_days, carry_expiry=carry_expiry_days, contract_labels=contract_labels, volumes=volumes, positions=positions, ) return results_dict_code
def setup_roll_data(data: dataBlob, instrument_code: str) -> RollData: diag_positions = diagPositions(data) diag_contracts = diagContracts(data) original_roll_status = diag_positions.get_roll_state(instrument_code) priced_contract_date = diag_contracts.get_priced_contract_id( instrument_code) position_priced_contract = ( diag_positions.get_position_for_instrument_and_contract_date( instrument_code, priced_contract_date)) allowable_roll_states = allowable_roll_state_from_current_and_position( original_roll_status, position_priced_contract) roll_data = RollData(instrument_code, original_roll_status, position_priced_contract, allowable_roll_states) return roll_data
def update_expiry_for_contract(contract_object: futuresContract, data: dataBlob): """ Get an expiry from IB, check if same as database, otherwise update the database :param contract_object: contract object :param data: dataBlob :param log: log :return: None """ log = data.log diag_contracts = diagContracts(data) data_broker = dataBroker(data) contract_date = contract_object.date_str instrument_code = contract_object.instrument_code log = log.setup( instrument_code=instrument_code, contract_date=contract_date) db_contract = diag_contracts.get_contract_object( instrument_code, contract_date) db_expiry_date = db_contract.expiry_date broker_expiry_date = \ data_broker.get_actual_expiry_date_for_single_contract(db_contract) if broker_expiry_date is missing_contract: log.msg( "Can't find expiry for %s, could be a connection problem but could be because contract has already expired" % (str(contract_object)) ) ## don't warn as probably expired we'll remove it from the sampling list return None if broker_expiry_date == db_expiry_date: log.msg( "No change to contract expiry %s to %s" % (str(contract_object), str(broker_expiry_date)) ) return None # Different! update_contract_object_with_new_expiry_date(data, broker_expiry_date, contract_object)
def update_expiries_of_sampled_contracts(instrument_code, data, log=logtoscreen("")): """ # Now to check if expiry dates are resolved # For everything in the database which is sampling # - if it hasn't got an IB expiry recorded, then check for the expiry in IB (can fail) # - if expiry found, add expiry to database, and flag in lookup table as found :param instrument_code: :param data: dataBlob :return: None """ diag_contracts = diagContracts(data) all_contracts_in_db = diag_contracts.get_all_contract_objects_for_instrument_code(instrument_code) currently_sampling_contracts = all_contracts_in_db.currently_sampling() for contract_object in currently_sampling_contracts: update_expiry_for_contract(contract_object, data) return None
def update_expiry_for_contract(contract_object: futuresContract, data: dataBlob): """ Get an expiry from IB, check if same as database, otherwise update the database :param contract_object: contract object :param data: dataBlob :param log: log :return: None """ log = data.log diag_contracts = diagContracts(data) data_broker = dataBroker(data) contract_date = contract_object.date_str instrument_code = contract_object.instrument_code log = log.setup(instrument_code=instrument_code, contract_date=contract_date) db_contract = diag_contracts.get_contract_object(instrument_code, contract_date) db_expiry_date = db_contract.expiry_date broker_expiry_date = \ data_broker.get_actual_expiry_date_for_contract(db_contract) if broker_expiry_date is missing_contract: log.warn("Couldn't get expiry date for %s" % (str(contract_object))) return None if broker_expiry_date == db_expiry_date: log.msg("No change to contract expiry %s to %s" % (str(contract_object), str(broker_expiry_date))) return None # Different! update_contract_object_with_new_expiry_date(data, broker_expiry_date, contract_object)
def stop_expired_contracts_sampling(instrument_code: str, data: dataBlob): ## expiry dates will have been updated and are correct current_contract_chain_in_db = get_current_contract_chain_in_db(data, instrument_code) diag_contracts = diagContracts(data) update_contracts = updateContracts(data) log = data.log.setup(instrument_code=instrument_code) for contract_date_object in current_contract_chain_in_db: contract_date = contract_date_object.date_str # Mark it as stop sampling in the database contract = diag_contracts.get_contract_object( instrument_code, contract_date) if contract.expired() and contract.currently_sampling: contract.sampling_off() update_contracts.add_contract_data( contract, ignore_duplication=True) log.msg( "Contract %s has now stopped sampling" % str(contract), contract_date=contract.date_str, )
def update_multiple_prices_on_roll(data, current_multiple_prices, instrument_code): """ Roll multiple prices Adds rows to multiple prices First row: (optionally) Inferred price and forward prices If there is no (old) forward contract price, one needs to be inferred If there is no (old) price contract price, one needs to be inferred Time index = Last time index + 1 second Second row: Time index: Last time index + 1 second PRICE = last price of the forward contract PRICE_CONTRACT = previous forward contract FORWARD_CONTRACT = the new forward contract FORWARD_PRICE = the new forward price, this can be Nan; it will get filled in CARRY_CONTRACT = the new carry contract CARRY_PRICE = the new carry price: if possible infer from price, this can be Nan :param data: dataBlob :param current_multiple_prices: futuresMultiplePrices :return: new futuresMultiplePrices """ new_multiple_prices = futuresMultiplePrices(copy(current_multiple_prices)) ## If the last row is all Nans, we can't do this new_multiple_prices = new_multiple_prices.sort_index() new_multiple_prices = new_multiple_prices.drop_trailing_nan() price_column = price_column_names['PRICE'] fwd_column = price_column_names['FORWARD'] current_contract_dict = new_multiple_prices.current_contract_dict() old_forward_contract = current_contract_dict[fwd_column] old_priced_contract_last_price, price_inferred = get_or_infer_latest_price( new_multiple_prices, price_col=price_column) old_forward_contract_last_price, forward_inferred = get_or_infer_latest_price( new_multiple_prices, price_col=fwd_column) diag_contracts = diagContracts(data) instrument_object = futuresInstrument(instrument_code) ## Old forward contract -> New price contract new_price_contract_date_object = diag_contracts.get_contract_date_object_with_roll_parameters( instrument_code, old_forward_contract) new_price_contract_object = futuresContract( instrument_object, new_price_contract_date_object) new_forward_contract_object = new_price_contract_object.next_held_contract( ) new_carry_contract_object = new_price_contract_object.carry_contract() new_price_price = get_final_matched_price_from_contract_object( data, new_price_contract_object, new_multiple_prices) new_forward_price = get_final_matched_price_from_contract_object( data, new_forward_contract_object, new_multiple_prices) new_carry_price = get_final_matched_price_from_contract_object( data, new_carry_contract_object, new_multiple_prices) new_price_contractid = new_price_contract_object.date new_forward_contractid = new_forward_contract_object.date new_carry_contractid = new_carry_contract_object.date # If any prices had to be inferred, then add row with both current priced and forward prices # Otherwise adjusted prices will break if price_inferred or forward_inferred: new_multiple_prices = new_multiple_prices.add_one_row_with_time_delta( dict(price=old_priced_contract_last_price, forward=old_forward_contract_last_price)) ## SOME KIND OF WARNING HERE...? # Now we add a row with the new rolled contracts new_multiple_prices = new_multiple_prices.add_one_row_with_time_delta( dict(price=new_price_price, forward=new_forward_price, carry=new_carry_price, price_contract=new_price_contractid, forward_contract=new_forward_contractid, carry_contract=new_carry_contractid)) return new_multiple_prices