示例#1
0
    def __init__(self, trades: List[Trade], fx: FXConnector, trade_updated_handler=None):
        super().__init__()
        self.fx = fx
        self.balances = AccountBalances()

        self.order_updated_handler = trade_updated_handler
        # ExchangeInfo().update(fx.get_exchange_info())
        self.strategies: List[TradingStrategy] = []

        # self.logInfo('Creating {} with {} trades.'.format(self.__class__.__name__, len(trades)))
        #
        # for t in trades:
        #     try:
        #         if t.symbol not in ExchangeInfo().symbols:
        #             self.logError('Exchange doesn\'t have market "{}"'.format(t.symbol))
        #             continue
        #
        #         self.strategies.append(
        #             TargetsAndStopLossStrategy(t, fx, trade_updated_handler, self.balances.get_balance(t.asset)))
        #     except Exception:
        #         self.logError(traceback.format_exc())

        self.strategies_dict = {}
        self.tradeid_strategy_dict = {}
        self.trade_info_ticker_buf = {}

        self.process_delay = 500
        self.last_ts = dt.now()
        self.first_processing = True
        self.socket_message_rcvd = False
        self.paused = False

        self.lock = RLock()
示例#2
0
    def add_trades(self, trades: [Trade], start_listening=True):
        self.logInfo('Adding {} trades to the TradeHandler.'.format(
            len(trades)))
        # try:
        self.stop_listening()

        # if not ExchangeInfo().has_all_symbol(self.strategies_dict.keys()):
        ExchangeInfo().update(self.fx.get_exchange_info())
        AccountBalances().update_balances(self.fx.get_all_balances_dict())

        for trade in trades:
            new_strategy = TargetsAndStopLossStrategy(
                trade, self.fx, self.order_updated_handler,
                self.balances.get_balance(trade.asset))

            if self.handle_completed_strategy(new_strategy):
                self.logInfo('Strategy is completed [{}]'.format(
                    new_strategy.symbol()))
                continue

            self.add_new_strategy(new_strategy, listen_symbols=False)

        self.fx.listen_symbols([s.symbol() for s in self.strategies],
                               self.listen_handler, self.user_data_handler)

        if start_listening:
            self.start_listening()
示例#3
0
    def emergent_close_position(self):
        try:
            self.cancel_all_open_orders()

            AccountBalances().update_balances(self.fx.get_all_balances_dict())

            # price = self.exchange_info.adjust_price(self.get_sl_limit_price())
            bal = self.trade.get_cap(self.get_balance_for_side().avail)

            volume = round(bal / self.get_single_price(self.last_price),
                           8) if self.trade_side().is_buy() else bal

            if volume < self.exchange_info.minQty:
                adjusted_vol = 0
            else:
                adjusted_vol = self.exchange_info.adjust_quanity(volume)

            self.logInfo('Closing positions ({}): {}, v: {:.08f}'.format(
                self.symbol(), self.trade_side(), adjusted_vol))

            if adjusted_vol > 0:
                order = self.fx.create_makret_order(self.symbol(),
                                                    self.trade_side().name,
                                                    adjusted_vol)

            self.logInfo('Positions [{}] Closed'.format(self.symbol()))
            self.trade.set_completed()
            self.trigger_target_updated()
        except BinanceAPIException as bae:
            self.logError(str(bae))
示例#4
0
    def on_order_status_changed(self, t: Target, data):
        complete_trade = False

        if t.is_completed():
            if t.is_entry_target():
                # validate balance and activate trade only if there are trading targets
                if self.strategy_exit:
                    AccountBalances().update_balances(
                        self.fx.get_all_balances_dict())
                    self.trade.cap = self.get_balance_for_side().avail
                    self.trade.set_active()
                    self.trigger_target_updated()
                else:
                    complete_trade = True
            elif t.is_exit_target():
                if self.trade.exit and self.trade.exit.is_completed():
                    # if all targets are completed, set trade as completed
                    complete_trade = True
            elif t.is_stoploss_target():
                complete_trade = True

        if complete_trade:
            self.set_trade_completed()

        [s.on_order_status_changed(t, data) for s in self.all_strategies()]
