[Add] 将OkexFutureRestClient做成独立的API分离出来
This commit is contained in:
parent
b34dcf6a73
commit
f5755b222a
337
vnpy/api/okexfuture/OkexFutureApi.py
Normal file
337
vnpy/api/okexfuture/OkexFutureApi.py
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
from enum import Enum
|
||||||
|
from typing import Any, Callable, List, Union
|
||||||
|
|
||||||
|
from vnpy.api.okexfuture.vnokexFuture import OkexFutureRestBase
|
||||||
|
from vnpy.network.RestClient import Request
|
||||||
|
|
||||||
|
|
||||||
|
class _OkexFutureCustomExtra(object):
|
||||||
|
|
||||||
|
def __init__(self, onSuccess, onFailed, extra):
|
||||||
|
self.onFailed = onFailed
|
||||||
|
self.onSuccess = onSuccess
|
||||||
|
self.extra = extra
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFuturePriceType(Enum):
|
||||||
|
Buy = 'buy'
|
||||||
|
Sell = 'sell'
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFutureContractType(Enum):
|
||||||
|
ThisWeek = 'this_week'
|
||||||
|
NextWeek = 'next_week'
|
||||||
|
Quarter = 'quarter'
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFutureStatus(Enum):
|
||||||
|
NoTraded = '0'
|
||||||
|
PartialTraded = '1'
|
||||||
|
AllTraded = '2'
|
||||||
|
Canceled = '-1'
|
||||||
|
CancelProcessing = '4'
|
||||||
|
Canceling = '5'
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFutureOrderType(Enum):
|
||||||
|
OpenLong = '1'
|
||||||
|
OpenShort = '2'
|
||||||
|
CloseLong = '3'
|
||||||
|
CloseShort = '4'
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFutureOrder(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.symbol = None
|
||||||
|
self.volume = None
|
||||||
|
self.price = None
|
||||||
|
self.priceAvg = None
|
||||||
|
self.status = None
|
||||||
|
self.orderType = None
|
||||||
|
self.unitAmount = None
|
||||||
|
self.leverRate = None
|
||||||
|
self.remoteId = None
|
||||||
|
self.fee = None
|
||||||
|
self.tradedVolume = None
|
||||||
|
self.createDate = None
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFutureUserInfo(object):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.accountRights = None
|
||||||
|
self.keepDeposit = None
|
||||||
|
self.profitReal = None
|
||||||
|
self.profitUnreal = None
|
||||||
|
self.riskRate = None
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFuturePosition(object):
|
||||||
|
|
||||||
|
def __init__(self, ):
|
||||||
|
self.forceLiquidatePrice = None
|
||||||
|
self.holding = [] # type: List[OkexFuturePositionDetail]
|
||||||
|
|
||||||
|
|
||||||
|
class OkexFuturePositionDetail(object):
|
||||||
|
|
||||||
|
def __init__(self, ):
|
||||||
|
self.buyAmount = None
|
||||||
|
self.buyAvailable = None
|
||||||
|
self.buyPriceAvg = None
|
||||||
|
self.buyPriceCost = None
|
||||||
|
self.buyProfitReal = None
|
||||||
|
self.contractId = None
|
||||||
|
self.createDate = None
|
||||||
|
self.leverRate = None
|
||||||
|
self.sellAmount = None
|
||||||
|
self.sellAvailable = None
|
||||||
|
self.sellPriceAvg = None
|
||||||
|
self.sellPriceCost = None
|
||||||
|
self.sellProfitReal = None
|
||||||
|
self.symbol = None
|
||||||
|
self.contractType = None
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class OkexFutureRestClient(OkexFutureRestBase):
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(OkexFutureRestClient, self).__init__()
|
||||||
|
|
||||||
|
self.client = ()
|
||||||
|
|
||||||
|
self._redirectedOnError = None # type: Callable[[object, object, object, Request], Any]
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def setOnError(self, callback): # type: (Callable[[object, object, object, Request], Any])->None
|
||||||
|
self._redirectedOnError = callback
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onError(self, exceptionType, exceptionValue, tb, req):
|
||||||
|
if self._redirectedOnError:
|
||||||
|
self._redirectedOnError(exceptionType, exceptionValue, tb, req)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onFailed(self, httpStatusCode, req):
|
||||||
|
super(OkexFutureRestClient, self).onFailed(httpStatusCode, req)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def sendOrder(self, symbol, contractType, orderType, volume,
|
||||||
|
onSuccess, onFailed=None,
|
||||||
|
price=None, useMarketPrice=False, leverRate=None,
|
||||||
|
extra=None): # type:(str, OkexFutureContractType, OkexFutureOrderType, float, Callable[[int, Any], Any], Callable[[object], Any], float, bool, Union[int, None], Any)->Request
|
||||||
|
"""
|
||||||
|
:param symbol: str
|
||||||
|
:param contractType: OkexFutureContractType
|
||||||
|
:param orderType: OkexFutureOrderType
|
||||||
|
:param volume: float
|
||||||
|
:param onSuccess: (orderId: int)->Any
|
||||||
|
:param onFailed: ()->Any
|
||||||
|
:param price: float
|
||||||
|
:param useMarketPrice: bool
|
||||||
|
:param leverRate: int | None
|
||||||
|
:param extra: Any
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
|
||||||
|
data = {}
|
||||||
|
if useMarketPrice:
|
||||||
|
data['match_price'] = 1
|
||||||
|
else:
|
||||||
|
data['price'] = price
|
||||||
|
data.update({
|
||||||
|
'symbol': symbol,
|
||||||
|
'contract_typ': contractType, # 合约类型:当周/下周/季度
|
||||||
|
'amount': volume,
|
||||||
|
'type': orderType,
|
||||||
|
'lever_rate': leverRate # 杠杆倍数
|
||||||
|
})
|
||||||
|
|
||||||
|
request = self.addReq('POST',
|
||||||
|
'/future_trade.do',
|
||||||
|
callback=self.onOrderSent,
|
||||||
|
data=data,
|
||||||
|
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
|
||||||
|
return request
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def cancelOrder(self, symbol, contractType, orderId, onSuccess, onFailed=None,
|
||||||
|
extra=None): # type: (str, OkexFutureContractType, str, Callable[[object], Any], Callable[[object], Any], Any)->Request
|
||||||
|
"""
|
||||||
|
:param symbol: str
|
||||||
|
:param contractType: OkexFutureContractType
|
||||||
|
:param orderId: str
|
||||||
|
:param onSuccess: ()->Any
|
||||||
|
:param onFailed: ()->Any
|
||||||
|
:param extra: Any
|
||||||
|
:return: Request
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'symbol': symbol,
|
||||||
|
'contractType': contractType,
|
||||||
|
'order_id': orderId
|
||||||
|
}
|
||||||
|
return self.addReq('POST',
|
||||||
|
'/future_cancel.do',
|
||||||
|
callback=self.onOrderCanceled,
|
||||||
|
data=data,
|
||||||
|
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def queryOrder(self, symbol, contractType, orderId, onSuccess, onFailed=None,
|
||||||
|
extra=None): # type: (str, OkexFutureContractType, str, Callable[[OkexFutureOrder, Any], Any], Callable[[Any], Any], Any)->Request
|
||||||
|
"""
|
||||||
|
:param symbol: str
|
||||||
|
:param contractType: OkexFutureContractType
|
||||||
|
:param orderId: str
|
||||||
|
:param onSuccess: (OkexFutureOrder, extra:Any)->Any
|
||||||
|
:param onFailed: (extra: Any)->Any
|
||||||
|
:param extra: Any
|
||||||
|
:return: Request
|
||||||
|
"""
|
||||||
|
data = {
|
||||||
|
'symbol': symbol,
|
||||||
|
'contractType': contractType,
|
||||||
|
'order_id': orderId
|
||||||
|
}
|
||||||
|
return self.addReq('POST',
|
||||||
|
'/future_order_info.do',
|
||||||
|
callback=self.onOrder,
|
||||||
|
data=data,
|
||||||
|
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def queryUserInfo(self, onSuccess, onFailed=None,
|
||||||
|
extra=None): # type: (Callable[[List[OkexFutureUserInfo], Any], Any], Callable[[Any], Any], Any)->Request
|
||||||
|
"""
|
||||||
|
查询用户信息
|
||||||
|
:param onSuccess: (userInfos: List[OkexFutureUserInfo], extra: Any)->Any
|
||||||
|
:param onFailed: (extra: Any)->Any
|
||||||
|
:param extra: Any
|
||||||
|
:return: Request
|
||||||
|
"""
|
||||||
|
return self.addReq('POST',
|
||||||
|
'/future_userinfo.do',
|
||||||
|
callback=self.onOrder,
|
||||||
|
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def queryPosition(self, symbol, contractType,
|
||||||
|
onSuccess, onFailed=None,
|
||||||
|
extra=None): # type: (str, OkexFutureContractType, Callable[[OkexFuturePosition, Any], Any], Callable[[Any], Any], Any)->Request
|
||||||
|
data = {
|
||||||
|
'symbol': symbol,
|
||||||
|
'contractType': contractType
|
||||||
|
}
|
||||||
|
return self.addReq('POST',
|
||||||
|
'/future_position.do',
|
||||||
|
data=data,
|
||||||
|
callback=self.onPosition,
|
||||||
|
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def onOrderSent(data, req): # type: (dict, Request)->None
|
||||||
|
"""
|
||||||
|
下单回执,一般用来保存sysId
|
||||||
|
"""
|
||||||
|
extra = req.extra # type: _OkexFutureCustomExtra
|
||||||
|
if data['result'] is True:
|
||||||
|
remoteId = data['order_id']
|
||||||
|
extra.onSuccess(remoteId, extra.extra)
|
||||||
|
else:
|
||||||
|
extra.onFailed(extra.extra)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def onOrderCanceled(data, req): # type: (dict, Request)->None
|
||||||
|
"""
|
||||||
|
取消订单回执
|
||||||
|
"""
|
||||||
|
success = data['result']
|
||||||
|
extra = req.extra # type: _OkexFutureCustomExtra
|
||||||
|
if success:
|
||||||
|
extra.onSuccess(extra.extra)
|
||||||
|
else:
|
||||||
|
extra.onFailed(extra.extra)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def onOrder(data, req): # type: (dict, Request)->None
|
||||||
|
success = data['result']
|
||||||
|
extra = req.extra # type: _OkexFutureCustomExtra
|
||||||
|
if success:
|
||||||
|
order = data['orders'][0]
|
||||||
|
okexOrder = OkexFutureOrder()
|
||||||
|
|
||||||
|
okexOrder.symbol = order['symbol']
|
||||||
|
okexOrder.volume = order['amount']
|
||||||
|
okexOrder.price = order['price']
|
||||||
|
okexOrder.priceAvg = order['price_avg']
|
||||||
|
okexOrder.status = order['status']
|
||||||
|
okexOrder.orderType = order['type']
|
||||||
|
okexOrder.unitAmount = order['unit_amount']
|
||||||
|
okexOrder.leverRate = order['lever_rate']
|
||||||
|
okexOrder.remoteId = order['order_id']
|
||||||
|
okexOrder.fee = order['fee']
|
||||||
|
okexOrder.tradedVolume = order['deal_amount']
|
||||||
|
okexOrder.createDate = order['create_date']
|
||||||
|
|
||||||
|
extra.onSuccess(okexOrder, extra.extra)
|
||||||
|
else:
|
||||||
|
extra.onFailed(extra.extra)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def onUserInfo(data, req): # type: (dict, Request)->None
|
||||||
|
success = data['result']
|
||||||
|
extra = req.extra # type: _OkexFutureCustomExtra
|
||||||
|
if success:
|
||||||
|
infos = data['info']
|
||||||
|
uis = []
|
||||||
|
for symbol, info in infos.items(): # type: str, dict
|
||||||
|
ui = OkexFutureUserInfo()
|
||||||
|
ui.accountRights = info['account_rights']
|
||||||
|
ui.keepDeposit = info['keep_deposit']
|
||||||
|
ui.profitReal = info['profit_real']
|
||||||
|
ui.profitUnreal = info['profit_unreal']
|
||||||
|
ui.riskRate = info['risk_rate']
|
||||||
|
uis.append(ui)
|
||||||
|
extra.onSuccess(uis, extra.extra)
|
||||||
|
else:
|
||||||
|
extra.onFailed(extra.extra)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
@staticmethod
|
||||||
|
def onPosition(data, req): # type: (dict, Request)->None
|
||||||
|
success = data['result']
|
||||||
|
extra = req.extra # type: _OkexFutureCustomExtra
|
||||||
|
if success:
|
||||||
|
pos = OkexFuturePosition()
|
||||||
|
pos.forceLiquidatePrice = data['force_liqu_price']
|
||||||
|
for item in data['holding']:
|
||||||
|
posDetail = OkexFuturePositionDetail()
|
||||||
|
posDetail.buyAmount = item['buy_amount']
|
||||||
|
posDetail.buyAvailable = item['buy_available']
|
||||||
|
posDetail.buyPriceAvg = item['buy_price_avg']
|
||||||
|
posDetail.buyPriceCost = item['buy_price_cost']
|
||||||
|
posDetail.buyProfitReal = item['buy_profit_real']
|
||||||
|
posDetail.contractId = item['contract_id']
|
||||||
|
posDetail.contractType = item['contract_type']
|
||||||
|
posDetail.createDate = item['create_date']
|
||||||
|
posDetail.leverRate = item['lever_rate']
|
||||||
|
posDetail.sellAmount = item['sell_amount']
|
||||||
|
posDetail.sellAvailable = item['sell_available']
|
||||||
|
posDetail.sellPriceAvg = item['sell_price_avg']
|
||||||
|
posDetail.sellPriceCost = item['sell_price_cost']
|
||||||
|
posDetail.sellProfitReal = item['sell_profit_real']
|
||||||
|
posDetail.symbol = item['symbol']
|
||||||
|
pos.holding.append(posDetail)
|
||||||
|
extra.onSuccess(pos, extra.extra)
|
||||||
|
else:
|
||||||
|
extra.onFailed(extra.extra)
|
@ -8,11 +8,11 @@ from vnpy.network.RestClient import RestClient, Request
|
|||||||
|
|
||||||
|
|
||||||
########################################################################
|
########################################################################
|
||||||
class OkexFutureRestClient(RestClient):
|
class OkexFutureRestBase(RestClient):
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
#----------------------------------------------------------------------
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(OkexFutureRestClient, self).__init__()
|
super(OkexFutureRestBase, self).__init__()
|
||||||
self.apiKey = None
|
self.apiKey = None
|
||||||
self.apiSecret = None
|
self.apiSecret = None
|
||||||
|
|
||||||
@ -20,7 +20,7 @@ class OkexFutureRestClient(RestClient):
|
|||||||
# noinspection PyMethodOverriding
|
# noinspection PyMethodOverriding
|
||||||
def init(self, apiKey, apiSecret):
|
def init(self, apiKey, apiSecret):
|
||||||
# type: (str, str) -> any
|
# type: (str, str) -> any
|
||||||
super(OkexFutureRestClient, self).init('https://www.okex.com/api/v1')
|
super(OkexFutureRestBase, self).init('https://www.okex.com/api/v1')
|
||||||
self.apiKey = apiKey
|
self.apiKey = apiKey
|
||||||
self.apiSecret = apiSecret
|
self.apiSecret = apiSecret
|
||||||
|
|
||||||
|
@ -5,16 +5,15 @@ from __future__ import print_function
|
|||||||
import json
|
import json
|
||||||
from abc import abstractmethod, abstractproperty
|
from abc import abstractmethod, abstractproperty
|
||||||
|
|
||||||
from vnpy.api.okexfuture.vnokexFuture import OkexFutureRestClient
|
from vnpy.api.okexfuture.OkexFutureApi import *
|
||||||
from vnpy.network.RestClient import Request
|
|
||||||
from vnpy.trader.vtFunction import getJsonPath
|
from vnpy.trader.vtFunction import getJsonPath
|
||||||
from vnpy.trader.vtGateway import *
|
from vnpy.trader.vtGateway import *
|
||||||
|
|
||||||
orderTypeMap = {
|
orderTypeMap = {
|
||||||
(constant.DIRECTION_LONG, constant.OFFSET_OPEN): 1,
|
(constant.DIRECTION_LONG, constant.OFFSET_OPEN): OkexFutureOrderType.OpenLong,
|
||||||
(constant.DIRECTION_SHORT, constant.OFFSET_OPEN): 2,
|
(constant.DIRECTION_SHORT, constant.OFFSET_OPEN): OkexFutureOrderType.OpenShort,
|
||||||
(constant.DIRECTION_LONG, constant.OFFSET_CLOSE): 3,
|
(constant.DIRECTION_LONG, constant.OFFSET_CLOSE): OkexFutureOrderType.CloseLong,
|
||||||
(constant.DIRECTION_SHORT, constant.OFFSET_CLOSE): 4,
|
(constant.DIRECTION_SHORT, constant.OFFSET_CLOSE): OkexFutureOrderType.CloseShort,
|
||||||
}
|
}
|
||||||
orderTypeMapReverse = {v: k for k, v in orderTypeMap.items()}
|
orderTypeMapReverse = {v: k for k, v in orderTypeMap.items()}
|
||||||
|
|
||||||
@ -23,9 +22,9 @@ contracts = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
contractTypeMap = {
|
contractTypeMap = {
|
||||||
'THISWEEK': 'this_week',
|
'THISWEEK': OkexFutureContractType.ThisWeek,
|
||||||
'NEXTWEEK': 'next_week',
|
'NEXTWEEK': OkexFutureContractType.NextWeek,
|
||||||
'QUARTER': 'quarter',
|
'QUARTER': OkexFutureContractType.Quarter,
|
||||||
}
|
}
|
||||||
|
|
||||||
# symbols for ui,
|
# symbols for ui,
|
||||||
@ -98,7 +97,7 @@ class OkexFutureGateway(VnpyGateway):
|
|||||||
super(OkexFutureGateway, self).__init__(eventEngine)
|
super(OkexFutureGateway, self).__init__(eventEngine)
|
||||||
self.apiKey = None # type: str
|
self.apiKey = None # type: str
|
||||||
self.apiSecret = None # type: str
|
self.apiSecret = None # type: str
|
||||||
self.api = OkexFutureApi(self)
|
self.api = OkexFutureRestClient()
|
||||||
self.leverRate = 1.0
|
self.leverRate = 1.0
|
||||||
self.symbols = []
|
self.symbols = []
|
||||||
|
|
||||||
@ -166,249 +165,3 @@ class OkexFutureGateway(VnpyGateway):
|
|||||||
def close(self):
|
def close(self):
|
||||||
"""关闭"""
|
"""关闭"""
|
||||||
self.api.close()
|
self.api.close()
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
class VnpyOrder():
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"""
|
|
||||||
这个东西将VtOrderReq和VtOrderData还有Request三者绑定起来,以便查询
|
|
||||||
|
|
||||||
"""
|
|
||||||
self.vtRequest = None # type: VtOrderReq # 如果这个order是通过sendOrder产生的,则会有对应的vtRequest
|
|
||||||
self.request = None # type: Request # 如果这个order是通过sendOrder产生的,request就是对应的网络请求
|
|
||||||
self.order = None # type: VtOrderData # 对应的VtOrderData
|
|
||||||
|
|
||||||
self.remoteId = None # type: str # 当确定了这个order在交易所内部的id的时候,这个值才会有效
|
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
class ApiBase(object):
|
|
||||||
"""
|
|
||||||
写在前面:现在不打算重构MainEngine才会有这个类的存在
|
|
||||||
所以这个类注定活不久。
|
|
||||||
|
|
||||||
每个Api实现发单等等操作的时候,有太多重复代码。
|
|
||||||
于是我写了这个类,以期简化Api的实现。
|
|
||||||
|
|
||||||
发单实现:
|
|
||||||
重写_sendOrder函数。
|
|
||||||
在_sendOrder的下单请求回执中获取API使用的orderId,并调用_processOrderSent函数即可
|
|
||||||
|
|
||||||
例如:
|
|
||||||
def _sendOrder(self, vtRequest):
|
|
||||||
return self.httpClient.addReq(..., callback=self._onOrderSent)
|
|
||||||
|
|
||||||
def _onOrderSent(self, data, req):
|
|
||||||
remoteId = None
|
|
||||||
if data['success'] is True:
|
|
||||||
remoteId = data['order_id']
|
|
||||||
self._processOrderSent(req, remoteId)
|
|
||||||
|
|
||||||
撤单实现:
|
|
||||||
重写_cancelOrder函数。
|
|
||||||
"""
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def __init__(self, gateway):
|
|
||||||
self.gateway = gateway # type: VnpyGateway
|
|
||||||
|
|
||||||
self._lastOrderId = 0
|
|
||||||
|
|
||||||
self._orders = {} # type: dict[str, VnpyOrder]
|
|
||||||
self._cancelDict = {} # type: dict[str, VtCancelOrderReq]
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
# todo: push this / make this standalone
|
|
||||||
def generateVnpyOrder(self):
|
|
||||||
localId = str(self._lastOrderId)
|
|
||||||
self._lastOrderId += 1
|
|
||||||
|
|
||||||
order = VnpyOrder()
|
|
||||||
|
|
||||||
order.order = VtOrderData()
|
|
||||||
order.order.orderID = localId
|
|
||||||
order.order.vtOrderID = ".".join(self.gateway.gatewayName, localId)
|
|
||||||
order.order.exchange = self.gateway.exchange
|
|
||||||
|
|
||||||
self._orders[localId] = order
|
|
||||||
return order
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
@staticmethod
|
|
||||||
def fillVnpyOrder(order, symbol, price, totalVolume,
|
|
||||||
direction): # type: (VnpyOrder, str, float, float, str)->None
|
|
||||||
order.order.symbol = symbol
|
|
||||||
order.order.vtSymbol = '.'.join([order.order.symbol, order.order.exchange])
|
|
||||||
order.order.price = price
|
|
||||||
order.order.totalVolume = totalVolume
|
|
||||||
order.order.direction = direction
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def local2remote(self, localId):
|
|
||||||
"""将localId(orderId)转化为remoteId"""
|
|
||||||
return self._orders[localId]
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def getOrder(self, localId=None, remoteId=None):
|
|
||||||
"""通过localId或者remoteId获取order"""
|
|
||||||
if remoteId:
|
|
||||||
raise NotImplementedError()
|
|
||||||
return self._orders[localId]
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def sendOrder(self, vtRequest): # type: (VtOrderReq)->str
|
|
||||||
"""发单"""
|
|
||||||
|
|
||||||
# 内部状态相关
|
|
||||||
order = self.generateVnpyOrder()
|
|
||||||
self.fillVnpyOrder(order,
|
|
||||||
vtRequest.symbol,
|
|
||||||
vtRequest.price,
|
|
||||||
vtRequest.volume,
|
|
||||||
vtRequest.direction)
|
|
||||||
order.vtRequest = vtRequest
|
|
||||||
|
|
||||||
# 发送发单请求
|
|
||||||
order.request = self._sendOrder(vtRequest)
|
|
||||||
|
|
||||||
# 增加反向引用
|
|
||||||
# 这个写法在逻辑上有漏洞:当请求返回特别快(理论上可能)的时候,返回回调中的extra仍为空
|
|
||||||
# 但是这种情况几乎不可能出现,在Python中就更不可能会出现。所以就这样写把,美观一些
|
|
||||||
order.request.extra = order
|
|
||||||
|
|
||||||
return order.order.vtOrderID
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def cancelOrder(self, vtCancelRequest): # type: (VtCancelOrderReq)->Request
|
|
||||||
localId = vtCancelRequest.orderID
|
|
||||||
|
|
||||||
order = self.getOrder(localId)
|
|
||||||
if order.remoteId:
|
|
||||||
return self._cancelOrder(vtCancelRequest)
|
|
||||||
else:
|
|
||||||
self._cancelDict[localId] = vtCancelRequest
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def _processOrderSent(self, request, remoteId):
|
|
||||||
"""
|
|
||||||
如果在_sendOrder中发送了HTTP请求,则应该在收到响应的时候调用该函数,
|
|
||||||
并且将remoteId设置为交易所API使用的ID
|
|
||||||
|
|
||||||
如果该下单请求失败,将remoteId设为None即可
|
|
||||||
"""
|
|
||||||
order = request.extra # type: VnpyOrder
|
|
||||||
localId = order.order.orderID
|
|
||||||
if remoteId:
|
|
||||||
order.remoteId = remoteId # None就是失败或者未返回
|
|
||||||
self.gateway.onOrder(order.order)
|
|
||||||
order.order.status = constant.STATUS_NOTTRADED
|
|
||||||
|
|
||||||
# todo: 撤单委托相关
|
|
||||||
if localId in self._cancelDict:
|
|
||||||
req = self._cancelDict[localId]
|
|
||||||
self.cancelOrder(req)
|
|
||||||
del self._cancelDict[localId]
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def _processOrderCancel(self, req, success):
|
|
||||||
"""
|
|
||||||
如果在_cancelOrder中发送了HTTP请求,则应该在收到响应的时候调用该函数,
|
|
||||||
如果取消订单成功,应该将success设置为True。如果取消订单失败,则应该讲success设置为False
|
|
||||||
"""
|
|
||||||
order = req.extra # type: VnpyOrder
|
|
||||||
order.order.status = constant.STATUS_CANCELLED
|
|
||||||
pass
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
@abstractmethod
|
|
||||||
def _sendOrder(self, vtRequest): # type: (VtOrderReq)->Request
|
|
||||||
"""
|
|
||||||
这个函数实现下单请求。
|
|
||||||
:return: 如果发送了HTTP请求,就应该返回addReq的值。
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
@abstractmethod
|
|
||||||
def _cancelOrder(self, vtCancelRequest): # type: (VtCancelOrderReq)->Request
|
|
||||||
"""
|
|
||||||
这个函数实现下单请求。
|
|
||||||
:return: 如果发送了HTTP请求,就应该返回addReq的值。
|
|
||||||
"""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
########################################################################
|
|
||||||
class OkexFutureApi(ApiBase):
|
|
||||||
"""OKEX的API实现"""
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def __init__(self, gateway):
|
|
||||||
"""Constructor"""
|
|
||||||
super(OkexFutureApi, self).__init__()
|
|
||||||
self.gateway = gateway # type: OkexFutureGateway
|
|
||||||
|
|
||||||
self.localID = 0
|
|
||||||
self.client = OkexFutureRestClient()
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onOrderSent(self, data, req): # type: (dict, Request)->None
|
|
||||||
"""
|
|
||||||
下单回执,一般用来保存sysId
|
|
||||||
"""
|
|
||||||
remoteId = None
|
|
||||||
if data['result'] is True:
|
|
||||||
remoteId = data['order_id']
|
|
||||||
super(OkexFutureApi, self)._processOrderSent(req, remoteId)
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def onOrderCanceled(self, data, req): # type: (dict, Request)->None
|
|
||||||
"""
|
|
||||||
取消订单回执
|
|
||||||
:param data:
|
|
||||||
:param req:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
success = data['result']
|
|
||||||
super(OkexFutureApi, self)._processOrderCancel(req, success)
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def _cancelOrder(self, vtCancelRequest): # type: (VtCancelOrderReq)->Request
|
|
||||||
localId = vtCancelRequest.orderID
|
|
||||||
order = self.getOrder(localId)
|
|
||||||
|
|
||||||
data = {'symbol': order.order.symbol}
|
|
||||||
return self.client.addReq('POST',
|
|
||||||
'/future_cancel.do',
|
|
||||||
callback=self.onOrderCanceled,
|
|
||||||
data=data
|
|
||||||
)
|
|
||||||
|
|
||||||
#----------------------------------------------------------------------
|
|
||||||
def _sendOrder(self, vtRequest): # type: (VtOrderReq)->Request
|
|
||||||
"""
|
|
||||||
单纯的发单
|
|
||||||
"""
|
|
||||||
symbol, contractType = symbolsForUi[vtRequest.symbol]
|
|
||||||
orderType = orderTypeMap[(vtRequest.priceType, vtRequest.offset)] # 开多、开空、平多、平空
|
|
||||||
|
|
||||||
data = {}
|
|
||||||
if vtRequest.priceType == constant.PRICETYPE_MARKETPRICE:
|
|
||||||
data['match_price'] = 1
|
|
||||||
else:
|
|
||||||
data['price'] = vtRequest.price
|
|
||||||
data.update({
|
|
||||||
'symbol': symbol,
|
|
||||||
'contract_typ': contractType, # 合约类型:当周/下周/季度
|
|
||||||
'amount': vtRequest.volume,
|
|
||||||
'type': orderType,
|
|
||||||
'lever_rate': self.gateway.leverRate # 杠杆倍数
|
|
||||||
})
|
|
||||||
|
|
||||||
request = self.client.addReq('POST',
|
|
||||||
'/future_trade.do',
|
|
||||||
callback=self.onOrderSent,
|
|
||||||
data=data)
|
|
||||||
return request
|
|
||||||
|
Loading…
Reference in New Issue
Block a user