Exemple #1
0
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)
Exemple #2
0
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) + " 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', 'binanceSpot']:
            subbars.append(BinanceInterface.barArrayToBar(b))
        elif exchange == 'phemex':
            subbars.append(PhemexInterface.barArrayToBar(b, 10000))
    subbars.reverse()
    return process_low_tf_bars(subbars, wanted_tf, start_offset_minutes)
Exemple #3
0
    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.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)
        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
Exemple #4
0
    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
Exemple #5
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.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)
        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, fromAccountAction: bool = True):
        if fromAccountAction:
            delay = 2
        else:
            delay = 0
        self.last_tick = max(self.last_tick, time.time() + delay)
        self.logger.info("got tick " + str(fromAccountAction))

    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
                        newBar.bot_data = self.bars[
                            0].bot_data  # merge bot data to not loose it
                        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)
            traceback.print_exc()
        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):
                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