def initPositions(self):
     api_positions = self._execute(self.bybit.Positions.Positions_myPosition())
     self.positions[self.symbol] = AccountPosition(self.symbol, 0, 0, 0)
     if api_positions is not None:
         for pos in api_positions:
             if pos['is_valid']:
                 posdata = pos['data']
                 sizefac = -1 if posdata["side"] == "Sell" else 1
                 self.positions[posdata['symbol']] = AccountPosition(posdata['symbol'],
                                                                     avgEntryPrice=float(posdata["entry_price"]),
                                                                     quantity=posdata["size"] * sizefac,
                                                                     walletBalance=float(posdata['wallet_balance']))
Example #2
0
 def initPositions(self):
     api_positions = self._execute(self.bybit.Positions.Positions_myPosition())
     self.positions[self.symbol] = AccountPosition(self.symbol, 0, 0, 0)
     if api_positions is not None:
         for pos in api_positions:
             sizefac = -1 if pos["side"] == "Sell" else 1
             self.positions[pos['symbol']] = AccountPosition(pos['symbol'],
                                                             avgEntryPrice=pos["entry_price"],
                                                             quantity=pos["size"] * sizefac,
                                                             walletBalance=float(pos['wallet_balance']))
     self.logger.info(
         "starting with %.2f in wallet and pos  %.2f @ %.2f" % (self.positions[self.symbol].walletBalance,
                                                                self.positions[self.symbol].quantity,
                                                                self.positions[self.symbol].avgEntryPrice))
 def initPositions(self):
     account = self.client.query_account_n_positions(self.baseCurrency)
     self.positions[self.symbol] = AccountPosition(self.symbol, 0, 0, 0)
     if account is not None:
         walletBalance = account['data']['account'][
             'accountBalanceEv'] / self.valueScale
         for pos in account['data']['positions']:
             sizefac = -1 if pos["side"] == Client.SIDE_SELL else 1
             entryPrice = pos["avgEntryPrice"] if "avgEntryPrice" in pos \
                 else self.unscale_price(pos['avgEntryPriceEp'])
             self.positions[pos['symbol']] = AccountPosition(
                 pos['symbol'],
                 avgEntryPrice=entryPrice,
                 quantity=pos["size"] * sizefac,
                 walletBalance=walletBalance)
Example #4
0
 def initPositions(self):
     api_wallet=  self._execute(self.bybit.Wallet.Wallet_getBalance(coin=self.baseCurrency))
     balance= api_wallet[self.baseCurrency]["wallet_balance"]
     api_positions = self._execute(self.bybit.LinearPositions.LinearPositions_myPosition(symbol=self.symbol))
     self.longPos = AccountPosition(self.symbol, 0, 0, balance)
     self.shortPos = AccountPosition(self.symbol, 0, 0, balance)
     if api_positions is not None:
         for pos in api_positions:
             if pos["side"] == "Sell":
                 self.shortPos.avgEntryPrice=float(pos["entry_price"])
                 self.shortPos.quantity= -1*pos["size"]
             else:
                 self.longPos.avgEntryPrice=float(pos["entry_price"])
                 self.longPos.quantity= pos["size"]
     self.updatePosition_internally()
 def initPositions(self):
     api_wallet = self.handle_result(lambda: self.pybit.get_wallet_balance(coin=self.baseCurrency))
     balance = api_wallet[self.baseCurrency]["wallet_balance"]
     api_positions = self.handle_result(lambda: self.pybit.my_position(symbol=self.symbol))
     self.longPos = AccountPosition(self.symbol, 0, 0, balance)
     self.shortPos = AccountPosition(self.symbol, 0, 0, balance)
     if api_positions is not None:
         for pos in api_positions:
             if pos["side"] == "Sell":
                 self.shortPos.avgEntryPrice = float(pos["entry_price"])
                 self.shortPos.quantity = -1 * pos["size"]
             else:
                 self.longPos.avgEntryPrice = float(pos["entry_price"])
                 self.longPos.quantity = pos["size"]
     self.updatePosition_internally()
Example #6
0
 def get_position(self, symbol=None):
     if symbol is None:
         symbol = self.symbol
     pos = self.bitmex.position(symbol)
     return AccountPosition(symbol,
                            avgEntryPrice=pos["avgEntryPrice"],
                            quantity=pos["currentQty"])
