[Mod] OkexFuture改名为OkexFutures

[Add] 增加V3版本的OkexRestApi
This commit is contained in:
nanoric 2018-10-21 22:41:30 -04:00
parent f17793ed17
commit b702f77af9
7 changed files with 741 additions and 359 deletions

View File

@ -1,2 +0,0 @@
from .OkexFutureApi import OkexFutureRestClient, OkexFutureWebSocketClient, OkexFutureSymbol, OkexFutureContractType, OkexFutureOrder, OkexFutureOrderStatus, OkexFuturePosition, \
OkexFuturePositionDetail, OkexFuturePriceType, OkexFutureUserInfo

View File

@ -1,114 +0,0 @@
# encoding: UTF-8
import hashlib
import urllib
from vnpy.api.rest import Request, RestClient
from vnpy.api.websocket import WebSocketClient
#----------------------------------------------------------------------
def paramsToData(params):
return urllib.urlencode(sorted(params.items()))
#----------------------------------------------------------------------
def sign(dataWithApiKey, apiSecret):
"""
usage:
params = { ... , 'api_key': ...}
data = paramsToData(params)
signature = sign(data, apiSecret)
data += "&sign" + signature
:param dataWithApiKey: sorted urlencoded args with apiKey
:return: param 'sign' for okex api
"""
dataWithSecret = dataWithApiKey + "&secret_key=" + apiSecret
return hashlib.md5(dataWithSecret.encode()).hexdigest().upper()
########################################################################
class OkexFutureRestBase(RestClient):
host = 'https://www.okex.com/api/v1'
#----------------------------------------------------------------------
def __init__(self):
super(OkexFutureRestBase, self).__init__()
self.apiKey = None
self.apiSecret = None
#----------------------------------------------------------------------
# noinspection PyMethodOverriding
def init(self, apiKey, apiSecret):
# type: (str, str) -> any
super(OkexFutureRestBase, self).init(self.host)
self.apiKey = apiKey
self.apiSecret = apiSecret
#----------------------------------------------------------------------
def beforeRequest(self, req): # type: (Request)->Request
args = req.params or {}
args.update(req.data or {})
if 'sign' in args:
args.pop('sign')
if 'apiKey' not in args:
args['api_key'] = self.apiKey
data = paramsToData(args)
signature = sign(data, self.apiSecret)
data += "&sign=" + signature
req.headers = {'Content-Type': 'application/x-www-form-urlencoded'}
req.data = data
return req
########################################################################
class OkexFutureWebSocketBase(WebSocketClient):
"""
Okex期货websocket客户端
实例化后使用init设置apiKey和secretKeyapiSecret
"""
host = 'wss://real.okex.com:10440/websocket/okexapi'
def __init__(self):
super(OkexFutureWebSocketBase, self).__init__()
super(OkexFutureWebSocketBase, self).init(OkexFutureWebSocketBase.host)
self.apiKey = None
self.apiSecret = None
self.autoLogin = True
self.onConnected = self._onConnected
#----------------------------------------------------------------------
# noinspection PyMethodOverriding
def init(self, apiKey, secretKey, autoLogin=True):
self.apiKey = apiKey
self.apiSecret = secretKey
self.autoLogin = autoLogin
#----------------------------------------------------------------------
def sendPacket(self, dictObj, authenticate=False):
if authenticate:
data = urllib.urlencode(sorted(dictObj.items()))
signature = sign(data, self.apiSecret)
dictObj['sign'] = signature
return super(OkexFutureWebSocketBase, self).sendPacket(dictObj)
#----------------------------------------------------------------------
def _login(self, ):
params = {"api_key": self.apiKey, }
data = paramsToData(params)
signature = sign(data, self.apiSecret)
params['sign'] = signature
self.sendPacket({
"event": "login",
"parameters": params
}, authenticate=False)
#----------------------------------------------------------------------
def _onConnected(self):
if self.autoLogin:
self._login()

View File

