async def _auth_success_callback(self): # Get current open orders. success, error = await self._rest_api.get_open_orders(self._raw_symbol) if error: e = Error("get open orders error: {}".format(error)) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return for order_info in success["data"]: data = { "order-id": order_info["id"], "order-type": order_info["type"], "order-state": order_info["state"], "unfilled-amount": float(order_info["amount"]) - float(order_info["filled-amount"]), "order-price": float(order_info["price"]), "price": float(order_info["price"]), "order-amount": float(order_info["amount"]), "created-at": order_info["created-at"], "utime": order_info["created-at"], } self._update_order(data) # Subscript order channel. params = {"op": "sub", "topic": self._order_channel} await self._ws.send(params)
async def _check_connection(self, *args, **kwargs) -> None: """Check Websocket connection, if connection closed, re-connect immediately.""" if not self.ws: logger.warn("Websocket connection not connected yet!", caller=self) return if self.ws.closed: SingleTask.run(self.reconnect)
def _update_order(self, order_info): """Order update. Args: order_info: Order information. Returns: None. """ order_id = str(order_info["order_id"]) state = order_info["state"] remain = float(order_info["size"]) - float(order_info["filled_size"]) avg_price = order_info.get("last_fill_px") ctime = tools.utctime_str_to_ms(order_info["ctime"]) utime = tools.utctime_str_to_ms(order_info["utime"]) if state == "-2": status = ORDER_STATUS_FAILED elif state == "-1": status = ORDER_STATUS_CANCELED elif state == "0": status = ORDER_STATUS_SUBMITTED elif state == "1": status = ORDER_STATUS_PARTIAL_FILLED elif state == "2": status = ORDER_STATUS_FILLED else: logger.error("status error! order_info:", order_info, caller=self) SingleTask.run(self._error_callback, "order status error.") return None order = self._orders.get(order_id) if not order: info = { "platform": self._platform, "account": self._account, "strategy": self._strategy, "order_id": order_id, "client_order_id": order_info["client_oid"], "action": ORDER_ACTION_BUY if order_info["side"] == "buy" else ORDER_ACTION_SELL, "symbol": self._symbol, "price": order_info["price"], "quantity": order_info["size"] } order = Order(**info) self._orders[order_id] = order order.remain = remain order.status = status order.avg_price = avg_price if avg_price else 0 order.ctime = ctime order.utime = utime SingleTask.run(self._order_update_callback, copy.copy(order)) if status in [ ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED ]: self._orders.pop(order_id)
async def process(self, msg): """Process message that received from Websocket connection. Args: msg: message received from Websocket connection. """ logger.debug("msg:", json.dumps(msg), caller=self) e = msg.get("e") if e == "executionReport": # Order update. if msg["s"] != self._raw_symbol: return order_id = str(msg["i"]) if msg["X"] == "NEW": status = ORDER_STATUS_SUBMITTED elif msg["X"] == "PARTIALLY_FILLED": status = ORDER_STATUS_PARTIAL_FILLED elif msg["X"] == "FILLED": status = ORDER_STATUS_FILLED elif msg["X"] == "CANCELED": status = ORDER_STATUS_CANCELED elif msg["X"] == "REJECTED": status = ORDER_STATUS_FAILED elif msg["X"] == "EXPIRED": status = ORDER_STATUS_FAILED else: logger.warn("unknown status:", msg, caller=self) SingleTask.run(self._error_callback, "order status error.") return order = self._orders.get(order_id) if not order: info = { "platform": self._platform, "account": self._account, "strategy": self._strategy, "order_id": order_id, "client_order_id": msg["c"], "action": ORDER_ACTION_BUY if msg["S"] == "BUY" else ORDER_ACTION_SELL, "order_type": ORDER_TYPE_LIMIT if msg["o"] == "LIMIT" else ORDER_TYPE_MARKET, "symbol": self._symbol, "price": msg["p"], "quantity": msg["q"], "ctime": msg["O"] } order = Order(**info) self._orders[order_id] = order order.remain = float(msg["q"]) - float(msg["z"]) order.status = status order.utime = msg["T"] SingleTask.run(self._order_update_callback, copy.copy(order)) if status in [ ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED ]: self._orders.pop(order_id)
def __init__(self, **kwargs): """Initialize.""" e = None if not kwargs.get("account"): e = Error("param account miss") if not kwargs.get("strategy"): e = Error("param strategy miss") if not kwargs.get("symbol"): e = Error("param symbol miss") if not kwargs.get("host"): kwargs["host"] = "https://www.okex.com" if not kwargs.get("wss"): kwargs["wss"] = "wss://real.okex.com:8443" if not kwargs.get("access_key"): e = Error("param access_key miss") if not kwargs.get("secret_key"): e = Error("param secret_key miss") if not kwargs.get("passphrase"): e = Error("param passphrase miss") if e: logger.error(e, caller=self) SingleTask.run(kwargs["error_callback"], e) SingleTask.run(kwargs["init_callback"], False) return self._account = kwargs["account"] self._strategy = kwargs["strategy"] self._platform = kwargs["platform"] self._symbol = kwargs["symbol"] self._host = kwargs["host"] self._wss = kwargs["wss"] self._access_key = kwargs["access_key"] self._secret_key = kwargs["secret_key"] self._passphrase = kwargs["passphrase"] self._order_update_callback = kwargs.get("order_update_callback") self._init_callback = kwargs.get("init_callback") self._error_callback = kwargs.get("error_callback") self._raw_symbol = self._symbol.replace("/", "-") self._order_channel = "spot/order:{symbol}".format( symbol=self._raw_symbol) url = self._wss + "/ws/v3" self._ws = Websocket(url, self.connected_callback, process_binary_callback=self.process_binary) self._assets = { } # Asset object. e.g. {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... } self._orders = {} # Order objects. e.g. {"order_id": Order, ... } # Initializing our REST API client. self._rest_api = OKExRestAPI(self._access_key, self._secret_key, self._passphrase, self._host) # Create a loop run task to send ping message to server per 5 seconds. LoopRunTask.register(self._send_heartbeat_msg, 5)
async def _check_connection(self, *args, **kwargs): if self._connected and self._channel and self._channel.is_open: return logger.error("CONNECTION LOSE! START RECONNECT RIGHT NOW!", caller=self) self._connected = False self._protocol = None self._channel = None self._event_handler = {} SingleTask.run(self.connect, reconnect=True)
def subscribe(self, callback, multi=False): """Subscribe a event. Args: callback: Asynchronous callback function. multi: If subscribe multiple channels? """ from aioquant import quant self._callback = callback SingleTask.run(quant.event_center.subscribe, self, self.callback, multi)
def __init__(self) -> None: host = "https://api.binance.com" access_key = "access_key" secret_key = "secret_key" self._rest_api = BinanceRestAPI(host, access_key, secret_key) self.symbol = "EOSUSDT" SingleTask.run(self.get_orderbook)
async def _on_consume_event_msg(self, channel, body, envelope, properties): try: key = "{exchange}:{routing_key}".format(exchange=envelope.exchange_name, routing_key=envelope.routing_key) funcs = self._event_handler[key] for func in funcs: SingleTask.run(func, channel, body, envelope, properties) except: logger.error("event handle error! body:", body, caller=self) return finally: await self._channel.basic_client_ack(delivery_tag=envelope.delivery_tag) # response ack
async def get_open_order_ids(self): """Get open order id list. """ success, error = await self._rest_api.get_open_orders(self._raw_symbol) if error: SingleTask.run(self._error_callback, error) return None, error else: order_ids = [] for order_info in success: order_id = str(order_info["orderId"]) order_ids.append(order_id) return order_ids, None
def __init__(self, **kwargs): """Initialize Trade module.""" e = None if not kwargs.get("account"): e = Error("param account miss") if not kwargs.get("strategy"): e = Error("param strategy miss") if not kwargs.get("symbol"): e = Error("param symbol miss") if not kwargs.get("host"): kwargs["host"] = "https://api.huobi.pro" if not kwargs.get("wss"): kwargs["wss"] = "wss://api.huobi.pro" if not kwargs.get("access_key"): e = Error("param access_key miss") if not kwargs.get("secret_key"): e = Error("param secret_key miss") if e: logger.error(e, caller=self) SingleTask.run(self._error_callback, e) SingleTask.run(kwargs["init_callback"], False) return self._account = kwargs["account"] self._strategy = kwargs["strategy"] self._platform = kwargs["platform"] self._symbol = kwargs["symbol"] self._host = kwargs["host"] self._wss = kwargs["wss"] self._access_key = kwargs["access_key"] self._secret_key = kwargs["secret_key"] self._order_update_callback = kwargs.get("order_update_callback") self._init_callback = kwargs.get("init_callback") self._error_callback = kwargs.get("error_callback") self._raw_symbol = self._symbol.replace("/", "").lower() self._order_channel = "orders.{}".format(self._raw_symbol) self._assets = {} self._orders = {} # Initialize our REST API client. self._rest_api = HuobiRestAPI( self._access_key, self._secret_key, self._host, ) url = self._wss + "/ws/v1" self._ws = Websocket(url, self.connected_callback, process_binary_callback=self.process_binary)
async def _connect(self) -> None: logger.info("url:", self._url, caller=self) proxy = config.proxy session = aiohttp.ClientSession() try: self._ws = await session.ws_connect(self._url, proxy=proxy) except aiohttp.ClientConnectorError: logger.error("connect to Websocket server error! url:", self._url, caller=self) return if self._connected_callback: SingleTask.run(self._connected_callback) SingleTask.run(self._receive)
async def _init_websocket(self): """Initialize Websocket connection.""" # Get listen key first. success, error = await self._rest_api.get_listen_key() if error: e = Error("get listen key failed: {}".format(error)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return self._listen_key = success["listenKey"] uri = "/ws/" + self._listen_key url = urljoin(self._wss, uri) self._ws = Websocket(url, self.connected_callback, process_callback=self.process)
async def connected_callback(self): """After websocket connection created successfully, pull back all open order information.""" logger.info("Websocket connection authorized successfully.", caller=self) order_infos, error = await self._rest_api.get_open_orders(self._raw_symbol) if error: e = Error("get open orders error: {}".format(error)) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return for order_info in order_infos: if order_info["status"] == "NEW": status = ORDER_STATUS_SUBMITTED elif order_info["status"] == "PARTIALLY_FILLED": status = ORDER_STATUS_PARTIAL_FILLED elif order_info["status"] == "FILLED": status = ORDER_STATUS_FILLED elif order_info["status"] == "CANCELED": status = ORDER_STATUS_CANCELED elif order_info["status"] == "REJECTED": status = ORDER_STATUS_FAILED elif order_info["status"] == "EXPIRED": status = ORDER_STATUS_FAILED else: logger.warn("unknown status:", order_info, caller=self) SingleTask.run(self._error_callback, "order status error.") continue order_id = str(order_info["orderId"]) info = { "platform": self._platform, "account": self._account, "strategy": self._strategy, "order_id": order_id, "client_order_id": order_info["clientOrderId"], "action": ORDER_ACTION_BUY if order_info["side"] == "BUY" else ORDER_ACTION_SELL, "order_type": ORDER_TYPE_LIMIT if order_info["type"] == "LIMIT" else ORDER_TYPE_MARKET, "symbol": self._symbol, "price": order_info["price"], "quantity": order_info["origQty"], "remain": float(order_info["origQty"]) - float(order_info["executedQty"]), "status": status, "avg_price": order_info["price"], "ctime": order_info["time"], "utime": order_info["updateTime"] } order = Order(**info) self._orders[order_id] = order SingleTask.run(self._order_update_callback, copy.copy(order)) SingleTask.run(self._init_callback, True)
def __init__(self, strategy=None, platform=None, symbol=None, host=None, wss=None, account=None, access_key=None, secret_key=None, passphrase=None, order_update_callback=None, position_update_callback=None, init_callback=None, error_callback=None, **kwargs): """Initialize trade object.""" kwargs["strategy"] = strategy kwargs["platform"] = platform kwargs["symbol"] = symbol kwargs["host"] = host kwargs["wss"] = wss kwargs["account"] = account kwargs["access_key"] = access_key kwargs["secret_key"] = secret_key kwargs["passphrase"] = passphrase kwargs["order_update_callback"] = self._on_order_update_callback kwargs["position_update_callback"] = self._on_position_update_callback kwargs["init_callback"] = self._on_init_callback kwargs["error_callback"] = self._on_error_callback self._raw_params = copy.copy(kwargs) self._order_update_callback = order_update_callback self._position_update_callback = position_update_callback self._init_callback = init_callback self._error_callback = error_callback if platform == const.BINANCE: from aioquant.platform.binance import BinanceTrade as T elif platform == const.HUOBI: from aioquant.platform.huobi import HuobiTrade as T elif platform == const.OKEX: from aioquant.platform.okex import OKExTrade as T else: logger.error("platform error:", platform, caller=self) e = Error("platform error") SingleTask.run(self._on_error_callback, e) SingleTask.run(self._on_init_callback, False) return self._t = T(**kwargs)
def __init__(self, url, connected_callback=None, process_callback=None, process_binary_callback=None, check_conn_interval=10): """Initialize.""" self._url = url self._connected_callback = connected_callback self._process_callback = process_callback self._process_binary_callback = process_binary_callback self._check_conn_interval = check_conn_interval self._ws = None # Websocket connection object. LoopRunTask.register(self._check_connection, self._check_conn_interval) SingleTask.run(self._connect)
async def revoke_order(self, *order_ids): """Revoke (an) order(s). Args: order_ids: Order id list, you can set this param to 0 or multiple items. If you set 0 param, you can cancel all orders for this symbol(initialized in Trade object). If you set 1 param, you can cancel an order. If you set multiple param, you can cancel multiple orders. Do not set param length more than 100. Returns: Success or error, see bellow. NOTEs: DO NOT INPUT MORE THAT 10 ORDER IDs, you can invoke many times. """ # If len(order_ids) == 0, you will cancel all orders for this symbol(initialized in Trade object). if len(order_ids) == 0: order_infos, error = await self._rest_api.get_open_orders( self._raw_symbol) if error: SingleTask.run(self._error_callback, error) return False, error if len(order_infos) > 100: logger.warn("order length too long! (more than 100)", caller=self) for order_info in order_infos: order_id = order_info["order_id"] _, error = await self._rest_api.revoke_order( self._raw_symbol, order_id) if error: SingleTask.run(self._error_callback, error) return False, error return True, None # If len(order_ids) == 1, you will cancel an order. if len(order_ids) == 1: success, error = await self._rest_api.revoke_order( self._raw_symbol, order_ids[0]) if error: SingleTask.run(self._error_callback, error) return order_ids[0], error else: return order_ids[0], None # If len(order_ids) > 1, you will cancel multiple orders. if len(order_ids) > 1: success, error = [], [] for order_id in order_ids: _, e = await self._rest_api.revoke_order( self._raw_symbol, order_id) if e: SingleTask.run(self._error_callback, e) error.append((order_id, e)) else: success.append(order_id) return success, error
async def process_binary(self, raw): """Process binary message that received from websocket. Args: raw: Binary message received from websocket. Returns: None. """ msg = json.loads(gzip.decompress(raw).decode()) logger.debug("msg:", msg, caller=self) op = msg.get("op") if op == "auth": if msg["err-code"] != 0: e = Error( "Websocket connection authorized failed: {}".format(msg)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return logger.info("Websocket connection authorized successfully.", caller=self) await self._auth_success_callback() elif op == "ping": # ping params = {"op": "pong", "ts": msg["ts"]} await self._ws.send(params) elif op == "sub": if msg["topic"] != self._order_channel: return if msg["err-code"] != 0: e = Error("subscribe order event error: {}".format(msg)) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) else: SingleTask.run(self._init_callback, True) elif op == "notify": if msg["topic"] != self._order_channel: return data = msg["data"] data["utime"] = msg["ts"] self._update_order(data)
async def create_order(self, action, price, quantity, *args, **kwargs): """Create an order. Args: action: Trade direction, `BUY` or `SELL`. price: Price of each order. quantity: The buying or selling quantity. Returns: order_id: Order id if created successfully, otherwise it's None. error: Error information, otherwise it's None. """ client_order_id = kwargs["client_order_id"] result, error = await self._rest_api.create_order(action, self._raw_symbol, price, quantity, client_order_id) if error: SingleTask.run(self._error_callback, error) return None, error order_id = str(result["orderId"]) return order_id, None
async def create_order(self, action, price, quantity, *args, **kwargs): """Create an order. Args: action: Trade direction, `BUY` or `SELL`. price: Price of each order. quantity: The buying or selling quantity. kwargs: order_type: Order type, `LIMIT` / `MARKET`, default is `LIMIT`. Returns: order_id: Order id if created successfully, otherwise it's None. error: Error information, otherwise it's None. """ order_type = kwargs.get("order_type", ORDER_TYPE_LIMIT) client_order_id = kwargs.get("client_order_id") if action == ORDER_ACTION_BUY: if order_type == ORDER_TYPE_LIMIT: t = "buy-limit" elif order_type == ORDER_TYPE_MARKET: t = "buy-market" else: e = Error( "order_type error! order_type: {}".format(order_type)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) return None, "order type error" elif action == ORDER_ACTION_SELL: if order_type == ORDER_TYPE_LIMIT: t = "sell-limit" elif order_type == ORDER_TYPE_MARKET: t = "sell-market" else: e = Error( "order_type error! order_type:: {}".format(order_type)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) return None, "order type error" else: logger.error("action error! action:", action, caller=self) e = Error("action error! action:: {}".format(action)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) return None, "action error" result, error = await self._rest_api.create_order( self._raw_symbol, price, quantity, t, client_order_id) if error: SingleTask.run(self._error_callback, error) return None, error order_id = result["data"] return order_id, None
async def on_event_orderbook_update(self, orderbook: Orderbook): """订单薄更新回调""" if orderbook.platform == config.A["platform"] and orderbook.symbol == config.A["symbol"]: self._a_orderbook_ok = True self._a_orderbook = orderbook elif orderbook.platform == config.B["platform"] and orderbook.symbol == config.B["symbol"]: self._b_orderbook_ok = True self._b_orderbook = orderbook elif orderbook.platform == config.C["platform"] and orderbook.symbol == config.C["symbol"]: self._c_orderbook_ok = True self._c_orderbook = orderbook # 判断maker和taker订单薄是否准备就绪 if not self._a_orderbook_ok or not self._b_orderbook_ok or not self._c_orderbook_ok: logger.warn("orderbook not ok.", caller=self) return # A同时进行买入和卖出ETH的检查 SingleTask.run(self.a_do_action_buy) SingleTask.run(self.a_do_action_sell)
async def get_open_order_ids(self): """Get open order id list. Args: None. Returns: order_ids: Open order id list, otherwise it's None. error: Error information, otherwise it's None. """ success, error = await self._rest_api.get_open_orders(self._raw_symbol) if error: SingleTask.run(self._error_callback, error) return None, error else: if len(success) > 100: logger.warn("order length too long! (more than 100)", caller=self) order_ids = [] for order_info in success: order_ids.append(order_info["order_id"]) return order_ids, None
async def create_order(self, action, price, quantity, *args, **kwargs): """Create an order. Args: action: Trade direction, `BUY` or `SELL`. price: Price of each order. quantity: The buying or selling quantity. Returns: order_id: Order id if created successfully, otherwise it's None. error: Error information, otherwise it's None. """ order_type = kwargs.get("order_type", ORDER_TYPE_LIMIT) client_order_id = kwargs.get("client_order_id") result, error = await self._rest_api.create_order( action, self._raw_symbol, price, quantity, order_type, client_order_id) if error: SingleTask.run(self._error_callback, error) return None, error if not result["result"]: SingleTask.run(self._error_callback, result) return None, result return result["order_id"], None
def __init__(self, **kwargs): """Initialize Trade module.""" e = None if not kwargs.get("account"): e = Error("param account miss") if not kwargs.get("strategy"): e = Error("param strategy miss") if not kwargs.get("symbol"): e = Error("param symbol miss") if not kwargs.get("host"): kwargs["host"] = "https://api.binance.com" if not kwargs.get("wss"): kwargs["wss"] = "wss://stream.binance.com:9443" if not kwargs.get("access_key"): e = Error("param access_key miss") if not kwargs.get("secret_key"): e = Error("param secret_key miss") if e: logger.error(e, caller=self) SingleTask.run(kwargs["error_callback"], e) SingleTask.run(kwargs["init_callback"], False) self._account = kwargs["account"] self._strategy = kwargs["strategy"] self._platform = kwargs["platform"] self._symbol = kwargs["symbol"] self._host = kwargs["host"] self._wss = kwargs["wss"] self._access_key = kwargs["access_key"] self._secret_key = kwargs["secret_key"] self._order_update_callback = kwargs.get("order_update_callback") self._init_callback = kwargs.get("init_callback") self._error_callback = kwargs.get("error_callback") self._raw_symbol = self._symbol.replace( "/", "") # Row symbol name, same as Binance Exchange. self._listen_key = None # Listen key for Websocket authentication. self._assets = { } # Asset data. e.g. {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... } self._orders = {} # Order data. e.g. {order_id: order, ... } # Initialize our REST API client. self._rest_api = BinanceRestAPI(self._access_key, self._secret_key, self._host) # Create a loop run task to reset listen key every 30 minutes. LoopRunTask.register(self._reset_listen_key, 60 * 30) # Create a coroutine to initialize Websocket connection. SingleTask.run(self._init_websocket) LoopRunTask.register(self._send_heartbeat_msg, 10)
async def _receive(self): """Receive stream message from Websocket connection.""" async for msg in self.ws: if msg.type == aiohttp.WSMsgType.TEXT: if self._process_callback: try: data = json.loads(msg.data) except: data = msg.data SingleTask.run(self._process_callback, data) elif msg.type == aiohttp.WSMsgType.BINARY: if self._process_binary_callback: SingleTask.run(self._process_binary_callback, msg.data) elif msg.type == aiohttp.WSMsgType.CLOSED: logger.warn("receive event CLOSED:", msg, caller=self) SingleTask.run(self.reconnect) elif msg.type == aiohttp.WSMsgType.ERROR: logger.error("receive event ERROR:", msg, caller=self) else: logger.warn("unhandled msg:", msg, caller=self)
def publish(self): """Publish a event.""" from aioquant import quant SingleTask.run(quant.event_center.publish, self)
async def process_binary(self, raw): """Process binary message that received from websocket. Args: raw: Binary message received from websocket. Returns: None. """ decompress = zlib.decompressobj(-zlib.MAX_WBITS) msg = decompress.decompress(raw) msg += decompress.flush() msg = msg.decode() if msg == "pong": return logger.debug("msg:", msg, caller=self) msg = json.loads(msg) # Authorization message received. if msg.get("event") == "login": if not msg.get("success"): e = Error( "Websocket connection authorized failed: {}".format(msg)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return logger.info("Websocket connection authorized successfully.", caller=self) # Fetch orders from server. (open + partially filled) order_infos, error = await self._rest_api.get_open_orders( self._raw_symbol) if error: e = Error("get open orders error: {}".format(msg)) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return if len(order_infos) > 100: logger.warn("order length too long! (more than 100)", caller=self) for order_info in order_infos: order_info["ctime"] = order_info["created_at"] order_info["utime"] = order_info["timestamp"] self._update_order(order_info) # Subscribe order channel. data = {"op": "subscribe", "args": [self._order_channel]} await self._ws.send(data) return # Subscribe response message received. if msg.get("event") == "subscribe": if msg.get("channel") == self._order_channel: SingleTask.run(self._init_callback, True) else: e = Error("subscribe order event error: {}".format(msg)) SingleTask.run(self._error_callback, e) SingleTask.run(self._init_callback, False) return # Order update message received. if msg.get("table") == "spot/order": for data in msg["data"]: data["ctime"] = data["timestamp"] data["utime"] = data["last_fill_time"] self._update_order(data)
def _bind_and_consume(self): async def do_them(): for event, callback, multi in self._subscribers: await self._initialize(event, callback, multi) SingleTask.run(do_them)
def _update_order(self, order_info): """Order update. Args: order_info: Order information. Returns: None. Note: order-state: Order status, `submitting` / `submitted` / `partial-filled` / `partial-canceled` / `filled` / `canceled` """ order_id = str(order_info["order-id"]) action = ORDER_ACTION_BUY if order_info["order-type"] in [ "buy-market", "buy-limit" ] else ORDER_ACTION_SELL state = order_info["order-state"] remain = "%.8f" % float(order_info["unfilled-amount"]) avg_price = "%.8f" % float(order_info["price"]) ctime = order_info["created-at"] utime = order_info["utime"] if state == "canceled": status = ORDER_STATUS_CANCELED elif state == "partial-canceled": status = ORDER_STATUS_CANCELED elif state == "submitting": status = ORDER_STATUS_SUBMITTED elif state == "submitted": status = ORDER_STATUS_SUBMITTED elif state == "partial-filled": status = ORDER_STATUS_PARTIAL_FILLED elif state == "filled": status = ORDER_STATUS_FILLED else: e = Error("status error! order_info: {}".format(order_info)) logger.error(e, caller=self) SingleTask.run(self._error_callback, e) return None order = self._orders.get(order_id) if not order: info = { "platform": self._platform, "account": self._account, "strategy": self._strategy, "order_id": order_id, "action": action, "symbol": self._symbol, "price": "%.8f" % float(order_info["order-price"]), "quantity": "%.8f" % float(order_info["order-amount"]), "remain": remain, "status": status } order = Order(**info) self._orders[order_id] = order order.remain = remain order.status = status order.avg_price = avg_price order.ctime = ctime order.utime = utime SingleTask.run(self._order_update_callback, copy.copy(order)) if status in [ ORDER_STATUS_FAILED, ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED ]: self._orders.pop(order_id)