Exemple #1
0
    def __on_update_position(self, action, position):
        """
         포지션 갱신
        """
        # 포지션 사이즈 변경이 있었는지 체크
        is_update_pos_size = self.get_position(
        )['currentQty'] != position['currentQty']

        # 포지션 사이즈가 변경된 경우, Trail 개시가격을 현재의 가격에 리셋한다.
        if is_update_pos_size and position['currentQty'] != 0:
            self.set_trail_price(self.market_price)

        if is_update_pos_size:
            logger.info(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")
            notify(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")

        self.position = {
            **self.position,
            **position
        } if self.position is not None else self.position

        # 익손절의 평가
        self.eval_exit()
Exemple #2
0
    def __on_update_position(self, action, position):
        """
         ポジションを更新する
        """
        # ポジションサイズの変更がされたか
        is_update_pos_size = self.get_position(
        )['currentQty'] != position['currentQty']

        # ポジションサイズが変更された場合、トレイル開始価格を現在の価格にリセットする
        if is_update_pos_size and position['currentQty'] != 0:
            self.set_trail_price(self.market_price)

        if is_update_pos_size:
            logger.info(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")
            notify(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")

        self.position = {
            **self.position,
            **position
        } if self.position is not None else self.position

        # 利確損切の評価
        self.eval_exit()
Exemple #3
0
    def run(self):
        if self.hyperopt:
            raise Exception(
                "Trading View Strategy dose not support hyperopt Mode.")
        elif self.back_test:
            raise Exception(
                "Trading View Strategy dose not support backtest Mode.")
        elif self.stub_test:
            self.exchange = BitMexStub()
            logger.info(f"Bot Mode : Stub")
        else:
            self.exchange = BitMex(demo=self.test_net)
            logger.info(f"Bot Mode : Trade")

        logger.info(f"Starting Bot")
        logger.info(f"Strategy : {type(self).__name__}")
        logger.info(f"Resolution : {self.resolution()}")
        logger.info(f"Balance : {self.exchange.get_balance()}")

        notify(f"Starting Bot\n"
               f"Strategy : {type(self).__name__}\n"
               f"Resolution : {self.resolution()}\n"
               f"Balance : {self.exchange.get_balance()/100000000} XBT")

        self.subscriber.on_message(self.__on_message)
Exemple #4
0
    def __amend_order(self, ord_id, side, ord_qty, limit=0, stop=0):
        """
        注文を更新する
        """
        if limit > 0 and stop > 0:
            ord_type = "StopLimit"
            retry(lambda: self.private_client.Order.Order_amend(
                origClOrdID=ord_id, orderQty=ord_qty, price=limit, stopPx=stop)
                  .result())
        elif limit > 0:
            ord_type = "Limit"
            retry(lambda: self.private_client.Order.Order_amend(
                origClOrdID=ord_id, orderQty=ord_qty, price=limit).result())
        elif stop > 0:
            ord_type = "Stop"
            retry(lambda: self.private_client.Order.Order_amend(
                origClOrdID=ord_id, orderQty=ord_qty, stopPx=stop).result())
        else:
            ord_type = "Market"
            retry(lambda: self.private_client.Order.Order_amend(
                origClOrdID=ord_id, orderQty=ord_qty).result())

        if self.enable_trade_log:
            logger.info(f"========= Amend Order ==============")
            logger.info(f"ID     : {ord_id}")
            logger.info(f"Type   : {ord_type}")
            logger.info(f"Side   : {side}")
            logger.info(f"Qty    : {ord_qty}")
            logger.info(f"Limit  : {limit}")
            logger.info(f"Stop   : {stop}")
            logger.info(f"======================================")

            notify(
                f"Amend Order\nType: {ord_type}\nSide: {side}\nQty: {ord_qty}\nLimit: {limit}\nStop: {stop}"
            )
        def loop_function():
            while self.is_running:
                try:
                    # retries 10 times over 486secs
                    # before raising error/exception
                    # check binance_futures_api.py line 113
                    # for implementation details

                    #client.stream_keepalive()
                    listenKey = client.stream_get_listen_key()

                    if self.listenKey != listenKey:
                        logger.info("listenKey Changed!")
                        notify("listenKey Changed!")
                        self.listenKey = listenKey
                        self.ws.close()

                    # Send a heartbeat to Healthchecks.io
                    if self.use_healthcecks:
                        try:
                            requests.get(conf['healthchecks.io'][self.account]
                                         ['listenkey_heartbeat'])
                            #logger.info("Listen Key Heart Beat sent!")
                        except Exception as e:
                            pass

                    time.sleep(600)
                except Exception as e:
                    logger.error(f"Keep Alive Error - {str(e)}")
                    #logger.error(traceback.format_exc())

                    notify(f"Keep Alive Error - {str(e)}")
Exemple #6
0
    def __on_update_position(self, action, position):
        """
        Update position
        """
        # Was the position size changed?
        is_update_pos_size = self.get_position(
        )['currentQty'] != position['currentQty']

        # Reset trail to current price if position size changes
        if is_update_pos_size and position['currentQty'] != 0:
            self.set_trail_price(self.market_price)

        if is_update_pos_size:
            if 'avgEntryPrice' not in position:
                position.update(
                    {'avgEntryPrice': self.get_position()['avgEntryPrice']})
            logger.info(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")
            notify(
                f"Updated Position\n"
                f"Price: {self.get_position()['avgEntryPrice']} => {position['avgEntryPrice']}\n"
                f"Qty: {self.get_position()['currentQty']} => {position['currentQty']}\n"
                f"Balance: {self.get_balance()/100000000} XBT")

        self.position = {
            **self.position,
            **position
        } if self.position is not None else self.position

        # Evaluation of profit and loss
        self.eval_exit()
        self.eval_sltp()
Exemple #7
0
    def run(self):
        """
˜       Bot 기동
        """
        if self.hyperopt:
            logger.info(f"Bot Mode : Hyperopt")
            self.params_search()
            return

        elif self.stub_test:
            logger.info(f"Bot Mode : Stub")
            self.exchange = BitMexStub()
        elif self.back_test:
            logger.info(f"Bot Mode : Back test")
            self.exchange = BitMexBackTest()
        else:
            logger.info(f"Bot Mode : Trade")
            self.exchange = BitMex(demo=self.test_net)

        self.exchange.ohlcv_len = self.ohlcv_len()
        self.exchange.on_update(self.bin_size, self.strategy)

        logger.info(f"Starting Bot")
        logger.info(f"Strategy : {type(self).__name__}")
        logger.info(f"Resolution : {self.resolution()}")
        logger.info(f"Balance : {self.exchange.get_balance()}")

        notify(f"Starting Bot\n"
               f"Strategy : {type(self).__name__}\n"
               f"Resolution : {self.resolution()}\n"
               f"Balance : {self.exchange.get_balance()/100000000} XBT")

        self.exchange.show_result()
Exemple #8
0
    def run(self):
        if self.hyperopt:
            raise Exception(
                "Trading View Strategy dose not support hyperopt Mode.")
        elif self.back_test:
            raise Exception(
                "Trading View Strategy dose not support backtest Mode.")
        elif self.stub_test:
            # if you want to use binance futures
            # self.exchange = BinanceFuturesStub(account=self.account, pair=self.pair)
            self.exchange = BitMexStub(account=self.account, pair=self.pair)
            logger.info(f"Bot Mode : Stub")
        else:
            # if you want to use binance
            #self.exchange = BinanceFutures(account=self.account, pair=self.pair, demo=self.test_net)
            self.exchange = BitMex(account=self.account,
                                   pair=self.pair,
                                   demo=self.test_net)
            logger.info(f"Bot Mode : Trade")

        logger.info(f"Starting Bot")
        logger.info(f"Strategy : {type(self).__name__}")
        logger.info(f"Balance : {self.exchange.get_balance()}")

        notify(f"Starting Bot\n"
               f"Strategy : {type(self).__name__}\n"
               f"Balance : {self.exchange.get_balance()/100000000} XBT")

        self.subscriber.on_message(self.__on_message)
Exemple #9
0
    def __new_order(self, ord_id, side, ord_qty, limit=0, stop=0, post_only=False):
        """
        注文を作成する
        """
        if limit > 0 and post_only:
            ord_type = "Limit"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                              side=side, orderQty=ord_qty, price=limit,
                                                              execInst='ParticipateDoNotInitiate').result())
        elif limit > 0 and stop > 0:
            ord_type = "StopLimit"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                              side=side, orderQty=ord_qty, price=limit,
                                                              stopPx=stop).result())
        elif limit > 0:
            ord_type = "Limit"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                              side=side, orderQty=ord_qty, price=limit).result())
        elif stop > 0:
            ord_type = "Stop"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                              side=side, orderQty=ord_qty, stopPx=stop).result())
        elif post_only: # market order with post only
            ord_type = "Limit"
            i = 0
            while True:
                prices = self.ob.get_prices()
                limit = prices[1] if side == "Buy" else prices[0]
                retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                                  side=side, orderQty=ord_qty, price=limit,
                                                                  execInst='ParticipateDoNotInitiate').result())
                time.sleep(1)

                if not self.cancel(ord_id):
                    break
                time.sleep(2)
                i += 1
                if i > 10:
                    notify(f"Order retry count exceed")
                    break
            self.cancel_all()
        else:
            ord_type = "Market"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD", ordType=ord_type, clOrdID=ord_id,
                                                              side=side, orderQty=ord_qty).result())

        if self.enable_trade_log:
            logger.info(f"========= New Order ==============")
            logger.info(f"ID     : {ord_id}")
            logger.info(f"Type   : {ord_type}")
            logger.info(f"Side   : {side}")
            logger.info(f"Qty    : {ord_qty}")
            logger.info(f"Limit  : {limit}")
            logger.info(f"Stop   : {stop}")
            logger.info(f"======================================")

            notify(f"New Order\nType: {ord_type}\nSide: {side}\nQty: {ord_qty}\nLimit: {limit}\nStop: {stop}")