@ -1,14 +1,24 @@
# encoding: UTF-8
"""
# Okex Futures API V3 坑记:
* https://www.okex.com/api/futures/v3/instruments 返回值中的trade_increment有时候会变成quote_increment
* /api/futures/v3/order 如果下单时不提供client_id返回值将不会有client_id字段
* websocket居然还没升级好就把API放出来了
"""
from enum import Enum
from typing import Any, Callable, List, Union
from vnpy.api.okexfuture.vnokexFuture import OkexFutureRestBase, OkexFutureWebSocketBase
from vnpy.api.okexfutures.OkexFuturesBase import OkexFuturesRestBaseV1, OkexFuturesRestBaseV3, \
OkexFuturesWebSocketBase
from vnpy.api.rest import Request
########################################################################
class _OkexFutureCustomExtra(object):
class _OkexFuturesCustomExtra(object):
#----------------------------------------------------------------------
def __init__(self, onSuccess, onFailed, extra):
self.onFailed = onFailed
self.onSuccess = onSuccess
@ -16,7 +26,7 @@ class _OkexFutureCustomExtra(object):
########################################################################
class OkexFutureEasySymbol(object):
class OkexFuturesEasySymbol(object):
BTC = 'btc'
LTC = 'ltc'
ETH = 'eth'
@ -28,7 +38,7 @@ class OkexFutureEasySymbol(object):
########################################################################
class OkexFutureSymbol(object):
class OkexFuturesSymbol(object):
BTC = 'btc_usd'
LTC = 'ltc_usd'
ETH = 'eth_usd'
@ -37,20 +47,20 @@ class OkexFutureSymbol(object):
########################################################################
class OkexFuturePriceType(object):
class OkexFuturesPriceType(object):
Buy = 'buy'
Sell = 'sell'
########################################################################
class OkexFutureContractType(object):
class OkexFuturesContractType(object):
ThisWeek = 'this_week'
NextWeek = 'next_week'
Quarter = 'quarter'
########################################################################
class OkexFutureOrderType(object):
class OkexFuturesOrderType(object):
OpenLong = '1'
OpenShort = '2'
CloseLong = '3'
@ -58,13 +68,13 @@ class OkexFutureOrderType(object):
########################################################################
class OkexFutureOrderStatus(object):
class OkexFuturesOrderStatus(object):
NotFinished = '1'
Finished = '2'
########################################################################
class OkexFutureOrder(object):
class OkexFuturesOrder(object):
#----------------------------------------------------------------------
def __init__(self):
@ -84,7 +94,7 @@ class OkexFutureOrder(object):
########################################################################
class OkexFutureUserInfo(object):
class OkexFuturesUserInfo(object):
#----------------------------------------------------------------------
def __init__(self):
@ -97,16 +107,16 @@ class OkexFutureUserInfo(object):
########################################################################
class OkexFuturePosition(object):
class OkexFuturesPosition(object):
#----------------------------------------------------------------------
def __init__(self, ):
self.forceLiquidatePrice = None
self.holding = [] # type: List[OkexFuturePositionDetail]
self.holding = [] # type: List[OkexFuturesPositionDetail]
########################################################################
class OkexFuturePositionDetail(object):
class OkexFuturesPositionDetail(object):
#----------------------------------------------------------------------
def __init__(self, ):
@ -128,10 +138,11 @@ class OkexFuturePositionDetail(object):
########################################################################
class OkexFutureTickInfo(object):
class OkexFuturesTickInfo(object):
#----------------------------------------------------------------------
def __init__(self, symbol, remoteContractType, last, limitHigh, limitLow, vol, sell, buy, unitAmount, holdAmount,
def __init__(self, symbol, remoteContractType, last, limitHigh, limitLow, vol, sell, buy,
unitAmount, holdAmount,
contractId, high, low):
self.symbol = symbol
self.remoteContractType = remoteContractType
@ -149,7 +160,7 @@ class OkexFutureTickInfo(object):
########################################################################
class OkexFutureTradeInfo(object):
class OkexFuturesTradeInfo(object):
#----------------------------------------------------------------------
def __init__(self, symbol, remoteContractType, index, price, volume, time, direction, coinVolume):
@ -164,7 +175,7 @@ class OkexFutureTradeInfo(object):
########################################################################
class OkexFutureUserTradeInfo(object):
class OkexFuturesUserTradeInfo(object):
#----------------------------------------------------------------------
def __init__(self, symbol, remoteContractType, amount,
@ -190,39 +201,362 @@ class OkexFutureUserTradeInfo(object):
########################################################################
class OkexFutureRestClient(OkexFutureRestBase):
class OkexFuturesContractsInfoV3(object):
#----------------------------------------------------------------------
def __init__(self,
instrumentId,
underlyingIndex,
quoteCurrency,
quote_increment,
contractVal,
listing,
delivery,
tickSize,
):
self.symbol = instrumentId # String # 合约ID如BTC-USD-180213
self.underlyingIndex = underlyingIndex # String # 交易货币币种btc-usdt中的btc
self.quoteCurrency = quoteCurrency # String # 计价货币币种btc-usdt中的usdt
self.quoteIncrement = quote_increment # Number # 下单数量精度
self.contractVal = contractVal # Number # 合约面值(美元)
self.listing = listing # Date # 上线日期
self.delivery = delivery # Date # 交割日期
self.tickSize = tickSize # Number # 下单价格精度
########################################################################
class OkexFuturesAccountInfoV3(object):
#----------------------------------------------------------------------
def __init__(self, currency, balance, hold, available):
self.currency = currency # String # 币种
self.balance = balance # number # 余额
self.hold = hold # number # 冻结(不可用)
self.available = available # number # 可用于提现或资金划转的数量
########################################################################
class OkexFuturesPositionInfoV3(object):
#----------------------------------------------------------------------
def __init__(self, marginMode, liquidationPrice, longQty, longAvailQty, longAvgCost,
longSettlementPrice,
realizedPnl, shortQty, shortAvailQty, shortAvgCost, shortSettlementPrice,
instrumentId,
leverage, createAt, updatAt,
):
self.marginMode = marginMode # String # 账户类型:全仓 crossed
self.liquidationPrice = liquidationPrice # Price # 预估爆仓价
self.longQty = longQty # Number # 多仓数量
self.longAvailQty = longAvailQty # Number # 多仓可平仓数量
self.longAvgCost = longAvgCost # Price # 开仓平均价
self.longSettlementPrice = longSettlementPrice # Price # 多仓结算基准价
self.realizedPnl = realizedPnl # Number # 已实现盈余
self.shortQty = shortQty # Number # 空仓数量
self.shortAvailQty = shortAvailQty # Number # 空仓可平仓数量
self.shortAvgCost = shortAvgCost # Price # 开仓平均价
self.shortSettlementPrice = shortSettlementPrice # String # 空仓结算基准价
self.symbol = instrumentId # Number # 合约ID如BTC-USD-180213
self.leverage = leverage # Date # 杠杆倍数
self.createAt = createAt # Date # 创建时间
self.updatAt = updatAt # Date # 更新时间
########################################################################
class OkexFuturesOrderSentInfoV3(object):
#----------------------------------------------------------------------
def __init__(self, orderId, clientOid, errorCode, errorMessage):
self.orderId = orderId # String # 订单ID下单失败时此字段值为-1
self.clientOid = clientOid # String # 由您设置的订单ID来识别您的订单
self.errorCode = errorCode # Number # 错误码下单成功时为0下单失败时会显示相应错误码
self.errorMessage = errorMessage # String # 错误信息,下单成功时为空,下单失败时会显示错误信息
########################################################################
class OkexFuturesOrderDetailV3(object):
#----------------------------------------------------------------------
def __init__(self, instrumentId, size, timestamp, filledQty, fee, orderId, price, priceAvg,
status, orderType, contractVal, leverage, ):
self.symbol = instrumentId # String # 合约ID如BTC-USD-180213
self.volume = size # Number # 数量
self.timestamp = timestamp # Date # 委托时间
self.tradedVolume = filledQty # Number # 成交数量
self.fee = fee # Price # 手续费
self.remoteId = orderId # String # 订单ID
self.price = price # Price # 订单价格
self.priceAvg = priceAvg # Price # 平均价格
self.status = status # Number # 订单状态(0:等待成交 1:部分成交 2:已完成)
self.orderType = orderType # Number # 订单类型(1:开多 2:开空 3:开多 4:平空)
self.contractVal = contractVal # Price # 合约面值
self.leverage = leverage # Number # 杠杆倍数 value:10/20 默认10
########################################################################
class OkexFuturesRestClientV3(OkexFuturesRestBaseV3):
"""
Okex新出了V3版本的API这里用的是V3的版本
"""
#----------------------------------------------------------------------
def __init__(self):
"""Constructor"""
super(OkexFuturesRestClientV3, self).__init__()
#----------------------------------------------------------------------
def sendOrder(self,
symbol,
orderType,
price,
volume,
leverRate, # type: int # 档杆倍数10或者20
onSuccess, # type: Callable[[OkexFuturesOrderSentInfoV3, Any], Any]
onFailed=None, # type: Callable[[OkexFuturesOrderSentInfoV3, Any], Any]
matchPrice=False, # type: bool # 是否为市价单
clientOid=None, # type: str # OkexAPI提供的的用户自定义字段
extra=None
):
""" 下单 """
data = {
'client_oid': clientOid,
'instrument_id': symbol,
'type': orderType,
'size': volume,
'leverage': leverRate,
'price': price,
'match_price': '0'
}
# if matchPrice:
# data['match_price'] = '1'
# else:
# data['price'] = price
return self.addRequest('POST', '/api/futures/v3/order',
callback=self._onOrderSent,
data=data,
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra)
)
#----------------------------------------------------------------------
def cancelOrder(self,
symbol, # type: str
remoteId, # type: str
onSuccess, # type: Callable[[Any], Any]
onFailed=None, # type: Callable[[Any], Any]
extra=None
): # type: (...)->Request
"""撤单"""
path = '/api/futures/v3/cancel_order/' + symbol + '/' + remoteId
return self.addRequest('POST', path,
callback=self._onOrderCanceled,
data={
'instrument_id' : symbol,
'order_id': remoteId
},
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra)
)
#----------------------------------------------------------------------
def queryAccount(self,
onSuccess, # type: Callable[[List[OkexFuturesAccountInfoV3], Any], Any]
extra=None
): # type: (...)->Request
"""
查询全部账户资金
"""
return self.addRequest('GET', '/api/account/v3/wallet',
callback=self._onAccounts,
extra=_OkexFuturesCustomExtra(onSuccess, None, extra)
)
#----------------------------------------------------------------------
def queryOrders(self,
symbol,
status, # type: OkexFuturesOrderStatus
onSuccess, # type: Callable[[List[OkexFuturesOrderDetailV3], Any], Any]
onFailed=None, # type: Callable[[Any], Any]
startPage=0, # type: int # 取回的页数区间为:(start, end)
endPage=2, # type: int # 取回的页数区间为:(start, end)
numberPerPage=100, # type: int
extra=None
): # type: (...)->Request
"""查询账户订单"""
path = '/api/futures/v3/orders/' + symbol
return self.addRequest("POST", path,
data={
'status': status,
'instrument_id': symbol,
'from': startPage,
'to': endPage,
'limit': numberPerPage,
},
callback=self._onOrders,
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra)
)
#----------------------------------------------------------------------
def queryPositions(self,
onSuccess,
extra=None):
""" 获取全部持仓 """
return self.addRequest('GET', '/api/account/v3/position',
callback=self._onPositions,
extra=_OkexFuturesCustomExtra(onSuccess, None, extra)
)
#----------------------------------------------------------------------
def queryContracts(self,
onSuccess, # type: Callable[[List[OkexFuturesContractsInfoV3], Any], Any]
extra=None):
""" 获取全部合约信息 """
return self.addRequest('GET', '/api/futures/v3/instruments',
callback=self._onContracts,
extra=_OkexFuturesCustomExtra(onSuccess, None, extra)
)
#----------------------------------------------------------------------
@staticmethod
def _onOrderSent(data, request): #type: (dict, Request)->None
"""下单回调"""
extra = request.extra # type: _OkexFuturesCustomExtra
order = OkexFuturesOrderSentInfoV3(
data['order_id'],
data['client_oid'] if 'client_oid' in data else None,
data['error_code'],
data['error_message'],
)
if order.orderId != '-1':
extra.onSuccess(order, extra.extra)
else:
if extra.onFailed:
extra.onFailed(order, extra.extra)
#----------------------------------------------------------------------
def _onOrderCanceled(self, data, request): #type: (dict, Request)->None
"""撤单回调"""
extra = request.extra # type: _OkexFuturesCustomExtra
result = data['result']
if result is True:
extra.onSuccess(extra.extra)
else:
if extra.onFailed:
extra.onFailed(extra.extra)
#----------------------------------------------------------------------
@staticmethod
def _onAccounts(data, request): #type: (dict, Request)->None
"""账户资金回调"""
extra = request.extra # type: _OkexFuturesCustomExtra
accs = []
for acc in data:
accs.append(OkexFuturesAccountInfoV3(
acc['currency'],
acc['balance'],
acc['hold'],
acc['available'],
))
extra.onSuccess(accs, extra.extra)
#----------------------------------------------------------------------
@staticmethod
def _onOrders(data, request): #type: (dict, Request)->None
"""
查询订单回调
https://www.okex.com/docs/zh/#futures-list
"""
extra = request.extra # type: _OkexFuturesCustomExtra
if data['result'] is True:
os = []
for info in data['orders']:
os.append(OkexFuturesOrderDetailV3(
info['instrument_id'],
info['size'],
info['timestamp'],
info['filled_qty'],
info['fee'],
info['order_id'],
info['price'],
info['price_avg'],
info['status'],
info['type'],
info['contract_val'],
info['leverage'],
))
extra.onSuccess(os, extra.extra)
else:
if extra.onFailed:
extra.onFailed(extra.extra)
#----------------------------------------------------------------------
@staticmethod
def _onPositions(data, request): #type: (dict, Request)->None
extra = request.extra # type: _OkexFuturesCustomExtra
accs = []
for acc in data:
accs.append(OkexFuturesPositionInfoV3(
acc['margin_mode'],
acc['liquidation_price'],
acc['long_qty'],
acc['long_avail_qty'],
acc['long_avg_cost'],
acc['long_settlement_price'],
acc['realized_pnl'],
acc['short_qty'],
acc['short_avail_qty'],
acc['short_avg_cost'],
acc['short_settlement_price'],
acc['instrument_id'],
acc['leverage'],
acc['create_at'],
acc['updat_at'],
))
extra.onSuccess(accs, extra.extra)
#----------------------------------------------------------------------
@staticmethod
def _onContracts(data, request): #type: (dict, Request)->None
"""
合约信息回调
https://www.okex.com/docs/zh/#futures-contract_information
"""
extra = request.extra # type: _OkexFuturesCustomExtra
ins = []
for instrument in data:
ins.append(OkexFuturesContractsInfoV3(
instrument['instrument_id'],
instrument['underlying_index'],
instrument['quote_currency'],
instrument['quote_increment'] if 'quote_increment' in instrument else instrument['trade_increment'],
instrument['contract_val'],
instrument['listing'],
instrument['delivery'],
instrument['tick_size'],
))
extra.onSuccess(ins, extra.extra)
########################################################################
class OkexFuturesRestClientV1(OkexFuturesRestBaseV1):
"""
这里用的是旧的v1版本的OkexAPI
"""
#----------------------------------------------------------------------
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)
super(OkexFuturesRestClientV1, self).__init__()
#----------------------------------------------------------------------
def sendOrder(self, symbol, contractType, orderType, volume,
onSuccess, onFailed=None,
price=None, useMarketPrice=False, leverRate=None,
extra=None): # type:(str, OkexFutureContractType, OkexFutureOrderType, float, Callable[[str, Any], Any], Callable[[int, Any], Any], float, bool, Union[int, None], Any)->Request
extra=None): # type:(str, OkexFuturesContractType, OkexFuturesOrderType, float, Callable[[str, Any], Any], Callable[[int, Any], Any], float, bool, Union[int, None], Any)->Request
"""
:param symbol: str
:param contractType: OkexFutureContractType
:param orderType: OkexFutureOrderType
:param contractType: OkexFuturesContractType
:param orderType: OkexFuturesOrderType
:param volume: float
:param onSuccess: (orderId: int)->Any
:param onFailed: ()->Any
@ -251,15 +585,15 @@ class OkexFutureRestClient(OkexFutureRestBase):
'/future_trade.do',
callback=self.onOrderSent,
data=data,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
return request
#----------------------------------------------------------------------
def cancelOrder(self, symbol, contractType, orderId, onSuccess, onFailed=None,
extra=None): # type: (str, OkexFutureContractType, str, Callable[[object], Any], Callable[[int, Any], Any], Any)->Request
extra=None): # type: (str, OkexFuturesContractType, str, Callable[[object], Any], Callable[[int, Any], Any], Any)->Request
"""
:param symbol: str
:param contractType: OkexFutureContractType
:param contractType: OkexFuturesContractType
:param orderId: str
:param onSuccess: ()->Any
:param onFailed: ()->Any
@ -275,18 +609,18 @@ class OkexFutureRestClient(OkexFutureRestBase):
'/future_cancel.do',
callback=self.onOrderCanceled,
data=data,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
#----------------------------------------------------------------------
def queryOrder(self, symbol, contractType, orderId, onSuccess, onFailed=None,
extra=None): # type: (str, OkexFutureContractType, str, Callable[[List[OkexFutureOrder], Any], Any], Callable[[int, Any], Any], Any)->Request
extra=None): # type: (str, OkexFuturesContractType, str, Callable[[List[OkexFuturesOrder], Any], Any], Callable[[int, Any], Any], Any)->Request
"""
@note onSuccess接收的第一个参数是列表并且有可能为空
:param symbol: str
:param contractType: OkexFutureContractType
:param contractType: OkexFuturesContractType
:param orderId: str
:param onSuccess: (orders: List[OkexFutureOrder], extra:Any)->Any
:param onSuccess: (orders: List[OkexFuturesOrder], extra:Any)->Any
:param onFailed: (extra: Any)->Any
:param extra: Any
:return: Request
@ -300,19 +634,19 @@ class OkexFutureRestClient(OkexFutureRestBase):
'/future_order_info.do',
callback=self.onOrder,
data=data,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
#----------------------------------------------------------------------
def queryOrders(self, symbol, contractType, status,
onSuccess, onFailed=None,
pageIndex=0, pageLength=50,
extra=None): # type: (str, OkexFutureContractType, OkexFutureOrderStatus, Callable[[List[OkexFutureOrder], Any], Any], Callable[[int, Any], Any], int, int, Any)->Request
extra=None): # type: (str, OkexFuturesContractType, OkexFuturesOrderStatus, Callable[[List[OkexFuturesOrder], Any], Any], Callable[[int, Any], Any], int, int, Any)->Request
"""
@note onSuccess接收的第一个参数是列表并且有可能为空
:param symbol: str
:param contractType: OkexFutureContractType
:param onSuccess: (List[OkexFutureOrder], extra:Any)->Any
:param contractType: OkexFuturesContractType
:param onSuccess: (List[OkexFuturesOrder], extra:Any)->Any
:param onFailed: (extra: Any)->Any
:param pageIndex: 页码
:param pageLength: 最大显示数量最大值50
@ -332,14 +666,14 @@ class OkexFutureRestClient(OkexFutureRestBase):
'/future_order_info.do',
callback=self.onOrder,
data=data,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
#----------------------------------------------------------------------
def queryUserInfo(self, onSuccess, onFailed=None,
extra=None): # type: (Callable[[List[OkexFutureUserInfo], Any], Any], Callable[[int, Any], Any], Any)->Request
extra=None): # type: (Callable[[List[OkexFuturesUserInfo], Any], Any], Callable[[int, Any], Any], Any)->Request
"""
查询用户信息
:param onSuccess: (userInfos: List[OkexFutureUserInfo], extra: Any)->Any
:param onSuccess: (userInfos: List[OkexFuturesUserInfo], extra: Any)->Any
:param onFailed: (extra: Any)->Any
:param extra: Any
:return: Request
@ -347,16 +681,16 @@ class OkexFutureRestClient(OkexFutureRestBase):
return self.addRequest('POST',
'/future_userinfo.do',
callback=self.onOrder,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
#----------------------------------------------------------------------
def queryPosition(self, symbol, contractType,
onSuccess, onFailed=None,
extra=None): # type: (str, OkexFutureContractType, Callable[[OkexFuturePosition, Any], Any], Callable[[int, Any], Any], Any)->Request
extra=None): # type: (str, OkexFuturesContractType, Callable[[OkexFuturesPosition, Any], Any], Callable[[int, Any], Any], Any)->Request
"""
:param symbol: OkexFutureSymbol
:param contractType: OkexFutureContractType
:param onSuccess: (pos:OkexFuturePosition, extra: any)->Any
:param symbol: OkexFuturesSymbol
:param contractType: OkexFuturesContractType
:param onSuccess: (pos:OkexFuturesPosition, extra: any)->Any
:param onFailed: (errorCode: int, extra: any)->Any
:param extra:
:return:
@ -369,15 +703,15 @@ class OkexFutureRestClient(OkexFutureRestBase):
'/future_position.do',
data=data,
callback=self.onPosition,
extra=_OkexFutureCustomExtra(onSuccess, onFailed, extra))
extra=_OkexFuturesCustomExtra(onSuccess, onFailed, extra))
#----------------------------------------------------------------------
@staticmethod
def onOrderSent(data, req): # type: (dict, Request)->None
def onOrderSent(data, request): # type: (dict, Request)->None
"""
下单回执一般用来保存sysId
"""
extra = req.extra # type: _OkexFutureCustomExtra
extra = request.extra # type: _OkexFuturesCustomExtra
if data['result'] is True:
remoteId = data['order_id']
extra.onSuccess(remoteId, extra.extra)
@ -390,12 +724,12 @@ class OkexFutureRestClient(OkexFutureRestBase):
#----------------------------------------------------------------------
@staticmethod
def onOrderCanceled(data, req): # type: (dict, Request)->None
def onOrderCanceled(data, request): # type: (dict, Request)->None
"""
取消订单回执
"""
success = data['result']
extra = req.extra # type: _OkexFutureCustomExtra
extra = request.extra # type: _OkexFuturesCustomExtra
if success:
extra.onSuccess(extra.extra)
else:
@ -407,13 +741,13 @@ class OkexFutureRestClient(OkexFutureRestBase):
#----------------------------------------------------------------------
@staticmethod
def onOrder(data, req): # type: (dict, Request)->None
def onOrder(data, request): # type: (dict, Request)->None
success = data['result']
extra = req.extra # type: _OkexFutureCustomExtra
extra = request.extra # type: _OkexFuturesCustomExtra
if success:
orders = []
for order in data['orders']:
okexOrder = OkexFutureOrder()
okexOrder = OkexFuturesOrder()
okexOrder.volume = order['amount']
okexOrder.contractName = order['contract_name']
@ -421,7 +755,7 @@ class OkexFutureRestClient(OkexFutureRestBase):
okexOrder.tradedVolume = order['deal_amount']
okexOrder.fee = order['fee']
okexOrder.leverRate = order['lever_rate']
okexOrder.remoteId = order['order_id']
okexOrder.remoteId = str(order['orderId'])
okexOrder.price = order['price']
okexOrder.priceAvg = order['price_avg']
okexOrder.status = order['status']
@ -439,14 +773,14 @@ class OkexFutureRestClient(OkexFutureRestBase):
#----------------------------------------------------------------------
@staticmethod
def onUserInfo(data, req): # type: (dict, Request)->None
def onUserInfo(data, request): # type: (dict, Request)->None
success = data['result']
extra = req.extra # type: _OkexFutureCustomExtra
extra = request.extra # type: _OkexFuturesCustomExtra
if success:
infos = data['info']
uis = []
for easySymbol, info in infos.items(): # type: str, dict
ui = OkexFutureUserInfo()
ui = OkexFuturesUserInfo()
ui.easySymbol = easySymbol
ui.accountRights = info['account_rights']
ui.keepDeposit = info['keep_deposit']
@ -464,14 +798,14 @@ class OkexFutureRestClient(OkexFutureRestBase):
#----------------------------------------------------------------------
@staticmethod
def onPosition(data, req): # type: (dict, Request)->None
def onPosition(data, request): # type: (dict, Request)->None
success = data['result']
extra = req.extra # type: _OkexFutureCustomExtra
extra = request.extra # type: _OkexFuturesCustomExtra
if success:
pos = OkexFuturePosition()
pos = OkexFuturesPosition()
pos.forceLiquidatePrice = data['force_liqu_price']
for item in data['holding']:
posDetail = OkexFuturePositionDetail()
posDetail = OkexFuturesPositionDetail()
posDetail.buyAmount = item['buy_amount']
posDetail.buyAvailable = item['buy_available']
posDetail.buyPriceAvg = item['buy_price_avg']
@ -504,16 +838,16 @@ class OkexFutureRestClient(OkexFutureRestBase):
########################################################################
class OkexFutureWebSocketClient(OkexFutureWebSocketBase):
class OkexFuturesWebSocketClient(OkexFuturesWebSocketBase):
#----------------------------------------------------------------------
def __init__(self):
super(OkexFutureWebSocketClient, self).__init__()
super(OkexFuturesWebSocketClient, self).__init__()
self.onTick = self.defaultOnTick
self.onUserTrade = self.defaultOnUserTrade
#----------------------------------------------------------------------
def subscribe(self, easySymbol, contractType): # type: (OkexFutureEasySymbol, OkexFutureContractType)->None
def subscribe(self, easySymbol, contractType): # type: (OkexFuturesEasySymbol, OkexFuturesContractType)->None
self.sendPacket({
'event': 'addChannel',
'channel': 'ok_sub_futureusd_' + easySymbol + '_ticker_' + contractType
@ -521,18 +855,15 @@ class OkexFutureWebSocketClient(OkexFutureWebSocketBase):
#----------------------------------------------------------------------
def subscribeUserTrade(self):
# todo: 没有测试条件
self.sendPacket({
'event': 'addChannel',
'channel': 'ok_sub_futureusd_trades'
})
#----------------------------------------------------------------------
def defaultOnPacket(self, packets):
def onPacket(self, packets):
for packet in packets:
print('packets:')
print(packets)
channelName = None
if 'channel' in packet:
channelName = packet['channel']
@ -543,56 +874,55 @@ class OkexFutureWebSocketClient(OkexFutureWebSocketBase):
channel = parseChannel(channelName) # type: ExtraSymbolChannel
if channel.type == ChannelType.Tick:
self.onTick(OkexFutureTickInfo(
self.onTick(OkexFuturesTickInfo(
symbol=channel.symbol,
remoteContractType=channel.remoteContractType,
last=packet['last'], # float # 最高买入限制价格
limitHigh=packet['limitHigh'], # str # 最高买入限制价格
limitLow=packet['limitLow'], # str # 最低卖出限制价格
vol=packet['vol'], # float # 24 小时成交量
sell=packet['sell'], # float # 卖一价格
buy=packet['buy'], # float # 买一价格
unitAmount=packet['unitAmount'], # float # 合约价值
holdAmount=packet['hold_amount'], # float # 当前持仓量
contractId=packet['contractId'], # long # 合约ID
high=packet['high'], # float # 24 小时最高价格
low=packet['low'], # float # 24 小时最低价格
last=packet['last'],
limitHigh=packet['limitHigh'],
limitLow=packet['limitLow'],
vol=packet['vol'],
sell=packet['sell'],
buy=packet['buy'],
unitAmount=packet['unitAmount'],
holdAmount=packet['hold_amount'],
contractId=packet['contractId'],
high=packet['high'],
low=packet['low'],
))
# elif channel.type == ChannelType.Trade:
# trades = []
# for tradeInfo in packet:
# trades.append(OkexFutureTradeInfo(
# trades.append(OkexFuturesTradeInfo(
# channel.symbol, channel.remoteContractType, *tradeInfo
# ))
# self.onTrades(trades)
# todo: 没有测试条件
elif channel.type == ChannelType.UserTrade:
self.onUserTrade(OkexFutureUserTradeInfo(
symbol=packet['symbol'], # str # btc_usd ltc_usd eth_usd etc_usd bch_usd
self.onUserTrade(OkexFuturesUserTradeInfo(
symbol=packet['symbol'],
remoteContractType=packet['contract_type'],
amount=packet['amount'], # float # 委托数量
contractName=packet['contract_name'], # str # 合约名称
createdDate=packet['created_date'], # long # 委托时间
createDateStr=packet['create_date_str'], # str # 委托时间字符串
dealAmount=packet['deal_amount'], # float # 成交数量
fee=packet['fee'], # float # 手续费
orderId=packet['order_id'], # long # 订单ID
price=packet['price'], # float # 订单价格
priceAvg=packet['price_avg'], # float # 平均价格
status=packet['status'], # int # 订单状态(0等待成交 1部分成交 2全部成交 -1撤单 4撤单处理中)
type=packet['type'], # int # 订单类型 1开多 2开空 3平多 4平空
unitAmount=packet['unit_amount'], # float # 合约面值
leverRate=packet['lever_rate'], # float # 杠杆倍数 value:10/20 默认10
systemType=packet['system_type'], # int # 订单类型 0:普通 1:交割 2:强平 4:全平 5:系统反单
amount=packet['amount'],
contractName=packet['contract_name'],
createdDate=packet['created_date'],
createDateStr=packet['create_date_str'],
dealAmount=packet['deal_amount'],
fee=packet['fee'],
orderId=packet['order_id'],
price=packet['price'],
priceAvg=packet['price_avg'],
status=packet['status'],
type=packet['type'],
unitAmount=packet['unit_amount'],
leverRate=packet['lever_rate'],
systemType=packet['system_type'],
))
#----------------------------------------------------------------------
def defaultOnTick(self, tick): # type: (OkexFutureTickInfo)->None
def defaultOnTick(self, tick): # type: (OkexFuturesTickInfo)->None
pass
#----------------------------------------------------------------------
def defaultOnUserTrade(self, tick): # type: (OkexFutureUserTradeInfo)->None
def defaultOnUserTrade(self, tick): # type: (OkexFuturesUserTradeInfo)->None
pass
@ -823,5 +1153,5 @@ def remotePrefixToRemoteContractType(prefix):
return _prefixForRemoteContractType[prefix]
_prefixForRemoteContractType = {v.split('_')[0]: v for k, v in OkexFutureContractType.__dict__.items() if
_prefixForRemoteContractType = {v.split('_')[0]: v for k, v in OkexFuturesContractType.__dict__.items() if
not k.startswith('_')}

View File

@ -0,0 +1,171 @@
# encoding: UTF-8
import base64
import hashlib
import hmac
import json
import urllib
import time
from vnpy.api.rest import Request, RestClient
from vnpy.api.websocket import WebSocketClient
#----------------------------------------------------------------------
def paramsToDataV1(params):
return urllib.urlencode(sorted(params.items()))
#----------------------------------------------------------------------
def signV1(dataWithApiKey, apiSecret):
"""
usage:
params = { ... , 'api_key': ...}
data = paramsToData(params)
signature = sign(data, apiSecret)
data += "&sign" + signature
:param dataWithApiKey: sorted urlencoded args with apiKey
:return: param 'sign' for okex api
"""
dataWithSecret = dataWithApiKey + "&secret_key=" + apiSecret
return hashlib.md5(dataWithSecret.encode()).hexdigest().upper()
#----------------------------------------------------------------------
def signV3(dataToSign, apiSecret):
return base64.b64encode( hmac.new(apiSecret, dataToSign.encode(), hashlib.sha256).digest())
########################################################################
class OkexFuturesRestBaseV1(RestClient):
host = 'https://www.okex.com/api/v1'
#----------------------------------------------------------------------
def __init__(self):
super(OkexFuturesRestBaseV1, self).__init__()
self.apiKey = None
self.apiSecret = None
#----------------------------------------------------------------------
# noinspection PyMethodOverriding
def init(self, apiKey, apiSecret, apiPassphrase):
# type: (str, str, str) -> any
super(OkexFuturesRestBaseV1, self).init(self.host)
self.apiKey = apiKey
self.apiSecret = apiSecret
#----------------------------------------------------------------------
def sign(self, request): # type: (Request)->Request
args = request.params or {}
args.update(request.data or {})
if 'sign' in args:
args.pop('sign')
if 'apiKey' not in args:
args['api_key'] = self.apiKey
data = paramsToDataV1(args)
signature = signV1(data, self.apiSecret)
data += "&sign=" + signature
request.headers = {'Content-Type': 'application/x-www-form-urlencoded'}
request.data = data
return request
########################################################################
class OkexFuturesRestBaseV3(RestClient):
"""
Okex Rest API v3基础类
"""
host = 'https://www.okex.com'
#----------------------------------------------------------------------
def __init__(self):
super(OkexFuturesRestBaseV3, self).__init__()
self.apiKey = None
self.apiSecret = None
self.apiPassphrase = None
#----------------------------------------------------------------------
# noinspection PyMethodOverriding
def init(self, apiKey, apiSecret, apiPassphrase):
# type: (str, str, str) -> any
super(OkexFuturesRestBaseV3, self).init(self.host)
self.apiKey = apiKey
self.apiSecret = apiSecret
self.apiPassphrase = apiPassphrase
#----------------------------------------------------------------------
def sign(self, request): # type: (Request)->Request
timestamp = str(time.time())
data = json.dumps(request.data)
request.data = data
dataToSign = timestamp + request.method + request.path + data
signature = signV3(dataToSign, self.apiSecret)
request.headers = {
'OK-ACCESS-KEY': self.apiKey,
'OK-ACCESS-SIGN': signature,
'OK-ACCESS-TIMESTAMP': timestamp,
'OK-ACCESS-PASSPHRASE': self.apiPassphrase,
'Content-Type': 'application/json'
}
return request
########################################################################
class OkexFuturesWebSocketBase(WebSocketClient):
"""
Okex期货websocket客户端
实例化后使用init设置apiKey和secretKeyapiSecret
"""
host = 'wss://real.okex.com:10440/websocket/okexapi'
def __init__(self):
super(OkexFuturesWebSocketBase, self).__init__()
super(OkexFuturesWebSocketBase, self).init(OkexFuturesWebSocketBase.host)
self.apiKey = None
self.apiSecret = None
self.apiPassphrase = None
self.autoLogin = True
self.onConnected = self._onConnected
#----------------------------------------------------------------------
# noinspection PyMethodOverriding
def init(self, apiKey, secretKey, apiPassphrase, autoLogin=True):
self.apiKey = apiKey
self.apiSecret = secretKey
self.apiPassphrase = apiPassphrase
self.autoLogin = autoLogin
#----------------------------------------------------------------------
def sendPacket(self, dictObj, authenticate=False):
if authenticate:
pass
return super(OkexFuturesWebSocketBase, self).sendPacket(dictObj)
#----------------------------------------------------------------------
def _login(self, ):
timestamp = str(time.time())
data = timestamp + 'GET' + '/users/self/verify'
signature = signV3(data, self.apiSecret)
self.sendPacket({
"event": "login",
"parameters": {
"api_key": self.apiKey,
"timestamp": timestamp,
"passphrase": self.apiPassphrase,
"sign": signature,
}
}, authenticate=False)
#----------------------------------------------------------------------
def _onConnected(self):
if self.autoLogin:
self._login()

View File

@ -0,0 +1,6 @@
from .OkexFuturesApi import OkexFuturesAccountInfoV3, OkexFuturesContractType, \
OkexFuturesContractsInfoV3, OkexFuturesOrder, OkexFuturesOrderDetailV3, \
OkexFuturesOrderSentInfoV3, OkexFuturesOrderStatus, OkexFuturesPosition, \
OkexFuturesPositionDetail, OkexFuturesPositionInfoV3, OkexFuturesPriceType, \
OkexFuturesRestClientV1, OkexFuturesRestClientV3, OkexFuturesSymbol, OkexFuturesUserInfo, \
OkexFuturesWebSocketClient

View File

@ -3,57 +3,20 @@
from __future__ import print_function
import json
from abc import abstractmethod
from typing import Dict
from vnpy.api.okexfuture.OkexFutureApi import *
from vnpy.api.okexfutures.OkexFuturesApi import *
from vnpy.trader.vtFunction import getJsonPath
from vnpy.trader.vtGateway import *
########################################################################
class VnpyGateway(VtGateway):
"""
每个gateway有太多重复代码难以拓展和维护
于是我设计了这个类将重复代码抽取出来简化gateway的实现
"""
#----------------------------------------------------------------------
def readConfig(self):
"""
从json文件中读取设置并将其内容返回为一个dict
:一个一个return:
"""
fileName = self.gatewayName + '_connect.json'
filePath = getJsonPath(fileName, __file__)
try:
with open(filePath, 'rt') as f:
return json.load(f)
except IOError:
log = VtLogData()
log.gatewayName = self.gatewayName
log.logContent = u'读取连接配置出错,请检查'
# todo: pop a message box is better
self.onLog(log)
return
#----------------------------------------------------------------------
@abstractmethod
def loadSetting(self):
"""
载入设置在connect的时候会被调用到
"""
pass
########################################################################
class _Order(object):
_lastLocalId = 0
#----------------------------------------------------------------------
def __ini__(self):
def __init__(self):
_Order._lastLocalId += 1
self.localId = str(_Order._lastLocalId)
self.remoteId = None
@ -61,19 +24,21 @@ class _Order(object):
########################################################################
class OkexFutureGateway(VnpyGateway):
class OkexFuturesGateway(VtGateway):
"""OKEX期货交易接口"""
#----------------------------------------------------------------------
def __init__(self, eventEngine, *_, **__): # args, kwargs is needed for compatibility
"""Constructor"""
super(OkexFutureGateway, self).__init__(eventEngine, 'OkexFutureGateway')
super(OkexFuturesGateway, self).__init__(eventEngine, 'OkexFuturesGateway')
self.exchange = constant.EXCHANGE_OKEXFUTURE
self.apiKey = None # type: str
self.apiSecret = None # type: str
self.apiPassphrase = None # type: str
self.restApi = OkexFutureRestClient()
self.restApi = OkexFuturesRestClientV3()
self.webSocket = OkexFutureWebSocketClient()
self.webSocket = OkexFuturesWebSocketClient()
self.webSocket.onTick = self._onTick
self.webSocket.onUserTrade = self._onUserTrade
@ -83,14 +48,30 @@ class OkexFutureGateway(VnpyGateway):
self.tradeID = 0
self._orders = {} # type: Dict[str, _Order]
self._remoteIds = {} # type: Dict[str, _Order]
#----------------------------------------------------------------------
@property
def exchange(self): # type: ()->str
return constant.EXCHANGE_OKEXFUTURE
def readConfig(self):
"""
从json文件中读取设置并将其内容返回为一个dict
:一个一个return:
"""
fileName = self.gatewayName + '_connect.json'
filePath = getJsonPath(fileName, __file__)
try:
with open(filePath, 'rt') as f:
return json.load(f)
except IOError:
log = VtLogData()
log.gatewayName = self.gatewayName
log.logContent = u'读取连接配置出错,请检查'
# todo: pop a message box is better
self.onLog(log)
return None
#----------------------------------------------------------------------
def loadSetting(self):
"""载入设置"""
setting = self.readConfig()
if setting:
"""连接"""
@ -100,6 +81,7 @@ class OkexFutureGateway(VnpyGateway):
# or check by validator
self.apiKey = str(setting['apiKey'])
self.apiSecret = str(setting['secretKey'])
self.apiPassphrase = str(setting['passphrase'])
self.leverRate = setting['leverRate']
self.symbols = setting['symbols']
except KeyError:
@ -111,12 +93,13 @@ class OkexFutureGateway(VnpyGateway):
#----------------------------------------------------------------------
def connect(self):
"""连接"""
self.loadSetting()
self.restApi.init(self.apiKey, self.apiSecret)
self.webSocket.init(self.apiKey, self.apiSecret)
self.restApi.init(self.apiKey, self.apiSecret, self.apiPassphrase)
self.webSocket.init(self.apiKey, self.apiSecret, self.apiPassphrase)
self.restApi.start()
self.webSocket.start()
#----------------------------------------------------------------------
def subscribe(self, subscribeReq): # type: (VtSubscribeReq)->None
"""订阅行情"""
@ -125,63 +108,64 @@ class OkexFutureGateway(VnpyGateway):
#----------------------------------------------------------------------
def _getOrderByLocalId(self, localId):
"""从本地Id获取对应的内部Order对象"""
if localId in self._orders:
return self._orders[localId]
return None
#----------------------------------------------------------------------
def _getOrderByRemoteId(self, remoteId):
"""从Api的OrderId获取对应的内部Order对象"""
if remoteId in self._remoteIds:
return self._remoteIds[remoteId]
return None
#----------------------------------------------------------------------
def _saveRemoteId(self, remoteId, myorder):
"""将remoteId和队友的"""
myorder.remoteId = remoteId
self._remoteIds[remoteId] = myorder
#----------------------------------------------------------------------
def _genereteLocalOrder(self, symbol, price, volume, direction, offset):
def _generateLocalOrder(self, symbol, price, volume, direction, offset):
myorder = _Order()
localId = myorder.localId
self._orders[localId] = myorder
myorder.vtOrder = VtOrderData.createFromGateway(self,
self.exchange,
localId,
symbol,
price,
volume,
direction,
offset)
self.exchange,
localId,
symbol,
price,
volume,
direction,
offset)
return myorder
#----------------------------------------------------------------------
def sendOrder(self, vtRequest): # type: (VtOrderReq)->str
"""发单"""
myorder = self._genereteLocalOrder(vtRequest.symbol,
myorder = self._generateLocalOrder(vtRequest.symbol,
vtRequest.price,
vtRequest.volume,
vtRequest.direction,
vtRequest.offset)
remoteSymbol, remoteContractType = localSymbolToRemote(vtRequest.symbol)
orderType = _orderTypeMap[(vtRequest.priceType, vtRequest.offset)] # 开多、开空、平多、平空
orderType = _orderTypeMap[(vtRequest.direction, vtRequest.offset)] # 开多、开空、平多、平空
userMarketPrice = False
if vtRequest.priceType == constant.PRICETYPE_MARKETPRICE:
userMarketPrice = True
self.restApi.sendOrder(symbol=remoteSymbol,
contractType=remoteContractType,
self.restApi.sendOrder(symbol=vtRequest.symbol,
orderType=orderType,
volume=vtRequest.volume,
price=vtRequest.price,
useMarketPrice=userMarketPrice,
matchPrice=userMarketPrice,
leverRate=self.leverRate,
onSuccess=self._onOrderSent,
extra=None,
onFailed=self._onSendOrderFailed,
extra=myorder,
)
return myorder.localId
#----------------------------------------------------------------------
@ -190,54 +174,39 @@ class OkexFutureGateway(VnpyGateway):
myorder = self._getOrderByLocalId(vtCancel.orderID)
assert myorder is not None, u"理论上是无法取消一个不存在的本地单的"
symbol, contractType = localSymbolToRemote(vtCancel.symbol)
self.restApi.cancelOrder(symbol=symbol,
contractType=contractType,
orderId=myorder.remoteId,
self.restApi.cancelOrder(vtCancel.symbol,
myorder.remoteId,
onSuccess=self._onOrderCanceled,
extra=myorder,
extra=myorder
)
# cancelDict: 不存在的没有localId就没有remoteId没有remoteId何来cancel
#----------------------------------------------------------------------
def queryOrders(self, symbol, contractType,
status): # type: (str, str, OkexFutureOrderStatus)->None
def queryContracts(self):
self.restApi.queryContracts(onSuccess=self._onQueryContracts)
#----------------------------------------------------------------------
def queryOrders(self, symbol, status): # type: (str, OkexFuturesOrderStatus)->None
"""
:param symbol:
:param contractType: 这个参数可以传'THISWEEK', 'NEXTWEEK', 'QUARTER'也可以传OkexFutureContractType
:param status: OkexFutureOrderStatus
:param status: OkexFuturesOrderStatus
:return:
"""
if contractType in _contractTypeMap:
localContractType = contractType
remoteContractType = localContractTypeToRemote(localContractType)
else:
remoteContractType = contractType
localContractType = remoteContractTypeToLocal(remoteContractType)
self.restApi.queryOrders(symbol=symbol,
contractType=remoteContractType,
status=status,
onSuccess=self._onQueryOrders,
extra=localContractType)
)
#----------------------------------------------------------------------
def qryAccount(self):
self.restApi.queryUserInfo(onSuccess=self._onQueryAccount)
self.restApi.queryAccount(onSuccess=self._onQueryAccount)
"""查询账户资金"""
pass
#----------------------------------------------------------------------
def qryPosition(self):
"""查询持仓"""
for remoteSymbol in _remoteSymbols:
for localContractType, remoteContractType in _contractTypeMap.items():
self.restApi.queryPosition(remoteSymbol,
remoteContractType,
onSuccess=self._onQueryPosition,
extra=localContractType
)
self.restApi.queryPositions(onSuccess=self._onQueryPosition)
#----------------------------------------------------------------------
def close(self):
@ -246,19 +215,40 @@ class OkexFutureGateway(VnpyGateway):
self.webSocket.stop()
#----------------------------------------------------------------------
def _onOrderSent(self, remoteId, myorder): #type: (str, _Order)->None
myorder.remoteId = remoteId
def _onOrderSent(self, order, myorder): #type: (OkexFuturesOrderSentInfoV3, _Order)->None
myorder.remoteId = order.orderId
myorder.vtOrder.status = constant.STATUS_NOTTRADED
self._saveRemoteId(remoteId, myorder)
self._saveRemoteId(myorder.remoteId, myorder)
self.onOrder(myorder.vtOrder)
#----------------------------------------------------------------------
@staticmethod
def _onOrderCanceled(myorder): #type: (_Order)->None
def _onSendOrderFailed(order, myorder): #type: (OkexFuturesOrderSentInfoV3, _Order)->None
myorder.vtOrder.status = constant.STATUS_REJECTED
#----------------------------------------------------------------------
@staticmethod
def _onOrderCanceled(myorder): # type: (_Order)->Any
myorder.vtOrder.status = constant.STATUS_CANCELLED
#----------------------------------------------------------------------
def _onQueryContracts(self, contracts, extra): # type: (List[OkexFuturesContractsInfoV3], Any)->None
for contract in contracts:
vtContract = VtContractData.createFromGateway(
gateway=self,
exchange=self.exchange,
symbol=contract.symbol,
productClass=constant.PRODUCT_FUTURES,
priceTick=contract.tickSize,
size=contract.quoteIncrement,
name=contract.symbol,
expiryDate=contract.delivery,
underlyingSymbol=contract.underlyingIndex
)
self.onContract(vtContract)
#----------------------------------------------------------------------
def _onQueryOrders(self, orders, extra): # type: (List[OkexFutureOrder], Any)->None
def _onQueryOrders(self, orders, extra): # type: (List[OkexFuturesOrderDetailV3], Any)->None
localContractType = extra
for order in orders:
remoteId = order.remoteId
@ -277,52 +267,53 @@ class OkexFutureGateway(VnpyGateway):
# 缓存该订单,并推送
symbol = remoteSymbolToLocal(order.symbol, localContractType)
direction, offset = remoteOrderTypeToLocal(order.orderType)
myorder = self._genereteLocalOrder(symbol, order.price, order.volume, direction, offset)
myorder = self._generateLocalOrder(symbol, order.price, order.volume, direction, offset)
myorder.vtOrder.tradedVolume = order.tradedVolume
myorder.remoteId = order.remoteId
self._saveRemoteId(myorder.remoteId, myorder)
self.onOrder(myorder.vtOrder)
#----------------------------------------------------------------------
def _onQueryAccount(self, infos, _): # type: (List[OkexFutureUserInfo], Any)->None
def _onQueryAccount(self, infos, _): # type: (List[OkexFuturesAccountInfoV3], Any)->None
for info in infos:
vtAccount = VtAccountData()
vtAccount.accountID = info.easySymbol
vtAccount.accountID = info.currency
vtAccount.vtAccountID = self.gatewayName + '.' + vtAccount.accountID
vtAccount.balance = info.accountRights
vtAccount.margin = info.keepDeposit
vtAccount.closeProfit = info.profitReal
vtAccount.positionProfit = info.profitUnreal
vtAccount.balance = info.balance
vtAccount.available = info.available
vtAccount.margin = info.hold # todo: is this right?
self.onAccount(vtAccount)
#----------------------------------------------------------------------
def _onQueryPosition(self, posinfo, extra): # type: (OkexFuturePosition, Any)->None
def _onQueryPosition(self, posex, extra): # type: (List[OkexFuturesPositionInfoV3], Any)->None
localContractType = extra
for info in posinfo.holding:
# 先生成多头持仓
pos = VtPositionData.createFromGateway(
for pos in posex:
# 多头持仓
posex = VtPositionData.createFromGateway(
gateway=self,
exchange=self.exchange,
symbol=remoteSymbolToLocal(info.symbol, localContractType),
symbol=remoteSymbolToLocal(pos.symbol, localContractType),
direction=constant.DIRECTION_NET,
position=float(info.buyAmount),
position=float(pos.longQty),
price=pos.longAvgCost,
)
self.onPosition(pos)
self.onPosition(posex)
# 再生存空头持仓
pos = VtPositionData.createFromGateway(
# 空头持仓
posex = VtPositionData.createFromGateway(
gateway=self,
exchange=self.exchange,
symbol=remoteSymbolToLocal(info.symbol, localContractType),
symbol=remoteSymbolToLocal(pos.symbol, localContractType),
direction=constant.DIRECTION_SHORT,
position=float(info.sellAmount),
position=float(pos.shortQty),
price=pos.shortAvgCost,
)
self.onPosition(pos)
self.onPosition(posex)
#----------------------------------------------------------------------
def _onTick(self, info): # type: (OkexFutureTickInfo)->None
def _onTick(self, info): # type: (OkexFuturesTickInfo)->None
uiSymbol = remoteSymbolToLocal(info.symbol, remoteContractTypeToLocal(info.remoteContractType))
self.onTick(VtTickData.createFromGateway(
gateway=self,
@ -337,7 +328,7 @@ class OkexFutureGateway(VnpyGateway):
upperLimit=info.limitHigh,
))
def _onUserTrade(self, info): # type: (OkexFutureUserTradeInfo)->None
def _onUserTrade(self, info): # type: (OkexFuturesUserTradeInfo)->None
tradeID = str(self.tradeID)
self.tradeID += 1
order = self._getOrderByRemoteId(info.remoteId)
@ -380,7 +371,7 @@ def remoteContractTypeToLocal(remoteContractType):
#----------------------------------------------------------------------
def localSymbolToRemote(symbol): # type: (str)->(OkexFutureSymbol, OkexFutureContractType)
def localSymbolToRemote(symbol): # type: (str)->(OkexFuturesSymbol, OkexFuturesContractType)
"""
:return: remoteSymbol, remoteContractType
"""
@ -393,24 +384,24 @@ def remoteSymbolToLocal(remoteSymbol, localContractType):
_orderTypeMap = {
(constant.DIRECTION_LONG, constant.OFFSET_OPEN): OkexFutureOrderType.OpenLong,
(constant.DIRECTION_SHORT, constant.OFFSET_OPEN): OkexFutureOrderType.OpenShort,
(constant.DIRECTION_LONG, constant.OFFSET_CLOSE): OkexFutureOrderType.CloseLong,
(constant.DIRECTION_SHORT, constant.OFFSET_CLOSE): OkexFutureOrderType.CloseShort,
(constant.DIRECTION_LONG, constant.OFFSET_OPEN): OkexFuturesOrderType.OpenLong,
(constant.DIRECTION_SHORT, constant.OFFSET_OPEN): OkexFuturesOrderType.OpenShort,
(constant.DIRECTION_LONG, constant.OFFSET_CLOSE): OkexFuturesOrderType.CloseLong,
(constant.DIRECTION_SHORT, constant.OFFSET_CLOSE): OkexFuturesOrderType.CloseShort,
}
_orderTypeMapReverse = {v: k for k, v in _orderTypeMap.items()}
_contractTypeMap = {
k.upper(): v for k, v in OkexFutureContractType.__dict__.items() if not k.startswith('_')
k.upper(): v for k, v in OkexFuturesContractType.__dict__.items() if not k.startswith('_')
}
_contractTypeMapReverse = {v: k for k, v in _contractTypeMap.items()}
_easySymbols = {
v for k, v in OkexFutureEasySymbol.__dict__.items() if not k.startswith('_')
v for k, v in OkexFuturesEasySymbol.__dict__.items() if not k.startswith('_')
}
_remoteSymbols = {
v for k, v in OkexFutureSymbol.__dict__.items() if not k.startswith('_')
v for k, v in OkexFuturesSymbol.__dict__.items() if not k.startswith('_')
}
# symbols for ui,