Example #7
0
    def initPositions(self):
        balance = self.client.get_balance()
        usdBalance = 0
        for bal in balance:
            if bal.asset == "USDT":
                usdBalance = bal.balance
        api_positions = self.client.get_position()
        self.positions[self.symbol] = AccountPosition(self.symbol, 0, 0, 0)
        if api_positions is not None:
            for pos in api_positions:
                self.positions[pos.symbol] = AccountPosition(
                    pos.symbol,
                    avgEntryPrice=pos.entryPrice,
                    quantity=pos.positionAmt,
                    walletBalance=usdBalance if "USDT" in pos.symbol else 0)

        self.logger.info("starting with %.2f in wallet and pos  %.2f @ %.2f" %
                         (self.positions[self.symbol].walletBalance,
                          self.positions[self.symbol].quantity,
                          self.positions[self.symbol].avgEntryPrice))
Example #8
0
    def __init__(self, settings, logger, on_tick_callback=None, on_api_error=None):
        self.on_api_error = on_api_error
        self.bybit = bybit.bybit(test=settings.IS_TEST,
                                 api_key=settings.API_KEY,
                                 api_secret=settings.API_SECRET)
        hosts_private = ["wss://stream-testnet.bybit.com/realtime_private"] if settings.IS_TEST \
            else ["wss://stream.bybit.com/realtime_private", "wss://stream.bytick.com/realtime_private"]
        hosts_public = ["wss://stream-testnet.bybit.com/realtime_public"] if settings.IS_TEST \
            else ["wss://stream.bybit.com/realtime_public", "wss://stream.bytick.com/realtime_public"]
        super().__init__(settings, logger,
                         ws=BybitLinearWebsocket(wspublicURLs=hosts_public, wsprivateURLs= hosts_private,
                                           api_key=settings.API_KEY,
                                           api_secret=settings.API_SECRET,
                                           logger=logger,
                                           callback=self.socket_callback,
                                           symbol=settings.SYMBOL,
                                           minutesPerBar=settings.MINUTES_PER_BAR),
                         on_tick_callback=on_tick_callback)

        self.longPos= AccountPosition(self.symbol, 0, 0, 0)
        self.shortPos= AccountPosition(self.symbol, 0, 0, 0)
 def __init__(self, settings, logger, on_tick_callback=None, on_api_error=None, on_execution_callback=None):
     self.on_api_error = on_api_error
     self.pybit = HTTP(endpoint='https://api-testnet.bybit.com' if settings.IS_TEST else 'https://api.bybit.com',
                       api_key=settings.API_KEY,
                       api_secret=settings.API_SECRET,
                       logging_level=settings.LOG_LEVEL)
     hosts_private = ["wss://stream-testnet.bybit.com/realtime_private"] if settings.IS_TEST \
         else ["wss://stream.bybit.com/realtime_private", "wss://stream.bytick.com/realtime_private"]
     hosts_public = ["wss://stream-testnet.bybit.com/realtime_public"] if settings.IS_TEST \
         else ["wss://stream.bybit.com/realtime_public", "wss://stream.bytick.com/realtime_public"]
     self.longPos = AccountPosition(settings.SYMBOL, 0, 0, 0)
     self.shortPos = AccountPosition(settings.SYMBOL, 0, 0, 0)
     super().__init__(settings, logger,
                      ws=BybitLinearWebsocket(wspublicURLs=hosts_public, wsprivateURLs=hosts_private,
                                              api_key=settings.API_KEY,
                                              api_secret=settings.API_SECRET,
                                              logger=logger,
                                              callback=self.socket_callback,
                                              symbol=settings.SYMBOL,
                                              minutes_per_bar=settings.MINUTES_PER_BAR),
                      on_tick_callback=on_tick_callback, on_execution_callback=on_execution_callback)
     self.handles_executions = True