Exemple #10
0
    def run(self):
        """
˜       Function to run the bot
        """
        if self.hyperopt:
            logger.info(f"Bot Mode : Hyperopt")
            self.params_search()
            return

        elif self.stub_test:
            logger.info(f"Bot Mode : Stub")
            if self.exchange_arg == "binance":
                self.exchange = BinanceFuturesStub(account=self.account,
                                                   pair=self.pair)
            elif self.exchange_arg == "bitmex":
                self.exchange = BitMexStub(account=self.account,
                                           pair=self.pair)
            else:
                logger.info(f"--exchange argument missing or invalid")
                return
        elif self.back_test:
            logger.info(f"Bot Mode : Back test")
            if self.exchange_arg == "binance":
                self.exchange = BinanceFuturesBackTest(account=self.account,
                                                       pair=self.pair)
            elif self.exchange_arg == "bitmex":
                self.exchange = BitMexBackTest(account=self.account,
                                               pair=self.pair)
            else:
                logger.info(f"--exchange argument missing or invalid")
                return
        else:
            logger.info(f"Bot Mode : Trade")
            if self.exchange_arg == "binance":
                self.exchange = BinanceFutures(account=self.account,
                                               pair=self.pair,
                                               demo=self.test_net)
            elif self.exchange_arg == "bitmex":
                self.exchange = BitMex(account=self.account,
                                       pair=self.pair,
                                       demo=self.test_net)
            else:
                logger.info(f"--exchange argument missing or invalid")
                return
        self.exchange.ohlcv_len = self.ohlcv_len()
        self.exchange.on_update(self.bin_size, self.strategy)

        logger.info(f"Starting Bot")
        logger.info(f"Strategy : {type(self).__name__}")
        logger.info(f"Balance : {self.exchange.get_balance()}")

        notify(f"Starting Bot\n"
               f"Strategy : {type(self).__name__}\n"
               f"Balance : {self.exchange.get_balance()}")

        self.exchange.show_result()
