Beispiel #1
0
    def __init__(self, **kwargs):
        """ 初始化
        """
        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.deribit.com"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://deribit.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 = DERIBIT
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        self._order_channel = "user.orders.{symbol}.raw".format(symbol=self._symbol)  # 订单订阅频道

        url = self._wss + "/ws/api/v2"
        super(DeribitTrade, self).__init__(url, send_hb_interval=5)

        self._assets = {}  # 资产 {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account, self._strategy, self._symbol)  # 仓位

        self._query_id = 0  # 消息序号id,用来唯一标识请求消息
        self._queries = {}  # 未完成的post请求 {"request_id": future}

        self.initialize()

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account, self.on_event_asset_update)

        # 注册定时任务
        LoopRunTask.register(self._do_auth, 60 * 60)  # 每隔1小时重新授权
        LoopRunTask.register(self._check_position_update, 1)  # 获取持仓

        self._ok = False  # 是否建立授权成功的websocket连接
    def __init__(self, **kwargs):
        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.testnet.fmex.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 = FCOIN_FUTURE
        self._symbol = kwargs["symbol"]
        self._host = kwargs["host"]
        self._access_key = kwargs["access_key"]
        self._secret_key = kwargs["secret_key"]
        self._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")
        self._update_order_interval = kwargs.get("update_order_interval", 1)

        self._assets = {
        }  # 资产 {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # 标记订阅订单、持仓是否成功
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        # 初始化 REST API 对象
        self._rest_api = FCoinFutureRestAPI(self._host, self._access_key,
                                            self._secret_key)

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # 注册定时任务,定时查询订单更新、仓位更新情况
        if self._position_update_callback:
            LoopRunTask.register(self._check_position_update, 60)

        # 初始化订单订阅
        if self._order_update_callback:
            LoopRunTask.register(self.check_order_update,
                                 self._update_order_interval)
Beispiel #3
0
    def __init__(self, **kwargs):
        """ 初始化
        """
        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.gateio.ws"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://fx-ws.gateio.ws"
        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 = GATE_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")
        self._contract_update_callback = kwargs.get('contract_update_callback')
        self._user_id = None

        url = self._wss + "/v4/ws"
        super(GateFutureTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._assets = {
        }  # 资产 {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # 订单 {"order_no": order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)

        # 初始化 REST API 对象
        self._rest_api = GateFutureRestAPI(self._host, self._access_key,
                                           self._secret_key)

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # 注册定时任务
        LoopRunTask.register(self._check_position_update, 1)  # 获取持仓
Beispiel #4
0
    def __init__(self, **kwargs):
        """ 初始化
        """
        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.bitmex.com"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://www.bitmex.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 = BITMEX
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        url = self._wss + "/realtime"
        super(BitmexTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._order_channel = "order:{symbol}".format(symbol=self._symbol)  # 订单订阅频道
        self._position_channel = "position:{symbol}".format(symbol=self._symbol)  # 持仓订阅频道

        # 标记订阅订单、持仓是否成功
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        self._assets = {}  # 资产 {"XBT": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}
        self._position = Position(self._platform, self._account, self._strategy, self._symbol)  # 仓位

        # 初始化REST API对象
        self._rest_api = BitmexAPI(self._host, self._access_key, self._secret_key)

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account, self.on_event_asset_update)

        self.initialize()
Beispiel #5
0
    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_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        url = self._wss + "/notification"
        self._ws = Websocket(url, self.connected_callback, process_binary_callback=self.process_binary)
        self._ws.initialize()

        LoopRunTask.register(self.send_heartbeat_msg, 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.lower())
        self._position_channel = "positions.{symbol}".format(symbol=self._symbol.lower())

        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        self._rest_api = HuobiFutureRestAPI(self._host, self._access_key, self._secret_key)

        # Subscribe AssetEvent.
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account, self.on_event_asset_update)
Beispiel #6
0
 async def on_position_update_callback(self, position: Position):
     """ 持仓更新
     """
     if self.native_to_system:
         position.symbol = self.native_to_system[
             position.symbol]  #'交易所原始符号'转换成'量化平台通用符号'
     await self._original_on_position_update_callback(position)
Beispiel #7
0
    def __init__(self, account, strategy, symbol, host=None, wss=None, access_key=None, secret_key=None,
                 order_update_callback=None, position_update_callback=None):
        """ 初始化
        @param account 账户
        @param strategy 策略名称
        @param symbol 交易对(合约名称)
        @param host HTTP请求主机地址
        @param wss websocket连接地址
        @param access_key ACCESS KEY
        @param secret_key SECRET KEY
        @param order_update_callback 订单更新回调
        @param position_update_callback 持仓更新回调
        """
        self._account = account
        self._strategy = strategy
        self._platform = BITMEX
        self._symbol = symbol
        self._host = host
        self._wss = wss
        self._access_key = access_key
        self._secret_key = secret_key

        self._order_update_callback = order_update_callback
        self._position_update_callback = position_update_callback

        super(BitmexTrade, self).__init__(self._wss, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._orders = {}
        self._position = Position(self._platform, self._account, strategy, symbol)  # 仓位

        # 初始化REST API对象
        self._rest_api = BitmexAPI(self._host, self._access_key, self._secret_key)

        self.initialize()
Beispiel #8
0
    def __init__(self, account, strategy, symbol, host=None, wss=None, access_key=None, secret_key=None,
                 order_update_callback=None, position_update_callback=None):
        """ 初始化
        @param account 账户
        @param strategy 策略名称
        @param symbol 交易对(合约名称)
        @param host HTTP请求主机地址
        @param wss websocket连接地址
        @param access_key ACCESS KEY
        @param secret_key SECRET KEY
        @param order_update_callback 订单更新回调
        @param position_update_callback 持仓更新回调
        """
        self._account = account
        self._strategy = strategy
        self._platform = DERIBIT
        self._symbol = symbol
        self._host = host if host else "https://www.deribit.com"
        self._wss = wss if wss else "wss://deribit.com/ws/api/v2"
        self._access_key = access_key
        self._secret_key = secret_key

        self._order_update_callback = order_update_callback
        self._position_update_callback = position_update_callback

        self._order_channel = "user.orders.{symbol}.raw".format(symbol=symbol)  # 订单订阅频道

        super(DeribitTrade, self).__init__(self._wss, send_hb_interval=5)

        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account, strategy, symbol)  # 仓位

        self._query_id = 0  # 消息序号id,用来唯一标识请求消息
        self._queries = {}  # 未完成的post请求 {"request_id": future}

        self.initialize()

        # 注册定时任务
        LoopRunTask.register(self._do_auth, 60 * 60)  # 每隔1小时重新授权
        LoopRunTask.register(self._check_position_update, 1)  # 获取持仓

        self._ok = False  # 是否建立授权成功的websocket连接
Beispiel #9
0
    def __init__(self,
                 account,
                 strategy,
                 symbol,
                 host=None,
                 wss=None,
                 access_key=None,
                 secret_key=None,
                 passphrase=None,
                 order_update_callback=None,
                 position_update_callback=None):
        """ 初始化
        @param account 账户
        @param strategy 策略名称
        @param symbol 交易对(合约名称)
        @param host HTTP请求主机地址
        @param wss websocket连接地址
        @param access_key ACCESS KEY
        @param secret_key SECRET KEY
        @param passphrase 密码
        @param order_update_callback 订单更新回调
        @param position_update_callback 持仓更新回调
        """
        self._account = account
        self._strategy = strategy
        self._platform = OKEX_FUTURE
        self._symbol = symbol
        self._host = host if host else "https://www.okex.com"
        self._wss = wss if wss else "wss://real.okex.com:10442/ws/v3"
        self._access_key = access_key
        self._secret_key = secret_key
        self._passphrase = passphrase

        self._order_update_callback = order_update_callback
        self._position_update_callback = position_update_callback

        super(OKExFutureTrade, self).__init__(self._wss, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account, strategy,
                                  symbol)  # 仓位

        # 初始化 REST API 对象
        self._rest_api = OKExFutureRestAPI(self._host, self._access_key,
                                           self._secret_key, self._passphrase)

        self.initialize()