Example #10
0
 def initPositions(self):
     api_positions = self.handle_result(
         lambda: self.pybit.my_position(symbol=self.symbol))
     self.positions[self.symbol] = AccountPosition(self.symbol, 0, 0, 0)
     if api_positions is not None:
         if "symbol" in api_positions:  # single reply
             posdata = api_positions
             sizefac = -1 if posdata["side"] == "Sell" else 1
             self.positions[posdata['symbol']] = AccountPosition(
                 posdata['symbol'],
                 avgEntryPrice=float(posdata["entry_price"]),
                 quantity=posdata["size"] * sizefac,
                 walletBalance=float(posdata['wallet_balance']))
         else:
             for pos in api_positions:
                 if pos['is_valid']:
                     posdata = pos['data']
                     sizefac = -1 if posdata["side"] == "Sell" else 1
                     self.positions[posdata['symbol']] = AccountPosition(
                         posdata['symbol'],
                         avgEntryPrice=float(posdata["entry_price"]),
                         quantity=posdata["size"] * sizefac,
                         walletBalance=float(posdata['wallet_balance']))
Example #11
0
    def updatePosition_internally(self):
        if self.longPos.quantity > -self.shortPos.quantity:
            entry= self.longPos.avgEntryPrice
        else:
            entry= self.shortPos.avgEntryPrice

        if self.symbol in self.positions.keys() and \
                self.positions[self.symbol].quantity != self.longPos.quantity+self.shortPos.quantity:
            self.logger.info("position changed %.2f -> %.2f" % (
                self.positions[self.symbol].quantity, self.longPos.quantity+self.shortPos.quantity))

        self.positions[self.symbol] = AccountPosition(self.symbol,
                                                          quantity=self.longPos.quantity+self.shortPos.quantity,
                                                          avgEntryPrice= entry,
                                                          walletBalance=self.longPos.walletBalance)
