def lambda_handler(event, handler): binance_api_keys = get_secret() curr_date = datetime.date.today().strftime('%Y-%m-%d') curr_hour = datetime.datetime.now().strftime('%H') TRADE_HOUR = "" if curr_hour == "01" or curr_hour == "08" or curr_hour == "16": TRADE_HOUR = curr_date + " " + curr_hour + ":17:15" elif curr_hour == "23" or curr_hour == "07" or curr_hour == "15": curr_hour = str(int(curr_hour) + 1) if len(curr_hour) == 1: curr_hour = "0" + curr_hour TRADE_HOUR = curr_date + " " + curr_hour + ":00:15" else: print("Error") # time.sleep((datetime.datetime.strptime(TRADE_HOUR, '%Y-%m-%d %H:%M:%S') - datetime.datetime.now()).seconds) sub_client = SubscriptionClient(api_key=binance_api_keys["key"], secret_key=binance_api_keys["secret"]) sub_client.subscribe_mark_price_event("vetusdt", callback, error) while running: pass return "OK"
def __init__(self, requests_only=False): super().__init__() if not requests_only: self.sub_client = SubscriptionClient(api_key=self.api_key, secret_key=self.api_secret) self.request_client = RequestClient(api_key=self.api_key, secret_key=self.api_secret)
def __init__(self, settings, logger, on_tick_callback=None): super().__init__(settings, logger, on_tick_callback) self.symbol = settings.SYMBOL self.client = RequestClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.ws = SubscriptionClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.orders = {} self.positions = {} self.candles: List[Candlestick] = [] self.last = 0 self.open = False self.listen_key = "" self.init()
def __init__(self, settings, logger, on_tick_callback=None): super().__init__(settings, logger, on_tick_callback) self.symbol: str = settings.SYMBOL self.client = RequestClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.ws = SubscriptionClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) # for binance the key is the internal id (not the exchange id) cause we can't update order but have to cancel and reopen with same id. # that leads to different exchange id, but we need to know its the same. self.orders = {} self.positions = {} self.symbol_object: Symbol = None self.candles: List[Candlestick] = [] self.last = 0 self.open = False self.listen_key = "" self.lastUserDataKeep = None self.wantedResponses = 0 # needed to wait for realtime self.init()
class Futures(BinanceAPI): markPrice = None def __init__(self, requests_only=False): super().__init__() if not requests_only: self.sub_client = SubscriptionClient(api_key=self.api_key, secret_key=self.api_secret) self.request_client = RequestClient(api_key=self.api_key, secret_key=self.api_secret) def callback(self, data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: self.markPrice = event.markPrice else: print("Unknown Data:") def error(self, e: 'BinanceApiException'): return e.error_code + e.error_message def start_listening(self, ticker="btcusdt"): self.sub_client.subscribe_mark_price_event(ticker, self.callback, self.error) def stop_listening(self): self.sub_client.unsubscribe_all() def get_price(self, ticker="btcusdt"): try: return self.request_client.get_mark_price(symbol=ticker).markPrice except BinanceApiException as e: return "Invalid symbol." if e.error_code == "ExecuteError" else e.error_message
DATA_FILENAME = 'btcusdt_candles.json' from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) api_key = 'YOUR_API_KEY_HERE' api_secret = 'YOUR_API_SECRET_HERE' sub_client = SubscriptionClient(api_key=api_key, secret_key=api_secret) request_client = RequestClient(api_key=api_key, secret_key=api_secret) ### PARAMETERS ### # symbol to trade symbol = 'ETCUSDT' # order quantity order_quantity = 7.77 # states IDLE = 0 INVESTED = 1 state = IDLE # cooldown time between last sell wait_time = 5 * 1000 # last sell cooldown flag
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-client") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: PrintBasic.print_obj(event) #sub_client.unsubscribe_all() else: print("Unknown Data:") print() def error(e: 'BinanceApiException'): print(e.error_code + e.error_message)
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: PrintBasic.print_obj(event) else: print("Unknown Data:") print() def error(e: 'BinanceApiException'): print(e.error_code + e.error_message)
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: pass elif data_type == SubscribeMessageType.PAYLOAD: PrintMix.print_data(event.bids) PrintMix.print_data(event.asks) sub_client.unsubscribe_all() def error(e: 'BinanceApiException'): pass
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: print("Event type: ", event.eventType) print("Event time: ", event.eventTime) print("Symbol: ", event.symbol) print("Data:") PrintBasic.print_obj(event.data) sub_client.unsubscribe_all() else: print("Unknown Data:") print()
the_logger = logging.getLogger(log_id) the_logger.setLevel(logging.INFO) handler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter( "%(asctime)s [%(levelname)-5.5s] %(message)s") handler.setFormatter(formatter) the_logger.addHandler(handler) setup_logger("user-data-stream") setup_logger("binance-futures") setup_logger("binance-client") my_logger = logging.getLogger("user-data-stream") sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def simple_cb(data_type: SubscribeMessageType, event: 'any', msg): if data_type == SubscribeMessageType.PAYLOAD: my_logger.info(msg) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: if (event.eventType == "ACCOUNT_CONFIG_UPDATE"): print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction time: ", event.transactionTime)
result = request_client.keep_user_data_stream() print("Result: ", result) # Close user data stream # result = request_client.close_user_data_stream() # print("Result: ", result) logger = logging.getLogger("binance-client") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient( api_key="vB5t62MtpTHQLEDBydDLoQ5rtif4UDByVBi0Js1kkcHucdzNPsg1YWdomp0W489W", secret_key= "KxgT9wHCR03ctg7hS9B48J3l21s7Le6n5KOco9smvFPNasNvDZxtsOi8tfilQ1AH") def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: if (event.eventType == "ACCOUNT_UPDATE"): print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction time: ", event.transactionTime) print("=== Balances ===") PrintMix.print_data(event.balances) print("================") print("=== Positions ===")
def profit_order_start(user_info): """ user_info:api_lable, tg_id, b_api_key, b_secret_key, tg_token 启动单线程的数据订阅 """ # TODO 查询当前持仓 # 创建当前持仓列表,记录交易对,持仓方向, def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: if (event.eventType == "ACCOUNT_UPDATE"): print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction time: ", event.transactionTime) print("=== Balances ===") PrintMix.print_data(event.balances) balance_str = "" for user_balance in event.balances: asset = user_balance.asset # 交易对 walletBalance = user_balance.walletBalance # 余额 balance_str += "{} {}\n".format(walletBalance, asset) balance_str = "账户:{}\n".format(user_info[0]) + balance_str # 账户余额变化提醒 # tg_bot_send_text(balance_str, user_info[1], user_info[4]) print("================") print("=== Positions ===") PrintMix.print_data(event.positions) print("================") elif (event.eventType == "ORDER_TRADE_UPDATE"): symbol = event.symbol # 交易对 order_id = event.orderId # 订单ID order_type = event.type # 订单类型 side = event.side # 订单方向 # ----------------------------------------------------------- origQty = event.origQty # 订单原始数量 price = event.price # 订单原始价格 # ----------------------------------------------------------- avgPrice = event.avgPrice # 订单平均价格 # ------------------------------------------------------------ cumulativeFilledQty = event.cumulativeFilledQty # 订单累计成交量 lastFilledPrice = event.lastFilledPrice # 订单末次成交价 # ----------------------------------------------------------- executionType = event.executionType # 本次事件的执行类型 orderStatus = event.orderStatus # 订单当前状态 isMarkerSide = event.isMarkerSide # 该成交是否为挂单成交 positionSide = event.positionSide # 持仓方向 commissionAsset = event.commissionAsset # 手续费资产类型 commissionAmount = event.commissionAmount # 手续费数量 bidsNotional = event.bidsNotional # 买单净值 asksNotional = event.asksNotional # 卖单净值 orderProfit = event.orderProfit # 该交易实现盈亏 tz = pytz.timezone('Asia/ShangHai') dt = pytz.datetime.datetime.fromtimestamp(event.orderTradeTime / 1000, tz) dt.strftime('%Y-%m-%d %H:%M:%S') orderTradeTime = str(dt)[:-10] # 成交时间 if float(orderProfit) > 0: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:订单完结\n" \ "持仓量:{} {}\n" \ "持仓均价:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "手续费:{} {}\n" \ "本单盈亏:{} USDT %f0%9f%92%b0%f0%9f%92%b0%f0%9f%92%b0\n" \ "成交时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, cumulativeFilledQty, symbol.replace("USDT", ""), avgPrice, symbol.replace("USDT", ""), float(origQty) * float(avgPrice), commissionAmount, commissionAsset, orderProfit, orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) elif float(orderProfit) < 0: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:订单完结\n" \ "持仓量:{} {}\n" \ "持仓均价:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "手续费:{} {}\n" \ "本单盈亏:{} USDT %f0%9f%a5%ba%f0%9f%a5%ba%f0%9f%a5%ba\n" \ "成交时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, cumulativeFilledQty, symbol.replace("USDT", ""), avgPrice, symbol.replace("USDT", ""), float(origQty) * float(avgPrice), commissionAmount, commissionAsset, orderProfit, orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) # ====================================================================================================== if not event.activationPrice is None: print("Activation Price for Trailing Stop: ", event.activationPrice) if not event.callbackRate is None: print("Callback Rate for Trailing Stop: ", event.callbackRate) elif (event.eventType == "listenKeyExpired"): print("Event: ", event.eventType) print("Event time: ", event.eventTime) print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") else: print("Unknown Data:") def error(e: 'BinanceApiException'): print(e.error_code + e.error_message) # Start user data stream request_client = RequestClient(api_key=user_info[2], secret_key=user_info[3]) listen_key = request_client.start_user_data_stream() print("listenKey: ", listen_key) # Keep user data stream result = request_client.keep_user_data_stream() print("Result: ", result) # Close user data stream # result = request_client.close_user_data_stream() # print("Result: ", result) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) sub_client.subscribe_user_data_event(listen_key, callback, error)
def all_order_start(user_info): """ user_info:api_lable, tg_id, b_api_key, b_secret_key, tg_token 启动单线程的数据订阅 """ # TODO 查询当前持仓 # 创建当前持仓列表,记录交易对,持仓方向, def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: if (event.eventType == "ACCOUNT_UPDATE"): print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction time: ", event.transactionTime) print("=== Balances ===") PrintMix.print_data(event.balances) balance_str = "" for user_balance in event.balances: asset = user_balance.asset # 交易对 walletBalance = user_balance.walletBalance # 余额 balance_str += "{} {}\n".format(walletBalance, asset) balance_str = "账户:{}\n".format(user_info[0]) + balance_str # 账户余额变化提醒 # tg_bot_send_text(balance_str, user_info[1], user_info[4]) print("================") print("=== Positions ===") PrintMix.print_data(event.positions) print("================") elif (event.eventType == "ORDER_TRADE_UPDATE"): print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction Time: ", event.transactionTime) print("Symbol: ", event.symbol) print("Client Order Id: ", event.clientOrderId) print("Side: ", event.side) print("Order Type: ", event.type) print("Time in Force: ", event.timeInForce) print("Original Quantity: ", event.origQty) print("Position Side: ", event.positionSide) print("Price: ", event.price) print("Average Price: ", event.avgPrice) print("Stop Price: ", event.stopPrice) print("Execution Type: ", event.executionType) print("Order Status: ", event.orderStatus) print("Order Id: ", event.orderId) print("Order Last Filled Quantity: ", event.lastFilledQty) print("Order Filled Accumulated Quantity: ", event.cumulativeFilledQty) print("Last Filled Price: ", event.lastFilledPrice) print("Commission Asset: ", event.commissionAsset) print("Commissions: ", event.commissionAmount) print("Order Trade Time: ", event.orderTradeTime) print("Trade Id: ", event.tradeID) print("Bids Notional: ", event.bidsNotional) print("Ask Notional: ", event.asksNotional) print("Is this trade the maker side?: ", event.isMarkerSide) print("Is this reduce only: ", event.isReduceOnly) print("stop price working type: ", event.workingType) print("Is this Close-All: ", event.isClosePosition) print("========Orders=========") # order_str = "交易对:{}\n订单方向:{}\n订单类型:{}\n订单原始数量:{}\n订单原始价格:{}\n订单平均价格:{}\n" \ # "条件订单触发价格,对追踪止损单无效:{}\n本次事件的具体执行类型:{}\n订单的当前状态:{}\n订单ID:{}\n" \ # "订单末次成交量:{}\n订单累计已成交量:{}\n订单末次成交价格:{}\n手续费资产类型:{}\n手续费数量:{}\n" \ # "成交时间:{}\n该成交是作为挂单成交吗?:{}\n是否是只减仓单:{}\n触发价类型:{}\n原始订单类型:{}\n" \ # "持仓方向:{}\n该交易实现盈亏:{}".format( # event.symbol, event.side, event.type, event.origQty, # event.price, event.avgPrice, event.stopPrice, event.executionType, event.orderStatus, event.orderId, # event.lastFilledQty, event.cumulativeFilledQty, event.lastFilledPrice, event.commissionAsset, # event.commissionAmount, event.orderTradeTime, event.isMarkerSide, event.isReduceOnly, # event.workingType, event.initOrderStatus, event.positionSide, event.orderProfit # ) symbol = event.symbol # 交易对 order_id = event.orderId # 订单ID order_type = event.type # 订单类型 side = event.side # 订单方向 # ----------------------------------------------------------- origQty = event.origQty # 订单原始数量 price = event.price # 订单原始价格 # ----------------------------------------------------------- avgPrice = event.avgPrice # 订单平均价格 # ------------------------------------------------------------ cumulativeFilledQty = event.cumulativeFilledQty # 订单累计成交量 lastFilledPrice = event.lastFilledPrice # 订单末次成交价 # ----------------------------------------------------------- executionType = event.executionType # 本次事件的执行类型 orderStatus = event.orderStatus # 订单当前状态 isMarkerSide = event.isMarkerSide # 该成交是否为挂单成交 positionSide = event.positionSide # 持仓方向 commissionAsset = event.commissionAsset # 手续费资产类型 commissionAmount = event.commissionAmount # 手续费数量 bidsNotional = event.bidsNotional # 买单净值 asksNotional = event.asksNotional # 卖单净值 orderProfit = event.orderProfit # 该交易实现盈亏 tz = pytz.timezone('Asia/ShangHai') dt = pytz.datetime.datetime.fromtimestamp(event.orderTradeTime / 1000, tz) dt.strftime('%Y-%m-%d %H:%M:%S') orderTradeTime = str(dt)[:-10] # 成交时间 # 创建/取消订单 if (orderStatus == "NEW" or orderStatus == "CANCELED") and not isMarkerSide: if orderStatus == "NEW": send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:创建委托订单\n" \ "数量:{} {}\n" \ "平均价格:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "下单时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, origQty, symbol.replace("USDT", ""), price, float(origQty) * float(price), orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) else: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:取消委托订单\n" \ "数量:{} {}\n" \ "平均价格:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "取消时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, origQty, symbol.replace("USDT", ""), price, float(origQty) * float(price), orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) elif (orderStatus == "PARTIALLY_FILLED" or orderStatus == "FILLED") and executionType == "TRADE": if float(orderProfit) > 0: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:订单完结\n" \ "持仓量:{} {}\n" \ "持仓均价:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "手续费:{} {}\n" \ "本单盈亏:{} USDT %f0%9f%92%b0%f0%9f%92%b0%f0%9f%92%b0\n" \ "成交时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, cumulativeFilledQty, symbol.replace("USDT", ""), avgPrice, symbol.replace("USDT", ""), float(origQty) * float(avgPrice), commissionAmount, commissionAsset, orderProfit, orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) elif float(orderProfit) < 0: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:订单完结\n" \ "持仓量:{} {}\n" \ "持仓均价:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "手续费:{} {}\n" \ "本单盈亏:{} USDT %f0%9f%a5%ba%f0%9f%a5%ba%f0%9f%a5%ba\n" \ "成交时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, cumulativeFilledQty, symbol.replace("USDT", ""), avgPrice, symbol.replace("USDT", ""), float(origQty) * float(avgPrice), commissionAmount, commissionAsset, orderProfit, orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) else: send_str = "账户:{}\n" \ "交易对:{}\n" \ "订单号:{}\n" \ "订单状态:订单成交\n" \ "成交量:{} {}\n" \ "成交均价:{} USDT\n" \ "价值:{:.5f} USDT\n" \ "手续费:{} {}\n" \ "成交时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, cumulativeFilledQty, symbol.replace("USDT", ""), avgPrice, symbol.replace("USDT", ""), float(origQty) * float(avgPrice), commissionAmount, commissionAsset, orderTradeTime) tg_bot_send_text(send_str, user_info[1], user_info[4]) # else: # send_str = "账户:{}\n" \ # "交易对:{}\n" \ # "订单号:{}\n" \ # "订单状态:取消委托订单\n" \ # "数量:{} {}\n" \ # "平均价格:{} USDT\n" \ # "价值:{:.5f} USDT\n" \ # "取消时间:{}".format(user_info[0], symbol.replace("USDT", "_USDT"), order_id, # origQty, symbol.replace("USDT", ""), # price, float(origQty) * float(price), orderTradeTime) # tg_bot_send_text(send_str, user_info[1], user_info[4]) # ====================================================================================================== # tg_bot_send_text(order_str, user_info[1], user_info[4]) # ====================================================================================================== if not event.activationPrice is None: print("Activation Price for Trailing Stop: ", event.activationPrice) if not event.callbackRate is None: print("Callback Rate for Trailing Stop: ", event.callbackRate) elif (event.eventType == "listenKeyExpired"): print("Event: ", event.eventType) print("Event time: ", event.eventTime) print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") print("CAUTION: YOUR LISTEN-KEY HAS BEEN EXPIRED!!!") else: print("Unknown Data:") def error(e: 'BinanceApiException'): print(e.error_code + e.error_message) # Start user data stream request_client = RequestClient(api_key=user_info[2], secret_key=user_info[3]) listen_key = request_client.start_user_data_stream() print("listenKey: ", listen_key) # Keep user data stream result = request_client.keep_user_data_stream() print("Result: ", result) # Close user data stream # result = request_client.close_user_data_stream() # print("Result: ", result) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) sub_client.subscribe_user_data_event(listen_key, callback, error)
from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient( api_key='EvNt6yBQPge3oq5VX83mOGjwiGx3kzz9jPNMWlDlziSrZ2hLtdfvdIJWOX8Lika5', secret_key= 'qEixH9AQI4jkLIkVpQB7aUInmQDtLkzfnozUMyC8t7Hws57JZZTa3mtkCqzKXXRm') def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: print("Event type: ", event.eventType) print("Event time: ", event.eventTime) print("transaction time: ", event.transactionTime) print("Symbol: ", event.symbol) print("first update Id from last stream: ", event.firstUpdateId) print("last update Id from last stream: ", event.lastUpdateId) print("last update Id in last stream: ", event.lastUpdateIdInlastStream)
result = request_client.keep_user_data_stream() print("Result: ", result) # Close user data stream # result = request_client.close_user_data_stream() # print("Result: ", result) logger = logging.getLogger("binance-client") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") ) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: "SubscribeMessageType", event: "any"): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: if event.eventType == "ACCOUNT_UPDATE": print("Event Type: ", event.eventType) print("Event time: ", event.eventTime) print("Transaction time: ", event.transactionTime) print("=== Balances ===") PrintMix.print_data(event.balances) print("================") print("=== Positions ===") PrintMix.print_data(event.positions)
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: pass elif data_type == SubscribeMessageType.PAYLOAD: PrintBasic.print_obj(event) def error(e: 'BinanceApiException'): pass sub_client.subscribe_all_bookticker_event(callback, error)
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: pass elif data_type == SubscribeMessageType.PAYLOAD: PrintMix.print_data(event.bids) PrintMix.print_data(event.asks) def error(e: 'BinanceApiException'): pass # Valid limit values are 5, 10, or 20
class BinanceInterface(ExchangeInterface): def __init__(self, settings, logger, on_tick_callback=None): super().__init__(settings, logger, on_tick_callback) self.symbol = settings.SYMBOL self.client = RequestClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.ws = SubscriptionClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.orders = {} self.positions = {} self.candles: List[Candlestick] = [] self.last = 0 self.open = False self.listen_key = "" self.init() def init(self): self.logger.info("loading market data. this may take a moment") self.initOrders() self.initPositions() self.logger.info("got all data. subscribing to live updates.") self.listen_key = self.client.start_user_data_stream() self.ws.subscribe_user_data_event(self.listen_key, self.callback, self.error) subbarsIntervall = CandlestickInterval.MIN1 if self.settings.MINUTES_PER_BAR <= 60 else CandlestickInterval.HOUR1 self.ws.subscribe_candlestick_event(self.symbol, subbarsIntervall, self.callback, self.error) self.open = True self.lastUserDataKeep = time.time() self.logger.info("ready to go") 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 error(self, e: 'BinanceApiException'): self.exit() self.logger.error(e.error_code + e.error_message) def initOrders(self): apiOrders = self.client.get_open_orders() for o in apiOrders: order = self.convertOrder(o) if order.active: self.orders[order.exchange_id] = order def convertOrder(self, apiOrder: binance_f.model.Order) -> Order: direction = 1 if apiOrder.side == OrderSide.BUY else -1 order = Order(orderId=apiOrder.clientOrderId, amount=apiOrder.origQty * direction, limit=apiOrder.price, stop=apiOrder.stopPrice) order.executed_amount = apiOrder.executedQty * direction order.executed_price = apiOrder.avgPrice order.active = apiOrder.status in ["NEW", "PARTIALLY_FILLED"] order.exchange_id = apiOrder.orderId return order 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 exit(self): self.ws.unsubscribe_all() self.open = False def internal_cancel_order(self, order: Order): if order.exchange_id in self.orders.keys(): self.orders[order.exchange_id].active = False self.client.cancel_order(symbol=self.symbol, origClientOrderId=order.id) def internal_send_order(self, order: Order): order_type = OrderType.MARKET if order.limit_price is not None: if order.stop_price is not None: order_type = OrderType.STOP else: order_type = OrderType.LIMIT else: order_type = OrderType.STOP_MARKET resultOrder: binance_f.model.Order = self.client.post_order( symbol=self.symbol, side=OrderSide.BUY if order.amount > 0 else OrderSide.SELL, ordertype=order_type, timeInForce=TimeInForce.GTC, quantity=abs(order.amount), price=order.limit_price, stopPrice=order.stop_price, newClientOrderId=order.id) order.exchange_id = resultOrder.orderId def internal_update_order(self, order: Order): self.cancel_order(order) # stupid binance can't update orders self.send_order(order) def get_orders(self) -> List[Order]: return list(self.orders.values()) def get_bars(self, timeframe_minutes, start_offset_minutes) -> List[Bar]: tf = CandlestickInterval.MIN1 if timeframe_minutes <= 60 else CandlestickInterval.HOUR1 bars = self.client.get_candlestick_data(symbol=self.symbol, interval=tf, limit=1000) return self._aggregate_bars(reversed(bars), timeframe_minutes, start_offset_minutes) def recent_bars(self, timeframe_minutes, start_offset_minutes) -> List[Bar]: return self._aggregate_bars(self.bars, timeframe_minutes, start_offset_minutes) def _aggregate_bars(self, bars, timeframe_minutes, start_offset_minutes) -> List[Bar]: subbars = [] for b in bars: subbars.append(self.convertBar(b)) return process_low_tf_bars(subbars, timeframe_minutes, start_offset_minutes) def convertBar(self, apiBar: binance_f.model.candlestick.Candlestick): return Bar(tstamp=apiBar.openTime / 1000, open=apiBar.open, high=apiBar.high, low=apiBar.low, close=apiBar.close, volume=apiBar.volume) def get_instrument(self, symbol=None): if symbol is None: symbol = self.symbol instr: binance_f.model.exchangeinformation.ExchangeInformation = self.client.get_exchange_information( ) for symb in instr.symbols: if symb.symbol == symbol: baseLength = len(symb.baseAsset) lotSize = 0 tickSize = 0 for filter in symb.filters: if filter['filterType'] == 'LOT_SIZE': lotSize = filter['stepSize'] if filter['filterType'] == 'PRICE_FILTER': tickSize = filter['tickSize'] return Symbol( symbol=symb.symbol, isInverse=symb.baseAsset != symb.symbol[:baseLength], lotSize=lotSize, tickSize=tickSize, makerFee=0.02, takerFee=0.04) return None def get_position(self, symbol=None): if symbol is None: symbol = self.symbol return self.positions[symbol] if symbol in self.positions.keys( ) else None def is_open(self): return self.open def check_market_open(self): return self.open # TODO: is that the best we can do? def update_account(self, account: Account): pass
import logging from binance_f import SubscriptionClient from binance_f.constant.test import * from binance_f.model import * from binance_f.exception.binanceapiexception import BinanceApiException from binance_f.base.printobject import * logger = logging.getLogger("binance-futures") logger.setLevel(level=logging.INFO) handler = logging.StreamHandler() handler.setFormatter( logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')) logger.addHandler(handler) sub_client = SubscriptionClient(api_key=g_api_key, secret_key=g_secret_key) def callback(data_type: 'SubscribeMessageType', event: 'any'): if data_type == SubscribeMessageType.RESPONSE: print("Event ID: ", event) elif data_type == SubscribeMessageType.PAYLOAD: for item in event: PrintBasic.print_obj(item) print("") # sub_client.unsubscribe_all() else: print("Unknown Data:") print()
class BinanceInterface(ExchangeInterface): def __init__(self, settings, logger, on_tick_callback=None): super().__init__(settings, logger, on_tick_callback) self.symbol: str = settings.SYMBOL self.client = RequestClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) self.ws = SubscriptionClient(api_key=settings.API_KEY, secret_key=settings.API_SECRET) # for binance the key is the internal id (not the exchange id) cause we can't update order but have to cancel and reopen with same id. # that leads to different exchange id, but we need to know its the same. self.orders = {} self.positions = {} self.symbol_object: Symbol = None self.candles: List[Candlestick] = [] self.last = 0 self.open = False self.listen_key = "" self.lastUserDataKeep = None self.wantedResponses = 0 # needed to wait for realtime self.init() def init(self): self.logger.info("loading market data. this may take a moment") self.initOrders() self.initPositions() self.symbol_object = self.get_instrument() self.logger.info("got all data. subscribing to live updates.") self.listen_key = self.client.start_user_data_stream() self.lastUserDataKeep = time.time() self.wantedResponses = 2 subInt = CandlestickInterval.MIN1 if self.settings.MINUTES_PER_BAR <= 60 else CandlestickInterval.HOUR1 self.ws.subscribe_candlestick_event(self.symbol.lower(), subInt, self.callback, self.error) self.ws.subscribe_user_data_event(self.listen_key, self.callback, self.error) waitingTime = 0 while self.wantedResponses > 0 and waitingTime < 100: waitingTime += 1 time.sleep(0.1) if self.wantedResponses > 0: self.logger.error("got no response to subscription. outa here") self.open = False return self.open = True self.logger.info("ready to go") def callback(self, data_type: 'SubscribeMessageType', event: 'any'): gotTick = False fromAccount = False # refresh userdata every 5 min if self.lastUserDataKeep < time.time() - 5 * 60: self.lastUserDataKeep = time.time() self.client.keep_user_data_stream() if data_type == SubscribeMessageType.RESPONSE: self.wantedResponses -= 1 # tell the waiting init that we got it. otherwise we might be too fast 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 self.candles[ 0].startTime >= 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 gotTick = True fromAccount = True 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( symbol=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'} gotTick = True fromAccount = True sideMulti = 1 if event.side == 'BUY' else -1 order: Order = Order( orderId=event.clientOrderId, stop=event.stopPrice if event.stopPrice > 0 else None, limit=event.price if event.price > 0 else None, amount=event.origQty * sideMulti) order.exchange_id = event.orderId # trigger of a stoplimit in Binance means "update for order -> expired" then "update -> as limit" order.stop_triggered = event.type == "LIMIT" and event.stopPrice > 0 order.executed_amount = event.cumulativeFilledQty * sideMulti order.executed_price = event.avgPrice order.tstamp = event.transactionTime order.execution_tstamp = event.orderTradeTime / 1000 order.active = event.orderStatus in ["NEW", "PARTIALLY_FILLED"] prev: Order = self.orders[ order.id] if order.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.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( fromAccountAction=fromAccount) # got something new def error(self, e: BinanceApiException): self.logger.error(e.error_code + ": " + e.error_message) self.open = False def initOrders(self): apiOrders = self.client.get_open_orders() for o in apiOrders: order = self.convertOrder(o) if order.active: self.orders[order.id] = order @staticmethod def convertOrder(apiOrder: binance_f.model.Order) -> Order: direction = 1 if apiOrder.side == OrderSide.BUY else -1 order = Order( orderId=apiOrder.clientOrderId, amount=apiOrder.origQty * direction, limit=apiOrder.price if apiOrder.price > 0 else None, stop=apiOrder.stopPrice if apiOrder.stopPrice > 0 else None) order.executed_amount = apiOrder.executedQty * direction order.executed_price = apiOrder.avgPrice order.active = apiOrder.status in ["NEW", "PARTIALLY_FILLED"] order.exchange_id = apiOrder.orderId return order 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, avgEntryPrice=0, quantity=0, walletBalance=usdBalance if "USDT" in self.symbol else 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 exit(self): self.open = False if self.ws is not None: self.ws.close() self.ws = None self.client.close_user_data_stream() def internal_cancel_order(self, order: Order): if order.id in self.orders.keys(): self.orders[order.id].active = False self.client.cancel_order(symbol=self.symbol, origClientOrderId=order.id) def internal_send_order(self, order: Order): if order.limit_price is not None: order.limit_price = round(order.limit_price, self.symbol_object.pricePrecision) if order.stop_price is not None: order.stop_price = round(order.stop_price, self.symbol_object.pricePrecision) order_type = OrderType.STOP else: order_type = OrderType.LIMIT elif order.stop_price is not None: order.stop_price = round(order.stop_price, self.symbol_object.pricePrecision) order_type = OrderType.STOP_MARKET else: order_type = OrderType.MARKET order.amount = round(order.amount, self.symbol_object.quantityPrecision) quantityFormat = "{:." + str( self.symbol_object.quantityPrecision) + "f}" priceFormat = "{:." + str(self.symbol_object.pricePrecision) + "f}" # yes have to send the price and quantity in as str (although it wants float) cause otherwise it converts it inernally # and that sometimes f**k up the precision (0.023 -> 0.02299999999) resultOrder: binance_f.model.Order = self.client.post_order( symbol=self.symbol, side=OrderSide.BUY if order.amount > 0 else OrderSide.SELL, ordertype=order_type, timeInForce=TimeInForce.GTC if order_type in [OrderType.LIMIT, OrderType.STOP] else None, quantity=quantityFormat.format(abs(order.amount)), price=priceFormat.format(order.limit_price) if order.limit_price is not None else None, stopPrice=priceFormat.format(order.stop_price) if order.stop_price is not None else None, newClientOrderId=order.id) order.exchange_id = resultOrder.orderId def internal_update_order(self, order: Order): self.cancel_order(order) # stupid binance can't update orders self.on_tick_callback(True) # triggers a reset of the tick-delay. # otherwise we risk a tick to be calced after the cancel, before the new order self.send_order(order) self.on_tick_callback(True) # triggers a reset of the tick-delay def get_orders(self) -> List[Order]: return list(self.orders.values()) def get_bars(self, timeframe_minutes, start_offset_minutes) -> List[Bar]: tf = CandlestickInterval.MIN1 if timeframe_minutes <= 60 else CandlestickInterval.HOUR1 bars = self.client.get_candlestick_data(symbol=self.symbol, interval=tf, limit=1000) subbars = [] for b in reversed(bars): subbars.append(self.convertBar(b)) return process_low_tf_bars(subbars, timeframe_minutes, start_offset_minutes) def recent_bars(self, timeframe_minutes, start_offset_minutes) -> List[Bar]: subbars = [] for b in self.candles: subbars.append(self.convertBarevent(b)) return process_low_tf_bars(subbars, timeframe_minutes, start_offset_minutes) @staticmethod def convertBar(apiBar: binance_f.model.candlestick.Candlestick): return Bar(tstamp=apiBar.openTime / 1000, open=float(apiBar.open), high=float(apiBar.high), low=float(apiBar.low), close=float(apiBar.close), volume=float(apiBar.volume)) @staticmethod def convertBarevent(apiBar: binance_f.model.candlestickevent.Candlestick): return Bar(tstamp=apiBar.startTime / 1000, open=float(apiBar.open), high=float(apiBar.high), low=float(apiBar.low), close=float(apiBar.close), volume=float(apiBar.volume)) @staticmethod def barArrayToBar(b): return Bar(tstamp=b[0] / 1000, open=float(b[1]), high=float(b[2]), low=float(b[3]), close=float(b[4]), volume=float(b[5])) def get_instrument(self, symbol=None): if symbol is None: symbol = self.symbol instr: binance_f.model.exchangeinformation.ExchangeInformation = self.client.get_exchange_information( ) for symb in instr.symbols: if symb.symbol == symbol: baseLength = len(symb.baseAsset) lotSize = 0 tickSize = 0 for filterIt in symb.filters: if filterIt['filterType'] == 'LOT_SIZE': lotSize = filterIt['stepSize'] if filterIt['filterType'] == 'PRICE_FILTER': tickSize = filterIt['tickSize'] return Symbol( symbol=symb.symbol, isInverse=symb.baseAsset != symb.symbol[:baseLength], lotSize=lotSize, tickSize=tickSize, makerFee=0.02, takerFee=0.04, pricePrecision=symb.pricePrecision, quantityPrecision=symb.quantityPrecision) return None def get_position(self, symbol=None): if symbol is None: symbol = self.symbol return self.positions[symbol] if symbol in self.positions.keys( ) else None def is_open(self): return self.open def check_market_open(self): return self.open # TODO: is that the best we can do? def update_account(self, account: Account): pos = self.positions[self.symbol] account.open_position = pos account.equity = pos.walletBalance account.usd_equity = account.equity