示例#5
0
    def cancel_current_limit_order(self):
        if self.current_target.is_active():
            try:
                status = self.fx.get_order_status(self.symbol(),
                                                  self.current_target.id)

                if self.fx.cancel_order(self.symbol(), self.current_target.id):
                    canceled_time = datetime.now()
                    self.current_target.set_canceled()
                    self.trigger_target_updated()

                    # if balance hasn't been updated since order was cancelled
                    if AccountBalances().update_required(canceled_time):
                        if self.trade_side().is_sell():
                            self.balance.avail += (
                                float(status["origQty"]) -
                                float(status["executedQty"]))
                        else:
                            bal = self.get_balance_for_side()
                            price = float(status["price"])
                            bal.avail += round(
                                (float(status["origQty"]) * price -
                                 float(status["executedQty"]) * price), 8)
            except BinanceAPIException:
                self.logError(traceback.format_exc())
示例#6
0
    def set_stoploss_order(self):
        if self.trade.sl_settings.initial_target.is_active():
            return
            # self.logInfo('validating stoploss order')
            # if True: # validate it
            #     return
            # else:
            #     pass

        try:
            if self.simulate:
                order = self.fx.create_test_stop_order(self.symbol(),
                                                       self.trade_side().name,
                                                       self.current_stop_loss,
                                                       50)
                order['orderId'] = 2333123
            else:
                self.cancel_all_orders()
                AccountBalances().update_balances(
                    self.fx.get_all_balances_dict())

                price = self.exchange_info.adjust_price(
                    self.get_sl_limit_price())
                bal = self.trade.get_cap(self.get_balance_for_side().avail)

                bal = round(bal /
                            price, 8) if self.trade_side().is_buy() else bal

                volume = self.initial_sl().vol.get_val(bal)
                # stop_trigger
                try:
                    order = self.fx.create_stop_order(
                        sym=self.symbol(),
                        side=self.trade_side().name,
                        stop_price=self.exchange_info.adjust_price(
                            self.current_stop_loss),
                        price=price,
                        volume=self.exchange_info.adjust_quanity(volume))
                except BinanceAPIException as sl_exception:
                    if sl_exception.message.lower().find(
                            'order would trigger immediately') > -1:
                        order = self.fx.create_makret_order(
                            self.symbol(),
                            self.trade_side().name,
                            self.exchange_info.adjust_quanity(volume))
                    else:
                        raise

            self.trade.sl_settings.initial_target.set_active(order['orderId'])
            self.trigger_target_updated()
            self.logInfo('Setting stop loss order: {:.08f}:{:.08f}'.format(
                self.exchange_info.adjust_price(self.current_stop_loss),
                self.exchange_info.adjust_price(self.get_sl_limit_price())))
        except BinanceAPIException as bae:
            self.logError(str(bae))
示例#7
0
    def adjust_stoploss_order(self, current_price):
        threshold = self.trade.sl_settings.zone_entry.get_val(self.current_stop_loss)

        if (self.trade.is_sell() and (self.current_stop_loss + threshold + self.exit_threshold) >= current_price) or \
            (not self.trade.is_sell() and (self.current_stop_loss - threshold - self.exit_threshold) <= current_price):
            self.set_stoploss_order()

            # if price bounce between placing and canceling order - additing small exit threshold
            if self.exit_threshold == 0:
                self.exit_threshold = threshold / 2
        else:
            self.exit_threshold = 0

            if self.cancel_stoploss_orders():
                AccountBalances().update_balances(self.fx.get_all_balances_dict())