Exemple #11
0
    def __amend_order(self,
                      ord_id,
                      side,
                      ord_qty,
                      limit=0,
                      stop=0,
                      post_only=False):
        """
        주문 갱신
        """
        try:
            if limit > 0 and stop > 0:
                ord_type = "StopLimit"
                retry(lambda: self.private_client.Order.Order_amend(
                    origClOrdID=ord_id,
                    orderQty=ord_qty,
                    price=limit,
                    stopPx=stop).result())
            elif limit > 0:
                ord_type = "Limit"
                retry(lambda: self.private_client.Order.Order_amend(
                    origClOrdID=ord_id, orderQty=ord_qty, price=limit).result(
                    ))
            elif stop > 0:
                ord_type = "Stop"
                retry(lambda: self.private_client.Order.Order_amend(
                    origClOrdID=ord_id, orderQty=ord_qty, stopPx=stop).result(
                    ))
            elif post_only:  # market order with post only
                ord_type = "Limit"
                prices = self.ob.get_prices()
                limit = prices[1] if side == "Buy" else prices[0]
                retry(lambda: self.private_client.Order.Order_amend(
                    origClOrdID=ord_id, orderQty=ord_qty, price=limit).result(
                    ))
            else:
                ord_type = "Market"
                retry(lambda: self.private_client.Order.Order_amend(
                    origClOrdID=ord_id, orderQty=ord_qty).result())
        except Exception as e:
            logger.error('Exception: __amend_order : %s' % e)

        if self.enable_trade_log:
            logger.info(f"========= Amend Order ==============")
            logger.info(f"ID     : {ord_id}")
            logger.info(f"Type   : {ord_type}")
            logger.info(f"Side   : {side}")
            logger.info(f"Qty    : {ord_qty}")
            logger.info(f"Limit  : {limit}")
            logger.info(f"Stop   : {stop}")
            logger.info(f"======================================")

            notify(
                f"Amend Order\nType: {ord_type}\nSide: {side}\nQty: {ord_qty}\nLimit: {limit}\nStop: {stop}"
            )
Exemple #12
0
    def __on_error(self, ws, message):
        """
        WebSokcetでエラーが発生した場合
        :param ws:
        :param message:
        """
        logger.error(message)
        logger.error(traceback.format_exc())

        notify(f"Error occurred. {message}")
        notify(traceback.format_exc())
Exemple #13
0
    def __new_order(self, ord_id, side, ord_qty, limit=0, stop=0):
        """
        注文を作成する
        """
        if limit > 0 and stop > 0:
            ord_type = "StopLimit"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD",
                                                              ordType=ord_type,
                                                              clOrdID=ord_id,
                                                              side=side,
                                                              orderQty=ord_qty,
                                                              price=limit,
                                                              stopPx=stop).
                  result())
        elif limit > 0:
            ord_type = "Limit"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD",
                                                              ordType=ord_type,
                                                              clOrdID=ord_id,
                                                              side=side,
                                                              orderQty=ord_qty,
                                                              price=limit).
                  result())
        elif stop > 0:
            ord_type = "Stop"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD",
                                                              ordType=ord_type,
                                                              clOrdID=ord_id,
                                                              side=side,
                                                              orderQty=ord_qty,
                                                              stopPx=stop).
                  result())
        else:
            ord_type = "Market"
            retry(lambda: self.private_client.Order.Order_new(symbol="XBTUSD",
                                                              ordType=ord_type,
                                                              clOrdID=ord_id,
                                                              side=side,
                                                              orderQty=ord_qty)
                  .result())

        if self.enable_trade_log:
            logger.info(f"========= New Order ==============")
            logger.info(f"ID     : {ord_id}")
            logger.info(f"Type   : {ord_type}")
            logger.info(f"Side   : {side}")
            logger.info(f"Qty    : {ord_qty}")
            logger.info(f"Limit  : {limit}")
            logger.info(f"Stop   : {stop}")
            logger.info(f"======================================")

            notify(
                f"New Order\nType: {ord_type}\nSide: {side}\nQty: {ord_qty}\nLimit: {limit}\nStop: {stop}"
            )
    def __on_error(self, ws, message):
        """
        On Error listener
        :param ws:
        :param message:
        """
        logger.error(message)
        logger.error(traceback.format_exc())

        notify(f"Error occurred. {message}")
        notify(traceback.format_exc())