Example #12
0
    def callback(self, data_type: 'SubscribeMessageType', event: 'any'):
        gotTick = False
        # refresh userdata every 15 min
        if self.lastUserDataKeep < time.time() - 15 * 60:
            self.lastUserDataKeep = time.time()
            self.client.keep_user_data_stream()
        # TODO: implement! (update bars, orders and account)
        if data_type == SubscribeMessageType.RESPONSE:
            pass  # what to do herE?
        elif data_type == SubscribeMessageType.PAYLOAD:
            if event.eventType == "kline":
                # {'eventType': 'kline', 'eventTime': 1587064627164, 'symbol': 'BTCUSDT',
                # 'data': <binance_f.model.candlestickevent.Candlestick object at 0x0000016B89856760>}
                if event.symbol == self.symbol:
                    candle: Candlestick = event.data
                    if len(self.candles) > 0:
                        if candle.startTime <= self.candles[
                                0].startTime and candle.startTime > self.candles[
                                    -1].startTime:
                            # somewhere inbetween to replace
                            for idx in range(0, len(self.candles)):
                                if candle.startTime == self.candles[
                                        idx].startTime:
                                    self.candles[idx] = candle
                                    break
                        elif candle.startTime > self.candles[0].startTime:
                            self.candles.insert(0, candle)
                            gotTick = True
                    else:
                        self.candles.append(candle)
                        gotTick = True
            elif (event.eventType == "ACCOUNT_UPDATE"):
                # {'eventType': 'ACCOUNT_UPDATE', 'eventTime': 1587063874367, 'transactionTime': 1587063874365,
                # 'balances': [<binance_f.model.accountupdate.Balance object at 0x000001FAF470E100>,...],
                # 'positions': [<binance_f.model.accountupdate.Position object at 0x000001FAF470E1C0>...]}
                usdBalance = 0
                for b in event.balances:
                    bal: Balance = b
                    if bal.asset == "USDT":
                        usdBalance = bal.walletBalance
                for p in event.positions:
                    pos: Position = p
                    if pos.symbol not in self.positions.keys():
                        self.positions[pos.symbol] = AccountPosition(
                            pos.symbol,
                            avgEntryPrice=float(pos.entryPrice),
                            quantity=float(pos.amount),
                            walletBalance=usdBalance
                            if "USDT" in pos.symbol else 0)
                    else:
                        accountPos = self.positions[pos.symbol]
                        accountPos.quantity = float(pos.amount)
                        accountPos.avgEntryPrice = float(pos.entryPrice)
                        if "USDT" in pos.symbol:
                            accountPos.walletBalance = usdBalance

            elif (event.eventType == "ORDER_TRADE_UPDATE"):
                # {'eventType': 'ORDER_TRADE_UPDATE', 'eventTime': 1587063513592, 'transactionTime': 1587063513589,
                # 'symbol': 'BTCUSDT', 'clientOrderId': 'web_ybDNrTjCi765K3AvOMRK', 'side': 'BUY', 'type': 'LIMIT',
                # 'timeInForce': 'GTC', 'origQty': 0.01, 'price': 6901.0, 'avgPrice': 0.0, 'stopPrice': 0.0,
                # 'executionType': 'NEW', 'orderStatus': 'NEW', 'orderId': 2705199704, 'lastFilledQty': 0.0,
                # 'cumulativeFilledQty': 0.0, 'lastFilledPrice': 0.0, 'commissionAsset': None, 'commissionAmount': None,
                # 'orderTradeTime': 1587063513589, 'tradeID': 0, 'bidsNotional': 138.81, 'asksNotional': 0.0,
                # 'isMarkerSide': False, 'isReduceOnly': False, 'workingType': 'CONTRACT_PRICE'}
                sideMulti = 1 if event.side == 'BUY' else -1
                order: Order = Order(orderId=event.clientOrderId,
                                     stop=event.stopPrice,
                                     limit=event.price,
                                     amount=event.origQty * sideMulti)
                order.exchange_id = event.orderId
                #FIXME: how do i know stop triggered on binance?
                #order.stop_triggered =
                order.executed_amount = event.cumulativeFilledQty * sideMulti
                order.executed_price = event.avgPrice
                order.tstamp = event.transactionTime
                order.execution_tstamp = event.orderTradeTime

                prev: Order = self.orders[
                    order.
                    exchange_id] if order.exchange_id in self.orders.keys(
                    ) else None
                if prev is not None:
                    if prev.tstamp > order.tstamp or abs(
                            prev.executed_amount) > abs(order.executed_amount):
                        # already got newer information, probably the info of the stop order getting
                        # triggered, when i already got the info about execution
                        self.logger.info("ignoring delayed update for %s " %
                                         (prev.id))
                    if order.stop_price is None:
                        order.stop_price = prev.stop_price
                    if order.limit_price is None:
                        order.limit_price = prev.limit_price
                prev = order
                if not prev.active and prev.execution_tstamp == 0:
                    prev.execution_tstamp = datetime.utcnow().timestamp()
                self.orders[order.exchange_id] = prev

                self.logger.info("received order update: %s" % (str(order)))
        else:
            self.logger.warn("Unknown Data in websocket callback")

        if gotTick and self.on_tick_callback is not None:
            self.on_tick_callback()  # got something new