示例#8
0
    def extract_info(self, strategy):
        trade = strategy.trade
        self.symbol = trade.symbol
        self.status = trade
        self.balance = AccountBalances().get_balance(trade.asset)

        if isinstance(strategy, TargetsAndStopLossStrategy):
            if strategy.strategy_sl:
                sl_name = self.class_name(strategy.strategy_sl)
                if strategy.strategy_sl.is_stoploss_order_active():
                    self.active_strategy = sl_name

                self.possible_strategies.append(sl_name)

            if strategy.strategy_entry and not strategy.strategy_entry.is_completed(
            ) and trade.is_new():
                enty_name = self.class_name(strategy.strategy_exit)
                self.active_strategy = enty_name
                self.possible_strategies.append(enty_name)
示例#9
0
class TradeHandler(Logger):
    def __init__(self,
                 trades: List[Trade],
                 fx: FXConnector,
                 trade_updated_handler=None):
        super().__init__()
        self.fx = fx
        self.balances = AccountBalances()

        self.order_updated_handler = trade_updated_handler
        # ExchangeInfo().update(fx.get_exchange_info())
        self.strategies: List[TradingStrategy] = []

        # self.logInfo('Creating {} with {} trades.'.format(self.__class__.__name__, len(trades)))
        #
        # for t in trades:
        #     try:
        #         if t.symbol not in ExchangeInfo().symbols:
        #             self.logError('Exchange doesn\'t have market "{}"'.format(t.symbol))
        #             continue
        #
        #         self.strategies.append(
        #             TargetsAndStopLossStrategy(t, fx, trade_updated_handler, self.balances.get_balance(t.asset)))
        #     except Exception:
        #         self.logError(traceback.format_exc())

        self.strategies_dict = {}
        self.tradeid_strategy_dict = {}
        self.trade_info_ticker_buf = {}

        self.process_delay = 500
        self.last_ts = dt.now()
        self.first_processing = True
        self.socket_message_rcvd = False
        self.paused = False

        self.lock = RLock()

    def pause(self):
        self.logInfo('Pausing trade handler')
        self.paused = True

    def resume(self):
        self.logInfo('Resuming trade handler')
        self.paused = False

    def process_initial_prices(self):
        try:
            if not self.first_processing:
                return

            self.first_processing = False

            tickers = self.fx.get_orderbook_tickers()
            # tickers = self.fx.get_all_tickers()
            # prices = {t['symbol']: float(t['price']) for t in tickers}

            prices = {
                t['symbol']: {
                    'b': float(t['bidPrice']),
                    'a': float(t['askPrice'])
                }
                for t in tickers
            }
            self.execute_strategies(prices)
        except Exception:
            self.logError(traceback.format_exc())

    def start_listening(self):
        # self.init_trades()
        self.fx.start_listening()
        self.last_ts = dt.now()

    def remove_strategy(self, strategy: TradingStrategy, api_call=False):
        if strategy in self.strategies:
            self.strategies.remove(strategy)

        sym = strategy.symbol()
        if sym in self.strategies_dict:
            if len(self.strategies_dict[sym]) > 1:
                self.strategies_dict[sym].remove(strategy)
            else:
                self.strategies_dict.pop(sym, None)

        if strategy.trade.id in self.tradeid_strategy_dict:
            self.tradeid_strategy_dict.pop(strategy.trade.id, None)

        if api_call:
            strategy.set_trade_removed()

        self.fx.listen_symbols([s.symbol() for s in self.strategies],
                               self.listen_handler, self.user_data_handler)
        self.socket_message_rcvd = False

    def add_new_strategy(self, strategy: TradingStrategy, listen_symbols=True):
        self.strategies.append(strategy)

        sym = strategy.symbol()
        if sym in self.strategies_dict:
            self.strategies_dict[sym].append(strategy)
        else:
            self.strategies_dict[sym] = [strategy]

        self.tradeid_strategy_dict[strategy.trade.id] = strategy

        # self.balances.update_balances(self.fx.get_all_balances_dict())

        if not ExchangeInfo().has_all_symbol(self.strategies_dict.keys()):
            ExchangeInfo().update(self.fx.get_exchange_info())

        if listen_symbols:
            self.fx.listen_symbols([s.symbol() for s in self.strategies],
                                   self.listen_handler, self.user_data_handler)

        self.socket_message_rcvd = False

    # def init_strategies(self):
    #     # self.strategies_dict = {s.symbol(): s for s in self.strategies}
    #     self.strategies_dict = {}
    #     for strategy in self.strategies:
    #         sym = strategy.symbol()
    #
    #         if sym in self.strategies_dict:
    #             self.strategies_dict[sym].append(strategy)
    #         else:
    #             self.strategies_dict[sym] = [strategy]
    #
    #     self.tradeid_strategy_dict = {s.trade.id: s for s in self.strategies}
    #
    #     self.balances.update_balances(self.fx.get_all_balances_dict())
    #
    #     if not ExchangeInfo().has_all_symbol(self.strategies_dict.keys()):
    #         ExchangeInfo().update(self.fx.get_exchange_info())
    #
    #     self.process_initial_prices()
    #     self.fx.listen_symbols([s.symbol() for s in self.strategies], self.listen_handler, self.user_data_handler)
    #     self.socket_message_rcvd = False

    def stop_listening(self):
        self.fx.stop_listening()

    def user_data_handler(self, msg):
        try:
            if msg['e'] == 'outboundAccountInfo':
                self.balances.update_balances({
                    bal['a']: {
                        'f': float(bal['f']),
                        'l': float(bal['l'])
                    }
                    for bal in msg['B']
                })
            elif msg['e'] == 'executionReport':
                sym = msg['s']

                if sym in self.strategies_dict:
                    for s in self.strategies_dict[sym]:
                        s.on_execution_rpt({
                            'orderId': msg['i'],
                            'status': msg['X'],
                            'symbol': sym,
                            'side': msg['S'],
                            'vol': msg['q'],
                            'price': msg['p'],
                            'stop_price': msg['P']
                        })
                    # self.strategies_dict[sym].on_execution_rpt(
                    #     {'orderId': msg['i'],
                    #      'status': msg['X'],
                    #      'symbol': sym,
                    #      'side': msg['S'],
                    #      'vol': msg['q'],
                    #      'price': msg['p'],
                    #      'stop_price': msg['P']})
        except Exception as e:
            self.logError(traceback.format_exc())
            # self.logger.error(str(e))

    def listen_handler(self, msg):
        try:
            if self.paused:
                return

            if not self.socket_message_rcvd:
                self.confirm_socket_msg_rcvd()

            delta = dt.now() - self.last_ts
            if isinstance(msg, list):
                for ticker in msg:
                    if ticker['s'] in self.strategies_dict and ticker[
                            'e'] == '24hrTicker':
                        self.trade_info_ticker_buf[ticker['s']] = {
                            'b': float(ticker['b']),
                            'a': float(ticker['a'])
                        }
            else:
                d = msg['data']

                if 'error' in (msg.get('e', None), d.get('e', None)):
                    self.logError(msg)
                    return
                elif d['e'] == '24hrTicker':
                    self.trade_info_ticker_buf[d['s']] = {
                        'b': float(d['b']),
                        'a': float(d['a'])
                    }
                    # delta = dt.now() - self.last_ts

            if (delta.seconds * 1000 +
                (delta).microseconds / 1000) > self.process_delay:
                self.last_ts = dt.now()
                self.check_strategies_status()
                prices = dict(self.trade_info_ticker_buf)
                self.trade_info_ticker_buf = {}
                self.execute_strategies(prices)

        except Exception as e:
            self.logError(traceback.print_exc())

    def execute_strategies(self, prices):
        with self.lock:
            for s in self.strategies:
                if s.symbol() in prices and not s.paused:
                    s.execute(prices[s.symbol()])

    def check_strategies_status(self):
        for s in self.strategies[:]:
            self.handle_completed_strategy(s)

    def handle_completed_strategy(self, s):
        if s.is_completed():
            self.remove_trade_by_strategy(s)
        return s.is_completed()

    def remove_trade_by_strategy(self, strategy, api_call=False):
        if not strategy:
            return

        with self.lock:
            self.logInfo('Removing trade [{}]'.format(strategy.symbol()))
            try:
                self.stop_listening()
                self.remove_strategy(strategy, api_call)
            finally:
                self.start_listening()

    def force_reconnect_sockets(self):
        with self.lock:
            self.stop_listening()
            self.fx.listen_symbols([s.symbol() for s in self.strategies],
                                   self.listen_handler, self.user_data_handler)
            self.start_listening()

    def get_strategy_by_id(self, id) -> TradingStrategy:
        return self.tradeid_strategy_dict.get(id, None)

    def emergency_close_by_id(self, id):
        strategy: TradingStrategy = self.tradeid_strategy_dict.get(id, None)
        strategy.emergent_close_position()

    def remove_trade_by_id(self, id, api_call=False, close_trade=False):
        with self.lock:
            self.remove_trade_by_strategy(
                self.tradeid_strategy_dict.get(id, None), api_call)

    def add_trades(self, trades: [Trade], start_listening=True):
        self.logInfo('Adding {} trades to the TradeHandler.'.format(
            len(trades)))
        # try:
        self.stop_listening()

        # if not ExchangeInfo().has_all_symbol(self.strategies_dict.keys()):
        ExchangeInfo().update(self.fx.get_exchange_info())
        AccountBalances().update_balances(self.fx.get_all_balances_dict())

        for trade in trades:
            new_strategy = TargetsAndStopLossStrategy(
                trade, self.fx, self.order_updated_handler,
                self.balances.get_balance(trade.asset))

            if self.handle_completed_strategy(new_strategy):
                self.logInfo('Strategy is completed [{}]'.format(
                    new_strategy.symbol()))
                continue

            self.add_new_strategy(new_strategy, listen_symbols=False)

        self.fx.listen_symbols([s.symbol() for s in self.strategies],
                               self.listen_handler, self.user_data_handler)

        if start_listening:
            self.start_listening()
        # except Exception:
        #     self.logError(traceback.format_exc())
        # finally:

    def updated_trade(self, trade: Trade):
        with self.lock:
            if trade.id in self.tradeid_strategy_dict:
                # find by ID
                # self.strategies_dict[trade.symbol].update_trade(trade)
                self.tradeid_strategy_dict[trade.id].update_trade(trade)

                if self.handle_completed_strategy(
                        self.tradeid_strategy_dict[trade.id]):
                    self.logInfo('Strategy is completed [{}]'.format(
                        trade.symbol))
                    return

                self.balances.update_balances(self.fx.get_all_balances_dict())
                self.logInfo('Updating trade [{}]'.format(trade.symbol))
            else:
                self.logInfo('Adding trade [{}]'.format(trade.symbol))

                new_strategy = TargetsAndStopLossStrategy(
                    trade, self.fx, self.order_updated_handler,
                    self.balances.get_balance(trade.asset))

                if self.handle_completed_strategy(new_strategy):
                    self.logInfo('Strategy is completed [{}]'.format(
                        new_strategy.symbol()))
                    return

                try:
                    self.stop_listening()
                    self.add_new_strategy(new_strategy)
                finally:
                    self.start_listening()

    def confirm_socket_msg_rcvd(self):
        self.socket_message_rcvd = True
        self.logInfo('WebSocket message received')

    def fire_trade_updated(self, trade, need_cloud_sync):
        if self.order_updated_handler:
            self.order_updated_handler(trade, need_cloud_sync)
示例#10
0
 def secondary_asset_balance(self):
     return AccountBalances().get_balance(self.secondary_asset())
示例#11
0
 def self_update_balances(self):
     AccountBalances().update_balances(self.fx.get_all_balances_dict())