Exemple #15
0
 def __on_update_margin(self, action, margin):
     """
      Update margin 
     """
     if self.margin is not None:
         self.margin[0] = {
                             "asset": self.quote_asset,
                             "balance": float(margin['wb']),
                             "crossWalletBalance": float(margin['cw'])
                          }             
     else: self.get_margin() 
     notify(f"Balance: {self.margin[0]['balance']}")
     logger.info(f"Balance: {self.margin[0]['balance']} Cross Balance: {self.margin[0]['crossWalletBalance']}")     
Exemple #16
0
    def __update_ohlcv(self, action, new_data):
        """
        데이터를 취득한 후, 전략을 실행
        데이터가 없으면 서버와 접속해서 다운로드를 처음 함, 그 후는 어떻게 할까
        """
        if self.data is None:
            end_time = datetime.now(timezone.utc)

            start_time = end_time - self.ohlcv_len * delta(self.bin_size)
            d1 = self.fetch_ohlcv(self.bin_size, start_time, end_time)

            if len(d1) > 0:
                d2 = self.fetch_ohlcv(
                    allowed_range[self.bin_size][0],
                    d1.iloc[-1].name + delta(allowed_range[self.bin_size][0]),
                    end_time)

                self.data = pd.concat([d1, d2], sort=True)
            else:
                self.data = d1
        else:
            self.data = pd.concat([self.data, new_data], sort=True)

        # 마지막행은 불학정정보이기에 베제한다. (original)
        # re_sample_data = resample(self.data, self.bin_size)[:-1]

        # 마지막행도 반영한다. (by neo)
        re_sample_data = resample(self.data, self.bin_size)[:]

        if self.data.iloc[-1].name == re_sample_data.iloc[-1].name:
            self.data = re_sample_data.iloc[-1 * self.ohlcv_len:, :]

        if self.last_action_time is not None and \
                self.last_action_time == re_sample_data.iloc[-1].name:
            return

        open = re_sample_data['open'].values
        close = re_sample_data['close'].values
        high = re_sample_data['high'].values
        low = re_sample_data['low'].values
        volume = re_sample_data['volume'].values

        try:
            if self.strategy is not None:
                self.strategy(open, close, high, low, volume)
            self.last_action_time = re_sample_data.iloc[-1].name
        except FatalError as e:
            # 致命的エラー
            logger.error(f"Fatal error. {e}")
            logger.error(traceback.format_exc())

            notify(f"Fatal error occurred. Stopping Bot. {e}")
            notify(traceback.format_exc())
            self.stop()
        except Exception as e:
            logger.error(f"An error occurred. {e}")
            logger.error(traceback.format_exc())

            notify(f"An error occurred. {e}")
            notify(traceback.format_exc())
    def __update_ohlcv(self, action, new_data):
        new_data = new_data.rename(index={new_data.iloc[0].name: new_data.iloc[0].name.ceil(freq="1T")})
        """
        get OHLCV data and execute the strategy
        """
        if self.data is None:
            end_time = datetime.now(timezone.utc)
            start_time = end_time - self.ohlcv_len * delta(self.bin_size)
            # logger.info(f"start time fetch ohlcv: {start_time}")
            # logger.info(f"end time fetch ohlcv: {end_time}")
            self.data = self.fetch_ohlcv(self.bin_size, start_time, end_time)
            if self.data.iloc[-1].name > end_time:
                last_candle = self.data.iloc[-1].values
                self.data = self.data[:-1]
                self.data.loc[end_time.replace(microsecond=0)] = last_candle

            logger.info(f"Initial Buffer Fill - Last Candle: {self.data.iloc[-1].name}")

        else:
            if self.data.iloc[-1].name == new_data.iloc[0].name:
                self.data = pd.concat([self.data[:-1], new_data])
            else:
                self.data = pd.concat([self.data, new_data])

        # exclude current candle data
        re_sample_data = resample(self.data, self.bin_size)[:-1]

        if self.last_action_time is not None and self.last_action_time == re_sample_data.iloc[-1].name:
            return

        self.data = pd.concat([re_sample_data.iloc[-1 * self.ohlcv_len :, :], self.data.iloc[[-1]]])

        open = re_sample_data["open"].values
        close = re_sample_data["close"].values
        high = re_sample_data["high"].values
        low = re_sample_data["low"].values
        volume = re_sample_data["volume"].values

        try:
            if self.strategy is not None:
                self.timestamp = re_sample_data.iloc[-1].name.isoformat()
                self.strategy(open, close, high, low, volume)
                self.eval_exit()
            self.last_action_time = re_sample_data.iloc[-1].name
        except FatalError as e:
            # Fatal error
            logger.error(f"Fatal error. {e}")
            logger.error(traceback.format_exc())

            notify(f"Fatal error occurred. Stopping Bot. {e}")
            notify(traceback.format_exc())
            self.stop()
        except Exception as e:
            logger.error(f"An error occurred. {e}")
            logger.error(traceback.format_exc())

            notify(f"An error occurred. {e}")
            notify(traceback.format_exc())
