[Mod] OkexFuture改名为OkexFutures
[Add] 增加V3版本的OkexRestApi
This commit is contained in:
parent
f17793ed17
commit
b702f77af9
@ -1,2 +0,0 @@
|
||||
from .OkexFutureApi import OkexFutureRestClient, OkexFutureWebSocketClient, OkexFutureSymbol, OkexFutureContractType, OkexFutureOrder, OkexFutureOrderStatus, OkexFuturePosition, \
|
||||
OkexFuturePositionDetail, OkexFuturePriceType, OkexFutureUserInfo
|
@ -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和secretKey(apiSecret)
|
||||
"""
|
||||
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()
|
@ -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('_')}
|
171
vnpy/api/okexfutures/OkexFuturesBase.py
Normal file
171
vnpy/api/okexfutures/OkexFuturesBase.py
Normal 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和secretKey(apiSecret)
|
||||
"""
|
||||
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()
|
6
vnpy/api/okexfutures/__init__.py
Normal file
6
vnpy/api/okexfutures/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .OkexFuturesApi import OkexFuturesAccountInfoV3, OkexFuturesContractType, \
|
||||
OkexFuturesContractsInfoV3, OkexFuturesOrder, OkexFuturesOrderDetailV3, \
|
||||
OkexFuturesOrderSentInfoV3, OkexFuturesOrderStatus, OkexFuturesPosition, \
|
||||
OkexFuturesPositionDetail, OkexFuturesPositionInfoV3, OkexFuturesPriceType, \
|
||||
OkexFuturesRestClientV1, OkexFuturesRestClientV3, OkexFuturesSymbol, OkexFuturesUserInfo, \
|
||||
OkexFuturesWebSocketClient
|
@ -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,
|
Loading…
Reference in New Issue
Block a user