async def cancel_orders(self): """ 取消订单 """ order_nos = [orderno for orderno in self.trader.orders] if order_nos and self.last_ask_price != self.ask1_price: _, errors = await self.trader.revoke_order(*order_nos) if errors: logger.error(self.strategy, "cancel future order error! error:", errors, caller=self) else: logger.info(self.strategy, "cancel future order:", order_nos, caller=self)
def __init__(self, strategy=None, platform=None, symbol=None, host=None, wss=None, account=None, access_key=None, secret_key=None, asset_update_callback=None, order_update_callback=None, position_update_callback=None, init_success_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["asset_update_callback"] = asset_update_callback kwargs["order_update_callback"] = self._on_order_update_callback kwargs["position_update_callback"] = self._on_position_update_callback kwargs["init_success_callback"] = self._on_init_success_callback self._raw_params = copy.copy(kwargs) self._order_update_callback = order_update_callback self._position_update_callback = position_update_callback self._init_success_callback = init_success_callback if platform == const.HUOBI_SWAP: from alpha.platforms.huobi_swap_trade import HuobiSwapTrade as T elif platform == const.HUOBI_FUTURE: from alpha.platforms.huobi_future_trade import HuobiFutureTrade as T elif platform == const.HUOBI_OPTION: from alpha.platforms.huobi_option_trade import HuobiOptionTrade as T else: logger.error("platform error:", platform, caller=self) e = Error("platform error") SingleTask.run(self._init_success_callback, False, e) return kwargs.pop("platform") self._t = T(**kwargs)
async def cancel_orders(self): """ 取消订单 """ order_nos = [ orderno for orderno in self.trader.orders ] #if order_nos and self.last_mark_price != self.mark_price: if order_nos: _, errors = await self.trader.revoke_order(*order_nos) if errors: logger.error(self.strategy,"cancel option order error! error:", errors, caller=self) # 出错则取消所有挂单 _, errors = await self.trader.revoke_order() if errors: logger.error(self.strategy,"cancel all option orders error! error:", errors, caller=self) else: logger.info(self.strategy,"cancel all option orders success!", caller=self) else: logger.info(self.strategy,"cancel option order:", order_nos, caller=self)
def __init__(self, platform=None, symbol=None, contract_type=None, channels=None, orderbook_length=None, orderbook_step=None, orderbooks_length=None, klines_length=None, klines_period=None, trades_length=None, wss=None, orderbook_update_callback=None, kline_update_callback=None, trade_update_callback=None, rest_api=None, **kwargs): """initialize trade object.""" kwargs["platform"] = platform kwargs["symbol"] = symbol kwargs["channels"] = channels kwargs["orderbook_length"] = orderbook_length kwargs["orderbook_step"] = orderbook_step kwargs["orderbook_length"] = orderbook_length kwargs["orderbooks_length"] = orderbooks_length kwargs["klines_length"] = klines_length kwargs["klines_period"] = klines_period kwargs["trades_length"] = trades_length kwargs["wss"] = wss kwargs["orderbook_update_callback"] = orderbook_update_callback kwargs["kline_update_callback"] = kline_update_callback kwargs["trade_update_callback"] = trade_update_callback kwargs["rest_api"] = rest_api if contract_type == "this_week": kwargs["contract_type"] = symbol + "_CW" elif contract_type == "next_week": kwargs["contract_type"] = symbol + "_NW" elif contract_type == "quarter": kwargs["contract_type"] = symbol + "_CQ" else: logger.error("is deliverd. symbol:", symbol, "contract_type:", contract_type, caller=self) return self._raw_params = copy.copy(kwargs) self._on_orderbook_update_callback = orderbook_update_callback self._on_kline_update_callback = kline_update_callback self._on_trade_update_callback = trade_update_callback self._rest_api = rest_api if platform == const.HUOBI_SWAP: from alpha.platforms.swap.huobi_swap_market import HuobiSwapMarket as M if platform == const.HUOBI_DELIVERY: from alpha.platforms.delivery.huobi_delivery_market import HuobiDeliveryMarket as M else: logger.error("platform error:", platform, caller=self) return self._m = M(**kwargs)
def _symbol_to_channel(self, symbol, channel_type): """ Convert symbol to channel. Args: symbol: Trade pair name.such as BTC-USD channel_type: channel name, kline / ticker / depth. """ if channel_type == "kline": channel = "market.{s}.kline.1min".format(s=symbol.upper()) elif channel_type == "depth": channel = "market.{s}.depth.step6".format(s=symbol.upper()) elif channel_type == "trade": channel = "market.{s}.trade.detail".format(s=symbol.upper()) else: logger.error("channel type error! channel type:", channel_type, caller=self) return None self._c_to_s[channel] = symbol return channel
def post(access_key: str, secret_key: str, host: str, path: str, data: dict = None) -> json: try: url = 'https://{}{}?{}'.format( host, path, get_url_suffix('post', access_key, secret_key, host, path)) headers = { 'Accept': 'application/json', 'Content-type': 'application/json' } res = requests.post(url, json=data, headers=headers) data = res.json() return data except Exception as e: logger.error(e) return None
async def sub_callback(self, data): if data["err-code"] != 0: e = Error("subscribe {} failed!".format(data["topic"])) logger.error(e, caller=self) SingleTask.run(self._init_success_callback, False, e) return if data["topic"] == self._order_channel: self._subscribe_order_ok = True elif data["topic"] == self._position_channel: self._subscribe_position_ok = True elif data["topic"] == self._asset_channel: self._subscribe_asset_ok = True if self._subscribe_order_ok and self._subscribe_position_ok: success, error = await self._rest_api.get_open_orders(self._symbol) if error: e = Error("get open orders failed!") SingleTask.run(self._init_success_callback, False, e) for order_info in success["data"]["orders"]: order_info["ts"] = order_info["created_at"] self._update_order(order_info) SingleTask.run(self._init_success_callback, True, None)
async def on_ticker(self, *args, **kwargs): if not self.trade_init_result: logger.error("trade not init.", caller=self) return if not self.market.init_data(): logger.error("not init market data.", caller=self) return if not self.trader.init_data(): logger.error("not init trader data.", caller=self) return klines = self.market.klines if klines[-1].id == self.last_open_order_time: logger.info("haved order. ordertime:", self.last_open_order_time, caller=self) return ma_point = interval_handler(values=klines, periods=self.periods, vtype="close") if ma_point[self.periods[0]][1] < ma_point[self.periods[1]][1]: if ma_point[self.periods[0]][0] >= ma_point[self.periods[1]][0]: print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "开多平空") elif ma_point[self.periods[0]][1] > ma_point[self.periods[1]][1]: if ma_point[self.periods[0]][0] <= ma_point[self.periods[1]][0]: print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()), "开空平多")
async def process_binary(self, msg): """ Process binary message that received from Websocket connection. """ data = json.loads(gzip.decompress(msg).decode()) logger.debug("data:", json.dumps(data), caller=self) channel = data.get("ch") if not channel: if data.get("ping"): hb_msg = {"pong": data.get("ping")} await self.ws.send_json(hb_msg) return if channel.find("kline") != -1: await self.process_kline(data) elif channel.find("depth") != -1: await self.process_orderbook(data) elif channel.find("trade") != -1: await self.process_trade(data) else: logger.error("event error! msg:", msg, caller=self)
async def _send_heartbeat_msg(self, *args, **kwargs): """ 发送心跳给服务器 """ if not self.ws: logger.warn("websocket connection not connected yet!", caller=self) return if self.heartbeat_msg: try: if isinstance(self.heartbeat_msg, dict): await self.ws.send_json(self.heartbeat_msg) elif isinstance(self.heartbeat_msg, str): await self.ws.send_str(self.heartbeat_msg) else: logger.error("send heartbeat msg failed! heartbeat msg:", self.heartbeat_msg, caller=self) return logger.debug("send ping message:", self.heartbeat_msg, caller=self) except ConnectionResetError: traceback.print_exc() await asyncio.get_event_loop().create_task(self._reconnect())
async def connected_callback(self): """ After create Websocket connection successfully, we will subscribing orderbook/trade events. """ for ch in self._channels: if ch == "kline": channel = self._symbol_to_channel(self._symbol, "kline") if not channel: continue kline = {"sub": channel} await self.ws.send_json(kline) elif ch == "orderbook": channel = self._symbol_to_channel(self._symbol, "depth") if not channel: continue data = {"sub": channel} await self.ws.send_json(data) elif ch == "trade": channel = self._symbol_to_channel(self._symbol, "trade") if not channel: continue data = {"sub": channel} await self.ws.send_json(data) else: logger.error("channel error! channel:", ch, caller=self)
def __init__(self, strategy=None, platform=None, symbol=None, contract_type=None, host=None, wss=None, account=None, access_key=None, secret_key=None, asset_update_callback=None, order_update_callback=None, position_update_callback=None, init_success_callback=None, rest_api=None, **kwargs): """initialize trade object.""" kwargs["strategy"] = strategy kwargs["platform"] = platform kwargs["symbol"] = symbol kwargs["contract_type"] = contract_type kwargs["host"] = host kwargs["wss"] = wss kwargs["rest_api"] = rest_api kwargs["account"] = account kwargs["access_key"] = access_key kwargs["secret_key"] = secret_key kwargs["asset_update_callback"] = asset_update_callback kwargs["order_update_callback"] = self._on_order_update_callback kwargs["position_update_callback"] = self._on_position_update_callback kwargs["init_success_callback"] = self._on_init_success_callback self._raw_params = copy.copy(kwargs) self._order_update_callback = order_update_callback self._position_update_callback = position_update_callback self._init_success_callback = init_success_callback self._rest_api = rest_api if platform == const.HUOBI_SWAP: from alpha.platforms.swap.huobi_swap_trade import HuobiSwapTrade as T elif platform == const.HUOBI_DELIVERY: from alpha.platforms.delivery.huobi_delivery_trade import HuobiDeliveryTrade as T else: logger.error("platform error:", platform, caller=self) e = Error("platform error") SingleTask.run(self._init_success_callback, False, e) return kwargs.pop("platform") self._t = T(**kwargs)
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("contract_type"): e = Error("param contract_type miss") if not kwargs.get("host"): kwargs["host"] = "https://api.hbdm.com" if not kwargs.get("wss"): kwargs["wss"] = "wss://api.hbdm.com" 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) if kwargs.get("init_success_callback"): SingleTask.run(kwargs["init_success_callback"], False, e) return self._account = kwargs["account"] self._strategy = kwargs["strategy"] self._platform = HUOBI_SWAP self._symbol = kwargs["symbol"] self._contract_type = kwargs["contract_type"] 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._position_update_callback = kwargs.get("position_update_callback") self._asset_update_callback = kwargs.get("asset_update_callback") self._init_success_callback = kwargs.get("init_success_callback") url = self._wss + "/swap-notification" super(HuobiSwapTrade, self).__init__(url, send_hb_interval=5) self._assets = { } # Asset detail, {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }. self._orders = {} # Order objects, {"order_id": order, ...}. self._position = Position(self._platform, self._account, self._strategy, self._symbol + '/' + self._contract_type) self._order_channel = "orders.{symbol}".format(symbol=self._symbol) self._position_channel = "positions.{symbol}".format( symbol=self._symbol) self._asset_channel = "accounts.{symbol}".format(symbol=self._symbol) self._subscribe_order_ok = False self._subscribe_position_ok = False self._subscribe_asset_ok = False self._rest_api = HuobiSwapRestAPI(self._host, self._access_key, self._secret_key) self.initialize()
async def _send_heartbeat_msg(self, *args, **kwargs): data = {"op": "pong", "ts": str(int(time.time() * 1000))} if not self.ws: logger.error("Websocket connection not yeah!", caller=self) return await self.ws.send_json(data)
async def delta_hedging(self, *args, **kwargs): """ delta hedge """ logger.debug("delta hedging", caller=self) option_delta = 0 assets, error = await self.trader.rest_api.get_asset_info( self.raw_symbol) if error: logger.error(self.strategy, "get option asset error! error:", error, caller=self) else: for item in assets["data"]: if item["symbol"] == self.raw_symbol: o_margin_balance = item["margin_balance"] o_delta = item["delta"] o_gamma = item["gamma"] o_theta = item["theta"] o_vega = item["vega"] option_delta = o_delta + o_margin_balance #增加delta对冲,使用期货对冲。 accounts, error = await self.future_trader.rest_api.get_account_position( self.raw_symbol) if error: logger.error(self.strategy, "get future account and position error! error:", error, caller=self) else: margin_balance = accounts["data"][0]["margin_balance"] long_position = 0 short_position = 0 delta_long = 0 delta_short = 0 long_last_price = 0 short_last_price = 0 for position in accounts["data"][0]["positions"]: if position["direction"] == "buy": long_position = position["volume"] long_cost_open = position["cost_open"] long_last_price = position["last_price"] if position["direction"] == "sell": short_position = position["volume"] short_cost_open = position["cost_open"] short_last_price = position["last_price"] if long_position: delta_long = self.future_volume_usd * int( long_position) / float(long_last_price) if short_position: delta_short = self.future_volume_usd * int( short_position) / float(short_last_price) future_delta = margin_balance - delta_short + delta_long t_delta = option_delta + future_delta orders_data = [] # 对冲对应数量的币 if abs(t_delta) >= self.delta_limit: if t_delta > 0: # 开空单 price = 0 volume = int(t_delta * long_last_price / self.future_volume_usd) if volume: quantity = -volume # action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_MARKET }) else: # 开多单 price = 0 volume = abs( int(t_delta * long_last_price / self.future_volume_usd)) if volume: quantity = volume # action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_MARKET }) if orders_data: order_nos, error = await self.future_trader.create_orders( orders_data) if error: logger.error(self.strategy, "create future order error! error:", error, caller=self) else: logger.info(self.strategy, "create future orders success:", order_nos, caller=self)
async def place_orders(self): """ 下单 """ orders_data = [] if self.trader.position and self.trader.position.short_quantity: # 平空单 price = round(self.mark_price - self.spread, 1) quantity = -self.trader.position.short_quantity action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.position and self.trader.position.long_quantity: # 平多单 price = round(self.mark_price + self.spread, 1) quantity = self.trader.position.long_quantity action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.assets and self.trader.assets.assets.get( self.raw_symbol).get("free"): # 开空单 if self.trader.position and self.trader.position.short_quantity and self.trader.position.short_quantity >= self.max_quantity: logger.warn("option short position exceeds the max quantity: ", self.symbol, self.trader.position.short_quantity, self.max_quantity, caller=self) else: price = round(self.mark_price + self.spread, 1) volume = self.volume if volume: quantity = -volume # 空张 action = ORDER_ACTION_SELL new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if self.trader.assets and self.trader.assets.assets.get( self.partition_symbol).get("free"): # 开多单 if self.trader.position and self.trader.position.long_quantity and self.trader.position.long_quantity >= self.max_quantity: logger.warn("option long position exceeds the max quantity: ", self.symbol, self.trader.position.long_quantity, self.max_quantity, caller=self) else: price = round(self.mark_price - self.spread, 1) volume = self.volume if volume: quantity = volume # 多张 action = ORDER_ACTION_BUY new_price = str(price) # 将价格转换为字符串,保持精度 if quantity: orders_data.append({ "price": new_price, "quantity": quantity, "action": action, "order_type": ORDER_TYPE_LIMIT }) self.last_mark_price = self.mark_price if orders_data: order_nos, error = await self.trader.create_orders(orders_data) if error: logger.error(self.strategy, "create future order error! error:", error, caller=self) logger.info(self.strategy, "create future orders success:", order_nos, caller=self)
async def fetch(cls, method, url, params=None, body=None, data=None, headers=None, timeout=30, **kwargs): """ Create a HTTP request. Args: method: HTTP request method. (GET/POST/PUT/DELETE) url: Request url. params: HTTP query params. body: HTTP request body, string or bytes format. data: HTTP request body, dict format. headers: HTTP request header. timeout: HTTP request timeout(seconds), default is 30s. kwargs: proxy: HTTP proxy. Return: code: HTTP response code. success: HTTP response data. If something wrong, this field is None. error: If something wrong, this field will holding a Error information, otherwise it's None. Raises: HTTP request exceptions or response data parse exceptions. All the exceptions will be captured and return Error information. """ session = cls._get_session(url) if not kwargs.get("proxy"): kwargs["proxy"] = config.proxy try: if method == "GET": response = await session.get(url, params=params, headers=headers, timeout=timeout, **kwargs) elif method == "POST": response = await session.post(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) elif method == "PUT": response = await session.put(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) elif method == "DELETE": response = await session.delete(url, params=params, data=body, json=data, headers=headers, timeout=timeout, **kwargs) else: error = "http method error!" return None, None, error except Exception as e: logger.error("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "Error:", e, caller=cls) return None, None, e code = response.status if code not in (200, 201, 202, 203, 204, 205, 206): text = await response.text() logger.error("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, "data:", data, "code:", code, "result:", text, caller=cls) return code, None, text try: result = await response.json() except: result = await response.text() # logger.debug("method:", method, "url:", url, "headers:", headers, "params:", params, "body:", body, # "data:", data, "code:", code, "result:", json.dumps(result), caller=cls) return code, result, None