Beispiel #10
0
    async def get_position(self, symbol):
        """ 获取当前持仓

        Args:
            symbol: Trade target

        Returns:
            position: Position if successfully, otherwise it's None.
            error: Error information, otherwise it's None.
        """

        #{"result": [{"collateralUsed": 0.35986, "cost": -1.7984, "entryPrice": 179.84, "estimatedLiquidationPrice": 11184.0123266, "future": "ETH-PERP", "initialMarginRequirement": 0.2, "longOrderSize": 0.0, "maintenanceMarginRequirement": 0.03, "netSize": -0.01, "openSize": 0.01, "realizedPnl": 0.01866927, "recentAverageOpenPrice": 179.84, "recentPnl": -0.0009, "shortOrderSize": 0.0, "side": "sell", "size": 0.01, "unrealizedPnl": -0.0009}], "success": true}

        success, error = await self._rest_api.get_positions(True)
        if error:
            return None, error
        if not success["success"]:
            return None, "get_position error"

        p = next(filter(lambda x: x['future'] == symbol, success["result"]),
                 None)
        if p == None:
            return None, "symbol not exist"

        if p["netSize"] == 0:
            return None, "currently no positions"

        pos = Position(self._platform, self._account, self._strategy, symbol)
        if p["netSize"] < 0:
            #空头仓位
            pos.update(short_quantity=abs(p["netSize"]),
                       short_avg_price=p["recentAverageOpenPrice"],
                       liquid_price=p["estimatedLiquidationPrice"])
        else:
            #多头仓位
            pos.update(long_quantity=abs(p["netSize"]),
                       long_avg_price=p["recentAverageOpenPrice"],
                       liquid_price=p["estimatedLiquidationPrice"])

        #因为ftx websocket接口里面没有仓位通知,所以只能这样模拟
        SingleTask.run(self.cb.on_position_update_callback, pos)

        return pos, None
Beispiel #11
0
class DeribitTrade(Websocket):
    """ Deribit Trade module 交易模块
    """

    def __init__(self, account, strategy, symbol, host=None, wss=None, access_key=None, secret_key=None,
                 order_update_callback=None, position_update_callback=None):
        """ 初始化
        @param account 账户
        @param strategy 策略名称
        @param symbol 交易对(合约名称)
        @param host HTTP请求主机地址
        @param wss websocket连接地址
        @param access_key ACCESS KEY
        @param secret_key SECRET KEY
        @param order_update_callback 订单更新回调
        @param position_update_callback 持仓更新回调
        """
        self._account = account
        self._strategy = strategy
        self._platform = DERIBIT
        self._symbol = symbol
        self._host = host if host else "https://www.deribit.com"
        self._wss = wss if wss else "wss://deribit.com/ws/api/v2"
        self._access_key = access_key
        self._secret_key = secret_key

        self._order_update_callback = order_update_callback
        self._position_update_callback = position_update_callback

        self._order_channel = "user.orders.{symbol}.raw".format(symbol=symbol)  # 订单订阅频道

        super(DeribitTrade, self).__init__(self._wss, send_hb_interval=5)

        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account, strategy, symbol)  # 仓位

        self._query_id = 0  # 消息序号id,用来唯一标识请求消息
        self._queries = {}  # 未完成的post请求 {"request_id": future}

        self.initialize()

        # 注册定时任务
        LoopRunTask.register(self._do_auth, 60 * 60)  # 每隔1小时重新授权
        LoopRunTask.register(self._check_position_update, 1)  # 获取持仓

        self._ok = False  # 是否建立授权成功的websocket连接

    @property
    def position(self):
        return copy.copy(self._position)

    @property
    def orders(self):
        return copy.copy(self._orders)

    async def connected_callback(self):
        """ 建立连接之后,授权登陆,然后订阅order和position
        """
        # 授权
        success, error = await self._do_auth()
        if error:
            return
        if success.get("access_token"):
            self._ok = True
        else:
            return

        # 获取未完全成交的订单
        success, error = await self.get_open_orders()
        if error:
            return
        for order_info in success:
            order = self._update_order(order_info)
            if self._order_update_callback:
                SingleTask.run(self._order_update_callback, order)

        # 获取持仓
        await self._check_position_update()

        # 授权成功之后,订阅数据
        method = "private/subscribe"
        params = {
            "channels": [
                self._order_channel
            ]
        }
        await self._send_message(method, params)

    async def _do_auth(self, *args, **kwargs):
        """ 鉴权
        """
        method = "public/auth"
        params = {
            "grant_type": "client_credentials",
            "client_id": self._access_key,
            "client_secret": self._secret_key
        }
        success, error = await self._send_message(method, params)
        return success, error

    async def get_server_time(self):
        """ 获取服务器时间
        """
        method = "public/get_time"
        params = {}
        success, error = await self._send_message(method, params)
        return success, error

    async def get_position(self):
        """ 获取当前持仓
        """
        method = "private/get_position"
        params = {"instrument_name": self._symbol}
        success, error = await self._send_message(method, params)
        return success, error

    async def create_order(self, action, price, quantity, order_type=ORDER_TYPE_LIMIT):
        """ 创建订单
        @param action 委托方向 BUY SELL
        @param price 委托价格
        @param quantity 委托数量
        @param order_type 委托类型 limit/market
        """
        if int(quantity) > 0:
            if action == ORDER_ACTION_BUY:
                trade_type = TRADE_TYPE_BUY_OPEN
            else:
                trade_type = TRADE_TYPE_SELL_CLOSE
        else:
            if action == ORDER_ACTION_BUY:
                trade_type = TRADE_TYPE_BUY_CLOSE
            else:
                trade_type = TRADE_TYPE_SELL_OPEN
        quantity = abs(int(quantity))
        if action == ORDER_ACTION_BUY:
            method = "private/buy"
        elif action == ORDER_ACTION_SELL:
            method = "private/sell"
        else:
            logger.error("action error! action:", action, caller=self)
            return None
        if order_type == ORDER_TYPE_LIMIT:
            type_ = "limit"
        else:
            type_ = "market"
        params = {
            "instrument_name": self._symbol,
            "price": price,
            "amount": quantity,
            "type": type_,
            "label": str(trade_type)
        }
        success, error = await self._send_message(method, params)
        if error:
            return None, error
        order_no = success["order"]["order_id"]
        return order_no, None

    async def revoke_order(self, *order_nos):
        """ 撤销订单
        @param order_nos 订单号,如果没有指定订单号,那么撤销所有订单
        * NOTE: 单次调换最多只能撤销100个订单,如果订单超过100个,请多次调用
        """
        # 如果传入order_nos为空,即撤销全部委托单
        if len(order_nos) == 0:
            method = "private/cancel_all_by_instrument"
            params = {"instrument_name": self._symbol}
            success, error = await self._send_message(method, params)
            if error:
                return False, error
            else:
                return True, None

        # 如果传入order_nos为一个委托单号,那么只撤销一个委托单
        if len(order_nos) == 1:
            method = "private/cancel"
            params = {"order_id": order_nos[0]}
            success, error = await self._send_message(method, params)
            if error:
                return order_nos[0], error
            else:
                return order_nos[0], None

        # 如果传入order_nos数量大于1,那么就批量撤销传入的委托单
        if len(order_nos) > 1:
            success, error = [], []
            method = "private/cancel"
            for order_no in order_nos:
                params = {"order_id": order_no}
                r, e = await self._send_message(method, params)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

    async def get_order_status(self, order_no):
        """ 获取订单状态
        @param order_no 订单号
        """
        method = "private/get_order_state"
        params = {"order_id": order_no}
        success, error = await self._send_message(method, params)
        return success, error

    async def get_open_orders(self):
        """ 获取未完全成交订单
        """
        method = "private/get_open_orders_by_instrument"
        params = {"instrument_name": self._symbol}
        success, error = await self._send_message(method, params)
        return success, error

    async def get_open_order_nos(self):
        """ 获取未完全成交订单号列表
        """
        method = "private/get_open_orders_by_instrument"
        params = {"instrument_name": self._symbol}
        success, error = await self._send_message(method, params)
        if error:
            return None, error
        else:
            order_nos = []
            for item in success:
                order_nos.append(item["order_id"])
            return order_nos, None

    async def _send_message(self, method, params):
        """ 发送消息
        """
        f = asyncio.futures.Future()
        request_id = await self._generate_query_id()
        self._queries[request_id] = f
        data = {
            "jsonrpc": "2.0",
            "id": request_id,
            "method": method,
            "params": params
        }
        await self.ws.send_json(data)
        logger.debug("send message:", data, caller=self)
        success, error = await f
        if error:
            logger.error("data:", data, "error:", error, caller=self)
        return success, error

    @async_method_locker("generate_query_id.locker")
    async def _generate_query_id(self):
        """ 生成query id,加锁,确保每个请求id唯一
        """
        self._query_id += 1
        return self._query_id

    @async_method_locker("process.locker")
    async def process(self, msg):
        """ 处理websocket消息
        """
        logger.debug("msg:", json.dumps(msg), caller=self)

        # 请求消息
        request_id = msg.get("id")
        if request_id:
            f = self._queries.pop(request_id)
            if f.done():
                return
            success = msg.get("result")
            error = msg.get("error")
            f.set_result((success, error))

        # 推送订阅消息
        if msg.get("method") == "subscription":
            if msg["params"]["channel"] == self._order_channel:
                order_info = msg["params"]["data"]
                order = self._update_order(order_info)
                if self._order_update_callback:
                    SingleTask.run(self._order_update_callback, copy.copy(order))

    async def _check_position_update(self, *args, **kwargs):
        """ 定时获取持仓
        """
        if not self._ok:
            return
        update = False
        success, error = await self.get_position()
        if error:
            return
        if not self._position.utime:  # 如果持仓还没有被初始化,那么初始化之后推送一次
            update = True
            self._position.update()
        size = int(success["size"])
        average_price = float(success["average_price"])
        liquid_price = float(success["estimated_liquidation_price"])
        if size > 0:
            if self._position.long_quantity != size:
                update = True
                self._position.update(0, 0, size, average_price, liquid_price)
        elif size < 0:
            if self._position.short_quantity != abs(size):
                update = True
                self._position.update(abs(size), average_price, 0, 0, liquid_price)
        elif size == 0:
            if self._position.long_quantity != 0 or self._position.short_quantity != 0:
                update = True
                self._position.update()
        if update:
            await self._position_update_callback(self._position)

    def _update_order(self, order_info):
        """ 更新订单信息
        @param order_info 订单信息
        """
        order_no = order_info["order_id"]
        quantity = int(order_info["amount"])
        filled_amount = int(order_info["filled_amount"])
        remain = quantity - filled_amount
        average_price = order_info.get("average_price")
        state = order_info["order_state"]
        if state == "open":
            status = ORDER_STATUS_SUBMITTED
            if filled_amount > 0:
                status = ORDER_STATUS_PARTIAL_FILLED
        elif state == "filled":
            status = ORDER_STATUS_FILLED
        elif state == "cancelled":
            status = ORDER_STATUS_CANCELED
        else:
            status = ORDER_STATUS_FAILED

        order = self._orders.get(order_no)
        if not order:
            action = ORDER_ACTION_BUY if order_info["direction"] == "buy" else ORDER_ACTION_SELL
            trade_type = int(order_info.get("label"))
            info = {
                "platform": self._platform,
                "account": self._account,
                "strategy": self._strategy,
                "symbol": self._symbol,
                "order_no": order_no,
                "action": action,
                "price": order_info["price"],
                "quantity": quantity,
                "remain": remain,
                "trade_type": trade_type
            }
            order = Order(**info)
            self._orders[order_no] = order
        order.status = status
        order.remain = remain
        order.avg_price = average_price
        order.ctime = order_info["creation_timestamp"]
        order.utime = order_info["last_update_timestamp"]
        if order.status in [ORDER_STATUS_FILLED, ORDER_STATUS_CANCELED, ORDER_STATUS_FAILED]:
            self._orders.pop(order.order_no)
        return order
