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']))
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)
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()
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"])
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))
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
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']))
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)
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
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