def load_bars(days_in_history, wanted_tf, start_offset_minutes=0, exchange='bybit', symbol='BTCUSD'): #empty symbol is legacy and means btcusd end = known_history_files[exchange + "_" + symbol] start = max(0, end - int(days_in_history * 1440 / 50000)) m1_bars_temp = [] logger.info("loading " + str(end - start + 1) + " history files from " + exchange) for i in range(start, end + 1): with open(history_file_name(i, exchange, symbol)) as f: m1_bars_temp += json.load(f) logger.info("done loading files, now preparing them") start = max(0, len(m1_bars_temp) - (days_in_history * 1440)) m1_bars = m1_bars_temp[start:] subbars: List[Bar] = [] for b in m1_bars: if exchange == 'bybit': if b['open'] is None: continue subbars.append(ByBitInterface.barDictToBar(b)) elif exchange == 'bitmex': if b['open'] is None: continue subbars.append(BitmexInterface.barDictToBar(b, wanted_tf)) elif exchange in ['binance_future', 'binanceSpot']: subbars.append(BinanceFuturesInterface.barArrayToBar(b)) elif exchange == 'phemex': subbars.append(PhemexInterface.barArrayToBar(b, 10000)) subbars.reverse() return process_low_tf_bars(subbars, wanted_tf, start_offset_minutes)
def load_bars(days_in_history, wanted_tf, start_offset_minutes=0, exchange='bitmex'): knownfiles = {"bitmex": 45, "bybit": 14, "binance": 6, "binanceSpot": 28} end = knownfiles[exchange] start = max(0, end - int(days_in_history * 1440 / 50000)) m1_bars = [] logger.info("loading " + str(end - start) + " history files from " + exchange) for i in range(start, end + 1): with open('history/' + exchange + '/M1_' + str(i) + '.json') as f: m1_bars += json.load(f) logger.info("done loading files, now preparing them") subbars: List[Bar] = [] for b in m1_bars: if exchange == 'bybit': if b['open'] is None: continue subbars.append(ByBitInterface.barDictToBar(b)) elif exchange == 'bitmex': if b['open'] is None: continue subbars.append(BitmexInterface.barDictToBar(b, wanted_tf)) elif exchange in ['binance', 'binanceSpot']: subbars.append(BinanceInterface.barArrayToBar(b)) subbars.reverse() return process_low_tf_bars(subbars, wanted_tf, start_offset_minutes)
def __init__(self, settings, trading_bot: TradingBot): self.settings = settings self.id = self.settings.id self.last_tick = 0 self.logger = log.setup_custom_logger( name=settings.id, log_level=settings.LOG_LEVEL, logToConsole=settings.LOG_TO_CONSOLE, logToFile=settings.LOG_TO_FILE) self.exchange: ExchangeInterface = None if settings.EXCHANGE == 'bitmex': self.exchange = BitmexInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) elif settings.EXCHANGE == 'bybit': self.exchange = ByBitInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) else: self.logger.error("unkown exchange: " + settings.EXCHANGE) self.alive = False return self.alive = True if self.exchange.is_open(): self.logger.info( "############# Starting Live Trading Engine for %s ##############" % self.exchange.symbol) self.symbolInfo: Symbol = self.exchange.get_instrument() self.bot: TradingBot = trading_bot self.bot.prepare(self.logger, self) # init market data dict to be filled later self.bars: List[Bar] = [] self.update_bars() self.account: Account = Account() self.update_account() self.bot.reset() else: self.alive = False
def load_bars(days_in_history, wanted_tf, start_offset_minutes=0,exchange='bitmex'): end = 45 if exchange == 'bitmex' else 14 start = max(0,end - int(days_in_history * 1440 / 50000)) m1_bars = [] logger.info("loading " + str(end - start) + " history files from "+exchange) for i in range(start, end + 1): with open('history/'+exchange+'/M1_' + str(i) + '.json') as f: m1_bars += json.load(f) logger.info("done loading files, now preparing them") subbars: List[Bar] = [] if exchange == 'bybit': for b in m1_bars: if b['open'] is None: continue subbars.append(ByBitInterface.barDictToBar(b)) else: for b in m1_bars: if b['open'] is None: continue subbars.append(BitmexInterface.barDictToBar(b,wanted_tf)) subbars.reverse() return process_low_tf_bars(subbars, wanted_tf, start_offset_minutes)
def __init__(self, settings, telegram: TelegramBot, trading_bot: TradingBot): self.settings = settings self.id = self.settings.id self.last_tick = 0 self.logger = log.setup_custom_logger( name=settings.id, log_level=settings.LOG_LEVEL, logToConsole=settings.LOG_TO_CONSOLE, logToFile=settings.LOG_TO_FILE) self.telegram_bot = telegram self.logger.info("#############################") self.logger.info("############ Start LiveTrading " + settings.id + " on " + settings.EXCHANGE + " #################") self.exchange: ExchangeInterface = None if settings.EXCHANGE == 'bitmex': self.exchange = BitmexInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) elif settings.EXCHANGE == 'bybit': self.exchange = ByBitInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) elif settings.EXCHANGE == 'binance': self.exchange = BinanceInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) elif settings.EXCHANGE == 'phemex': self.exchange = PhemexInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) else: self.logger.error("unkown exchange: " + settings.EXCHANGE) self.alive = False return self.alive = True if self.exchange.is_open(): self.logger.info(" Starting Live Trading Engine for %s " % self.exchange.symbol) self.symbolInfo: Symbol = self.exchange.get_instrument() self.bot: TradingBot = trading_bot self.bot.prepare(self.logger, self) # init market data dict to be filled later self.bars: List[Bar] = [] self.update_bars() self.account: Account = Account() self.update_account() self.bot.reset() if self.telegram_bot is not None: pos = "no pos" if self.account.open_position is not None and self.account.open_position.avgEntryPrice is not None: pos = "%.2f @ %.2f" % ( self.account.open_position.quantity, self.account.open_position.avgEntryPrice) self.telegram_bot.send_log( "%s loaded, ready to go with %.2f in wallet and pos %s" % (self.id, self.account.equity, pos)) else: self.alive = False
from kuegi_bot.exchanges.bitmex.bitmex_interface import BitmexInterface from kuegi_bot.exchanges.bybit.bybit_interface import ByBitInterface from kuegi_bot.utils import log from kuegi_bot.utils.helper import load_settings_from_args settings = load_settings_from_args() logger = log.setup_custom_logger("cryptobot", log_level=settings.LOG_LEVEL, logToConsole=True, logToFile=False) def onTick(): logger.info("got Tick") if settings.EXCHANGE == 'bybit': interface = ByBitInterface(settings=settings, logger=logger, on_tick_callback=onTick) b = interface.bybit w = interface.ws else: interface = BitmexInterface(settings=settings, logger=logger, on_tick_callback=onTick) bars = interface.get_bars(240, 0)
class LiveTrading(OrderInterface): def __init__(self, settings, trading_bot: TradingBot): self.settings = settings self.id = self.settings.id self.last_tick = 0 self.logger = log.setup_custom_logger( name=settings.id, log_level=settings.LOG_LEVEL, logToConsole=settings.LOG_TO_CONSOLE, logToFile=settings.LOG_TO_FILE) self.exchange: ExchangeInterface = None if settings.EXCHANGE == 'bitmex': self.exchange = BitmexInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) elif settings.EXCHANGE == 'bybit': self.exchange = ByBitInterface(settings=settings, logger=self.logger, on_tick_callback=self.on_tick) else: self.logger.error("unkown exchange: " + settings.EXCHANGE) self.alive = False return self.alive = True if self.exchange.is_open(): self.logger.info( "############# Starting Live Trading Engine for %s ##############" % self.exchange.symbol) self.symbolInfo: Symbol = self.exchange.get_instrument() self.bot: TradingBot = trading_bot self.bot.prepare(self.logger, self) # init market data dict to be filled later self.bars: List[Bar] = [] self.update_bars() self.account: Account = Account() self.update_account() self.bot.reset() else: self.alive = False def on_tick(self): self.last_tick = time.time() def print_status(self): """Print the current status.""" self.logger.info("Current Contract Position: %d" % self.exchange.get_position()) """TODO: open orders""" ### # Order handling ### def send_order(self, order: Order): if order.amount == 0: self.logger.error("trying to send order without amount") return order.tstamp = self.bars[0].tstamp if order not in self.account.open_orders: # bot might add it himself temporarily. self.account.open_orders.append(order) self.exchange.send_order(order) def update_order(self, order: Order): self.exchange.update_order(order) def cancel_order(self, order: Order): order.active = False # already mark it as cancelled, so not to mess up next loop self.exchange.cancel_order(order) ### # Sanity ## def sanity_check(self): """Perform checks before placing orders.""" # Ensure market is still open. self.exchange.check_market_open() ### # Running ### def update_account(self): self.exchange.update_account(self.account) orders = self.exchange.get_orders() prevOpenIds = [] for o in self.account.open_orders: prevOpenIds.append(o.id) self.account.open_orders = [] for o in orders: if o.active: self.account.open_orders.append(o) elif len(o.id) > 0 and o.id in prevOpenIds: self.logger.info( "order %s got %s @ %s" % (o.id, ("executed" if o.executed_amount != 0 else "canceled"), ("%.1f" % o.executed_price) if o.executed_price is not None else None)) self.account.order_history.append(o) def update_bars(self): """get data from exchange""" if len(self.bars) < 10: self.bars = self.exchange.get_bars(self.settings.MINUTES_PER_BAR, 0) else: new_bars = self.exchange.recent_bars(self.settings.MINUTES_PER_BAR, 0) for b in reversed(new_bars): if b.tstamp < self.bars[0].tstamp: continue elif b.tstamp == self.bars[0].tstamp: # merge? if b.subbars[-1].tstamp == self.bars[0].subbars[-1].tstamp: self.bars[0] = b else: # merge! first = self.bars[0].subbars[-1] newBar = Bar(tstamp=b.tstamp, open=first.open, high=first.high, low=first.low, close=first.close, volume=first.volume, subbars=[first]) for sub in reversed(self.bars[0].subbars[:-1]): if sub.tstamp < b.subbars[-1].tstamp: newBar.add_subbar(sub) else: break for sub in reversed(b.subbars): if sub.tstamp > newBar.subbars[0].tstamp: newBar.add_subbar(sub) else: continue self.bars[0] = newBar else: # b.tstamp > self.bars[0].tstamp self.bars.insert(0, b) def check_connection(self): """Ensure the WS connections are still open.""" return self.exchange.is_open() def exit(self): if not self.alive: return self.logger.info( "Shutting down. open orders are not touched! Close manually!") try: self.exchange.exit() except errors.AuthenticationError as e: self.logger.info("Was not authenticated; could not cancel orders.") except Exception as e: self.logger.info("Unable to exit exchange: %s" % e) self.alive = False def handle_tick(self): try: self.update_bars() self.update_account() self.bot.on_tick(self.bars, self.account) for bar in self.bars: bar.did_change = False except Exception as e: self.logger.error("Exception in handle_tick: " + traceback.format_exc()) raise e def run_loop(self): if self.alive: self.bot.init(bars=self.bars, account=self.account, symbol=self.symbolInfo, unique_id=self.settings.id) last = 0 while self.alive: current = time.time() # execute if last execution is to long ago # or there was a tick since the last execution but the tick is more than debounce ms ago (to prevent race condition of account updates etc.) if current - last > self.settings.LOOP_INTERVAL or ( last < self.last_tick < current - 2): last = time.time() if not self.check_connection(): self.logger.error( "Realtime data connection unexpectedly closed, exiting." ) self.exit() else: self.handle_tick() sleep(0.5) def prepare_plot(self): self.logger.info("running timelines") time = list(map(lambda b: datetime.fromtimestamp(b.tstamp), self.bars)) open = list(map(lambda b: b.open, self.bars)) high = list(map(lambda b: b.high, self.bars)) low = list(map(lambda b: b.low, self.bars)) close = list(map(lambda b: b.close, self.bars)) self.logger.info("creating plot") fig = go.Figure(data=[ go.Candlestick(x=time, open=open, high=high, low=low, close=close, name="XBTUSD") ]) self.logger.info("adding bot data") self.bot.add_to_plot(fig, self.bars, time) fig.update_layout(xaxis_rangeslider_visible=False) return fig