Exemple #18
0
    def __update_ohlcv(self, action, new_data):
        """
        get OHLCV data and execute the strategy
        """
        if self.data is None:
            end_time = datetime.now(timezone.utc)
            start_time = end_time - self.ohlcv_len * delta(self.bin_size)
            #logger.info(f"start time fetch ohlcv: {start_time}")
            #logger.info(f"end time fetch ohlcv: {end_time}")
            d1 = self.fetch_ohlcv(self.bin_size, start_time, end_time)
            if len(d1) > 0:
                d2 = self.fetch_ohlcv(
                    allowed_range[self.bin_size][0],
                    d1.iloc[-1].name + delta(allowed_range[self.bin_size][0]),
                    end_time)

                self.data = pd.concat([d1, d2])
            else:
                self.data = d1

        else:
            self.data = pd.concat([self.data, new_data])

        # exclude current candle data
        re_sample_data = resample(self.data, self.bin_size)[:-1]

        if self.data.iloc[-1].name == re_sample_data.iloc[-1].name:
            self.data = re_sample_data.iloc[-1 * self.ohlcv_len:, :]

        if self.last_action_time is not None and \
                self.last_action_time == re_sample_data.iloc[-1].name:
            return

        open = re_sample_data['open'].values
        close = re_sample_data['close'].values
        high = re_sample_data['high'].values
        low = re_sample_data['low'].values
        volume = re_sample_data['volume'].values

        try:
            if self.strategy is not None:
                self.strategy(open, close, high, low, volume)
            self.last_action_time = re_sample_data.iloc[-1].name
        except FatalError as e:
            # Fatal error
            logger.error(f"Fatal error. {e}")
            logger.error(traceback.format_exc())

            notify(f"Fatal error occurred. Stopping Bot. {e}")
            notify(traceback.format_exc())
            self.stop()
        except Exception as e:
            logger.error(f"An error occurred. {e}")
            logger.error(traceback.format_exc())

            notify(f"An error occurred. {e}")
            notify(traceback.format_exc())
Exemple #19
0
    def __on_update_position(self, action, position):
        """
        Update position
        """    

        if len(position) > 0:
            position = [p for p in position if p["s"].startswith(self.pair)]   
            if len(position) == 0:
                # logger.info(f"Some other pair was traded!")
                return
        else:
            return         
            
        # Was the position size changed?
        is_update_pos_size = self.get_position_size() != float(position[0]['pa'])        

        # Reset trail to current price if position size changes
        if is_update_pos_size and float(position[0]['pa']) != 0:
            self.set_trail_price(self.market_price)
        
        if is_update_pos_size:
            logger.info(f"Updated Position\n"
                        f"Price: {self.position[0]['entryPrice']} => {position[0]['ep']}\n"
                        f"Qty: {self.position[0]['positionAmt']} => {position[0]['pa']}\n"
                        f"Balance: {self.get_balance()} {self.quote_asset}")
            notify(f"Updated Position\n"
                   f"Price: {self.position[0]['entryPrice']} => {position[0]['ep']}\n"
                   f"Qty: {self.position[0]['positionAmt']} => {position[0]['pa']}\n"
                   f"Balance: {self.get_balance()} {self.quote_asset}")
       
        self.position[0] = {
                            "entryPrice": position[0]['ep'],
                            "marginType": position[0]['mt'],                            
                            "positionAmt":  position[0]['pa'], 
                            "symbol": position[0]['s'], 
                            "unRealizedProfit":  position[0]['up'], 
                            "positionSide": position[0]['ps'],
                            } if self.position is not None else self.position[0]

        self.position_size = float(self.position[0]['positionAmt'])
        self.entry_price = float(self.position[0]['entryPrice'])        
    
        # Evaluation of profit and loss
        self.eval_exit()
        self.eval_sltp()