Beispiel #12
0
class OKExSwapTrade(Websocket):
    """ OKEx Swap Trade module. You can initialize trade object with some attributes in kwargs.

    Attributes:
        account: Account name for this trade exchange.
        strategy: What's name would you want to created for you strategy.
        symbol: Symbol name for your trade.
        host: HTTP request host. (default "https://www.okex.com")
        wss: Websocket address. (default "wss://real.okex.com:10442")
        access_key: Account's ACCESS KEY.
        secret_key Account's SECRET KEY.
        passphrase API KEY Passphrase.
        init_success_callback: You can use this param to specific a async callback function when you initializing Trade
            object. `init_success_callback` is like `async def on_init_success_callback(success: bool, error: Error): pass`
            and this callback function will be executed asynchronous after Trade module object initialized successfully.
    """
    def __init__(self, **kwargs):
        """ 初始化
        """
        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:10442"
        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)
            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 = OKEX_SWAP
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        url = self._wss + "/ws/v3"
        super(OKExSwapTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._assets = {
        }  # Asset object. e.g. {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # Order objects. e.g. {"order_no": Order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # Subscribing our channels.
        self._order_channel = "swap/order:{symbol}".format(symbol=self._symbol)
        self._position_channel = "swap/position:{symbol}".format(
            symbol=self._symbol)

        # If our channels that subscribed successfully.
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        # Initializing our REST API client.
        self._rest_api = OKExSwapRestAPI(self._host, self._access_key,
                                         self._secret_key, self._passphrase)

        # Subscribing our asset event.
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        self.initialize()

    @property
    def assets(self):
        return copy.copy(self._assets)

    @property
    def orders(self):
        return copy.copy(self._orders)

    @property
    def position(self):
        return copy.copy(self._position)

    @property
    def rest_api(self):
        return self._rest_api

    async def connected_callback(self):
        """ After websocket connection created successfully, we will send a message to server for authentication.
        """
        timestamp = str(time.time()).split(".")[0] + "." + str(
            time.time()).split(".")[1][:3]
        message = str(timestamp) + "GET" + "/users/self/verify"
        mac = hmac.new(bytes(self._secret_key, encoding="utf8"),
                       bytes(message, encoding="utf8"),
                       digestmod="sha256")
        d = mac.digest()
        signature = base64.b64encode(d).decode()
        data = {
            "op": "login",
            "args": [self._access_key, self._passphrase, timestamp, signature]
        }
        await self.ws.send_json(data)

    @async_method_locker("process_binary.locker")
    async def process_binary(self, raw):
        """ Process binary message that receive from websocket.

        Args:
            raw Binary message receive from websocket.

        Returns:
            None.
        """
        decompress = zlib.decompressobj(-zlib.MAX_WBITS)
        msg = decompress.decompress(raw)
        msg += decompress.flush()
        msg = msg.decode()

        # Heartbeat message received.
        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)
                if self._init_success_callback:
                    SingleTask.run(self._init_success_callback, False, e)
                return
            logger.info("Websocket connection authorized successfully.",
                        caller=self)

            # Fetch orders from server. (open + partially filled)
            result, error = await self._rest_api.get_order_list(
                self._symbol, 6)
            if error:
                e = Error("get open orders error: {}".format(error))
                if self._init_success_callback:
                    SingleTask.run(self._init_success_callback, False, e)
                return
            for order_info in result["order_info"]:
                order = self._update_order(order_info)
                if self._order_update_callback:
                    SingleTask.run(self._order_update_callback, order)

            # Fetch positions from server.
            position, error = await self._rest_api.get_position(self._symbol)
            if error:
                e = Error("get position error: {}".format(error))
                if self._init_success_callback:
                    SingleTask.run(self._init_success_callback, False, e)
                return
            self._update_position(position)
            if self._position_update_callback:
                SingleTask.run(self._position_update_callback, self.position)

            # Subscribe order channel and position channel.
            data = {
                "op": "subscribe",
                "args": [self._order_channel, self._position_channel]
            }
            await self.ws.send_json(data)
            return

        # Subscribe response message received.
        if msg.get("event") == "subscribe":
            if msg.get("channel") == self._order_channel:
                self._subscribe_order_ok = True
            if msg.get("channel") == self._position_channel:
                self._subscribe_position_ok = True
            if self._subscribe_order_ok and self._subscribe_position_ok:
                if self._init_success_callback:
                    SingleTask.run(self._init_success_callback, True, None)
            return

        # Order update message received.
        if msg.get("table") == "swap/order":
            for data in msg["data"]:
                order = self._update_order(data)
                if order and self._order_update_callback:
                    SingleTask.run(self._order_update_callback, order)
            return

        # Position update message receive.
        if msg.get("table") == "swap/position":
            for data in msg["data"]:
                self._update_position(data)
                if self._position_update_callback:
                    SingleTask.run(self._position_update_callback,
                                   self.position)

    async def create_order(self,
                           action,
                           price,
                           quantity,
                           order_type=ORDER_TYPE_LIMIT,
                           match_price=0,
                           **kwargs):
        """ Create an order.

        Args:
            action: Trade direction, BUY or SELL.
            price: Price of each contract.
            quantity: The buying or selling quantity.
            order_type:
            match_price: Order at best counter party price? (0: no, 1: yes), When posting orders at best bid price,
                            order_type can only be 0 (regular order).
            order_type: Fill in number for parameter, 0: Normal limit order (Unfilled and 0 represent normal limit
                            order) 1: Post only, 2: Fill Or Kill, 3: Immediately Or Cancel.

        Returns:
            order_no: Order ID if created successfully, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        if int(quantity) > 0:
            if action == ORDER_ACTION_BUY:
                trade_type = "1"
            else:
                trade_type = "3"
        else:
            if action == ORDER_ACTION_BUY:
                trade_type = "4"
            else:
                trade_type = "2"
        quantity = abs(int(quantity))
        if order_type == ORDER_TYPE_LIMIT:
            order_type_2 = 0
        elif order_type == ORDER_TYPE_MARKET:
            order_type_2 = 2
        else:
            return None, "order type error"
        result, error = await self._rest_api.create_order(
            self._symbol, trade_type, price, quantity, match_price,
            order_type_2)
        if error:
            return None, error
        order_no = result["order_id"]
        return order_no, None

    async def revoke_order(self, *order_nos):
        """ Revoke (an) order(s).

        Args:
            order_nos: 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.
        """
        # If len(order_nos) == 0, you will cancel all orders for this symbol(initialized in Trade object).
        if len(order_nos) == 0:
            result, error = await self._rest_api.get_order_list(
                self._symbol, 6)
            if error:
                return False, error
            for order_info in result["order_info"]:
                order_no = order_info["order_id"]
                _, error = await self._rest_api.revoke_order(
                    self._symbol, order_no)
                if error:
                    return False, error
            return True, None

        # If len(order_nos) == 1, you will cancel an order.
        if len(order_nos) == 1:
            success, error = await self._rest_api.revoke_order(
                self._symbol, order_nos[0])
            if error:
                return order_nos[0], error
            else:
                return order_nos[0], None

        # If len(order_nos) > 1, you will cancel multiple orders.
        if len(order_nos) > 1:
            success, error = [], []
            for order_no in order_nos:
                _, e = await self._rest_api.revoke_order(
                    self._symbol, order_no)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

    async def get_open_order_nos(self):
        """ Get open order id list.

        Args:
            None.

        Returns:
            order_nos: Open order id list, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        success, error = await self._rest_api.get_order_list(self._symbol, 6)
        if error:
            return None, error
        else:
            order_nos = []
            for order_info in success["order_info"]:
                order_nos.append(order_info["order_id"])
            return order_nos, None

    def _update_order(self, order_info):
        """ Order update.

        Args:
            order_info: Order information.

        Returns:
            Return order object if or None.
        """
        order_no = str(order_info["order_id"])
        state = order_info["state"]
        remain = int(order_info["size"]) - int(order_info["filled_qty"])
        ctime = tools.utctime_str_to_mts(order_info["timestamp"])
        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:
            return None

        order = self._orders.get(order_no)
        if not order:
            info = {
                "platform":
                self._platform,
                "account":
                self._account,
                "strategy":
                self._strategy,
                "order_no":
                order_no,
                "action":
                ORDER_ACTION_BUY
                if order_info["type"] in ["1", "4"] else ORDER_ACTION_SELL,
                "symbol":
                self._symbol,
                "price":
                order_info["price"],
                "quantity":
                order_info["size"],
                "trade_type":
                int(order_info["type"])
            }
            order = Order(**info)
        order.remain = remain
        order.status = status
        order.avg_price = order_info["price_avg"]
        order.ctime = ctime
        order.utime = ctime
        self._orders[order_no] = order
        if state in ["-1", "2"]:
            self._orders.pop(order_no)
        return order

    def _update_position(self, position_info):
        """ Position update.

        Args:
            position_info: Position information.

        Returns:
            None.
        """
        if len(
                position_info["holding"]
        ) == 0:  # When the length of `holding` is 0, specific all the position is closed
            self._position.update(0, 0, 0, 0, 0)
            return
        for item in position_info["holding"]:
            if item["side"] == "long":
                self._position.liquid_price = item["liquidation_price"]
                self._position.long_quantity = int(item["position"])
                self._position.long_avg_price = item["avg_cost"]
            elif item["side"] == "short":
                self._position.short_quantity = int(item["position"])
                self._position.short_avg_price = item["avg_cost"]
            else:
                continue
            self._position.utime = tools.utctime_str_to_mts(item["timestamp"])

    async def on_event_asset_update(self, asset: Asset):
        """ Asset event data callback.

        Args:
            asset: Asset object callback from EventCenter.

        Returns:
            None.
        """
        self._assets = asset
        SingleTask.run(self._asset_update_callback, asset)
