def update_fx_prices_for_code(fx_code, data): broker_fx_source = dataBroker(data) db_fx_data = currencyData(data) new_fx_prices = broker_fx_source.get_fx_prices( fx_code) # returns fxPrices object rows_added = db_fx_data.update_fx_prices( fx_code, new_fx_prices, check_for_spike=True ) if rows_added is data_error: msg = ( "Spike found in prices for %s: need to manually check by running interactive_manual_check_fx_prices" % str(fx_code)) data.log.warn(msg) try: send_production_mail_msg( data, msg, "FX Price Spike %s" % str(fx_code)) except BaseException: data.log.warn("Couldn't send email about price spike") return success
def algo_market(data, contract_order): """ Simplest possible execution algo Submits a single market order for the entire quantity :param data: dataBlob :param contract_order: contractOrder :returns: tuple, (broker_order, reference of controlling algo) """ log = contract_order.log_with_attributes(data.log) if not contract_order.fill_equals_zero(): log.warn( "Simple market algo can only deal with orders that have no existing fill, not %s!" % str(contract_order)) return missing_order, "" qty = contract_order.trade ## do full order qty_for_broker = qty data_broker = dataBroker(data) broker_order_with_controls = data_broker.get_and_submit_broker_order_for_contract_order_with_quantity( contract_order, qty_for_broker) broker_order = broker_order_with_controls.order ## Need some kind of keystore for controlling Algos ## However as this is a 'fire and forget' algo that just runs once without any permanent thread ## this doesn't matter, except perhaps for some complex case that we don't want to worry about right now ## When we introduce hooks for picking up fills, we're probably going to want to do this properly reference_of_controlling_algo = "algo_market" return broker_order, reference_of_controlling_algo
def get_and_add_prices_for_frequency(data, log, contract_object, frequency="D"): broker_data_source = dataBroker(data) db_futures_prices = updatePrices(data) try: ib_prices = broker_data_source.get_prices_at_frequency_for_contract_object( contract_object, frequency) rows_added = db_futures_prices.update_prices_for_contract( contract_object, ib_prices, check_for_spike=True) if rows_added is data_error: # SPIKE # Need to email user about this as will need manually checking msg = ( "Spike found in prices for %s: need to manually check by running interactive_manual_check_historical_prices" % str(contract_object)) log.warn(msg) try: send_production_mail_msg( data, msg, "Price Spike %s" % contract_object.instrument_code) except BaseException: log.warn("Couldn't send email about price spike for %s" % str(contract_object)) return failure log.msg("Added %d rows at frequency %s for %s" % (rows_added, frequency, str(contract_object))) return success except Exception as e: log.warn("Exception %s when getting data at frequency %s for %s" % (e, frequency, str(contract_object))) return failure
def get_and_check_prices_for_frequency(data, log, contract_object, frequency="D"): broker_data = dataBroker(data) price_data = diagPrices(data) price_updater = updatePrices(data) try: old_prices = price_data.get_prices_for_contract_object(contract_object) ib_prices = broker_data.get_prices_at_frequency_for_contract_object(contract_object, frequency) if len(ib_prices) == 0: raise Exception("No IB prices found for %s nothing to check" % str(contract_object)) print("\n\n Manually checking prices for %s \n\n" % str(contract_object)) new_prices_checked = manual_price_checker(old_prices, ib_prices, column_to_check='FINAL', delta_columns=['OPEN', 'HIGH', 'LOW'], type_new_data=futuresContractPrices ) result = price_updater.update_prices_for_contract(contract_object, new_prices_checked, check_for_spike=False) return result except Exception as e: log.warn("Exception %s when getting or checking data at frequency %s for %s" % (e, frequency, str(contract_object))) return failure
def prepare_and_submit_trade(data, contract_order): log = contract_order.log_with_attributes(data.log) data_broker = dataBroker(data) cut_down_contract_order = contract_order.reduce_trade_size_proportionally_so_smallest_leg_is_max_size( SIZE_LIMIT) if cut_down_contract_order.trade != contract_order.trade: log.msg( "Cut down order to size %s from %s because of algo size limit" % (str(contract_order.trade), str(cut_down_contract_order.trade))) ticker_object = data_broker.get_ticker_object_for_order( cut_down_contract_order) okay_to_do_limit_trade = limit_trade_viable(ticker_object) if okay_to_do_limit_trade: # create and issue limit order broker_order_with_controls = ( data_broker.get_and_submit_broker_order_for_contract_order( cut_down_contract_order, order_type="limit", limit_price_from="offside_price", ticker_object=ticker_object, )) else: # do a market order log.msg( "Conditions are wrong so doing market trade instead of limit trade" ) broker_order_with_controls = ( data_broker.get_and_submit_broker_order_for_contract_order( cut_down_contract_order, order_type="market")) return broker_order_with_controls
def cancel_order( data: dataBlob, broker_order_with_controls: orderWithControls) -> orderWithControls: log = broker_order_with_controls.order.log_with_attributes(data.log) data_broker = dataBroker(data) data_broker.cancel_order_given_control_object(broker_order_with_controls) # Wait for cancel. It's vitual we do this since if a fill comes in before we finish it will screw # everything up... timer = quickTimer(seconds=CANCEL_WAIT_TIME) not_cancelled = True while not_cancelled: is_cancelled = data_broker.check_order_is_cancelled_given_control_object( broker_order_with_controls) if is_cancelled: log.msg("Cancelled order") break if timer.finished: log.warn( "Ran out of time to cancel order - may cause weird behaviour!") break return broker_order_with_controls
def get_broker_account_value(data: dataBlob): data_broker = dataBroker(data) capital_value = data_broker.get_total_capital_value_in_base_currency() return capital_value
def create_broker_order_for_contract_order(self, contract_order_id, check_if_open=True): original_contract_order = self.contract_stack.get_order_with_id_from_stack(contract_order_id) log = original_contract_order.log_with_attributes(self.log) data_locks = dataLocks(self.data) instrument_locked = data_locks.is_instrument_locked(original_contract_order.instrument_code) if instrument_locked: log.msg("Instrument is locked, not spawning order") return None if check_if_open: data_broker = dataBroker(self.data) market_open = data_broker.is_instrument_code_and_contract_date_okay_to_trade(original_contract_order.instrument_code, original_contract_order.contract_id) if not market_open: return None # We can deal with partially filled contract orders: that's how hard we are! remaining_contract_order = original_contract_order.order_with_remaining() ## Check the order doesn't breach trade limits contract_order = self.what_contract_trade_is_possible(remaining_contract_order) ## Note we don't save the algo method, but reallocate each time ## This is useful if trading is about to finish, because we switch to market orders ## (assuming a bunch of limit orders haven't worked out so well) contract_order = check_and_if_required_allocate_algo_to_single_contract_order(self.data, contract_order) algo_to_use_str = contract_order.algo_to_use algo_method = resolve_function(algo_to_use_str) ## The algo method submits an order to the broker, and returns a broker order object ## We then save the brokerorder in the broker stack, and add it as a child to a contract order ## Algos may be 'fire and forget' (a simple market order, as implemented initially) or 'active' ## Active algos need to keep running on another thread (need to work out how to do this) ## They will set the property 'reference_of_controlling_algo' in contract order ## Fills are picked up by another process (or if the algo is an active thing, potentially by itself) broker_order, reference_of_controlling_algo = algo_method(self.data, contract_order) if broker_order is missing_order: # something bad has happened and we can't submit an order to the broker # Nae bother, maybe try again later # Unlock the contract order in case we want to do this later self.contract_stack.release_order_from_algo_control(contract_order_id) return None ## update trade limits self.add_trade_to_trade_limits(broker_order) broker_order_id = self.broker_stack.put_order_on_stack(broker_order) if type(broker_order_id) is not int: # We've created a broker order but can't add it to the broker order database # Probably safest to leave the contract order locked otherwise there could be multiple # broker orders issued and nobody wants that! log.critical("Created a broker order %s but can't add it to the order stack!! (condition %s)" % (str(broker_order), str(broker_order_id))) return failure # ....create new algo lock # This means nobody else can try and execute this order until it is released # Only the algo itself can release! # This only applies to 'fire and forget' orders that aren't controlled by an algo self.contract_stack.add_controlling_algo_ref(contract_order_id, reference_of_controlling_algo) # This broker order is a child of the parent contract order # We add 'another' child since it's valid to have multiple broker orders self.contract_stack.add_another_child_to_order(contract_order_id, broker_order_id) return success