Example #13
0
    def socket_callback(self, topic):
        try:
            gotTick = False
            msgs = self.ws.get_data(topic)
            while len(msgs) > 0:
                if topic == 'order' or topic == 'stop_order':
                    # {'order_id': '96319991-c6ac-4ad5-bdf8-a5a79b624951', 'order_link_id': '', 'symbol': 'BTCUSD',
                    # 'side': 'Buy', 'order_type': 'Limit', 'price': '7325.5', 'qty': 1, 'time_in_force':
                    # 'GoodTillCancel', 'order_status': 'Filled', 'leaves_qty': 0, 'cum_exec_qty': 1,
                    # 'cum_exec_value': '0.00013684', 'cum_exec_fee': '0.00000011', 'timestamp':
                    # '2019-12-26T20:02:19.576Z', 'take_profit': '0', 'stop_loss': '0', 'trailing_stop': '0',
                    # 'last_exec_price': '7307.5'}
                    for o in msgs:
                        order = self.orderDictToOrder(o)
                        prev: Order = self.orders[
                            order.
                            exchange_id] if order.exchange_id in self.orders.keys(
                            ) else None
                        if prev is not None:
                            if prev.tstamp > order.tstamp or abs(
                                    prev.executed_amount) > abs(
                                        order.executed_amount):
                                # already got newer information, probably the info of the stop order getting
                                # triggered, when i already got the info about execution
                                self.logger.info(
                                    "ignoring delayed update for %s " %
                                    (prev.id))
                                continue
                            # ws removes stop price when executed
                            if order.stop_price is None:
                                order.stop_price = prev.stop_price
                            if order.limit_price is None:
                                order.limit_price = prev.limit_price
                        prev = order
                        if not prev.active and prev.execution_tstamp == 0:
                            prev.execution_tstamp = datetime.utcnow(
                            ).timestamp()
                        self.orders[order.exchange_id] = prev

                        self.logger.info("received order update: %s" %
                                         (str(order)))
                elif topic == 'execution':
                    # {'symbol': 'BTCUSD', 'side': 'Buy', 'order_id': '96319991-c6ac-4ad5-bdf8-a5a79b624951',
                    # 'exec_id': '22add7a8-bb15-585f-b068-3a8648f6baff', 'order_link_id': '', 'price': '7307.5',
                    # 'order_qty': 1, 'exec_type': 'Trade', 'exec_qty': 1, 'exec_fee': '0.00000011', 'leaves_qty': 0,
                    # 'is_maker': False, 'trade_time': '2019-12-26T20:02:19.576Z'}
                    for exec in msgs:
                        if exec['order_id'] in self.orders.keys():
                            sideMulti = 1 if exec['side'] == "Buy" else -1
                            order = self.orders[exec['order_id']]
                            order.executed_amount = (
                                exec['order_qty'] -
                                exec['leaves_qty']) * sideMulti
                            if (order.executed_amount -
                                    order.amount) * sideMulti >= 0:
                                order.active = False
                            self.logger.info(
                                "got order execution: %s %.1f @ %.1f " %
                                (exec['order_link_id'], exec['exec_qty'] *
                                 sideMulti, float(exec['price'])))

                elif topic == 'position':
                    # {'user_id': 712961, 'symbol': 'BTCUSD', 'size': 1, 'side': 'Buy', 'position_value':
                    # '0.00013684', 'entry_price': '7307.80473546', 'liq_price': '6674', 'bust_price': '6643.5',
                    # 'leverage': '10', 'order_margin': '0', 'position_margin': '0.00001369', 'available_balance':
                    # '0.17655005', 'take_profit': '0', 'stop_loss': '0', 'realised_pnl': '-0.00000011',
                    # 'trailing_stop': '0', 'wallet_balance': '0.17656386', 'risk_id': 1, 'occ_closing_fee':
                    # '0.00000012', 'occ_funding_fee': '0', 'auto_add_margin': 0, 'cum_realised_pnl': '0.00175533',
                    # 'position_status': 'Normal', 'position_seq': 505770784}
                    for pos in msgs:
                        sizefac = -1 if pos["side"] == "Sell" else 1
                        if self.positions[pos[
                                'symbol']].quantity != pos["size"] * sizefac:
                            self.logger.info(
                                "position changed %.2f -> %.2f" %
                                (self.positions[pos['symbol']].quantity,
                                 pos["size"] * sizefac))
                        if pos['symbol'] not in self.positions.keys():
                            self.positions[pos['symbol']] = AccountPosition(
                                pos['symbol'],
                                avgEntryPrice=float(pos["entry_price"]),
                                quantity=pos["size"] * sizefac,
                                walletBalance=float(pos['wallet_balance']))
                        else:
                            accountPos = self.positions[pos['symbol']]
                            accountPos.quantity = pos["size"] * sizefac
                            accountPos.avgEntryPrice = float(
                                pos["entry_price"])
                            accountPos.walletBalance = float(
                                pos['wallet_balance'])
                elif topic.startswith('klineV2.') and topic.endswith(
                        '.' + self.symbol):
                    # TODO: must integrate new data into existing bars, otherwise we might miss final data from
                    #  previous bar
                    msgs.sort(key=lambda b: b['start'], reverse=True)
                    if len(self.bars) > 0:
                        for b in reversed(msgs):
                            if self.bars[0]['start'] >= b[
                                    'start'] >= self.bars[-1]['start']:
                                # find bar to fix
                                for idx in range(0, len(self.bars)):
                                    if b['start'] == self.bars[idx]['start']:
                                        self.bars[idx] = b
                                        break
                            elif b['start'] > self.bars[0]['start']:
                                self.bars.insert(0, b)
                                gotTick = True
                            # ignore old bars
                    else:
                        self.bars = msgs
                        gotTick = True

                elif topic == 'instrument_info.100ms.' + self.symbol:
                    obj = msgs
                    if 'update' in obj.keys():
                        obj = obj['update'][0]
                    if obj['symbol'] == self.symbol and 'last_price_e4' in obj.keys(
                    ):
                        self.last = obj['last_price_e4'] / 10000
                else:
                    self.logger.error('got unkown topic in callback: ' + topic)
                msgs = self.ws.get_data(topic)

            # new bars is handling directly in the messagecause we get a new one on each tick
            if topic in ["order", "stop_order", "execution"]:
                gotTick = True
            if gotTick and self.on_tick_callback is not None:
                self.on_tick_callback(fromAccountAction=topic
                                      in ["order", "stop_order",
                                          "execution"])  # got something new
        except Exception as e:
            self.logger.error("error in socket data(%s): %s " %
                              (topic, str(e)))
    def socket_callback(self, messageType, data):
        gotTick = False
        if messageType == "kline":
            if data["type"] == "snapshot":
                self.bars = []
                for k in sorted(data["kline"],
                                key=lambda b: b[0],
                                reverse=True):
                    self.bars.append(self.barArrayToBar(k, self.priceScale))
            else:  # incremental
                for k in sorted(data["kline"],
                                key=lambda b: b[0],
                                reverse=True):
                    bar = self.barArrayToBar(k, self.priceScale)
                    if self.bars[0].tstamp >= bar.tstamp >= self.bars[
                            -1].tstamp:
                        # find bar to fix
                        for idx in range(0, len(self.bars)):
                            if bar.tstamp == self.bars[idx].tstamp:
                                self.bars[idx] = bar
                                break
                    elif bar.tstamp > self.bars[0].tstamp:
                        self.bars.insert(0, bar)
                        gotTick = True

            self.last = self.bars[0].close

        if messageType == "account":
            '''{"accounts":[{"accountBalanceEv":9992165009,"accountID":604630001,"currency":"BTC",
            "totalUsedBalanceEv":10841771568,"userID":60463}],"orders":[{"accountID":604630001,...}],"positions":[{
            "accountID":604630001,...}],"sequence":11450, "timestamp":<timestamp>, "type":"<type>"} '''

            # snapshots and incremental are handled the same
            walletBalance = None
            for account in data['accounts']:
                if account['currency'] == self.baseCurrency:
                    walletBalance = account[
                        'accountBalanceEv'] / self.valueScale

            for pos in data['positions']:
                entryPrice = pos["avgEntryPrice"] if "avgEntryPrice" in pos \
                    else pos['avgEntryPriceEp'] / self.priceScale
                if pos['symbol'] in self.positions:
                    gotTick = True
                    sizefac = -1 if pos["side"] == Client.SIDE_SELL else 1
                    accountPos = self.positions[pos['symbol']]
                    if accountPos.quantity != pos["size"] * sizefac:
                        self.logger.info(
                            "position changed %.2f -> %.2f" %
                            (accountPos.quantity, pos["size"] * sizefac))
                    accountPos.quantity = pos["size"] * sizefac
                    accountPos.avgEntryPrice = entryPrice
                    if pos['currency'] == self.baseCurrency and walletBalance is not None:
                        accountPos.walletBalance = walletBalance
                else:
                    sizefac = -1 if pos["side"] == Client.SIDE_SELL else 1
                    balance = walletBalance if pos[
                        'currency'] == self.baseCurrency else 0
                    self.positions[pos['symbol']] = AccountPosition(
                        pos['symbol'],
                        avgEntryPrice=entryPrice,
                        quantity=pos["size"] * sizefac,
                        walletBalance=balance)

            for json_order in data['orders']:
                if 'ordStatus' in json_order:  # otherwise its SettleFunding
                    order = self.orderDictToOrder(json_order)
                    self.orders[order.exchange_id] = order
                    if data['type'] != "snapshot":
                        self.logger.info("got order update: %s" % str(order))
                    gotTick = True

        if gotTick and self.on_tick_callback is not None:
            self.on_tick_callback(fromAccountAction=messageType ==
                                  "account")  # got something new