Beispiel #13
0
    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://fapi.binance.com"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://fstream.binance.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 = BINANCE_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        self._ok = False  # Initialize successfully ?

        self._raw_symbol = self._symbol  # 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_no: order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # Initialize our REST API client.
        self._rest_api = BinanceFutureRestAPI(self._host, self._access_key,
                                              self._secret_key)

        # Subscribe our AssetEvent.
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # Create a loop run task to reset listen key every 20 minutes.
        LoopRunTask.register(self._reset_listen_key, 60 * 20)

        # Create a loop run task to check position information per 1 second.
        LoopRunTask.register(self._check_position_update, 1)

        # Create a loop run task to send ping message to server per 30 seconds.
        # LoopRunTask.register(self._send_heartbeat_msg, 10)

        # Create a coroutine to initialize Websocket connection.
        SingleTask.run(self._init_websocket)
Beispiel #14
0
    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)
            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 = OKEX_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        url = self._wss + "/ws/v3"
        super(OKExFutureTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._assets = {
        }  # Asset object. e.g. {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # Order objects. e.g. {"order_no": Order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)

        # Subscribing our channels.
        self._order_channel = "futures/order:{symbol}".format(
            symbol=self._symbol)
        self._position_channel = "futures/position:{symbol}".format(
            symbol=self._symbol)

        # If our channels that subscribed successfully.
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        # Initializing our REST API client.
        self._rest_api = OKExFutureRestAPI(self._host, self._access_key,
                                           self._secret_key, self._passphrase)

        # Subscribing our asset event.
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        self.initialize()
class FCoinFutureTrade:
    """ FCOIN Future Trade module
        """
    def __init__(self, **kwargs):
        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.testnet.fmex.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 = FCOIN_FUTURE
        self._symbol = kwargs["symbol"]
        self._host = kwargs["host"]
        self._access_key = kwargs["access_key"]
        self._secret_key = kwargs["secret_key"]
        self._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")
        self._update_order_interval = kwargs.get("update_order_interval", 1)

        self._assets = {
        }  # 资产 {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # 标记订阅订单、持仓是否成功
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        # 初始化 REST API 对象
        self._rest_api = FCoinFutureRestAPI(self._host, self._access_key,
                                            self._secret_key)

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # 注册定时任务,定时查询订单更新、仓位更新情况
        if self._position_update_callback:
            LoopRunTask.register(self._check_position_update, 60)

        # 初始化订单订阅
        if self._order_update_callback:
            LoopRunTask.register(self.check_order_update,
                                 self._update_order_interval)

    async def on_event_asset_update(self, asset: Asset):
        """ 资产数据更新回调
        """
        self._assets = asset
        SingleTask.run(self._asset_update_callback, asset)

    @property
    def assets(self):
        return copy.copy(self._assets)

    @property
    def orders(self):
        return copy.copy(self._orders)

    @property
    def position(self):
        return copy.copy(self._position)

    async def create_order(self,
                           action,
                           price,
                           quantity,
                           order_type=ORDER_TYPE_LIMIT):
        """ 创建订单
        @param action 交易方向 BUY/SELL
        @param price 委托价格
        @param quantity 委托数量(可以是正数,也可以是复数)
        @param order_type 委托类型 limit/market
        """
        if int(quantity) > 0:
            if action == ORDER_ACTION_BUY:
                trade_type = "1"
            else:
                trade_type = "3"
        else:
            if action == ORDER_ACTION_BUY:
                trade_type = "4"
            else:
                trade_type = "2"
        quantity = abs(int(quantity))
        result, error = await self._rest_api.create_order(
            self._symbol, trade_type, price, quantity)
        if error:
            return None, error
        return result['data']["id"], None

    async def revoke_order(self, *order_nos):
        """ 撤销订单
            @param order_nos 订单号,可传入任意多个,如果不传入,那么就撤销所有订单
            * NOTE: 单次调用最多只能撤销100个订单,如果订单超过100个,请多次调用
        """
        # 如果传入order_nos为空,即撤销全部委托单
        if len(order_nos) == 0:
            result, error = self._rest_api.get_open_order_list()
            if error:
                return False, error
            success, error = [], []
            for order_info in result['data']['results']:
                order_no = order_info['id']
                _, e = await self._rest_api.revoke_order(order_no)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

        # 如果传入order_nos为一个委托单号,那么只撤销一个委托单
        if len(order_nos) == 1:
            success, error = await self._rest_api.revoke_order(order_nos[0])
            if error:
                return order_nos[0], error
            else:
                return order_nos[0], None

        # 如果传入order_nos数量大于1,那么就批量撤销传入的委托单
        if len(order_nos) > 1:
            success, error = [], []
            for order_no in order_nos:
                _, e = await self._rest_api.revoke_order(order_no)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

    async def get_open_order_info(self, order_no):
        """查询活动订单详情"""
        result, error = await self._rest_api.get_open_order_info(order_no)

        if error:
            return None, error
        else:
            for data in result['data']['results']:
                if data['id'] == order_no:
                    logger.info(data)
                    is_update, order = self._update_order(data)
                    if is_update and self._order_update_callback:
                        SingleTask.run(self._order_update_callback,
                                       copy.copy(order))
                    return copy.copy(order), None

    async def get_open_order_nos(self):
        """ 获取未完全成交订单号列表
        """
        success, error = await self._rest_api.get_open_order_list()
        if error:
            return None, error
        else:
            order_nos = []
            for order_info in success['data']['results']:
                order_nos.append(order_info['id'])
            return order_nos, None

    @async_method_locker('check_order_update', False)
    async def check_order_update(self):
        """定时查询订单信息"""
        open_result, error = await self._rest_api.get_open_order_list()
        closed_result, error = await self._rest_api.get_closed_order_list(
            self._symbol)

        orders = list()
        # 查询所有未完成订单
        if open_result:
            open_orders = open_result['data']['results']
            orders += open_orders

        # 查询所有已关闭订单
        if closed_result:
            close_orders = open_result['data']['results']
            orders += close_orders

        if len(orders) != 0:
            for order_info in copy.copy(orders):
                is_update, order = await self._update_order(order_info)
                if is_update:
                    if self._order_update_callback:
                        SingleTask.run(self._order_update_callback,
                                       copy.copy(order))

    async def _update_order(self, order_info):
        """
        更新订单信息
        """
        order_no = order_info.get('id')
        is_updated = False
        if order_no is None:
            return is_updated, None
        remain = order_info['unfilled_quantity']
        quantity = order_info['quantity']
        state = order_info['status']
        ctime = order_info['created_at']
        utime = order_info['utime']
        if state == 'FULLY_FILLED':
            status = ORDER_STATUS_FAILED
        elif state == 'PARTIAL_FILLED':
            status = ORDER_STATUS_PARTIAL_FILLED
        elif state == 'PENDING':
            status = ORDER_STATUS_SUBMITTED
        elif state == 'PARTIAL_CANCELLED':
            status = ORDER_STATUS_PARTIAL_CANCELED
        elif state == 'FULLY_CANCELLED':
            status = ORDER_STATUS_CANCELED
        else:
            logger.error('订单状态未处理', order_info)
            return is_updated, None

        order = self._orders.get(order_no)
        if not order:
            info = {
                "platform":
                self._platform,
                "account":
                self._account,
                "strategy":
                self._strategy,
                "order_no":
                order_no,
                "action":
                ORDER_ACTION_BUY
                if order_info["direction"] == 'LONG' else ORDER_ACTION_SELL,
                "symbol":
                self._symbol,
                "price":
                order_info["price"],
                "quantity":
                quantity,
                "trade_type":
                TRADE_TYPE_NONE,
                'remain':
                remain,
                'status':
                status
            }
            order = Order(**info)
            is_updated = True
        else:
            if order.remain != remain:
                is_updated = True
                order.remain = remain
            elif order.status != status:
                is_updated = True
                order.status = status
        order.ctime = ctime
        order.utime = utime
        self._orders[order_no] = order
        if state in ('FULLY_FILLED', 'PARTIAL_CANCELLED', 'FULLY_CANCELLED'):
            self._orders.pop(order_no)
        return is_updated, order

    async def _check_position_update(self):
        """更新持仓信息"""
        positions, error = await self._rest_api.get_position_list()
        if error:
            logger.error("get position error: {}".format(error))
            return

        for position_info in positions['data']['results']:
            if position_info['symbol'] == self._symbol:
                update = False
                if not self._position.utime:  # 如果持仓还没有被初始化,那么初始化之后推送一次
                    update = True
                    self._position.update()
                size = position_info['quantity']
                average_price = position_info['entry_price']
                liquid_price = position_info['liquidation_price']
                direction = position_info['direction']
                if direction == 'SHORT':
                    if self._position.short_quantity != size:
                        update = True
                        self._position.update(size, average_price, 0, 0,
                                              liquid_price)
                else:
                    if self._position.long_quantity != size:
                        update = True
                        self._position.update(0, 0, size, average_price,
                                              liquid_price)
                if update and self._position_update_callback:
                    SingleTask.run(self._position_update_callback,
                                   copy.copy(self._position))
Beispiel #16
0
    async def get_position(self, symbol):
        """ 获取当前持仓

        Args:
            symbol: Trade target

        Returns:
            position: Position if successfully, otherwise it's None.
            error: Error information, otherwise it's None.
        """

        #{"result": [{"collateralUsed": 0.35986, "cost": -1.7984, "entryPrice": 179.84, "estimatedLiquidationPrice": 11184.0123266, "future": "ETH-PERP", "initialMarginRequirement": 0.2, "longOrderSize": 0.0, "maintenanceMarginRequirement": 0.03, "netSize": -0.01, "openSize": 0.01, "realizedPnl": 0.01866927, "recentAverageOpenPrice": 179.84, "recentPnl": -0.0009, "shortOrderSize": 0.0, "side": "sell", "size": 0.01, "unrealizedPnl": -0.0009}], "success": true}
        success, error = await self._rest_api.get_positions(True)
        if error:
            return None, error
        if not success["success"]:
            return None, "get_position error"

        p = next(filter(lambda x: x['future'] == symbol, success["result"]),
                 None)
        if p == None:
            return Position(self._platform, self._account, self._strategy,
                            symbol), None

        if p["netSize"] == 0:
            return Position(self._platform, self._account, self._strategy,
                            symbol), None

        pos = Position(self._platform, self._account, self._strategy, symbol)
        pos.margin_mode = MARGIN_MODE_CROSSED  #ftx只有全仓模式,如果想要逐仓模式的话就用子账户的方式来实现
        pos.utime = tools.get_cur_timestamp_ms()
        if p["netSize"] < 0:  #空头仓位
            pos.long_quantity = 0
            pos.long_avail_qty = 0
            pos.long_open_price = 0
            pos.long_hold_price = 0
            pos.long_liquid_price = 0
            pos.long_unrealised_pnl = 0
            pos.long_leverage = 0
            pos.long_margin = 0
            #
            pos.short_quantity = abs(p["netSize"])
            pos.short_avail_qty = pos.short_quantity - p["longOrderSize"] if p[
                "longOrderSize"] < pos.short_quantity else 0
            pos.short_open_price = p["recentAverageOpenPrice"]
            pos.short_hold_price = p["entryPrice"]
            pos.short_liquid_price = p["estimatedLiquidationPrice"]
            pos.short_unrealised_pnl = p["unrealizedPnl"]
            pos.short_leverage = int(1 / p["initialMarginRequirement"])
            pos.short_margin = p["collateralUsed"]
        else:  #多头仓位
            pos.long_quantity = abs(p["netSize"])
            pos.long_avail_qty = pos.long_quantity - p["shortOrderSize"] if p[
                "shortOrderSize"] < pos.long_quantity else 0
            pos.long_open_price = p["recentAverageOpenPrice"]
            pos.long_hold_price = p["entryPrice"]
            pos.long_liquid_price = p["estimatedLiquidationPrice"]
            pos.long_unrealised_pnl = p["unrealizedPnl"]
            pos.long_leverage = int(1 / p["initialMarginRequirement"])
            pos.long_margin = p["collateralUsed"]
            #
            pos.short_quantity = 0
            pos.short_avail_qty = 0
            pos.short_open_price = 0
            pos.short_hold_price = 0
            pos.short_liquid_price = 0
            pos.short_unrealised_pnl = 0
            pos.short_leverage = 0
            pos.short_margin = 0

        return pos, None
Beispiel #17
0
 def parse(self):
     """ Parse self._data to Order object.
     """
     position = Position(**self.data)
     return position
Beispiel #18
0
class BinanceFutureTrade:
    """ Binance Future Trade module. You can initialize trade object with some attributes in kwargs.

    Attributes:
        account: Account name for this trade exchange.
        strategy: What's name would you want to created for you strategy.
        symbol: Symbol name for your trade.
        host: HTTP request host. (default "https://fapi.binance.com")
        wss: Websocket address. (default "wss://fstream.binance.com")
        access_key: Account's ACCESS KEY.
        secret_key Account's SECRET KEY.
        asset_update_callback: You can use this param to specific a async callback function when you initializing Trade
            object. `asset_update_callback` is like `async def on_asset_update_callback(asset: Asset): pass` and this
            callback function will be executed asynchronous when received AssetEvent.
        order_update_callback: You can use this param to specific a async callback function when you initializing Trade
            object. `order_update_callback` is like `async def on_order_update_callback(order: Order): pass` and this
            callback function will be executed asynchronous when some order state updated.
        init_success_callback: You can use this param to specific a async callback function when you initializing Trade
            object. `init_success_callback` is like `async def on_init_success_callback(success: bool, error: Error, **kwargs): pass`
            and this callback function will be executed asynchronous after Trade module object initialized successfully.
    """
    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://fapi.binance.com"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://fstream.binance.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 = BINANCE_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        self._ok = False  # Initialize successfully ?

        self._raw_symbol = self._symbol  # 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_no: order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # Initialize our REST API client.
        self._rest_api = BinanceFutureRestAPI(self._host, self._access_key,
                                              self._secret_key)

        # Subscribe our AssetEvent.
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # Create a loop run task to reset listen key every 20 minutes.
        LoopRunTask.register(self._reset_listen_key, 60 * 20)

        # Create a loop run task to check position information per 1 second.
        LoopRunTask.register(self._check_position_update, 1)

        # Create a loop run task to send ping message to server per 30 seconds.
        # LoopRunTask.register(self._send_heartbeat_msg, 10)

        # Create a coroutine to initialize Websocket connection.
        SingleTask.run(self._init_websocket)

    @property
    def assets(self):
        return copy.copy(self._assets)

    @property
    def orders(self):
        return copy.copy(self._orders)

    @property
    def rest_api(self):
        return self._rest_api

    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._init_success_callback, False, e)
            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)
        self._ws.initialize()

    async def _reset_listen_key(self, *args, **kwargs):
        """ Reset listen key.
        """
        if not self._listen_key:
            logger.error("listen key not initialized!", caller=self)
            return
        await self._rest_api.put_listen_key(self._listen_key)
        logger.info("reset listen key success!", caller=self)

    # async def _send_heartbeat_msg(self, *args, **kwargs):
    #     """Send ping to server."""
    #     hb = {"ping": tools.get_cur_timestamp_ms()}
    #     await self._ws.send(hb)

    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._init_success_callback, False, e)
            return
        for order_info in order_infos:
            order_no = "{}_{}".format(order_info["orderId"],
                                      order_info["clientOrderId"])
            if order_info["status"] == "NEW":
                status = ORDER_STATUS_SUBMITTED
            elif order_info["status"] == "PARTIAL_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)
                continue

            info = {
                "platform":
                self._platform,
                "account":
                self._account,
                "strategy":
                self._strategy,
                "order_no":
                order_no,
                "action":
                order_info["side"],
                "order_type":
                order_info["type"],
                "symbol":
                self._symbol,
                "price":
                order_info["price"],
                "quantity":
                order_info["origQty"],
                "remain":
                float(order_info["origQty"]) -
                float(order_info["executedQty"]),
                "status":
                status,
                "trade_type":
                int(order_info["clientOrderId"][-1]),
                "ctime":
                order_info["updateTime"],
                "utime":
                order_info["updateTime"]
            }
            order = Order(**info)
            self._orders[order_no] = order
            SingleTask.run(self._order_update_callback, copy.copy(order))

        self._ok = True
        SingleTask.run(self._init_success_callback, True, 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 contract.
            quantity: The buying or selling quantity.

        Returns:
            order_no: Order ID if created successfully, otherwise it's None.
            error: Error information, otherwise it's None.
        """
        if float(quantity) > 0:
            if action == ORDER_ACTION_BUY:
                trade_type = TRADE_TYPE_BUY_OPEN
            else:
                trade_type = TRADE_TYPE_SELL_CLOSE
        else:
            if action == ORDER_ACTION_BUY:
                trade_type = TRADE_TYPE_BUY_CLOSE
            else:
                trade_type = TRADE_TYPE_SELL_OPEN
        quantity = abs(float(quantity))
        price = tools.float_to_str(price)
        quantity = tools.float_to_str(quantity)
        client_order_id = tools.get_uuid1().replace("-",
                                                    "")[:21] + str(trade_type)
        result, error = await self._rest_api.create_order(
            action, self._raw_symbol, price, quantity, client_order_id)
        if error:
            return None, error
        order_no = "{}_{}".format(result["orderId"], result["clientOrderId"])
        return order_no, None

    async def revoke_order(self, *order_nos):
        """ Revoke (an) order(s).

        Args:
            order_nos: 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.
        """
        # If len(order_nos) == 0, you will cancel all orders for this symbol(initialized in Trade object).
        if len(order_nos) == 0:
            order_infos, error = await self._rest_api.get_open_orders(
                self._raw_symbol)
            if error:
                return False, error
            for order_info in order_infos:
                _, error = await self._rest_api.revoke_order(
                    self._raw_symbol, order_info["orderId"],
                    order_info["clientOrderId"])
                if error:
                    return False, error
            return True, None

        # If len(order_nos) == 1, you will cancel an order.
        if len(order_nos) == 1:
            order_id, client_order_id = order_nos[0].split("_")
            success, error = await self._rest_api.revoke_order(
                self._raw_symbol, order_id, client_order_id)
            if error:
                return order_nos[0], error
            else:
                return order_nos[0], None

        # If len(order_nos) > 1, you will cancel multiple orders.
        if len(order_nos) > 1:
            success, error = [], []
            for order_no in order_nos:
                order_id, client_order_id = order_no.split("_")
                _, e = await self._rest_api.revoke_order(
                    self._raw_symbol, order_id, client_order_id)
                if e:
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

    async def get_open_order_nos(self):
        """ Get open order no list.
        """
        success, error = await self._rest_api.get_open_orders(self._raw_symbol)
        if error:
            return None, error
        order_nos = []
        for order_info in success:
            order_no = "{}_{}".format(order_info["orderId"],
                                      order_info["clientOrderId"])
            order_nos.append(order_no)
        return order_nos, None

    @async_method_locker("BinanceTrade.process.locker")
    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 == "ORDER_TRADE_UPDATE":  # Order update.
            self._update_order(msg["o"])

    async def _check_position_update(self, *args, **kwargs):
        """Check position update."""
        if not self._ok:
            return
        update = False
        success, error = await self._rest_api.get_position()
        if error:
            return

        position_info = None
        for item in success:
            if item["symbol"] == self._raw_symbol:
                position_info = item
                break

        if not self._position.utime:  # Callback position info when initialized.
            update = True
            self._position.update()
        size = float(position_info["positionAmt"])
        average_price = float(position_info["entryPrice"])
        if size > 0:
            if self._position.long_quantity != size:
                update = True
                self._position.update(0, 0, size, average_price, 0)
        elif size < 0:
            if self._position.short_quantity != abs(size):
                update = True
                self._position.update(abs(size), average_price, 0, 0, 0)
        elif size == 0:
            if self._position.long_quantity != 0 or self._position.short_quantity != 0:
                update = True
                self._position.update()
        if update:
            await self._position_update_callback(copy.copy(self._position))

    def _update_order(self, order_info):
        """ Order update.

        Args:
            order_info: Order information.

        Returns:
            Return order object if or None.
        """
        if order_info["s"] != self._raw_symbol:
            return
        order_no = "{}_{}".format(order_info["i"], order_info["c"])

        if order_info["X"] == "NEW":
            status = ORDER_STATUS_SUBMITTED
        elif order_info["X"] == "PARTIAL_FILLED":
            status = ORDER_STATUS_PARTIAL_FILLED
        elif order_info["X"] == "FILLED":
            status = ORDER_STATUS_FILLED
        elif order_info["X"] == "CANCELED":
            status = ORDER_STATUS_CANCELED
        elif order_info["X"] == "REJECTED":
            status = ORDER_STATUS_FAILED
        elif order_info["X"] == "EXPIRED":
            status = ORDER_STATUS_FAILED
        else:
            return
        order = self._orders.get(order_no)
        if not order:
            info = {
                "platform": self._platform,
                "account": self._account,
                "strategy": self._strategy,
                "order_no": order_no,
                "action": order_info["S"],
                "order_type": order_info["o"],
                "symbol": self._symbol,
                "price": order_info["p"],
                "quantity": order_info["q"],
                "ctime": order_info["T"]
            }
            order = Order(**info)
            self._orders[order_no] = order
        order.remain = float(order_info["q"]) - float(order_info["z"])
        order.avg_price = order_info["L"]
        order.status = status
        order.utime = order_info["T"]
        order.trade_type = int(order_no[-1])
        SingleTask.run(self._order_update_callback, copy.copy(order))

    async def on_event_asset_update(self, asset: Asset):
        """ Asset data update callback.

        Args:
            asset: Asset object.
        """
        self._assets = asset
        SingleTask.run(self._asset_update_callback, asset)
Beispiel #19
0
    def __init__(self, **kwargs):
        """ 初始化
        """
        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:10442"
        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)
            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 = OKEX_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")

        url = self._wss + "/ws/v3"
        super(OKExFutureTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._orders = {}  # 订单
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)  # 仓位

        # 订阅频道
        # ch_account = "futures/account:BTC"
        self._order_channel = "futures/order:{symbol}".format(
            symbol=self._symbol)
        self._position_channel = "futures/position:{symbol}".format(
            symbol=self._symbol)

        # 标记订阅订单、持仓是否成功
        self._subscribe_order_ok = False
        self._subscribe_position_ok = False

        # 初始化 REST API 对象
        self._rest_api = OKExFutureRestAPI(self._host, self._access_key,
                                           self._secret_key, self._passphrase)

        self.initialize()
Beispiel #20
0
class GateFutureTrade(Websocket):
    """
    OKEX Future Trade module
    """
    def __init__(self, **kwargs):
        """ 初始化
        """
        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.gateio.ws"
        if not kwargs.get("wss"):
            kwargs["wss"] = "wss://fx-ws.gateio.ws"
        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 = GATE_FUTURE
        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._asset_update_callback = kwargs.get("asset_update_callback")
        self._order_update_callback = kwargs.get("order_update_callback")
        self._position_update_callback = kwargs.get("position_update_callback")
        self._init_success_callback = kwargs.get("init_success_callback")
        self._contract_update_callback = kwargs.get('contract_update_callback')
        self._user_id = None

        url = self._wss + "/v4/ws"
        super(GateFutureTrade, self).__init__(url, send_hb_interval=5)
        self.heartbeat_msg = "ping"

        self._assets = {
        }  # 资产 {"BTC": {"free": "1.1", "locked": "2.2", "total": "3.3"}, ... }
        self._orders = {}  # 订单 {"order_no": order, ... }
        self._position = Position(self._platform, self._account,
                                  self._strategy, self._symbol)

        # 初始化 REST API 对象
        self._rest_api = GateFutureRestAPI(self._host, self._access_key,
                                           self._secret_key)

        # 初始化资产订阅
        if self._asset_update_callback:
            AssetSubscribe(self._platform, self._account,
                           self.on_event_asset_update)

        # 注册定时任务
        LoopRunTask.register(self._check_position_update, 1)  # 获取持仓

    async def on_event_asset_update(self, asset: Asset):
        """ 资产数据更新回调
        """
        self._assets = asset
        SingleTask.run(self._asset_update_callback, asset)

    @property
    def assets(self):
        return copy.copy(self._assets)

    @property
    def orders(self):
        return copy.copy(self._orders)

    @property
    def rest_api(self):
        return self._rest_api

    @property
    def position(self):
        return copy.copy(self._position)

    async def _check_position_update(self):
        update = False
        success, error = await self._rest_api.get_position(self._symbol)
        if error:
            return
        if not self._position.utime:  # 如果持仓还没有被初始化,那么初始化之后推送一次
            update = True
            self._position.update()
        size = success['size']
        average_price = float(success['entry_price'])
        liquid_price = float(success["liq_price"])
        if size > 0:
            if self._position.long_quantity != size:
                update = True
                self._position.update(0, 0, size, average_price, liquid_price)
        elif size < 0:
            if self._position.short_quantity != abs(size):
                update = True
                self._position.update(abs(size), average_price, 0, 0,
                                      liquid_price)
        elif size == 0:
            if self._position.long_quantity != 0 or self._position.short_quantity != 0:
                update = True
                self._position.update()
        if update:
            await self._position_update_callback(copy.copy(self._position))

    async def connected_callback(self):
        """ 建立连接之后,然后订阅order和position
        """
        # 订阅order

        while True:
            success, error = await self._rest_api.get_user_account()
            if success:
                self._user_id = success['user']
                break
        t = int(time.time())
        order_message = 'channel=%s&event=%s&time=%s' % ('futures.orders',
                                                         'subscribe', t)
        sign = hmac.new(self._secret_key, order_message,
                        hashlib.sha512).hexdigest()

        data = {
            'time': t,
            'channel': "futures.orders",
            "event": "subscribe",
            "payload": [self._user_id, self._symbol],
            "auth": {
                "method": "api_key",
                "KEY": self._access_key,
                "SIGN": sign
            }
        }
        await self.ws.send_json(data)

        # 获取持仓
        await self._check_position_update()

        # # 订阅仓位
        # positon_message = 'channel=%s&event=%s&time=%s' % ('futures.position_closes', 'subscribe', t)
        # sign = hmac.new(self._secret_key, positon_message, hashlib.sha512).hexdigest()
        # data = {
        #     'time': t,
        #     'channel': "futures.position_closes",
        #     "event": "subscribe",
        #     "payload": [self._user_id, self._symbol],
        #     "auth": {
        #         "method": "api_key",
        #         "KEY": self._access_key,
        #         "SIGN": sign
        #     }
        # }
        # await self.ws.send_json(data)

    @async_method_locker('process.locker')
    async def process(self, msg):
        channel = msg['channel']
        event = msg['event']
        result = msg['result']
        if channel == "futures.orders":
            # 订单订阅返回消息
            if event == "subscribe":
                error = msg['error']
                if error:
                    if self._init_success_callback:
                        e = Error(
                            "subscribe order event error: {}".format(error))
                        SingleTask.run(self._init_success_callback, False, e)
                else:
                    # 获取之前未完成的订单信息并推送
                    result, error = await self._rest_api.get_order_list(
                        self._symbol, open)
                    if error:
                        e = Error("get open orders error: {}".format(error))
                        if self._init_success_callback:
                            SingleTask.run(self._init_success_callback, False,
                                           e)
                        return
                    for order_info in result:
                        is_update, order = self._update_order(order_info)
                        if is_update:
                            if self._order_update_callback:
                                SingleTask.run(self._order_update_callback,
                                               copy.copy(order))

            # 订单更新推送
            else:
                for data in result:
                    is_update, order = self._update_order(data)
                    if is_update:
                        if order and self._order_update_callback:
                            SingleTask.run(self._order_update_callback,
                                           copy.copy(order))
                return

        else:
            logger.warn("unhandle msg:", msg, caller=self)

        # elif channel == 'futures.position_closes':
        #     # 仓位订阅返回消息
        #     if event == "subscribe":
        #         error = msg['error']
        #         if error:
        #             if self._init_success_callback:
        #                 e = Error("subscribe position event error: {}".format(error))
        #                 SingleTask.run(self._init_success_callback, False, e)

    async def create_order(self,
                           action,
                           price,
                           quantity,
                           order_type=ORDER_TYPE_LIMIT):
        """

        :param action: 交易方向 BUY/SELL
        :param price: 价格,数字,如果等于0表示是市价单
        :param quantity: 委托数量(可以是正数,也可以是负数)
        :param order_type:ORDER_TYPE_LIMIT/ORDER_TYPE_MARKET
        :return:
        """
        if int(quantity) > 0:
            if action == ORDER_ACTION_BUY:
                trade_type = "1"
            else:
                trade_type = "3"
        else:
            if action == ORDER_ACTION_BUY:
                trade_type = "4"
            else:
                trade_type = "2"
        result, error = self._rest_api.create_order(self._symbol,
                                                    trade_type,
                                                    price,
                                                    quantity,
                                                    order_type=order_type)
        if error:
            return None, error
        return result['id'], None

    async def revoker_order(self, *order_nos):
        # 如果传入order_nos为空,即撤销全部委托单
        if len(order_nos) == 0:
            result, error = await self._rest_api.revoke_orders(self._symbol,
                                                               side=None)
            if error:
                return False, error
            return True, None

        # 如果传入order_nos为一个委托单号,那么只撤销一个委托单
        elif len(order_nos) == 1:
            success, error = await self._rest_api.revoke_order(order_nos[0])
            if error:
                # 如果撤销失败,查询订单详情
                # if error.get('label', '') == 'ORDER_FINISHED':
                #     await self.get_order_info(order_nos[0])
                return order_nos[0], error
            else:
                return order_nos[0], None

        # 如果传入order_nos数量大于1,那么就批量撤销传入的委托单
        elif len(order_nos) > 1:
            success, error = [], []
            for order_no in order_nos:
                _, e = await self._rest_api.revoke_order(order_no)
                if e:
                    # if e.get('label') == 'ORDER_FINISHED':
                    #     await self.get_order_info(order_nos[0])
                    error.append((order_no, e))
                else:
                    success.append(order_no)
            return success, error

    async def get_order_info(self, order_no):
        order_info, error = await self._rest_api.get_order_info(order_no)
        if error:
            return None, error
        else:
            logger.info(order_info)
            is_update, order = await self._update_order(order_info)
            if is_update:
                if self._order_update_callback:
                    SingleTask.run(self._order_update_callback,
                                   copy.copy(order))
            return copy.copy(order), None

    async def _update_order(self, order_info):
        """
        更新订单信息
        :param order_info: 订单信息
        :return:
        """
        order_no = order_info.get('id')
        is_updated = False
        if order_no is None:
            return is_updated, None
        remain = order_info['left']
        quantity = order_info['size']
        finish_as = order_info['finish_as']
        state = order_info['status']
        ctime = order_info['create_tim']
        if state == 'finished':
            if finish_as == 'filled' or finish_as == 'ioc' or finish_as == 'auto_deleveraged':
                status = ORDER_STATUS_FILLED
            elif finish_as == 'cancelled' or finish_as == 'liquidated' or finish_as == 'reduce_only':
                status = ORDER_STATUS_CANCELED
            else:
                logger.error("status error! order_info:",
                             order_info,
                             caller=self)
                return None
        elif state == 'open':
            if quantity != remain:
                if remain != 0:
                    status = ORDER_STATUS_PARTIAL_FILLED
                else:
                    status = ORDER_STATUS_FILLED
            else:
                status = ORDER_STATUS_SUBMITTED
        else:
            logger.error("status error! order_info:", order_info, caller=self)
            return None

        order = self._orders.get(order_no)
        if order:
            if order.remain != remain:
                is_updated = True
                order.remain = remain
            elif order.status != status:
                is_updated = True
                order.status = status
            elif order.avg_price != order_info['fill_price']:
                is_updated = True
                order.price = order_info["price"]
        else:
            info = {
                "platform": self._platform,
                "account": self._account,
                "strategy": self._strategy,
                "order_no": order_no,
                "action": ORDER_ACTION_BUY
                if order_info["size"] > 0 else ORDER_ACTION_SELL,
                "symbol": self._symbol,
                "price": float(order_info["price"]),
                "quantity": abs(quantity),
                "trade_type": int(order_info["text"].split('-')[1]),
                "remain": abs(remain),
                "status": status,
                "avg_price": order_info["fill_price"]
            }
            order = Order(**info)
            self._orders[order_no] = order
            is_updated = True
        order.ctime = ctime
        order.utime = int(time.time())
        if status in [ORDER_STATUS_CANCELED, ORDER_STATUS_FILLED]:
            self._orders.pop(order_no)
        return is_updated, order