def sell(self, contract, position): self.ib.qualifyContracts(contract) if position.position>0: order = 'Sell' else: order = 'Buy' marketorder = MarketOrder(order, abs(position.position)) if self.tradeTime!=0: timeDelta = datetime.datetime.now() - self.tradeTime if timeDelta.seconds > self.waitTimeInSeconds: marketTrade, contract, self.tradeTime = self.placeOrder(contract, marketorder) else: marketTrade, contract, tradeTime = self.placeOrder(contract, marketorder) condition = marketTrade.isDone timeout = 20 for c in self.ib.loopUntil(condition=condition, timeout=timeout): marketorder = MarketOrder('Sell', position.position) marketTrade = self.ib.placeOrder(contract, marketorder) if not condition == 'Filled': self.ib.cancelOrder(marketorder) marketorder = MarketOrder('Sell', position.position) marketTrade = self.ib.placeOrder(contract, marketorder)
def _create_fx_market_order_for_submission( self, trade: float, account_id: str = arg_not_supplied) -> MarketOrder: ib_BS_str, ib_qty = resolveBS(trade) ib_order = MarketOrder(ib_BS_str, ib_qty) if account_id is not arg_not_supplied: ib_order.account = account_id return ib_order
def order_send(self, type, lots, sl=0, tp=0, comment=''): market_order = MarketOrder(type, lots) #initial_margin, maintenance_margin = self.get_margins(market_order) self.ib.placeOrder(self.contract, market_order) id = market_order.orderId self.number += 1 price = 0 while price == 0: self.ib.sleep(1) price, commission = self.order_values(id) profit = self.calculate_profit(type, price, lots) trade = {'date':str(self.date)+' '+str(self.hour), 'id':id, 'type':type, 'lots':lots, 'price':price, 'S/L':sl, 'T/P':tp, 'commission':commission, 'comment':comment, 'profit':profit} self.save_trade(trade) self.pool = pd.concat([self.pool,pd.DataFrame(trade,index=[self.number])], sort=False) self.history = pd.concat([self.history,pd.DataFrame(trade,index=[self.number])], sort=False) mult = (lambda dir: 1 if dir == 'BUY' else -1)(type) self.position += (mult*lots) self.pool_check() if self.verbose: print('%s %s | %sING %d units at %5.5f in %s (market)' % (str(self.date), str(self.hour), type, lots, price, self.symbol)) if self.notification: if self.position != 0: self.send_message_in(type, price, sl, tp, lots) else: self.send_message_out(type, price, lots, profit, commission, commission)
def place_market_order(self, contract, qty, fn_on_filled, orderType): order = MarketOrder(order_util.get_order_action(qty), abs(qty), openClose=orderType) trade = self.ib.placeOrder(contract, order) self.loggerOrderHistory.info('\nOpened\n' + str(trade) + '\n\n') trade.filledEvent += fn_on_filled return trade
def buy(self, contract): self.ib.qualifyContracts(contract) marketorder = MarketOrder('Buy', 1) if self.tradeTime!=0: timeDelta = datetime.datetime.now() - self.tradeTime if timeDelta.seconds > self.waitTimeInSeconds: marketTrade, contract, self.tradeTime = self.placeOrder(contract, marketorder) else: marketTrade, contract, tradeTime = self.placeOrder(contract, marketorder) condition = marketTrade.isDone timeout = 10 for c in self.ib.loopUntil(condition=condition, timeout=timeout): marketorder = MarketOrder('Buy', 1) marketTrade = self.ib.placeOrder(contract, marketorder) if not condition == 'Filled': self.ib.cancelOrder(marketorder) marketorder = MarketOrder('Buy', 1) marketTrade = self.ib.placeOrder(contract, marketorder)
def entry_order(action: str, quantity: int) -> Order: """ Return order to be used for entry transactions. """ return MarketOrder(action, quantity, algoStrategy='Adaptive', algoParams=[ TagValue('adaptivePriority', 'Normal')], tif='Day')
def trade(self, contract: Contract, signal: int, amount: int) -> Trade: direction = {1: 'BUY', -1: 'SELL'} order = MarketOrder(direction[signal], amount, algoStrategy='Adaptive', algoParams=[TagValue('adaptivePriority', 'Normal')]) message = (f'entering {direction[signal]} order for {amount} ' f'{contract.localSymbol}') log.debug(message) return self.ib.placeOrder(contract, order)
def reqCommissionsFromIB(self, contracts: List) -> Dict: order = MarketOrder('BUY', 1) commissions = {contract.symbol: self.read_from_file_or_ib( 'commission', 'whatIfOrder', contract, order) for contract in contracts} missing_commissions = [] for contract, commission in commissions.copy().items(): if not commission: missing_commissions.append(contract) del commissions[contract] commissions.update(self.getCommissionBySymbol(missing_commissions)) return commissions
def update_details(ib: IB, store: AbstractBaseStore, keys: Optional[Union[str, List[str]]] = None) -> None: """ Pull contract details from ib and update metadata in store. Args: ib: connected IB instance store: datastore instance, for which data will be updated keys (Optional): keys in datastore, for which data is to be updated, if not given, update all keys """ if keys is None: keys = store.keys() elif isinstance(keys, str): keys = [keys] contracts = {} for key in keys: try: contract = eval(store.read_metadata(key)['repr']) except TypeError: log.error(f'Metadata missing for {key}') continue contract.update(includeExpired=True) contracts[key] = contract ib.qualifyContracts(*contracts.values()) details = {} for k, v in contracts.copy().items(): try: details[k] = ib.reqContractDetails(v)[0] except IndexError: log.error(f'Contract unavailable: {k}') del contracts[k] # get commission levels order = MarketOrder('BUY', 1) commissions = {} for k, v in contracts.items(): try: commissions[k] = ib.whatIfOrder(v, order).commission except AttributeError: log.error(f'Commission unavailable for: {k}') commissions[k] = np.nan for c, d in details.items(): _d = {'name': d.longName, 'min_tick': d.minTick, 'commission': commissions[c] } store.write_metadata(c, _d) log.info('Data written to store.')
def sell(self, contract, position): self.ib.qualifyContracts(contract) if position.position > 0: order = 'Sell' else: order = 'Buy' marketorder = MarketOrder(order, abs(position.position)) marketTrade, contract, tradeTime = self.placeOrder( contract, marketorder) while self.ib.position.position != 0: self.ib.sleep(1) self.mySemaphore.release()
def sell(self, ticker, rank, order_type): log_start = datetime.datetime.now() log = logging_.Logging( self.runtime_tm, log_start, str(self.__class__.__name__ + ',' + sys._getframe().f_code.co_name)) self.hlprs.add_to_manager(self.strat_name, *log.monitor()) order_log_msg = None symbol = ticker.contract.symbol try: ix = self.portfolio_instr.index(symbol) except ValueError: status = -1 print( 'not quite sure why this error sometimes occurs and if this is maybe to early to leave?' ) return status # if isinstance(ticker.domBids, str) == True: # offer_price = ticker.domAsks.price # offer_size = ticker.domAsks.size # else: # offer_price = ticker.domAsks[rank].price # offer_size = ticker.domAsks[rank].size price_ix = 2 size_ix = 3 # held_price = self.held[ix][price_ix] held_size = self.portfolio[ix][size_ix] cnt = 0 max_order_filled_cnts = int(ORDER_CANCEL_IF_NOT_FILLED_SECS / ORDER_FILLED_CHECKED_CYCLE_SECS) if not self.debugging.dummy_data: if order_type == 'MKT': order = MarketOrder('SELL', held_size) # https://github.com/erdewit/ib_insync/blob/master/notebooks/ordering.ipynb trade = self.ib.placeOrder(ticker.contract, order) while cnt < max_order_filled_cnts: order_log_msg = trade.log self.ib.sleep(ORDER_FILLED_CHECKED_CYCLE_SECS) cnt += 1 if trade.orderStatus.status == 'Filled': order_success = True break self.ib.cancelOrder(trade) while not trade.isDone(): print("not sure if this makes sense") self.ib.waitOnUpdate() elif order_type == 'LMT': raise Exception("order type not defined") else: raise Exception("order type not defined") else: order_success = True order_success = True if order_success: status = 0 del self.portfolio[ix] self.hlprs.add_to_manager(self.strat_name, 'portfolio', self.portfolio) del self.portfolio_instr[ix] # self.add_to_monitor('portfolio_instr', self.portfolio_instr) print('not sure if this works') self.cnt_trades_per_instr_per_day[ticker.contract.symbol] += 1 self.hlprs.add_to_manager(self.strat_name, 'cnt_trades_per_instr_per_day', self.cnt_trades_per_instr_per_day) self.heartbeat_q.put([ self.strat_name, 'cnt_trades_per_instr_per_day', self.cnt_trades_per_instr_per_day ]) self.hlprs.add_to_manager( self.strat_name, 'cap_usd', self.cash.available_funds(self.report.pnl(), self.account_curr)) else: status = 1 log.log(self.portfolio, self.portfolio_instr, self.cnt_trades_per_instr_per_day, order_log_msg) return status
def buy(self, ticker, rank, size, order_type): log_start = datetime.datetime.now() log = logging_.Logging( self.runtime_tm, log_start, str(self.__class__.__name__ + ',' + sys._getframe().f_code.co_name)) self.hlprs.add_to_manager(self.strat_name, *log.monitor()) order_log_msg = None symbol = ticker.contract.symbol if self._ticker_len_n_type_check(ticker.domBids) > 1: offer_price = ticker.domBids[rank].price # offer_size = ticker.domBids[rank].size else: offer_price = ticker.domBids.price # offer_size = ticker.domBids.size cnt = 0 max_order_filled_cnts = int(ORDER_CANCEL_IF_NOT_FILLED_SECS / ORDER_FILLED_CHECKED_CYCLE_SECS) if self.debugging.dummy_data: order_success = True else: if order_type == 'MKT': order = MarketOrder('BUY', size) trade = self.ib.placeOrder(ticker.contract, order) while cnt < max_order_filled_cnts: # a bit complicated but it does actually make sense order_log_msg = trade.log self.ib.sleep(ORDER_FILLED_CHECKED_CYCLE_SECS) cnt += 1 if not trade.orderStatus.status != 'Filled': # PendingSubmit = 'PendingSubmit' # PendingCancel = 'PendingCancel' # PreSubmitted = 'PreSubmitted' # Submitted = 'Submitted' # ApiPending = 'ApiPending' # undocumented, can be returned from req(All)OpenOrders # ApiCancelled = 'ApiCancelled' # Cancelled = 'Cancelled' # Filled = 'Filled' # Inactive = 'Inactive' order_success = True break else: self.ib.cancelOrder(trade) # while not trade.isDone(): # print("not sure if this makes sense") # self.ib.waitOnUpdate() elif order_type == 'LMT': raise Exception("order type not defined") else: raise Exception("order type not defined") if order_success: if self.debugging.dummy_time: _now = self._manipulated_time(datetime.datetime.now()) else: _now = datetime.datetime.now() filled_tm = self.us_tz_op(_now) status = 0 self.portfolio.append([symbol, filled_tm, offer_price, size]) self.hlprs.add_to_manager(self.strat_name, 'portfolio', self.portfolio) self.portfolio_instr.append(symbol) # self.add_to_monitor('portfolio_instr', 'self.portfolio_instr') print('not sure if this works') self.cnt_trades_per_instr_per_day[ticker.contract.symbol] += 1 self.hlprs.add_to_manager(self.strat_name, 'cnt_trades_per_instr_per_day', self.cnt_trades_per_instr_per_day) self.heartbeat_q.put([ self.strat_name, 'cnt_trades_per_instr_per_day', self.cnt_trades_per_instr_per_day ]) self.hlprs.add_to_manager( self.strat_name, 'cap_usd', self.cash.available_funds(self.report.pnl(), self.account_curr)) else: status = 1 log.log(self.portfolio, self.portfolio_instr, self.cnt_trades_per_instr_per_day, order_log_msg) return status
async def buy(self, contract): await self.semaphore.acquire() self.ib.qualifyContracts(contract) marketorder = MarketOrder('Buy', 1) marketTrade = self.ib.placeOrder(contract, marketorder)
def close_order(action: str, quantity: int) -> Order: return MarketOrder(action, quantity, tif='GTC')
def place_market_order(self, contract, qty, fn_on_filled): order = MarketOrder(order_util.get_order_action(qty), abs(qty)) trade = self.ib.placeOrder(contract, order) trade.filledEvent += fn_on_filled return trade
def main(): # query config config = db.collection('config').document('paper' if TRADING_MODE == 'local' else TRADING_MODE).get().to_dict() # activity log for Firestore activity_log = { 'agent': (re.match('([\\w-]+)-([0-9]+|manual-[0-9a-z]+)-[0-9a-z]+$', HOSTNAME)).group(1) if HOSTNAME is not None else 'localhost', 'environment': {'DRY_RUN': DRY_RUN, 'ORDER_PROPERTIES': ORDER_PROPERTIES, 'STRATEGIES': STRATEGIES, 'TRADING_MODE': TRADING_MODE}, 'config': config, 'exception': None } main_e = None try: strategies = STRATEGIES.split(',') if STRATEGIES is not None else [] gateway = 'localhost' if TRADING_MODE == 'local' else 'ib-gw-' + TRADING_MODE order_properties = json.loads(ORDER_PROPERTIES) logger.info('Running allocator for {}...'.format(strategies)) # get signals for all strategies signals = {s: get_signal('localhost' if TRADING_MODE == 'local' else s) for s in strategies} activity_log['signals'] = signals # scale w/ exposure scaled_signals = [ { instr: alloc * config['exposure']['strategies'][strat] for instr, alloc in sig.items() } for strat, sig in signals.items() ] activity_log['scaledSignals'] = scaled_signals # consolidate strategies allocation = make_allocation(scaled_signals) activity_log['allocation'] = allocation logger.info('Allocation: {}'.format(activity_log['allocation'])) # connect to IB gateway ib_gw.connect(gateway, 4003, 1) # get net liquidation value account_values = get_account_values(config['account']) base_currency = list(account_values['NetLiquidation'].keys())[0] net_liquidation = float(account_values['NetLiquidation'][base_currency]) activity_log['netLiquidation'] = net_liquidation # get positions positions = {item.contract.conId: item.position for item in ib_gw.positions(config['account'])} activity_log['positions'] = positions # get contract details contract_data = get_contract_data(set(list(allocation.keys()) + list(positions.keys()))) # build contractId->symbol lookup dict symbol_map = {k: v['contract'].localSymbol for k, v in contract_data.items()} activity_log['contractIds'] = {v['contract'].localSymbol: k for k, v in contract_data.items()} # replace dict keys activity_log['signals'] = {k: {symbol_map[k]: v for k, v in v.items()} for k, v in signals.items()} activity_log['scaledSignals'] = [{symbol_map[k]: v for k, v in s.items()} for s in scaled_signals] activity_log['allocation'] = {symbol_map[k]: v for k, v in allocation.items()} activity_log['positions'] = {symbol_map[k]: v for k, v in positions.items()} # get relevant currencies and corresponding FX ratese currencies = {v['contract'].currency for v in contract_data.values()} fx = { c: 1 if c == base_currency else get_tickers(Forex(c + base_currency)) for c in currencies } activity_log['fx'] = { v.contract.symbol + v.contract.currency: v.midpoint() if v.midpoint() == v.midpoint() else v.close for v in fx.values() } # calculate target positions target_positions = { k: round(config['exposure']['overall'] * v * net_liquidation / (contract_data[k]['ticker'].close * int(contract_data[k]['contract'].multiplier) * (fx[contract_data[k]['contract'].currency].midpoint() if fx[contract_data[k]['contract'].currency].midpoint() == fx[contract_data[k]['contract'].currency].midpoint() else fx[contract_data[k]['contract'].currency].close))) for k, v in allocation.items() } for k in target_positions.keys(): if k not in positions: positions[k] = 0 for k in positions.keys(): if k not in target_positions: target_positions[k] = 0 activity_log['positions'] = {symbol_map[k]: v for k, v in positions.items()} activity_log['targetPositions'] = {symbol_map[k]: v for k, v in target_positions.items()} # calculate trade trades = {k: target_positions[k] - positions[k] for k in target_positions.keys()} trades = {k: int(v) for k, v in trades.items() if v != 0} activity_log['trades'] = {symbol_map[k]: v for k, v in trades.items()} logger.info('Trades: {}'.format(activity_log['trades'])) perm_ids = [] if not DRY_RUN: # place orders for k, v in trades.items(): order = ib_gw.placeOrder(contract_data[k]['contract'], MarketOrder(action='BUY' if v > 0 else 'SELL', totalQuantity=abs(v)).update(**order_properties)) perm_ids.append(order.order.permId) ib_gw.sleep(5) # give the IB Gateway a couple of seconds to digest orders and to raise possible errors activity_log['orders'] = { t.contract.localSymbol: { 'order': { k: v for k, v in t.order.nonDefaults().items() if isinstance(v, (int, float, str)) }, 'orderStatus': { k: v for k, v in t.orderStatus.nonDefaults().items() if isinstance(v, (int, float, str)) }, 'isActive': t.isActive() } for t in ib_gw.trades() if t.order.permId in perm_ids } logging.info('Orders placed: {}'.format(activity_log['orders'])) except Exception as e: logger.error(e) activity_log['exception'] = str(e) main_e = e finally: ib_gw.disconnect() try: activity_log['timestamp'] = datetime.now(timezone.utc) db.collection('activity').document().set(activity_log) except Exception as e: logger.error(e) logger.info(activity_log) if main_e is not None: # raise main exception so that CronJob is restarted raise main_e logger.info('Done.')
def close_order(action: str, quantity: int) -> Order: """ Return order to be used for close transactions. """ return MarketOrder(action, quantity, tif='GTC')