Exemple #20
0
    def __update_ohlcv(self, action, new_data):
        """
        データを取得して、戦略を実行する。
        """

        if self.data is None:
            end_time = datetime.now(timezone.utc)
            start_time = end_time - self.ohlcv_len * delta(self.bin_size)
            d1 = self.fetch_ohlcv(self.bin_size, start_time, end_time)
            if len(d1) > 0:
                d2 = self.fetch_ohlcv(allowed_range[self.bin_size][0],
                                      d1.iloc[-1].name + delta(allowed_range[self.bin_size][0]), end_time)

                self.data = pd.concat([d1, d2], sort=True)
            else:
                self.data = d1
        else:
            self.data = pd.concat([self.data, new_data], sort=True)

        # 最後の行は不確定情報のため、排除する
        re_sample_data = resample(self.data, self.bin_size)[:-1]

        if self.data.iloc[-1].name == re_sample_data.iloc[-1].name:
            self.data = re_sample_data.iloc[-1 * self.ohlcv_len:, :]

        if self.last_action_time is not None and \
                self.last_action_time == re_sample_data.iloc[-1].name:
            return

        open = re_sample_data['open'].values
        close = re_sample_data['close'].values
        high = re_sample_data['high'].values
        low = re_sample_data['low'].values
        volume = re_sample_data['volume'].values

        try:
            if self.strategy is not None:
                self.strategy(open, close, high, low, volume)
            self.last_action_time = re_sample_data.iloc[-1].name
        except FatalError as e:
            # 致命的エラー
            logger.error(f"Fatal error. {e}")
            logger.error(traceback.format_exc())

            notify(f"Fatal error occurred. Stopping Bot. {e}")
            notify(traceback.format_exc())
            self.stop()
        except Exception as e:
            logger.error(f"An error occurred. {e}")
            logger.error(traceback.format_exc())

            notify(f"An error occurred. {e}")
            notify(traceback.format_exc())
    def __on_update_position(self, action, position):
        """
        Update position
        """

        if len(position) > 0:
            position = [p for p in position if p["s"] == self.pair]
            # logger.info(f'position: {position}')
            # Was the position size changed?
        if len(position) == 1:
            is_update_pos_size = self.get_position_size != float(position[0]["pa"])

            # Reset trail to current price if position size changes
            if is_update_pos_size and float(position[0]["pa"]) != 0:
                self.set_trail_price(self.market_price)

            if is_update_pos_size:
                logger.info(f"Updated Position")
                logger.info(f"Price: {self.position[0]['entryPrice']} => {position[0]['ep']}")
                logger.info(f"Qty: {self.position[0]['positionAmt']} => {position[0]['pa']}")
                logger.info(f"Balance: {self.get_balance()} USDT")
                notify(f"Updated Position\n" f"Price: {self.position[0]['entryPrice']} => {position[0]['ep']}\n" f"Qty: {self.position[0]['positionAmt']} => {position[0]['pa']}\n" f"Balance: {self.get_balance()} USDT")

            self.position[0] = (
                {
                    "entryPrice": position[0]["ep"],
                    "marginType": position[0]["mt"],
                    "positionAmt": position[0]["pa"],
                    "symbol": position[0]["s"],
                    "unRealizedProfit": position[0]["up"],
                    "positionSide": position[0]["ps"],
                }
                if self.position is not None
                else self.position[0]
            )

            self.position_size = float(self.position[0]["positionAmt"])
            self.entry_price = float(self.position[0]["entryPrice"])

        # Evaluation of profit and loss
        self.eval_exit()
        self.eval_sltp()
    def __on_close(self, ws):
        """
        On Close Listener
        :param ws:
        """
        if 'close' in self.handlers:
            self.handlers['close']()

        if self.is_running:
            logger.info("Websocket restart")
            notify(f"Websocket restart")

            self.ws = websocket.WebSocketApp(self.endpoint,
                                 on_message=self.__on_message,
                                 on_error=self.__on_error,
                                 on_close=self.__on_close,
                                 header=self.__get_auth())
            self.wst = threading.Thread(target=self.__start)
            self.wst.daemon = True
            self.wst.start()
    def __on_close(self, ws):
        """
        On Close Listener
        :param ws:
        """
        if 'close' in self.handlers:
            self.handlers['close']()

        if self.is_running:
            logger.info(f"Websocket On Close: Restart")
            notify(f"Websocket On Close: Restart")

            time.sleep(60)
            # Listen Key can change after disconnects, so the url can change too
            self.ws = websocket.WebSocketApp(self.__get_wss_endpoint(),
                                             on_message=self.__on_message,
                                             on_error=self.__on_error,
                                             on_close=self.__on_close)

            self.wst = threading.Thread(target=self.__start)
            self.wst.daemon = True
            self.wst.start()
