From 8c167c392e980dbdb656f513e9ec948e88cf9b3b Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 12 Jun 2017 17:14:34 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0VnTrader=E4=B8=AD=E7=9A=84?= =?UTF-8?q?=E4=BB=B7=E5=B7=AE=E4=BA=A4=E6=98=93=E6=A8=A1=E5=9D=97=EF=BC=8C?= =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=BB=B7=E5=B7=AE=E8=A1=8C=E6=83=85=E7=9A=84?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97=E5=92=8C=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/VnTrader/run.py | 3 +- vnpy/trader/app/ctaStrategy/ctaBase.py | 4 + vnpy/trader/app/dataRecorder/drBase.py | 2 + vnpy/trader/app/spreadTrading/ST_setting.json | 64 +++++++ vnpy/trader/app/spreadTrading/__init__.py | 10 + vnpy/trader/app/spreadTrading/st.ico | Bin 0 -> 45118 bytes vnpy/trader/app/spreadTrading/stBase.py | 162 ++++++++++++++++ vnpy/trader/app/spreadTrading/stEngine.py | 176 ++++++++++++++++++ vnpy/trader/app/spreadTrading/uiStWidget.py | 97 ++++++++++ vnpy/trader/gateway/ctpGateway/ctpGateway.py | 2 - .../trader/gateway/windGateway/windGateway.py | 3 + vnpy/trader/vtEvent.py | 12 +- vnpy/trader/vtFunction.py | 15 ++ 13 files changed, 536 insertions(+), 14 deletions(-) create mode 100644 vnpy/trader/app/spreadTrading/ST_setting.json create mode 100644 vnpy/trader/app/spreadTrading/__init__.py create mode 100644 vnpy/trader/app/spreadTrading/st.ico create mode 100644 vnpy/trader/app/spreadTrading/stBase.py create mode 100644 vnpy/trader/app/spreadTrading/stEngine.py create mode 100644 vnpy/trader/app/spreadTrading/uiStWidget.py diff --git a/examples/VnTrader/run.py b/examples/VnTrader/run.py index e174bd53..22c5a54a 100644 --- a/examples/VnTrader/run.py +++ b/examples/VnTrader/run.py @@ -18,7 +18,7 @@ from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, # 加载上层应用 from vnpy.trader.app import (riskManager, dataRecorder, - ctaStrategy) + ctaStrategy, spreadTrading) #---------------------------------------------------------------------- @@ -45,6 +45,7 @@ def main(): me.addApp(riskManager) me.addApp(dataRecorder) me.addApp(ctaStrategy) + me.addApp(spreadTrading) # 创建主窗口 mw = MainWindow(me, ee) diff --git a/vnpy/trader/app/ctaStrategy/ctaBase.py b/vnpy/trader/app/ctaStrategy/ctaBase.py index 1bc92b79..10e257ad 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBase.py +++ b/vnpy/trader/app/ctaStrategy/ctaBase.py @@ -33,6 +33,10 @@ MINUTE_DB_NAME = 'VnTrader_1Min_Db' ENGINETYPE_BACKTESTING = 'backtesting' # 回测 ENGINETYPE_TRADING = 'trading' # 实盘 +# CTA模块事件 +EVENT_CTA_LOG = 'eCtaLog' # CTA相关的日志事件 +EVENT_CTA_STRATEGY = 'eCtaStrategy.' # CTA策略状态变化事件 + # CTA引擎中涉及的数据类定义 from vnpy.trader.vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT diff --git a/vnpy/trader/app/dataRecorder/drBase.py b/vnpy/trader/app/dataRecorder/drBase.py index cddfd90a..43c4f05d 100644 --- a/vnpy/trader/app/dataRecorder/drBase.py +++ b/vnpy/trader/app/dataRecorder/drBase.py @@ -12,6 +12,8 @@ TICK_DB_NAME = 'VnTrader_Tick_Db' DAILY_DB_NAME = 'VnTrader_Daily_Db' MINUTE_DB_NAME = 'VnTrader_1Min_Db' +# 行情记录模块事件 +EVENT_DATARECORDER_LOG = 'eDataRecorderLog' # 行情记录日志更新事件 # CTA引擎中涉及的数据类定义 from vnpy.trader.vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT diff --git a/vnpy/trader/app/spreadTrading/ST_setting.json b/vnpy/trader/app/spreadTrading/ST_setting.json new file mode 100644 index 00000000..b2edf2c1 --- /dev/null +++ b/vnpy/trader/app/spreadTrading/ST_setting.json @@ -0,0 +1,64 @@ +[ + { + "name": "IF.07-09", + + "activeLeg": + { + "vtSymbol": "IF1707", + "ratio": 1, + "multiplier": 1.0, + "payup": 2 + }, + + "passiveLegs": [ + { + "vtSymbol": "IF1709", + "ratio": -1, + "multiplier": -1.0, + "payup": 2 + } + ] + }, + + { + "name": "IH.07-09", + + "activeLeg": + { + "vtSymbol": "IH1707", + "ratio": 1, + "multiplier": 1.0, + "payup": 2 + }, + + "passiveLegs": [ + { + "vtSymbol": "IH1709", + "ratio": -1, + "multiplier": -1.0, + "payup": 2 + } + ] + }, + + { + "name": "IC.07-09", + + "activeLeg": + { + "vtSymbol": "IC1707", + "ratio": 1, + "multiplier": 1.0, + "payup": 2 + }, + + "passiveLegs": [ + { + "vtSymbol": "IC1709", + "ratio": -1, + "multiplier": -1.0, + "payup": 2 + } + ] + } +] \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/__init__.py b/vnpy/trader/app/spreadTrading/__init__.py new file mode 100644 index 00000000..722ecaf7 --- /dev/null +++ b/vnpy/trader/app/spreadTrading/__init__.py @@ -0,0 +1,10 @@ +# encoding: UTF-8 + +from .stEngine import StEngine +from .uiStWidget import StManager + +appName = 'SpreadTrading' +appDisplayName = u'价差交易' +appEngine = StEngine +appWidget = StManager +appIco = 'st.ico' \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/st.ico b/vnpy/trader/app/spreadTrading/st.ico new file mode 100644 index 0000000000000000000000000000000000000000..a66c245e0dc6c55842f923177515889ca5b9ce4e GIT binary patch literal 45118 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 literal 0 HcmV?d00001 diff --git a/vnpy/trader/app/spreadTrading/stBase.py b/vnpy/trader/app/spreadTrading/stBase.py new file mode 100644 index 00000000..9297b764 --- /dev/null +++ b/vnpy/trader/app/spreadTrading/stBase.py @@ -0,0 +1,162 @@ +# encoding: UTF-8 + +from __future__ import division + +from math import floor +from datetime import datetime + +from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, + EMPTY_STRING, EMPTY_UNICODE) + + + +EVENT_SPREADTRADING_TICK = 'eSpreadTradingTick.' + + + +######################################################################## +class StLeg(object): + """""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.vtSymbol = EMPTY_STRING # 代码 + self.ratio = EMPTY_INT # 实际交易时的比例 + self.multiplier = EMPTY_FLOAT # 计算价差时的乘数 + self.payup = EMPTY_INT # 对冲时的超价tick + + self.bidPrice = EMPTY_FLOAT + self.askPrice = EMPTY_FLOAT + self.bidVolume = EMPTY_INT + self.askVolume = EMPTY_INT + + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + +######################################################################## +class StSpread(object): + """""" + + #---------------------------------------------------------------------- + def __init__(self): + """Constructor""" + self.name = EMPTY_UNICODE # 名称 + self.symbol = EMPTY_STRING # 代码(基于组成腿计算) + + self.activeLeg = None # 主动腿 + self.passiveLegs = [] # 被动腿(支持多条) + self.allLegs = [] # 所有腿 + + self.bidPrice = EMPTY_FLOAT + self.askPrice = EMPTY_FLOAT + self.bidVolume = EMPTY_INT + self.askVolume = EMPTY_INT + self.time = EMPTY_STRING + + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + #---------------------------------------------------------------------- + def initSpread(self): + """初始化价差""" + # 价差最少要有一条主动腿 + if not self.activeLeg: + return + + # 生成所有腿列表 + self.allLegs.append(self.activeLeg) + self.allLegs.extend(self.passiveLegs) + + # 生成价差代码 + legSymbolList = [] + + for leg in self.allLegs: + if leg.multiplier >= 0: + legSymbol = '+%s*%s' %(leg.multiplier, leg.vtSymbol) + else: + legSymbol = '%s*%s' %(leg.multiplier, leg.vtSymbol) + legSymbolList.append(legSymbol) + + self.symbol = ''.join(legSymbolList) + + #---------------------------------------------------------------------- + def calculatePrice(self): + """计算价格""" + # 清空价格和委托量数据 + self.bidPrice = EMPTY_FLOAT + self.askPrice = EMPTY_FLOAT + self.askVolume = EMPTY_INT + self.bidVolume = EMPTY_INT + + # 遍历价差腿列表 + for n, leg in enumerate(self.allLegs): + # 计算价格 + if leg.multiplier > 0: + self.bidPrice += leg.bidPrice * leg.multiplier + self.askPrice += leg.askPrice * leg.multiplier + else: + self.bidPrice += leg.askPrice * leg.multiplier + self.askPrice += leg.bidPrice * leg.multiplier + + # 计算报单量 + if leg.ratio > 0: + legAdjustedBidVolume = floor(leg.bidVolume / leg.ratio) + legAdjustedAskVolume = floor(leg.askVolume / leg.ratio) + else: + legAdjustedBidVolume = floor(leg.askVolume / abs(leg.ratio)) + legAdjustedAskVolume = floor(leg.bidVolume / abs(leg.ratio)) + + if n == 0: + self.bidVolume = legAdjustedBidVolume # 对于第一条腿,直接初始化 + self.askVolume = legAdjustedAskVolume + else: + self.bidVolume = min(self.bidVolume, legAdjustedBidVolume) # 对于后续的腿,价差可交易报单量取较小值 + self.askVolume = min(self.askVolume, legAdjustedAskVolume) + + # 更新时间 + self.time = datetime.now().strftime('%H:%M:%S.%f')[:-3] + + #---------------------------------------------------------------------- + def calculatePos(self): + """计算持仓""" + # 清空持仓数据 + self.longPos = EMPTY_INT + self.shortPos = EMPTY_INT + self.netPos = EMPTY_INT + + # 遍历价差腿列表 + for n, leg in enumerate(self.allLegs): + if leg.ratio > 0: + legAdjustedLongPos = floor(leg.longPos / leg.ratio) + legAdjustedShortPos = floor(leg.shortPos / leg.ratio) + else: + legAdjustedLongPos = floor(leg.shortPos / abs(leg.ratio)) + legAdjustedShortPos = floor(leg.longPos / abs(leg.ratio)) + + if n == 0: + self.longPos = legAdjustedLongPos + self.shortPos = legAdjustedShortPos + else: + self.longPos = min(self.longPos, legAdjustedLongPos) + self.shortPos = min(self.shortPos, legAdjustedShortPos) + + # 计算净仓位 + self.netPos = self.longPos - self.shortPos + + #---------------------------------------------------------------------- + def addActiveLeg(self, leg): + """添加主动腿""" + self.activeLeg = leg + + #---------------------------------------------------------------------- + def addPassiveLeg(self, leg): + """添加被动腿""" + self.passiveLegs.append(leg) + + + + \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py new file mode 100644 index 00000000..d5f38a9b --- /dev/null +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -0,0 +1,176 @@ +# encoding: UTF-8 + +import json +from copy import copy + +from vnpy.event import Event +from vnpy.trader.vtFunction import getJsonPath +from vnpy.trader.vtEvent import EVENT_TICK, EVENT_TRADE, EVENT_POSITION +from vnpy.trader.vtObject import VtSubscribeReq + +from .stBase import StLeg, StSpread, EVENT_SPREADTRADING_TICK + + +######################################################################## +class StEngine(object): + """""" + settingFileName = 'ST_setting.json' + settingFilePath = getJsonPath(settingFileName, __file__) + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine): + """Constructor""" + self.mainEngine = mainEngine + self.eventEngine = eventEngine + + # 腿、价差相关字典 + self.legDict = {} # vtSymbol:StLeg + self.spreadDict = {} # name:StSpread + self.vtSymbolSpreadDict = {} # vtSymbol:StSpread + + self.registerEvent() + + #---------------------------------------------------------------------- + def loadSetting(self): + """加载配置""" + with open(self.settingFilePath) as f: + l = json.load(f) + + for setting in l: + self.createSpread(setting) + + #---------------------------------------------------------------------- + def saveSetting(self): + """保存配置""" + with open(self.settingFilePath) as f: + pass + + #---------------------------------------------------------------------- + def createSpread(self, setting): + """创建价差""" + result = False + msg = '' + + # 检查价差重名 + if setting['name'] in self.spreadDict: + msg = u'%s价差重名' %setting['name'] + return result, msg + + # 检查腿是否已使用 + l = [] + l.append(setting['activeLeg']['vtSymbol']) + for d in setting['passiveLegs']: + l.append(d['vtSymbol']) + + for vtSymbol in l: + if vtSymbol in self.vtSymbolSpreadDict: + existingSpread = self.vtSymbolSpreadDict[vtSymbol] + msg = u'%s合约已经存在于%s价差中' %(vtSymbol, existingSpread.name) + return result, msg + + # 创建价差 + spread = StSpread() + spread.name = setting['name'] + self.spreadDict[spread.name] = spread + + # 创建主动腿 + activeSetting = setting['activeLeg'] + + activeLeg = StLeg() + activeLeg.vtSymbol = activeSetting['vtSymbol'] + activeLeg.ratio = activeSetting['ratio'] + activeLeg.multiplier = activeSetting['multiplier'] + activeLeg.payup = activeSetting['payup'] + + spread.addActiveLeg(activeLeg) + self.legDict[activeLeg.vtSymbol] = activeLeg + self.vtSymbolSpreadDict[activeLeg.vtSymbol] = spread + + self.subscribeMarketData(activeLeg.vtSymbol) + + # 创建被动腿 + passiveSettingList = setting['passiveLegs'] + passiveLegList = [] + + for d in passiveSettingList: + passiveLeg = StLeg() + passiveLeg.vtSymbol = d['vtSymbol'] + passiveLeg.ratio = d['ratio'] + passiveLeg.multiplier = d['multiplier'] + passiveLeg.payup = d['payup'] + + spread.addPassiveLeg(passiveLeg) + self.legDict[passiveLeg.vtSymbol] = passiveLeg + self.vtSymbolSpreadDict[passiveLeg.vtSymbol] = spread + + self.subscribeMarketData(passiveLeg.vtSymbol) + + # 初始化价差 + spread.initSpread() + + # 返回结果 + result = True + msg = u'%s价差创建成功' %spread.name + return result, msg + + #---------------------------------------------------------------------- + def processTickEvent(self, event): + """处理行情推送""" + # 检查行情是否需要处理 + tick = event.dict_['data'] + if tick.vtSymbol not in self.legDict: + return + + # 更新腿价格 + leg = self.legDict[tick.vtSymbol] + leg.bidPrice = tick.bidPrice1 + leg.askPrice = tick.askPrice1 + leg.bidVolume = tick.bidVolume1 + leg.askVolume = tick.askVolume1 + + # 更新价差价格 + spread = self.vtSymbolSpreadDict[tick.vtSymbol] + spread.calculatePrice() + + # 推送价差更新 + newSpread = copy(spread) + event = Event(EVENT_SPREADTRADING_TICK) + event.dict_['data'] = newSpread + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def processTradeEvent(self, event): + """""" + pass + + #---------------------------------------------------------------------- + def processPositionEvent(self, event): + """""" + pass + + #---------------------------------------------------------------------- + def registerEvent(self): + """""" + self.eventEngine.register(EVENT_TICK, self.processTickEvent) + self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) + self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) + + #---------------------------------------------------------------------- + def subscribeMarketData(self, vtSymbol): + """订阅行情""" + contract = self.mainEngine.getContract(vtSymbol) + if not contract: + return + + req = VtSubscribeReq() + req.symbol = contract.symbol + req.exchange = contract.exchange + + self.mainEngine.subscribe(req, contract.gatewayName) + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + pass + + \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py new file mode 100644 index 00000000..c0cd5b21 --- /dev/null +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -0,0 +1,97 @@ +# encoding: UTF-8 + +from collections import OrderedDict + +from vnpy.trader.uiQt import QtWidgets +from vnpy.trader.uiBasicWidget import (BasicMonitor, BasicCell, + AskCell, BidCell, BASIC_FONT) + +from .stBase import EVENT_SPREADTRADING_TICK + + + +######################################################################## +class StTickMonitor(BasicMonitor): + """""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine, parent=None): + """Constructor""" + super(StTickMonitor, self).__init__(mainEngine, eventEngine, parent) + + # 设置表头有序字典 + d = OrderedDict() + d['name'] = {'chinese':u'价差名称', 'cellType':BasicCell} + d['bidPrice'] = {'chinese':u'买价', 'cellType':BidCell} + d['bidVolume'] = {'chinese':u'买量', 'cellType':BidCell} + d['askPrice'] = {'chinese':u'卖价', 'cellType':AskCell} + d['askVolume'] = {'chinese':u'卖量', 'cellType':AskCell} + d['time'] = {'chinese':u'时间', 'cellType':BasicCell} + d['symbol'] = {'chinese':u'代码', 'cellType':BasicCell} + self.setHeaderDict(d) + + # 设置数据键 + self.setDataKey('name') + + # 设置监控事件类型 + self.setEventType(EVENT_SPREADTRADING_TICK) + + # 设置字体 + self.setFont(BASIC_FONT) + + # 初始化表格 + self.initTable() + + # 注册事件监听 + self.registerEvent() + + +######################################################################## +class StManager(QtWidgets.QWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, stEngine, eventEngine, parent=None): + """Constructor""" + super(StManager, self).__init__(parent) + + self.stEngine = stEngine + self.mainEngine = stEngine.mainEngine + self.eventEngine = eventEngine + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setWindowTitle(u'价差交易') + + # 创建按钮 + buttonLoadSetting = QtWidgets.QPushButton(u'加载配置') + + buttonLoadSetting.clicked.connect(self.stEngine.loadSetting) + + # 创建组件 + tickMonitor = StTickMonitor(self.mainEngine, self.eventEngine) + + # 设置布局 + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(buttonLoadSetting) + hbox.addStretch() + + vbox = QtWidgets.QVBoxLayout() + vbox.addLayout(hbox) + vbox.addWidget(tickMonitor) + + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def show(self): + """重载显示""" + self.showMaximized() + + + + + + \ No newline at end of file diff --git a/vnpy/trader/gateway/ctpGateway/ctpGateway.py b/vnpy/trader/gateway/ctpGateway/ctpGateway.py index 619eacea..2294cd21 100644 --- a/vnpy/trader/gateway/ctpGateway/ctpGateway.py +++ b/vnpy/trader/gateway/ctpGateway/ctpGateway.py @@ -91,8 +91,6 @@ class CtpGateway(VtGateway): self.tdConnected = False # 交易API连接状态 self.qryEnabled = False # 循环查询 - - self.requireAuthentication = False #---------------------------------------------------------------------- def connect(self): diff --git a/vnpy/trader/gateway/windGateway/windGateway.py b/vnpy/trader/gateway/windGateway/windGateway.py index 108643d1..d1307841 100644 --- a/vnpy/trader/gateway/windGateway/windGateway.py +++ b/vnpy/trader/gateway/windGateway/windGateway.py @@ -26,6 +26,9 @@ exchangeMap[EXCHANGE_CZCE] = 'CZC' exchangeMap[EXCHANGE_UNKNOWN] = '' exchangeMapReverse = {v:k for k,v in exchangeMap.items()} +# Wind接口相关事件 +EVENT_WIND_CONNECTREQ = 'eWindConnectReq' # Wind接口请求连接事件 + ######################################################################## class WindGateway(VtGateway): diff --git a/vnpy/trader/vtEvent.py b/vnpy/trader/vtEvent.py index b26175fb..4c5c67ef 100644 --- a/vnpy/trader/vtEvent.py +++ b/vnpy/trader/vtEvent.py @@ -17,14 +17,4 @@ EVENT_ORDER = 'eOrder.' # 报单回报事件 EVENT_POSITION = 'ePosition.' # 持仓回报事件 EVENT_ACCOUNT = 'eAccount.' # 账户回报事件 EVENT_CONTRACT = 'eContract.' # 合约基础信息回报事件 -EVENT_ERROR = 'eError.' # 错误回报事件 - -# CTA模块相关 -EVENT_CTA_LOG = 'eCtaLog' # CTA相关的日志事件 -EVENT_CTA_STRATEGY = 'eCtaStrategy.' # CTA策略状态变化事件 - -# 行情记录模块相关 -EVENT_DATARECORDER_LOG = 'eDataRecorderLog' # 行情记录日志更新事件 - -# Wind接口相关 -EVENT_WIND_CONNECTREQ = 'eWindConnectReq' # Wind接口请求连接事件 \ No newline at end of file +EVENT_ERROR = 'eError.' # 错误回报事件 \ No newline at end of file diff --git a/vnpy/trader/vtFunction.py b/vnpy/trader/vtFunction.py index 189d1d82..32bc99a4 100644 --- a/vnpy/trader/vtFunction.py +++ b/vnpy/trader/vtFunction.py @@ -64,5 +64,20 @@ def getTempPath(name): path = os.path.join(tempPath, name) return path +#---------------------------------------------------------------------- +def getJsonPath(name, moduleFile): + """ + 获取JSON配置文件的路径: + 1. 优先从当前工作目录查找JSON文件 + 2. 若无法找到则前往模块所在目录查找 + """ + currentFolder = os.getcwd() + currentJsonPath = os.path.join(currentFolder, name) + if os.path.isfile(currentJsonPath): + return currentJsonPath + + moduleFolder = os.path.abspath(os.path.dirname(moduleFile)) + moduleJsonPath = os.path.join(moduleFolder, '.', name) + return moduleJsonPath