创建通联数据历史数据模块,等待zed的代码。
vn.trader模块开发进行中。
This commit is contained in:
parent
c3d6e0aa3b
commit
1e793c15f9
1
vn.datayes/README.md
Normal file
1
vn.datayes/README.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
To be completed.
|
991
vn.trader/ctpGateway.py
Normal file
991
vn.trader/ctpGateway.py
Normal file
@ -0,0 +1,991 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
from vnctpmd import MdApi
|
||||||
|
from vnctptd import TdApi
|
||||||
|
|
||||||
|
from gateway import *
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class CtpGateway(VtGateway):
|
||||||
|
"""CTP接口"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self, eventEngine):
|
||||||
|
"""Constructor"""
|
||||||
|
super(CtpGateway, self).__init__(eventEngine)
|
||||||
|
|
||||||
|
self.mdApi = None # 行情API
|
||||||
|
self.tdApi = None # 交易API
|
||||||
|
|
||||||
|
self.mdConnected = False # 行情API连接状态
|
||||||
|
self.tdConnected = False # 交易API连接状态
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class CtpMdApi(MdApi):
|
||||||
|
"""CTP行情API实现"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self, gateway, userID, password, brokerID, address):
|
||||||
|
"""Constructor"""
|
||||||
|
super(CtpMdApi, self).__init__()
|
||||||
|
|
||||||
|
self.gateway = gateway # gateway对象
|
||||||
|
self.gatewayName = gateway.gatewayName # gateway对象名称
|
||||||
|
|
||||||
|
self.reqID = EMPTY_INT # 操作请求编号
|
||||||
|
|
||||||
|
self.connectionStatus = False # 连接状态
|
||||||
|
self.loginStatus = False # 登录状态
|
||||||
|
|
||||||
|
self.userID = userID # 账号
|
||||||
|
self.password = password # 密码
|
||||||
|
self.brokerID = brokerID # 经纪商代码
|
||||||
|
self.address = address # 服务器地址
|
||||||
|
|
||||||
|
self.subscribedSymbols = set() # 已订阅合约代码
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onFrontConnected(self):
|
||||||
|
"""服务器连接"""
|
||||||
|
self.connectionStatus = True
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'行情服务器连接成功'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onFrontDisconnected(self, n):
|
||||||
|
"""服务器断开"""
|
||||||
|
self.connectionStatus = False
|
||||||
|
self.loginStatus = False
|
||||||
|
self.gateway.mdConnected = False
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'行情服务器连接断开'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onHeartBeatWarning(self, n):
|
||||||
|
"""心跳报警"""
|
||||||
|
# 因为API的心跳报警比较常被触发,且与API工作关系不大,因此选择忽略
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspError(self, error, n, last):
|
||||||
|
"""错误回报"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUserLogin(self, data, error, n, last):
|
||||||
|
"""登陆回报"""
|
||||||
|
# 如果登录成功,推送日志信息
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
self.loginStatus = True
|
||||||
|
self.gateway.mdConnected = True
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.logContent = u'行情服务器登录完成'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
# 重新订阅之前订阅的合约
|
||||||
|
for subscribeReq in self.subscribedSymbols:
|
||||||
|
self.subscribe(subscribeReq)
|
||||||
|
|
||||||
|
# 否则,推送错误信息
|
||||||
|
else:
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUserLogout(self, data, error, n, last):
|
||||||
|
"""登出回报"""
|
||||||
|
# 如果登出成功,推送日志信息
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
self.loginStatus = False
|
||||||
|
self.gateway.tdConnected = False
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'行情服务器登出完成'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
# 否则,推送错误信息
|
||||||
|
else:
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspSubMarketData(self, data, error, n, last):
|
||||||
|
"""订阅合约回报"""
|
||||||
|
# 通常不在乎订阅错误,选择忽略
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUnSubMarketData(self, data, error, n, last):
|
||||||
|
"""退订合约回报"""
|
||||||
|
# 同上
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnDepthMarketData(self, data):
|
||||||
|
"""行情推送"""
|
||||||
|
tick = VtTickData()
|
||||||
|
|
||||||
|
tick.symbol = data['InstrumentID']
|
||||||
|
tick.vtSymbol = '.'.join([self.gatewayName, tick.symbol])
|
||||||
|
|
||||||
|
tick.lastPrice = data['LastPrice']
|
||||||
|
tick.volume = data['Volume']
|
||||||
|
tick.openInterest = data['OpenInterest']
|
||||||
|
tick.tickTime = '.'.join([data['UpdateTime'], str(data['UpdateMillisec']/100]))
|
||||||
|
|
||||||
|
# CTP只有一档行情
|
||||||
|
tick.bidPrice1 = data['BidPrice1']
|
||||||
|
tick.bidVolume1 = data['BidVolume1']
|
||||||
|
tick.askPrice1 = data['AskPrice1']
|
||||||
|
tick.askVolume1 = data['AskVolume1']
|
||||||
|
|
||||||
|
self.gateway.onTick(tick)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspSubForQuoteRsp(self, data, error, n, last):
|
||||||
|
"""订阅期权询价"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUnSubForQuoteRsp(self, data, error, n, last):
|
||||||
|
"""退订期权询价"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnForQuoteRsp(self, data):
|
||||||
|
"""期权询价推送"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def connect(self):
|
||||||
|
"""初始化连接"""
|
||||||
|
# 如果尚未建立服务器连接,则进行连接
|
||||||
|
if not self.connectionStatus:
|
||||||
|
# 创建C++环境中的API对象,这里传入的参数是需要用来保存.con文件的文件夹路径
|
||||||
|
path = os.getcwd() + '\\temp\\' + self.gatewayName + '\\'
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
self.createFtdcMdApi(path)
|
||||||
|
|
||||||
|
# 注册服务器地址
|
||||||
|
self.registerFront(self.address)
|
||||||
|
|
||||||
|
# 初始化连接,成功会调用onFrontConnected
|
||||||
|
self.init()
|
||||||
|
|
||||||
|
# 若已经连接但尚未登录,则进行登录
|
||||||
|
else:
|
||||||
|
if not self.loginStatus:
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def subscribe(self, subscribeReq):
|
||||||
|
"""订阅合约"""
|
||||||
|
self.subscribeMarketData(subscribeReq.symbol)
|
||||||
|
self.subscribedSymbols.add(subscribeReq)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def login(self):
|
||||||
|
"""登录"""
|
||||||
|
# 如果填入了用户名密码等,则登录
|
||||||
|
if self.userID and self.password and self.brokerID:
|
||||||
|
req = {}
|
||||||
|
req['UserID'] = self.userID
|
||||||
|
req['Password'] = self.password
|
||||||
|
req['BrokerID'] = self.brokerID
|
||||||
|
self.reqID += 1
|
||||||
|
self.reqUserLogin(req, self.reqID)
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class CtpTdApi(TdApi):
|
||||||
|
"""CTP交易API实现"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self, gateway, userID, password, brokerID, address):
|
||||||
|
"""API对象的初始化函数"""
|
||||||
|
super(CtpTdApi, self).__init__()
|
||||||
|
|
||||||
|
self.gateway = gateway # gateway对象
|
||||||
|
self.gatewayName = gateway.gatewayName # gateway对象名称
|
||||||
|
|
||||||
|
self.reqID = EMPTY_INT # 操作请求编号
|
||||||
|
self.orderRef = EMPTY_INT # 订单编号
|
||||||
|
|
||||||
|
self.connectionStatus = False # 连接状态
|
||||||
|
self.loginStatus = False # 登录状态
|
||||||
|
|
||||||
|
self.userID = userID # 账号
|
||||||
|
self.password = password # 密码
|
||||||
|
self.brokerID = brokerID # 经纪商代码
|
||||||
|
self.address = address # 服务器地址
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onFrontConnected(self):
|
||||||
|
"""服务器连接"""
|
||||||
|
self.connectionStatus = True
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'交易服务器连接成功'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
self.login()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onFrontDisconnected(self, n):
|
||||||
|
"""服务器断开"""
|
||||||
|
self.connectionStatus = False
|
||||||
|
self.loginStatus = False
|
||||||
|
self.gateway.tdConnected = False
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'交易服务器连接断开'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onHeartBeatWarning(self, n):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspAuthenticate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUserLogin(self, data, error, n, last):
|
||||||
|
"""登陆回报"""
|
||||||
|
# 如果登录成功,推送日志信息
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
self.loginStatus = True
|
||||||
|
self.gateway.mdConnected = True
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'交易服务器登录完成'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
# 确认结算信息
|
||||||
|
req = {}
|
||||||
|
req['BrokerID'] = self.brokerID
|
||||||
|
req['InvestorID'] = self.userID
|
||||||
|
self.reqID += 1
|
||||||
|
self.reqSettlementInfoConfirm(req, self.reqID)
|
||||||
|
|
||||||
|
# 否则,推送错误信息
|
||||||
|
else:
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gateway
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUserLogout(self, data, error, n, last):
|
||||||
|
"""登出回报"""
|
||||||
|
# 如果登出成功,推送日志信息
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
self.loginStatus = False
|
||||||
|
self.gateway.tdConnected = False
|
||||||
|
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'交易服务器登出完成'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
# 否则,推送错误信息
|
||||||
|
else:
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspUserPasswordUpdate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspTradingAccountPasswordUpdate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspOrderInsert(self, data, error, n, last):
|
||||||
|
"""发单错误(柜台)"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspParkedOrderInsert(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspParkedOrderAction(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspOrderAction(self, data, error, n, last):
|
||||||
|
"""撤单错误(柜台)"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQueryMaxOrderVolume(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspSettlementInfoConfirm(self, data, error, n, last):
|
||||||
|
"""确认结算信息回报"""
|
||||||
|
log = VtLogData()
|
||||||
|
log.gatewayName = self.gatewayName
|
||||||
|
log.logContent = u'结算信息确认完成'
|
||||||
|
self.gateway.onLog(log)
|
||||||
|
|
||||||
|
# 查询合约代码
|
||||||
|
self.reqID += 1
|
||||||
|
self.reqQryInstrument({}, self.reqID)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspRemoveParkedOrder(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspRemoveParkedOrderAction(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspExecOrderInsert(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspExecOrderAction(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspForQuoteInsert(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQuoteInsert(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQuoteAction(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryOrder(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTrade(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInvestorPosition(self, data, error, n, last):
|
||||||
|
"""持仓查询回报"""
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
event = Event(type_=EVENT_POSITION)
|
||||||
|
event.dict_['data'] = data
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
else:
|
||||||
|
event = Event(type_=EVENT_LOG)
|
||||||
|
log = u'持仓查询回报,错误代码:' + unicode(error['ErrorID']) + u',' + u'错误信息:' + error['ErrorMsg'].decode('gbk')
|
||||||
|
event.dict_['log'] = log
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTradingAccount(self, data, error, n, last):
|
||||||
|
"""资金账户查询回报"""
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
event = Event(type_=EVENT_ACCOUNT)
|
||||||
|
event.dict_['data'] = data
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
else:
|
||||||
|
event = Event(type_=EVENT_LOG)
|
||||||
|
log = u'账户查询回报,错误代码:' + unicode(error['ErrorID']) + u',' + u'错误信息:' + error['ErrorMsg'].decode('gbk')
|
||||||
|
event.dict_['log'] = log
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInvestor(self, data, error, n, last):
|
||||||
|
"""投资者查询回报"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTradingCode(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInstrumentMarginRate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInstrumentCommissionRate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryExchange(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryProduct(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInstrument(self, data, error, n, last):
|
||||||
|
"""
|
||||||
|
合约查询回报
|
||||||
|
由于该回报的推送速度极快,因此不适合全部存入队列中处理,
|
||||||
|
选择先储存在一个本地字典中,全部收集完毕后再推送到队列中
|
||||||
|
(由于耗时过长目前使用其他进程读取)
|
||||||
|
"""
|
||||||
|
if error['ErrorID'] == 0:
|
||||||
|
event = Event(type_=EVENT_INSTRUMENT)
|
||||||
|
event.dict_['data'] = data
|
||||||
|
event.dict_['last'] = last
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
else:
|
||||||
|
event = Event(type_=EVENT_LOG)
|
||||||
|
log = u'合约投资者回报,错误代码:' + unicode(error['ErrorID']) + u',' + u'错误信息:' + error['ErrorMsg'].decode('gbk')
|
||||||
|
event.dict_['log'] = log
|
||||||
|
self.__eventEngine.put(event)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryDepthMarketData(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQrySettlementInfo(self, data, error, n, last):
|
||||||
|
"""查询结算信息回报"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTransferBank(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInvestorPositionDetail(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryNotice(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQrySettlementInfoConfirm(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInvestorPositionCombineDetail(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryCFMMCTradingAccountKey(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryEWarrantOffset(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryInvestorProductGroupMargin(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryExchangeMarginRate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryExchangeMarginRateAdjust(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryExchangeRate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQrySecAgentACIDMap(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryOptionInstrTradeCost(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryOptionInstrCommRate(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryExecOrder(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryForQuote(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryQuote(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTransferSerial(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryAccountregister(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspError(self, error, n, last):
|
||||||
|
"""错误回报"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnOrder(self, data):
|
||||||
|
"""报单回报"""
|
||||||
|
# 更新最大报单编号
|
||||||
|
newref = data['OrderRef']
|
||||||
|
self.orderRef = max(self.orderRef, int(newref))
|
||||||
|
|
||||||
|
# 创建报单数据对象
|
||||||
|
order = VtOrderData()
|
||||||
|
order.gatewayName = self.gatewayName
|
||||||
|
|
||||||
|
# 保存代码和报单号
|
||||||
|
order.symbol = data['InstrumentID']
|
||||||
|
order.vtSymbol = '.'.join([self.gatewayName, order.symbol])
|
||||||
|
|
||||||
|
order.orderID = data['OrderRef']
|
||||||
|
order.vtOrderID = '.'.join([self.gatewayName, order.orderID])
|
||||||
|
|
||||||
|
# 方向
|
||||||
|
if data['Direction'] == '0':
|
||||||
|
order.direction = DIRECTION_LONG
|
||||||
|
elif data['Direction'] == '1':
|
||||||
|
order.direction = DIRECTION_SHORT
|
||||||
|
else:
|
||||||
|
order.direction = DIRECTION_UNKNOWN
|
||||||
|
|
||||||
|
# 多空
|
||||||
|
if data['']
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnTrade(self, data):
|
||||||
|
"""成交回报"""
|
||||||
|
# 常规成交事件
|
||||||
|
event1 = Event(type_=EVENT_TRADE)
|
||||||
|
event1.dict_['data'] = data
|
||||||
|
self.__eventEngine.put(event1)
|
||||||
|
|
||||||
|
# 特定合约成交事件
|
||||||
|
event2 = Event(type_=(EVENT_TRADE_CONTRACT+data['InstrumentID']))
|
||||||
|
event2.dict_['data'] = data
|
||||||
|
self.__eventEngine.put(event2)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnOrderInsert(self, data, error):
|
||||||
|
"""发单错误回报(交易所)"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnOrderAction(self, data, error):
|
||||||
|
"""撤单错误回报(交易所)"""
|
||||||
|
err = VtErrorData()
|
||||||
|
err.gatewayName = self.gatewayName
|
||||||
|
err.errorID = error['ErrorID']
|
||||||
|
err.errorMsg = error['ErrorMsg'].decode('gbk')
|
||||||
|
self.gateway.onError(err)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnInstrumentStatus(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnTradingNotice(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnErrorConditionalOrder(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnExecOrder(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnExecOrderInsert(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnExecOrderAction(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnForQuoteInsert(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnQuote(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnQuoteInsert(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnQuoteAction(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnForQuoteRsp(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryContractBank(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryParkedOrder(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryParkedOrderAction(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryTradingNotice(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryBrokerTradingParams(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQryBrokerTradingAlgos(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnFromBankToFutureByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnFromFutureToBankByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromBankToFutureByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromFutureToBankByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnFromBankToFutureByFuture(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnFromFutureToBankByFuture(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromBankToFutureByFutureManual(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromFutureToBankByFutureManual(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnQueryBankBalanceByFuture(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnBankToFutureByFuture(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnFutureToBankByFuture(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnRepealBankToFutureByFutureManual(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnRepealFutureToBankByFutureManual(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onErrRtnQueryBankBalanceByFuture(self, data, error):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromBankToFutureByFuture(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnRepealFromFutureToBankByFuture(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspFromBankToFutureByFuture(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspFromFutureToBankByFuture(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRspQueryBankAccountMoneyByFuture(self, data, error, n, last):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnOpenAccountByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnCancelAccountByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onRtnChangeAccountByBank(self, data):
|
||||||
|
""""""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def login(self, address, userid, password, brokerid):
|
||||||
|
"""连接服务器"""
|
||||||
|
self.__userid = userid
|
||||||
|
self.__password = password
|
||||||
|
self.__brokerid = brokerid
|
||||||
|
|
||||||
|
# 数据重传模式设为从本日开始
|
||||||
|
self.subscribePrivateTopic(0)
|
||||||
|
self.subscribePublicTopic(0)
|
||||||
|
|
||||||
|
# 注册服务器地址
|
||||||
|
self.registerFront(address)
|
||||||
|
|
||||||
|
# 初始化连接,成功会调用onFrontConnected
|
||||||
|
self.init()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def getInstrument(self):
|
||||||
|
"""查询合约"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
self.reqQryInstrument({}, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def getAccount(self):
|
||||||
|
"""查询账户"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
self.reqQryTradingAccount({}, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def getInvestor(self):
|
||||||
|
"""查询投资者"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
self.reqQryInvestor({}, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def getPosition(self):
|
||||||
|
"""查询持仓"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
req = {}
|
||||||
|
req['BrokerID'] = self.__brokerid
|
||||||
|
req['InvestorID'] = self.__userid
|
||||||
|
self.reqQryInvestorPosition(req, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def sendOrder(self, instrumentid, exchangeid, price, pricetype, volume, direction, offset):
|
||||||
|
"""发单"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
req = {}
|
||||||
|
|
||||||
|
req['InstrumentID'] = instrumentid
|
||||||
|
req['OrderPriceType'] = pricetype
|
||||||
|
req['LimitPrice'] = price
|
||||||
|
req['VolumeTotalOriginal'] = volume
|
||||||
|
req['Direction'] = direction
|
||||||
|
req['CombOffsetFlag'] = offset
|
||||||
|
|
||||||
|
self.__orderref = self.__orderref + 1
|
||||||
|
req['OrderRef'] = str(self.__orderref)
|
||||||
|
|
||||||
|
req['InvestorID'] = self.__userid
|
||||||
|
req['UserID'] = self.__userid
|
||||||
|
req['BrokerID'] = self.__brokerid
|
||||||
|
req['CombHedgeFlag'] = defineDict['THOST_FTDC_HF_Speculation'] # 投机单
|
||||||
|
req['ContingentCondition'] = defineDict['THOST_FTDC_CC_Immediately'] # 立即发单
|
||||||
|
req['ForceCloseReason'] = defineDict['THOST_FTDC_FCC_NotForceClose'] # 非强平
|
||||||
|
req['IsAutoSuspend'] = 0 # 非自动挂起
|
||||||
|
req['TimeCondition'] = defineDict['THOST_FTDC_TC_GFD'] # 今日有效
|
||||||
|
req['VolumeCondition'] = defineDict['THOST_FTDC_VC_AV'] # 任意成交量
|
||||||
|
req['MinVolume'] = 1 # 最小成交量为1
|
||||||
|
|
||||||
|
self.reqOrderInsert(req, self.__reqid)
|
||||||
|
|
||||||
|
# 返回订单号,便于某些算法进行动态管理
|
||||||
|
return self.__orderref
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def cancelOrder(self, instrumentid, exchangeid, orderref, frontid, sessionid):
|
||||||
|
"""撤单"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
req = {}
|
||||||
|
|
||||||
|
req['InstrumentID'] = instrumentid
|
||||||
|
req['ExchangeID'] = exchangeid
|
||||||
|
req['OrderRef'] = orderref
|
||||||
|
req['FrontID'] = frontid
|
||||||
|
req['SessionID'] = sessionid
|
||||||
|
|
||||||
|
req['ActionFlag'] = defineDict['THOST_FTDC_AF_Delete']
|
||||||
|
req['BrokerID'] = self.__brokerid
|
||||||
|
req['InvestorID'] = self.__userid
|
||||||
|
|
||||||
|
self.reqOrderAction(req, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def getSettlement(self):
|
||||||
|
"""查询结算信息"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
req = {}
|
||||||
|
|
||||||
|
req['BrokerID'] = self.__brokerid
|
||||||
|
req['InvestorID'] = self.__userid
|
||||||
|
|
||||||
|
self.reqQrySettlementInfo(req, self.__reqid)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def confirmSettlement(self):
|
||||||
|
"""确认结算信息"""
|
||||||
|
self.__reqid = self.__reqid + 1
|
||||||
|
req = {}
|
||||||
|
|
||||||
|
req['BrokerID'] = self.__brokerid
|
||||||
|
req['InvestorID'] = self.__userid
|
||||||
|
|
||||||
|
self.reqSettlementInfoConfirm(req, self.__reqid)
|
196
vn.trader/eventEngine.py
Normal file
196
vn.trader/eventEngine.py
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
# 系统模块
|
||||||
|
from Queue import Queue, Empty
|
||||||
|
from threading import Thread
|
||||||
|
|
||||||
|
# 第三方模块
|
||||||
|
from PyQt4.QtCore import QTimer
|
||||||
|
|
||||||
|
# 自己开发的模块
|
||||||
|
from eventType import *
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class EventEngine:
|
||||||
|
"""
|
||||||
|
事件驱动引擎
|
||||||
|
|
||||||
|
事件驱动引擎中所有的变量都设置为了私有,这是为了防止不小心
|
||||||
|
从外部修改了这些变量的值或状态,导致bug。
|
||||||
|
|
||||||
|
变量说明
|
||||||
|
__queue:私有变量,事件队列
|
||||||
|
__active:私有变量,事件引擎开关
|
||||||
|
__thread:私有变量,事件处理线程
|
||||||
|
__timer:私有变量,计时器
|
||||||
|
__handlers:私有变量,事件处理函数字典
|
||||||
|
|
||||||
|
|
||||||
|
方法说明
|
||||||
|
__run: 私有方法,事件处理线程连续运行用
|
||||||
|
__process: 私有方法,处理事件,调用注册在引擎中的监听函数
|
||||||
|
__onTimer:私有方法,计时器固定事件间隔触发后,向事件队列中存入计时器事件
|
||||||
|
start: 公共方法,启动引擎
|
||||||
|
stop:公共方法,停止引擎
|
||||||
|
register:公共方法,向引擎中注册监听函数
|
||||||
|
unregister:公共方法,向引擎中注销监听函数
|
||||||
|
put:公共方法,向事件队列中存入新的事件
|
||||||
|
|
||||||
|
事件监听函数必须定义为输入参数仅为一个event对象,即:
|
||||||
|
|
||||||
|
函数
|
||||||
|
def func(event)
|
||||||
|
...
|
||||||
|
|
||||||
|
对象方法
|
||||||
|
def method(self, event)
|
||||||
|
...
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""初始化事件引擎"""
|
||||||
|
# 事件队列
|
||||||
|
self.__queue = Queue()
|
||||||
|
|
||||||
|
# 事件引擎开关
|
||||||
|
self.__active = False
|
||||||
|
|
||||||
|
# 事件处理线程
|
||||||
|
self.__thread = Thread(target = self.__run)
|
||||||
|
|
||||||
|
# 计时器,用于触发计时器事件
|
||||||
|
self.__timer = QTimer()
|
||||||
|
self.__timer.timeout.connect(self.__onTimer)
|
||||||
|
|
||||||
|
# 这里的__handlers是一个字典,用来保存对应的事件调用关系
|
||||||
|
# 其中每个键对应的值是一个列表,列表中保存了对该事件进行监听的函数功能
|
||||||
|
self.__handlers = {}
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __run(self):
|
||||||
|
"""引擎运行"""
|
||||||
|
while self.__active == True:
|
||||||
|
try:
|
||||||
|
event = self.__queue.get(block = True, timeout = 1) # 获取事件的阻塞时间设为1秒
|
||||||
|
self.__process(event)
|
||||||
|
except Empty:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __process(self, event):
|
||||||
|
"""处理事件"""
|
||||||
|
# 检查是否存在对该事件进行监听的处理函数
|
||||||
|
if event.type_ in self.__handlers:
|
||||||
|
# 若存在,则按顺序将事件传递给处理函数执行
|
||||||
|
[handler(event) for handler in self.__handlers[event.type_]]
|
||||||
|
|
||||||
|
# 以上语句为Python列表解析方式的写法,对应的常规循环写法为:
|
||||||
|
#for handler in self.__handlers[event.type_]:
|
||||||
|
#handler(event)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __onTimer(self):
|
||||||
|
"""向事件队列中存入计时器事件"""
|
||||||
|
# 创建计时器事件
|
||||||
|
event = Event(type_=EVENT_TIMER)
|
||||||
|
|
||||||
|
# 向队列中存入计时器事件
|
||||||
|
self.put(event)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def start(self):
|
||||||
|
"""引擎启动"""
|
||||||
|
# 将引擎设为启动
|
||||||
|
self.__active = True
|
||||||
|
|
||||||
|
# 启动事件处理线程
|
||||||
|
self.__thread.start()
|
||||||
|
|
||||||
|
# 启动计时器,计时器事件间隔默认设定为1秒
|
||||||
|
self.__timer.start(1000)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def stop(self):
|
||||||
|
"""停止引擎"""
|
||||||
|
# 将引擎设为停止
|
||||||
|
self.__active = False
|
||||||
|
|
||||||
|
# 停止计时器
|
||||||
|
self.__timer.stop()
|
||||||
|
|
||||||
|
# 等待事件处理线程退出
|
||||||
|
self.__thread.join()
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def register(self, type_, handler):
|
||||||
|
"""注册事件处理函数监听"""
|
||||||
|
# 尝试获取该事件类型对应的处理函数列表,若无则创建
|
||||||
|
try:
|
||||||
|
handlerList = self.__handlers[type_]
|
||||||
|
except KeyError:
|
||||||
|
handlerList = []
|
||||||
|
self.__handlers[type_] = handlerList
|
||||||
|
|
||||||
|
# 若要注册的处理器不在该事件的处理器列表中,则注册该事件
|
||||||
|
if handler not in handlerList:
|
||||||
|
handlerList.append(handler)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def unregister(self, type_, handler):
|
||||||
|
"""注销事件处理函数监听"""
|
||||||
|
# 尝试获取该事件类型对应的处理函数列表,若无则忽略该次注销请求
|
||||||
|
try:
|
||||||
|
handlerList = self.handlers[type_]
|
||||||
|
|
||||||
|
# 如果该函数存在于列表中,则移除
|
||||||
|
if handler in handlerList:
|
||||||
|
handlerList.remove(handler)
|
||||||
|
|
||||||
|
# 如果函数列表为空,则从引擎中移除该事件类型
|
||||||
|
if not handlerList:
|
||||||
|
del self.handlers[type_]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def put(self, event):
|
||||||
|
"""向事件队列中存入事件"""
|
||||||
|
self.__queue.put(event)
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class Event:
|
||||||
|
"""事件对象"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self, type_=None):
|
||||||
|
"""Constructor"""
|
||||||
|
self.type_ = type_ # 事件类型
|
||||||
|
self.dict_ = {} # 字典用于保存具体的事件数据
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def test():
|
||||||
|
"""测试函数"""
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from PyQt4.QtCore import QCoreApplication
|
||||||
|
|
||||||
|
def simpletest(event):
|
||||||
|
print u'处理每秒触发的计时器事件:%s' % str(datetime.now())
|
||||||
|
|
||||||
|
app = QCoreApplication(sys.argv)
|
||||||
|
|
||||||
|
ee = EventEngine()
|
||||||
|
ee.register(EVENT_TIMER, simpletest)
|
||||||
|
ee.start()
|
||||||
|
|
||||||
|
app.exec_()
|
||||||
|
|
||||||
|
|
||||||
|
# 直接运行脚本可以进行测试
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
53
vn.trader/eventType.py
Normal file
53
vn.trader/eventType.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
'''
|
||||||
|
本文件仅用于存放对于事件类型常量的定义。
|
||||||
|
|
||||||
|
由于python中不存在真正的常量概念,因此选择使用全大写的变量名来代替常量。
|
||||||
|
这里设计的命名规则以EVENT_前缀开头。
|
||||||
|
|
||||||
|
常量的内容通常选择一个能够代表真实意义的字符串(便于理解)。
|
||||||
|
|
||||||
|
建议将所有的常量定义放在该文件中,便于检查是否存在重复的现象。
|
||||||
|
'''
|
||||||
|
|
||||||
|
# 系统相关
|
||||||
|
EVENT_TIMER = 'eTimer' # 计时器事件,每隔1秒发送一次
|
||||||
|
EVENT_LOG = 'eLog' # 日志事件,全局通用
|
||||||
|
|
||||||
|
# Gateway相关
|
||||||
|
EVENT_TICK = 'eTick.' # TICK行情事件,可后接具体的vtSymbol
|
||||||
|
EVENT_TRADE = 'eTrade.' # 成交回报事件
|
||||||
|
EVENT_ORDER = 'eOrder.' # 报单回报事件
|
||||||
|
EVENT_POSITION = 'ePosition.' # 持仓回报事件
|
||||||
|
EVENT_ACCOUNT = 'eAccount.' # 账户回报事件
|
||||||
|
EVENT_ERROR = 'eError.' # 错误回报事件
|
||||||
|
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def test():
|
||||||
|
"""检查是否存在内容重复的常量定义"""
|
||||||
|
check_dict = {}
|
||||||
|
|
||||||
|
global_dict = globals()
|
||||||
|
|
||||||
|
for key, value in global_dict.items():
|
||||||
|
if '__' not in key: # 不检查python内置对象
|
||||||
|
if value in check_dict:
|
||||||
|
check_dict[value].append(key)
|
||||||
|
else:
|
||||||
|
check_dict[value] = [key]
|
||||||
|
|
||||||
|
for key, value in check_dict.items():
|
||||||
|
if len(value)>1:
|
||||||
|
print u'存在重复的常量定义:' + str(key)
|
||||||
|
for name in value:
|
||||||
|
print name
|
||||||
|
print ''
|
||||||
|
|
||||||
|
print u'测试完毕'
|
||||||
|
|
||||||
|
|
||||||
|
# 直接运行脚本可以进行测试
|
||||||
|
if __name__ == '__main__':
|
||||||
|
test()
|
348
vn.trader/gateway.py
Normal file
348
vn.trader/gateway.py
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
# encoding: UTF-8
|
||||||
|
|
||||||
|
from eventEngine import *
|
||||||
|
|
||||||
|
# 默认空值
|
||||||
|
EMPTY_STRING = ''
|
||||||
|
EMPTY_UNICODE = u''
|
||||||
|
EMPTY_INT = 0
|
||||||
|
EMPTY_FLOAT = 0.0
|
||||||
|
|
||||||
|
# 方向常量
|
||||||
|
DIRECTION_NONE = 'none'
|
||||||
|
DIRECTION_LONG = 'long'
|
||||||
|
DIRECTION_SHORT = 'short'
|
||||||
|
DIRECTION_UNKNOWN = 'unknown'
|
||||||
|
|
||||||
|
# 开平常量
|
||||||
|
OFFSET_NONE = 'none'
|
||||||
|
OFFSET_OPEN = 'open'
|
||||||
|
OFFSET_CLOSE = 'close'
|
||||||
|
OFFSET_UNKNOWN = 'unknown'
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtGateway(object):
|
||||||
|
"""交易接口"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self, eventEngine):
|
||||||
|
"""Constructor"""
|
||||||
|
self.eventEngine = eventEngine
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onTick(self, tick):
|
||||||
|
"""市场行情推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_TICK)
|
||||||
|
event1.dict_['data'] = tick
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
# 特定合约代码的事件
|
||||||
|
event2 = Event(type_=EVENT_TICK+tick.vtSymbol)
|
||||||
|
event2.dict_['data'] = tick
|
||||||
|
self.eventEngine.put(event2)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onTrade(self, trade):
|
||||||
|
"""成交信息推送"""
|
||||||
|
# 因为成交通常都是事后才会知道成交编号,因此只需要推送通用事件
|
||||||
|
event1 = Event(type_=EVENT_TRADE)
|
||||||
|
event1.dict_['data'] = trade
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onOrder(self, order):
|
||||||
|
"""订单变化推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_ORDER)
|
||||||
|
event1.dict_['data'] = order
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
# 特定订单编号的事件
|
||||||
|
event2 = Event(type_=EVENT_ORDER+order.vtOrderID)
|
||||||
|
event2.dict_['data'] = order
|
||||||
|
self.eventEngine.put(event2)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onPosition(self, position):
|
||||||
|
"""持仓信息推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_POSITION)
|
||||||
|
event1.dict_['data'] = position
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
# 特定合约代码的事件
|
||||||
|
event2 = Event(type_=EVENT_POSITION+position.vtPositionName)
|
||||||
|
event2.dict_['data'] = position
|
||||||
|
self.eventEngine.put(event2)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onAccount(self, account):
|
||||||
|
"""账户信息推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_ACCOUNT)
|
||||||
|
event1.dict_['data'] = account
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
# 特定合约代码的事件
|
||||||
|
event2 = Event(type_=EVENT_ACCOUNT+account.vtAccountID)
|
||||||
|
event2.dict_['data'] = account
|
||||||
|
self.eventEngine.put(event2)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onError(self, error):
|
||||||
|
"""错误信息推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_ERROR)
|
||||||
|
event1.dict_['data'] = error
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def onLog(self, log):
|
||||||
|
"""日志推送"""
|
||||||
|
# 通用事件
|
||||||
|
event1 = Event(type_=EVENT_LOG)
|
||||||
|
event1.dict_['data'] = log
|
||||||
|
self.eventEngine.put(event1)
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def connect(self):
|
||||||
|
"""连接"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def subscribe(self):
|
||||||
|
"""订阅行情"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def sendOrder(self):
|
||||||
|
"""发单"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def cancelOrder(self):
|
||||||
|
"""撤单"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def close(self):
|
||||||
|
"""关闭"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtBaseData(object):
|
||||||
|
"""回调函数推送数据的基础类,其他数据类继承于此"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
self.gatewayName = EMPTY_STRING # Gateway名称
|
||||||
|
self.rawData = None # 原始数据
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtTickData(VtBaseData):
|
||||||
|
"""Tick行情数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtTickData, self).__init__()
|
||||||
|
|
||||||
|
# 代码相关
|
||||||
|
self.symbol = EMPTY_STRING # 合约代码
|
||||||
|
self.vtSymbol = EMPTY_STRING # 合约在vt系统中的唯一代码,通常是 Gateway名.合约代码
|
||||||
|
|
||||||
|
# 成交数据
|
||||||
|
self.lastPrice = EMPTY_FLOAT # 最新成交价
|
||||||
|
self.volume = EMPTY_INT # 最新成交量
|
||||||
|
self.openInterest = EMPTY_INT # 持仓量
|
||||||
|
self.tickTime = EMPTY_STRING # 更新时间
|
||||||
|
|
||||||
|
# 五档行情
|
||||||
|
self.bidPrice1 = EMPTY_FLOAT
|
||||||
|
self.bidPrice2 = EMPTY_FLOAT
|
||||||
|
self.bidPrice3 = EMPTY_FLOAT
|
||||||
|
self.bidPrice4 = EMPTY_FLOAT
|
||||||
|
self.bidPrice5 = EMPTY_FLOAT
|
||||||
|
|
||||||
|
self.askPrice1 = EMPTY_FLOAT
|
||||||
|
self.askPrice2 = EMPTY_FLOAT
|
||||||
|
self.askPrice3 = EMPTY_FLOAT
|
||||||
|
self.askPrice4 = EMPTY_FLOAT
|
||||||
|
self.askPrice5 = EMPTY_FLOAT
|
||||||
|
|
||||||
|
self.bidVolume1 = EMPTY_INT
|
||||||
|
self.bidVolume2 = EMPTY_INT
|
||||||
|
self.bidVolume3 = EMPTY_INT
|
||||||
|
self.bidVolume4 = EMPTY_INT
|
||||||
|
self.bidVolume5 = EMPTY_INT
|
||||||
|
|
||||||
|
self.askVolume1 = EMPTY_INT
|
||||||
|
self.askVolume2 = EMPTY_INT
|
||||||
|
self.askVolume3 = EMPTY_INT
|
||||||
|
self.askVolume4 = EMPTY_INT
|
||||||
|
self.askVolume5 = EMPTY_INT
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtTradeData(VtBaseData):
|
||||||
|
"""成交数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtTradeData, self).__init__()
|
||||||
|
|
||||||
|
# 代码编号相关
|
||||||
|
self.symbol = EMPTY_STRING # 合约代码
|
||||||
|
self.vtSymbol = EMPTY_STRING # 合约在vt系统中的唯一代码,通常是 Gateway名.合约代码
|
||||||
|
|
||||||
|
self.tradeID = EMPTY_STRING # 成交编号
|
||||||
|
self.vtTradeID = EMPTY_STRING # 成交在vt系统中的唯一编号,通常是 Gateway名.成交编号
|
||||||
|
|
||||||
|
self.orderID = EMPTY_STRING # 订单编号
|
||||||
|
self.vtOrderID = EMPTY_STRING # 订单在vt系统中的唯一编号,通常是 Gateway名.订单编号
|
||||||
|
|
||||||
|
# 成交相关
|
||||||
|
self.direction = EMPTY_STRING # 成交方向
|
||||||
|
self.offset = EMPTY_STRING # 成交开平仓
|
||||||
|
self.price = EMPTY_FLOAT # 成交价格
|
||||||
|
self.volume = EMPTY_INT # 成交数量
|
||||||
|
self.tradeTime = EMPTY_STRING # 成交时间
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtOrderData(VtBaseData):
|
||||||
|
"""订单数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtOrderData, self).__init__()
|
||||||
|
|
||||||
|
# 代码编号相关
|
||||||
|
self.symbol = EMPTY_STRING # 合约代码
|
||||||
|
self.vtSymbol = EMPTY_STRING # 合约在vt系统中的唯一代码,通常是 Gateway名.合约代码
|
||||||
|
|
||||||
|
self.orderID = EMPTY_STRING # 订单编号
|
||||||
|
self.vtOrderID = EMPTY_STRING # 订单在vt系统中的唯一编号,通常是 Gateway名.订单编号
|
||||||
|
|
||||||
|
# 报单相关
|
||||||
|
self.direction = EMPTY_STRING # 报单方向
|
||||||
|
self.offset = EMPTY_STRING # 报单开平仓
|
||||||
|
self.price = EMPTY_FLOAT # 报单价格
|
||||||
|
self.totalVolume = EMPTY_INT # 报单总数量
|
||||||
|
self.tradedVolume = EMPTY_INT # 报单成交数量
|
||||||
|
self.status = EMPTY_STRING # 报单状态
|
||||||
|
|
||||||
|
self.orderTime = EMPTY_STRING # 发单时间
|
||||||
|
self.cancelTime = EMPTY_STRING # 撤单时间
|
||||||
|
|
||||||
|
# CTP/LTS相关
|
||||||
|
self.frontID = EMPTY_INT # 前置机编号
|
||||||
|
self.sessionID = EMPTY_INT # 连接编号
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtPositionData(VtBaseData):
|
||||||
|
"""持仓数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtPositionData, self).__init__()
|
||||||
|
|
||||||
|
# 代码编号相关
|
||||||
|
self.symbol = EMPTY_STRING # 合约代码
|
||||||
|
self.vtSymbol = EMPTY_STRING # 合约在vt系统中的唯一代码,通常是 Gateway名.合约代码
|
||||||
|
|
||||||
|
# 持仓相关
|
||||||
|
self.direction = EMPTY_STRING # 持仓方向
|
||||||
|
self.position = EMPTY_INT # 持仓量
|
||||||
|
self.frozen = EMPTY_INT # 冻结数量
|
||||||
|
self.price = EMPTY_FLOAT # 持仓均价
|
||||||
|
self.vtPositionName = EMPTY_STRING # 持仓在vt系统中的唯一代码,通常是vtSymbol.方向
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtAccountData(VtBaseData):
|
||||||
|
"""账户数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtAccountData, self).__init__()
|
||||||
|
|
||||||
|
# 账号代码相关
|
||||||
|
self.accountID = EMPTY_STRING # 账户代码
|
||||||
|
self.vtAccountID = EMPTY_STRING # 账户在vt中的唯一代码,通常是 Gateway名.账户代码
|
||||||
|
|
||||||
|
# 代码相关
|
||||||
|
self.preBalance = EMPTY_FLOAT # 昨日账户结算净值
|
||||||
|
self.balance = EMPTY_FLOAT # 账户净值
|
||||||
|
self.available = EMPTY_FLOAT # 可用资金
|
||||||
|
self.commission = EMPTY_FLOAT # 今日手续费
|
||||||
|
self.margin = EMPTY_FLOAT # 保证金占用
|
||||||
|
self.closeProfit = EMPTY_FLOAT # 平仓盈亏
|
||||||
|
self.positionProfit = EMPTY_FLOAT # 持仓盈亏
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtErrorData(VtBaseData):
|
||||||
|
"""错误数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtErrorData, self).__init__()
|
||||||
|
|
||||||
|
self.errorID = EMPTY_STRING # 错误代码
|
||||||
|
self.errorMsg = EMPTY_UNICODE # 错误信息
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtLogData(VtBaseData):
|
||||||
|
"""日志数据类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtLogData, self).__init__()
|
||||||
|
|
||||||
|
self.logContent = EMPTY_UNICODE # 日志信息
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtContractData(VtBaseData):
|
||||||
|
"""合约详细信息类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
super(VtBaseData, self).__init__()
|
||||||
|
|
||||||
|
self.priceTick = EMPTY_FLOAT
|
||||||
|
|
||||||
|
|
||||||
|
########################################################################
|
||||||
|
class VtSubscribeReq:
|
||||||
|
"""订阅行情时传入的对象类"""
|
||||||
|
|
||||||
|
#----------------------------------------------------------------------
|
||||||
|
def __init__(self):
|
||||||
|
"""Constructor"""
|
||||||
|
self.symbol = EMPTY_STRING
|
||||||
|
self.exchange = EMPTY_STRING
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
5
vn.trader/test.json
Normal file
5
vn.trader/test.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"1": 1,
|
||||||
|
"b": 2,
|
||||||
|
"c": "_____"
|
||||||
|
}
|
BIN
vn.trader/thostmduserapi.dll
Normal file
BIN
vn.trader/thostmduserapi.dll
Normal file
Binary file not shown.
BIN
vn.trader/thosttraderapi.dll
Normal file
BIN
vn.trader/thosttraderapi.dll
Normal file
Binary file not shown.
BIN
vn.trader/vnctpmd.pyd
Normal file
BIN
vn.trader/vnctpmd.pyd
Normal file
Binary file not shown.
BIN
vn.trader/vnctptd.pyd
Normal file
BIN
vn.trader/vnctptd.pyd
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user