Exemple #24
0
        """
        if key in self.handlers:
            self.handlers[key](action, value)

    def __on_close(self, ws):
        """
        クローズした場合
        :param ws:
        """
        if 'close' in self.handlers:
            self.handlers['close']()

<<<<<<< HEAD
        if self.is_running:
            logger.info("Websocket restart")
            notify(f"Websocket restart")

            self.ws = websocket.WebSocketApp(self.endpoint,
                                 on_message=self.__on_message,
                                 on_error=self.__on_error,
                                 on_close=self.__on_close,
                                 header=self.__get_auth())
            self.wst = threading.Thread(target=self.__start)
            self.wst.daemon = True
            self.wst.start()

    def on_close(self, func):
        """
        クローズの通知先を登録する。
        :param func:
        """
Exemple #25
0
    def __update_ohlcv(self, action, new_data):

        # Binance can output wierd timestamps - Eg. 2021-05-25 16:04:59.999000+00:00
        # We need to round up to the nearest second for further processing
        new_data = new_data.rename(index={new_data.iloc[0].name: new_data.iloc[0].name.ceil(freq='1T')})

        """
        get OHLCV data and execute the strategy
        """        
        if self.data is None:
            end_time = datetime.now(timezone.utc)
            start_time = end_time - self.ohlcv_len * delta(self.bin_size)
            #logger.info(f"start time fetch ohlcv: {start_time}")
            #logger.info(f"end time fetch ohlcv: {end_time}")
            self.data = self.fetch_ohlcv(self.bin_size, start_time, end_time)
            
            # The last candle is an incomplete candle with timestamp
            # in future
            if(self.data.iloc[-1].name > end_time):
                last_candle = self.data.iloc[-1].values # Store last candle
                self.data = self.data[:-1] # exclude last candle
                self.data.loc[end_time.replace(microsecond=0)] = last_candle #set last candle to end_time

            logger.info(f"Initial Buffer Fill - Last Candle: {self.data.iloc[-1].name}")
                
        else:
            #replace latest candle if timestamp is same or append
            if(self.data.iloc[-1].name == new_data.iloc[0].name):
                self.data = pd.concat([self.data[:-1], new_data])
            else:
                self.data = pd.concat([self.data, new_data])        

        # exclude current candle data 
        re_sample_data = resample(self.data, self.bin_size)[:-1]

        # logger.info(f"{self.last_action_time} : {self.data.iloc[-1].name} : {re_sample_data.iloc[-1].name}")  

        if self.last_action_time is not None and \
                self.last_action_time == re_sample_data.iloc[-1].name:
            return

        # The last candle in the buffer needs to be preserved 
        # while resetting the buffer as it may be incomlete
        # or contains latest data from WS
        self.data = pd.concat([re_sample_data.iloc[-1 * self.ohlcv_len:, :], self.data.iloc[[-1]]]) 
        #logger.info(f"Buffer Right Edge: {self.data.iloc[-1]}")

        open = re_sample_data['open'].values
        close = re_sample_data['close'].values
        high = re_sample_data['high'].values
        low = re_sample_data['low'].values
        volume = re_sample_data['volume'].values        

        try:
            if self.strategy is not None:   
                self.timestamp = re_sample_data.iloc[-1].name.isoformat()           
                self.strategy(open, close, high, low, volume)                
            self.last_action_time = re_sample_data.iloc[-1].name
        except FatalError as e:
            # Fatal error
            logger.error(f"Fatal error. {e}")
            logger.error(traceback.format_exc())

            notify(f"Fatal error occurred. Stopping Bot. {e}")
            notify(traceback.format_exc())
            self.stop()
        except Exception as e:
            logger.error(f"An error occurred. {e}")
            logger.error(traceback.format_exc())

            notify(f"An error occurred. {e}")
            notify(traceback.format_exc())
Exemple #26
0
    def __new_order(self,
                    ord_id,
                    side,
                    ord_qty,
                    limit=0,
                    stop=0,
                    post_only=False,
                    reduce_only=False,
                    trailing_stop=0,
                    activationPrice=0):
        """
        create an order
        """
        #removes "+" from order suffix, because of the new regular expression rule for newClientOrderId updated as ^[\.A-Z\:/a-z0-9_-]{1,36}$ (2021-01-26)
        ord_id = ord_id.replace("+", "k")

        if trailing_stop > 0 and activationPrice > 0:
            ord_type = "TRAILING_STOP_MARKET"
            retry(lambda: self.client.futures_create_order(
                symbol=self.pair,
                type=ord_type,
                newClientOrderId=ord_id,
                side=side,
                quantity=ord_qty,
                activationPrice=activationPrice,
                callbackRate=trailing_stop))
        elif trailing_stop > 0:
            ord_type = "TRAILING_STOP_MARKET"
            retry(lambda: self.client.futures_create_order(
                symbol=self.pair,
                type=ord_type,
                newClientOrderId=ord_id,
                side=side,
                quantity=ord_qty,
                callbackRate=trailing_stop))
        elif limit > 0 and post_only:
            ord_type = "LIMIT"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           price=limit,
                                                           timeInForce="GTX"))
        elif limit > 0 and stop > 0 and reduce_only:
            ord_type = "STOP"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           price=limit,
                                                           stopPrice=stop,
                                                           reduceOnly="true"))
        elif limit > 0 and reduce_only:
            ord_type = "LIMIT"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           price=limit,
                                                           reduceOnly="true",
                                                           timeInForce="GTC"))
        elif limit > 0 and stop > 0:
            ord_type = "STOP"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           price=limit,
                                                           stopPrice=stop))
        elif limit > 0:
            ord_type = "LIMIT"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           price=limit,
                                                           timeInForce="GTC"))
        elif stop > 0 and reduce_only:
            ord_type = "STOP_MARKET"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           stopPrice=stop,
                                                           reduceOnly="true"))
        elif stop > 0:
            ord_type = "STOP"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty,
                                                           stopPrice=stop))
        elif post_only:  # limit order with post only
            ord_type = "LIMIT"
            i = 0
            while True:
                prices = self.get_orderbook_ticker()
                limit = float(prices['bidPrice']) if side == "Buy" else float(
                    prices['askPrice'])
                retry(lambda: self.client.futures_create_order(
                    symbol=self.pair,
                    type=ord_type,
                    newClientOrderId=ord_id,
                    side=side,
                    quantity=ord_qty,
                    price=limit,
                    timeInForce="GTX"))
                time.sleep(4)

                self.cancel(ord_id)

                if float(self.get_position()['positionAmt']) > 0:
                    break
                i += 1
                if i > 10:
                    notify(f"Order retry count exceed")
                    break

            self.cancel_all()
        else:
            ord_type = "MARKET"
            retry(lambda: self.client.futures_create_order(symbol=self.pair,
                                                           type=ord_type,
                                                           newClientOrderId=
                                                           ord_id,
                                                           side=side,
                                                           quantity=ord_qty))

        if self.enable_trade_log:
            logger.info(f"========= New Order ==============")
            logger.info(f"ID     : {ord_id}")
            logger.info(f"Type   : {ord_type}")
            logger.info(f"Side   : {side}")
            logger.info(f"Qty    : {ord_qty}")
            logger.info(f"Limit  : {limit}")
            logger.info(f"Stop   : {stop}")
            logger.info(f"======================================")

            notify(
                f"New Order\nType: {ord_type}\nSide: {side}\nQty: {ord_qty}\nLimit: {limit}\nStop: {stop}"
            )
Exemple #27
0
    def __update_ohlcv(self, action, new_data):
        """
        get and update OHLCV data and execute the strategy
        """        
        # Binance can output wierd timestamps - Eg. 2021-05-25 16:04:59.999000+00:00
        # We need to round up to the nearest second for further processing
        new_data = new_data.rename(index={new_data.iloc[0].name: new_data.iloc[0].name.ceil(freq='1T')})               

        if self.timeframe_data is None:
            self.timeframe_data = {}
            for t in self.bin_size:
                bin_size = t
                end_time = datetime.now(timezone.utc)
                start_time = end_time - self.ohlcv_len * delta(bin_size)
                self.timeframe_data[bin_size] = self.fetch_ohlcv(bin_size, start_time, end_time)
                self.timeframe_info[bin_size] = {
                                                    "allowed_range": allowed_range_minute_granularity[t][0] if self.minute_granularity else allowed_range[t][0], 
                                                    "ohlcv": self.timeframe_data[t][:-1], # Dataframe with closed candles                                                   
                                                    "last_action_time": None,#self.timeframe_data[bin_size].iloc[-1].name, # Last strategy execution time
                                                    "last_candle": self.timeframe_data[bin_size].iloc[-2].values,  # Store last complete candle
                                                    "partial_candle": self.timeframe_data[bin_size].iloc[-1].values  # Store incomplete candle
                                                }
                # The last candle is an incomplete candle with timestamp in future                
                if self.timeframe_data[bin_size].iloc[-1].name > end_time:
                    last_candle = self.timeframe_data[t].iloc[-1].values # Store last candle
                    self.timeframe_data[bin_size] = self.timeframe_data[t][:-1] # Exclude last candle
                    self.timeframe_data[bin_size].loc[end_time.replace(microsecond=0)] = last_candle #set last candle to end_time

                logger.info(f"Initial Buffer Fill - Last Candle: {self.timeframe_data[bin_size].iloc[-1].name}")   
        #logger.info(f"{self.timeframe_data}") 

        timeframes_to_update = []

        for t in self.timeframe_info:            
            if self.timeframe_info[t]["allowed_range"] == action:
                # append minute count of a timeframe when sorting when sorting is need otherwise just add a string timeframe
                timeframes_to_update.append(allowed_range_minute_granularity[t][3]) if self.timeframes_sorted != None else timeframes_to_update.append(t)  

        # Sorting timeframes that will be updated
        if self.timeframes_sorted == True:
            timeframes_to_update.sort(reverse=True)
        if self.timeframes_sorted == False:
            timeframes_to_update.sort(reverse=False)

        #logger.info(f"timefeames to update: {timeframes_to_update}")        

        for t in timeframes_to_update:
            # Find timeframe string based on its minute count value
            if self.timeframes_sorted != None:             
                t = find_timeframe_string(t)               
                    
            # replace latest candle if timestamp is same or append
            if self.timeframe_data[t].iloc[-1].name == new_data.iloc[0].name:
                self.timeframe_data[t] = pd.concat([self.timeframe_data[t][:-1], new_data])
            else:
                self.timeframe_data[t] = pd.concat([self.timeframe_data[t], new_data])      

            # exclude current candle data and store partial candle data
            re_sample_data = resample(self.timeframe_data[t], t, minute_granularity=True if self.minute_granularity else False)
            self.timeframe_info[t]['partial_candle'] = re_sample_data.iloc[-1].values # store partial candle data
            re_sample_data =re_sample_data[:-1] # exclude current candle data

            #logger.info(f"{self.timeframe_info[t]['last_action_time']} : {self.timeframe_data[t].iloc[-1].name} : {re_sample_data.iloc[-1].name}")  

            if self.timeframe_info[t]["last_action_time"] is None:
                self.timeframe_info[t]["last_action_time"] = re_sample_data.iloc[-1].name
                
            if self.timeframe_info[t]["last_action_time"] == re_sample_data.iloc[-1].name:
                continue

            # The last candle in the buffer needs to be preserved 
            # while resetting the buffer as it may be incomlete
            # or contains latest data from WS
            self.timeframe_data[t] = pd.concat([re_sample_data.iloc[-1 * self.ohlcv_len:, :], self.timeframe_data[t].iloc[[-1]]]) 
            #store ohlcv dataframe to timeframe_info dictionary
            self.timeframe_info[t]["ohlcv"] = re_sample_data
            #logger.info(f"Buffer Right Edge: {self.data.iloc[-1]}")
            
            open = re_sample_data['open'].values
            close = re_sample_data['close'].values
            high = re_sample_data['high'].values
            low = re_sample_data['low'].values
            volume = re_sample_data['volume'].values 
                                    
            try:
                if self.strategy is not None:   
                    self.timestamp = re_sample_data.iloc[-1].name.isoformat()           
                    self.strategy(t, open, close, high, low, volume)              
                self.timeframe_info[t]['last_action_time'] = re_sample_data.iloc[-1].name
            except FatalError as e:
                # Fatal error
                logger.error(f"Fatal error. {e}")
                logger.error(traceback.format_exc())

                notify(f"Fatal error occurred. Stopping Bot. {e}")
                notify(traceback.format_exc())
                self.stop()
            except Exception as e:
                logger.error(f"An error occurred. {e}")
                logger.error(traceback.format_exc())    
                notify(f"An error occurred. {e}")
                notify(traceback.format_exc())