From 2898169b9bb563f7c2d472a4d2f79cca1bb65b6b Mon Sep 17 00:00:00 2001 From: LiuXiangyu Date: Sun, 16 Apr 2017 11:14:51 +0800 Subject: [PATCH 01/29] fix build.sh error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix build.sh error: cp: 目标 '../../vn.trader/ctpGateway/ ' 不是目录 --- vn.api/vn.ctp/build.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vn.api/vn.ctp/build.sh b/vn.api/vn.ctp/build.sh index 83858574..ed8475f8 100644 --- a/vn.api/vn.ctp/build.sh +++ b/vn.api/vn.ctp/build.sh @@ -12,6 +12,6 @@ cmake .. make VERBOSE=1 -j 1 ln -fs `pwd`/lib/vnctpmd.so ../vnctpmd/test/vnctpmd.so ln -fs `pwd`/lib/vnctptd.so ../vnctptd/test/vnctptd.so -cp ../vnctpmd/test/vnctpmd.* ../../vn.trader/ctpGateway/ -cp ../vnctptd/test/vnctptd.* ../../vn.trader/ctpGateway/ +cp ../vnctpmd/test/vnctpmd.* ../../../vn.trader/gateway/ctpGateway/ +cp ../vnctptd/test/vnctptd.* ../../../vn.trader/gateway/ctpGateway/ popd From 9870e34eb05aadc3394033345e4cdb6d01d4c199 Mon Sep 17 00:00:00 2001 From: chenxy123 Date: Wed, 7 Jun 2017 22:00:14 +0800 Subject: [PATCH 02/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=B8=AD=E4=BF=A1?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E8=8B=B1=E6=96=87=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README-en.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README-en.md b/README-en.md index 95bdd77f..a808f598 100644 --- a/README-en.md +++ b/README-en.md @@ -37,7 +37,8 @@ Using the vn.py project, institutional investors and professional traders, such - LTS(vn.lts) - QDP(vn.qdp) - + + - CSHSHLP(vn.cshshlp) **Chinese Precious Metal Market** From d89245a1c9654ad56d2bc3f6b1c6b29dd80c45c6 Mon Sep 17 00:00:00 2001 From: bukeyi Date: Fri, 9 Jun 2017 18:25:43 +0800 Subject: [PATCH 03/29] update new pip source --- docker/Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docker/Dockerfile b/docker/Dockerfile index d6ba79e6..fa6177eb 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -61,7 +61,7 @@ RUN echo "开始配置系vnpy环境" \ && echo "更改 pip 源" \ && mkdir ~/.pip \ && echo "[global]" >> ~/.pip/pip.conf \ - && echo "index-url = http://pypi.douban.com/simple" >> ~/.pip/pip.conf \ + && echo "index-url = https://pypi.doubanio.com/simple/" >> ~/.pip/pip.conf \ && echo "使用 pip 安装 python 库" \ && pip install TA-Lib \ && conda clean -ay \ @@ -70,4 +70,4 @@ RUN echo "开始配置系vnpy环境" \ WORKDIR /srv/vnpy # 暂时不设置入口点,否则不能使用 -it 交互模式 -# ENTRYPOINT python /srv/vnpy/vn.trader/vtServer.py \ No newline at end of file +# ENTRYPOINT python /srv/vnpy/vn.trader/vtServer.py From 8c167c392e980dbdb656f513e9ec948e88cf9b3b Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 12 Jun 2017 17:14:34 +0800 Subject: [PATCH 04/29] =?UTF-8?q?=E6=B7=BB=E5=8A=A0VnTrader=E4=B8=AD?= =?UTF-8?q?=E7=9A=84=E4=BB=B7=E5=B7=AE=E4=BA=A4=E6=98=93=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=EF=BC=8C=E5=AE=8C=E6=88=90=E4=BB=B7=E5=B7=AE=E8=A1=8C=E6=83=85?= =?UTF-8?q?=E7=9A=84=E8=87=AA=E5=8A=A8=E8=AE=A1=E7=AE=97=E5=92=8C=E6=98=BE?= =?UTF-8?q?=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 From e6762a63e3e289cebbd4d8e2cbd9cfcfaf7e7302 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 13 Jun 2017 14:03:16 +0800 Subject: [PATCH 05/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0wind=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=9C=A8=E6=9C=AA=E8=BF=9E=E6=8E=A5=E6=97=B6=E7=9A=84=E8=AE=A2?= =?UTF-8?q?=E9=98=85=E8=AF=B7=E6=B1=82=E7=BC=93=E5=AD=98=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../trader/gateway/windGateway/windGateway.py | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/vnpy/trader/gateway/windGateway/windGateway.py b/vnpy/trader/gateway/windGateway/windGateway.py index d1307841..279eac5c 100644 --- a/vnpy/trader/gateway/windGateway/windGateway.py +++ b/vnpy/trader/gateway/windGateway/windGateway.py @@ -85,6 +85,9 @@ class WindGateway(VtGateway): # 而vt中的tick是完整更新,因此需要本地维护一个所有字段的快照 self.tickDict = {} + # 订阅请求缓存 + self.subscribeBufferDict = {} + self.registerEvent() #---------------------------------------------------------------------- @@ -100,8 +103,14 @@ class WindGateway(VtGateway): def subscribe(self, subscribeReq): """订阅行情""" windSymbol = '.'.join([subscribeReq.symbol, exchangeMap[subscribeReq.exchange]]) - data = self.w.wsq(windSymbol, self.wsqParam, func=self.wsqCallBack) - + + # 若已经连接则直接订阅 + if self.connected: + data = self.w.wsq(windSymbol, self.wsqParam, func=self.wsqCallBack) + # 否则缓存在字典中 + else: + self.subscribeBufferDict[windSymbol] = subscribeReq + #---------------------------------------------------------------------- def sendOrder(self, orderReq): """发单""" @@ -160,7 +169,7 @@ class WindGateway(VtGateway): self.tickDict[windSymbol] = tick dt = data.Times[0] - tick.time = dt.strftime('%H:%M:%S') + tick.time = dt.strftime('%H:%M:%S.%f') tick.date = dt.strftime('%Y%m%d') # 采用遍历的形式读取数值 @@ -186,6 +195,11 @@ class WindGateway(VtGateway): if not result.ErrorCode: log.logContent = u'Wind接口连接成功' + + # 发出缓存的订阅请求 + for req in self.subscribeBufferDict.values(): + self.subscribe(req) + self.subscribeBufferDict.clear() else: log.logContent = u'Wind接口连接失败,错误代码%d' %result.ErrorCode self.onLog(log) \ No newline at end of file From e8fbab872d288fa09857a63e6afdc37e64c3d2ce Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 14 Jun 2017 13:41:59 +0800 Subject: [PATCH 06/29] =?UTF-8?q?=E4=BF=AE=E5=A4=8DCTA=E4=B8=AD=E7=9A=84bu?= =?UTF-8?q?g?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/ctaStrategy/uiCtaWidget.py | 3 ++- vnpy/trader/gateway/windGateway/windGateway.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py index f1b077ae..d9e8531b 100644 --- a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py +++ b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py @@ -9,7 +9,8 @@ from vnpy.event import Event from vnpy.trader.vtEvent import * from vnpy.trader.uiBasicWidget import QtGui, QtCore, QtWidgets, BasicCell -from vnpy.trader.app.ctaStrategy.language import text +from .ctaBase import EVENT_CTA_LOG, EVENT_CTA_STRATEGY +from .language import text ######################################################################## diff --git a/vnpy/trader/gateway/windGateway/windGateway.py b/vnpy/trader/gateway/windGateway/windGateway.py index 279eac5c..1a872cdf 100644 --- a/vnpy/trader/gateway/windGateway/windGateway.py +++ b/vnpy/trader/gateway/windGateway/windGateway.py @@ -196,6 +196,8 @@ class WindGateway(VtGateway): if not result.ErrorCode: log.logContent = u'Wind接口连接成功' + self.connected = True + # 发出缓存的订阅请求 for req in self.subscribeBufferDict.values(): self.subscribe(req) From 7ed32dca4b0b7020f7493cf9a90b36d8fd7c59ab Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Thu, 15 Jun 2017 14:43:49 +0800 Subject: [PATCH 07/29] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=BB=B7=E5=B7=AE?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E7=9A=84=E6=8C=81=E4=BB=93=E5=92=8C=E6=97=A5?= =?UTF-8?q?=E5=BF=97=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/ctaStrategy/uiCtaWidget.py | 15 +-- vnpy/trader/app/spreadTrading/stBase.py | 2 + vnpy/trader/app/spreadTrading/stEngine.py | 123 +++++++++++++++++--- vnpy/trader/app/spreadTrading/uiStWidget.py | 79 ++++++++++--- 4 files changed, 178 insertions(+), 41 deletions(-) diff --git a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py index d9e8531b..62366a89 100644 --- a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py +++ b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py @@ -268,13 +268,14 @@ class CtaEngineManager(QtWidgets.QWidget): #---------------------------------------------------------------------- def closeEvent(self, event): """关闭窗口时的事件""" - reply = QtWidgets.QMessageBox.question(self, text.SAVE_POSITION_DATA, - text.SAVE_POSITION_QUESTION, QtWidgets.QMessageBox.Yes | - QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) - - if reply == QtWidgets.QMessageBox.Yes: - self.ctaEngine.savePosition() - + if self.isVisible(): + reply = QtWidgets.QMessageBox.question(self, text.SAVE_POSITION_DATA, + text.SAVE_POSITION_QUESTION, QtWidgets.QMessageBox.Yes | + QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No) + + if reply == QtWidgets.QMessageBox.Yes: + self.ctaEngine.savePosition() + event.accept() diff --git a/vnpy/trader/app/spreadTrading/stBase.py b/vnpy/trader/app/spreadTrading/stBase.py index 9297b764..64f0f00f 100644 --- a/vnpy/trader/app/spreadTrading/stBase.py +++ b/vnpy/trader/app/spreadTrading/stBase.py @@ -11,6 +11,8 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, EVENT_SPREADTRADING_TICK = 'eSpreadTradingTick.' +EVENT_SPREADTRADING_POS = 'eSpreadTradingPos.' +EVENT_SPREADTRADING_LOG = 'eSpreadTradingLog' diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index d5f38a9b..4ce43a52 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -1,14 +1,18 @@ # encoding: UTF-8 import json +import traceback 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 vnpy.trader.vtObject import VtSubscribeReq, VtLogData +from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, + OFFSET_OPEN, OFFSET_CLOSE) -from .stBase import StLeg, StSpread, EVENT_SPREADTRADING_TICK +from .stBase import (StLeg, StSpread, EVENT_SPREADTRADING_TICK, + EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG) ######################################################################## @@ -33,11 +37,18 @@ class StEngine(object): #---------------------------------------------------------------------- def loadSetting(self): """加载配置""" - with open(self.settingFilePath) as f: - l = json.load(f) - - for setting in l: - self.createSpread(setting) + try: + with open(self.settingFilePath) as f: + l = json.load(f) + + for setting in l: + result, msg = self.createSpread(setting) + self.writeLog(msg) + + self.writeLog(u'价差配置加载完成') + except: + content = u'价差配置加载出错,原因:' + traceback.format_exc() + self.writeLog(content) #---------------------------------------------------------------------- def saveSetting(self): @@ -53,7 +64,7 @@ class StEngine(object): # 检查价差重名 if setting['name'] in self.spreadDict: - msg = u'%s价差重名' %setting['name'] + msg = u'%s价差存在重名' %setting['name'] return result, msg # 检查腿是否已使用 @@ -132,21 +143,89 @@ class StEngine(object): spread = self.vtSymbolSpreadDict[tick.vtSymbol] spread.calculatePrice() - # 推送价差更新 + # 推送价差行情更新 newSpread = copy(spread) - event = Event(EVENT_SPREADTRADING_TICK) - event.dict_['data'] = newSpread - self.eventEngine.put(event) + + event1 = Event(EVENT_SPREADTRADING_TICK+spread.name) + event1.dict_['data'] = newSpread + self.eventEngine.put(event1) + + event2 = Event(EVENT_SPREADTRADING_TICK) + event2.dict_['data'] = newSpread + self.eventEngine.put(event2) #---------------------------------------------------------------------- def processTradeEvent(self, event): - """""" - pass + """处理成交推送""" + # 检查成交是否需要处理 + trade = event.dict_['data'] + if trade.vtSymbol not in self.legDict: + return + + # 更新腿持仓 + leg = self.legDict[trade.vtSymbol] + direction = trade.direction + offset = trade.offst + + if direction == DIRECTION_LONG: + if offset == OFFSET_OPEN: + leg.longPos += trade.volume + else: + leg.shortPos -= trade.volume + else: + if offset == OFFSET_OPEN: + leg.shortPos += trade.volume + else: + leg.longPos -= trade.volume + leg.netPos = leg.longPos - leg.shortPos + + # 更新价差持仓 + spread = self.vtSymbolSpreadDict[trade.vtSymbol] + spread.calculatePos() + + # 推送价差持仓更新 + newSpread = copy(spread) + + event1 = Event(EVENT_SPREADTRADING_POS+spread.name) + event1.dict_['data'] = newSpread + self.eventEngine.put(event1) + + event2 = Event(EVENT_SPREADTRADING_POS) + event2.dict_['data'] = newSpread + self.eventEngine.put(event2) #---------------------------------------------------------------------- def processPositionEvent(self, event): - """""" - pass + """处理持仓推送""" + # 检查持仓是否需要处理 + pos = event.dict_['data'] + if pos.vtSymbol not in self.legDict: + return + + # 更新腿持仓 + leg = self.legDict[trade.vtSymbol] + direction = pos.direction + + if direction == DIRECTION_LONG: + leg.longPos = pos.position + else: + leg.shortPos = pos.position + leg.netPos = leg.longPos - leg.shortPos + + # 更新价差持仓 + spread = self.vtSymbolSpreadDict[trade.vtSymbol] + spread.calculatePos() + + # 推送价差持仓更新 + newSpread = copy(spread) + + event1 = Event(EVENT_SPREADTRADING_POS+spread.name) + event1.dict_['data'] = newSpread + self.eventEngine.put(event1) + + event2 = Event(EVENT_SPREADTRADING_POS) + event2.dict_['data'] = newSpread + self.eventEngine.put(event2) #---------------------------------------------------------------------- def registerEvent(self): @@ -160,7 +239,7 @@ class StEngine(object): """订阅行情""" contract = self.mainEngine.getContract(vtSymbol) if not contract: - return + self.writeLog(u'订阅行情失败,找不到该合约%s' %vtSymbol) req = VtSubscribeReq() req.symbol = contract.symbol @@ -168,6 +247,16 @@ class StEngine(object): self.mainEngine.subscribe(req, contract.gatewayName) + #---------------------------------------------------------------------- + def writeLog(self, content): + """发出日志""" + log = VtLogData() + log.logContent = content + + event = Event(EVENT_SPREADTRADING_LOG) + event.dict_['data'] = log + self.eventEngine.put(event) + #---------------------------------------------------------------------- def stop(self): """停止""" diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index c0cd5b21..9244fc4d 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -3,23 +3,23 @@ from collections import OrderedDict from vnpy.trader.uiQt import QtWidgets -from vnpy.trader.uiBasicWidget import (BasicMonitor, BasicCell, +from vnpy.trader.uiBasicWidget import (BasicMonitor, BasicCell, PnlCell, AskCell, BidCell, BASIC_FONT) -from .stBase import EVENT_SPREADTRADING_TICK +from .stBase import (EVENT_SPREADTRADING_TICK, EVENT_SPREADTRADING_POS, + EVENT_SPREADTRADING_LOG) ######################################################################## 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} @@ -30,22 +30,60 @@ class StTickMonitor(BasicMonitor): 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 StPosMonitor(BasicMonitor): + """价差持仓监控""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine, parent=None): + """Constructor""" + super(StPosMonitor, self).__init__(mainEngine, eventEngine, parent) + + d = OrderedDict() + d['name'] = {'chinese':u'价差名称', 'cellType':BasicCell} + d['netPos'] = {'chinese':u'净仓', 'cellType':PnlCell} + d['longPos'] = {'chinese':u'多仓', 'cellType':BasicCell} + d['shortPos'] = {'chinese':u'空仓', 'cellType':BasicCell} + d['symbol'] = {'chinese':u'代码', 'cellType':BasicCell} + self.setHeaderDict(d) + + self.setDataKey('name') + self.setEventType(EVENT_SPREADTRADING_POS) + self.setFont(BASIC_FONT) + + self.initTable() + self.registerEvent() + + +######################################################################## +class StLogMonitor(BasicMonitor): + """价差日志监控""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine, parent=None): + """Constructor""" + super(StLogMonitor, self).__init__(mainEngine, eventEngine, parent) + + d = OrderedDict() + d['logTime'] = {'chinese':u'时间', 'cellType':BasicCell} + d['logContent'] = {'chinese':u'日志', 'cellType':BasicCell} + self.setHeaderDict(d) + + self.setEventType(EVENT_SPREADTRADING_LOG) + self.setFont(BASIC_FONT) + + self.initTable() + self.registerEvent() + + ######################################################################## class StManager(QtWidgets.QWidget): """""" @@ -73,15 +111,22 @@ class StManager(QtWidgets.QWidget): # 创建组件 tickMonitor = StTickMonitor(self.mainEngine, self.eventEngine) + posMonitor = StPosMonitor(self.mainEngine, self.eventEngine) + logMonitor = StLogMonitor(self.mainEngine, self.eventEngine) # 设置布局 - hbox = QtWidgets.QHBoxLayout() - hbox.addWidget(buttonLoadSetting) - hbox.addStretch() + hbox1 = QtWidgets.QHBoxLayout() + hbox1.addWidget(buttonLoadSetting) + hbox1.addStretch() + + hbox2 = QtWidgets.QHBoxLayout() + hbox2.addWidget(tickMonitor) + hbox2.addWidget(posMonitor) vbox = QtWidgets.QVBoxLayout() - vbox.addLayout(hbox) - vbox.addWidget(tickMonitor) + vbox.addLayout(hbox1) + vbox.addLayout(hbox2) + vbox.addWidget(logMonitor) self.setLayout(vbox) From a2a075ba6ad68d3f11fb108ed70f4ff24f588620 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 21 Jun 2017 17:19:21 +0800 Subject: [PATCH 08/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=B7=E5=B7=AE?= =?UTF-8?q?=E7=AE=97=E6=B3=95=E5=BC=95=E6=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/rpc/vnrpc.py | 4 +- vnpy/trader/app/ctaStrategy/ctaBacktesting.py | 5 +- vnpy/trader/app/spreadTrading/stAlgo.py | 294 ++++++++++++++++++ vnpy/trader/app/spreadTrading/stEngine.py | 185 +++++++++-- 4 files changed, 466 insertions(+), 22 deletions(-) create mode 100644 vnpy/trader/app/spreadTrading/stAlgo.py diff --git a/vnpy/rpc/vnrpc.py b/vnpy/rpc/vnrpc.py index c3a979c9..f8c00047 100644 --- a/vnpy/rpc/vnrpc.py +++ b/vnpy/rpc/vnrpc.py @@ -180,7 +180,7 @@ class RpcServer(RpcObject): def publish(self, topic, data): """ 广播推送数据 - topic:主题内容 + topic:主题内容(注意必须是ascii编码) data:具体的数据 """ # 序列化数据 @@ -294,6 +294,8 @@ class RpcClient(RpcObject): 订阅特定主题的广播数据 可以使用topic=''来订阅所有的主题 + + 注意topic必须是ascii编码 """ self.__socketSUB.setsockopt(zmq.SUBSCRIBE, topic) diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 62b07b9d..01b29280 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -812,7 +812,7 @@ class BacktestingEngine(object): l.append(pool.apply_async(optimize, (strategyClass, setting, targetName, self.mode, self.startDate, self.initDays, self.endDate, - self.slippage, self.rate, self.size, + self.slippage, self.rate, self.size, self.priceTick, self.dbName, self.symbol))) pool.close() pool.join() @@ -929,7 +929,7 @@ def formatNumber(n): #---------------------------------------------------------------------- def optimize(strategyClass, setting, targetName, mode, startDate, initDays, endDate, - slippage, rate, size, + slippage, rate, size, priceTick, dbName, symbol): """多进程优化时跑在每个进程中运行的函数""" engine = BacktestingEngine() @@ -939,6 +939,7 @@ def optimize(strategyClass, setting, targetName, engine.setSlippage(slippage) engine.setRate(rate) engine.setSize(size) + engine.setPriceTick(priceTick) engine.setDatabase(dbName, symbol) engine.initStrategy(strategyClass, setting) diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py new file mode 100644 index 00000000..ba6e1a86 --- /dev/null +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -0,0 +1,294 @@ +# encoding: UTF-8 + +from math import floor + +from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, + EMPTY_STRING, EMPTY_UNICODE, + DIRECTION_LONG, DIRECTION_SHORT, + STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED) + + + +######################################################################## +class StAlgoTemplate(object): + """价差算法交易模板""" + MODE_LONGSHORT = 'longshort' + MODE_LONGONLY = 'long' + MODE_SHORTONLY = 'short' + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spread): + """Constructor""" + self.algoEngine = algoEngine # 算法引擎 + self.spreadName = spread.name # 价差名称 + self.spread = spread # 价差对象 + + self.algoName = EMPTY_STRING # 算法名称 + + self.active = False # 工作状态 + self.mode = self.MODE_LONGSHORT # 工作模式 + + self.buyPrice = EMPTY_FLOAT # 开平仓价格 + self.sellPrice = EMPTY_FLOAT + self.shortPrice = EMPTY_FLOAT + self.coverPrice = EMPTY_FLOAT + + self.maxPosSize = EMPTY_INT # 最大单边持仓量 + self.maxOrderSize = EMPTY_INT # 最大单笔委托量 + + #---------------------------------------------------------------------- + def updateSpreadTick(self, spread): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def updateSpreadPos(self, spread): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def updateTrade(self, trade): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def updateOrder(self, order): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def updateTimer(self): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def start(self): + """""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def stop(self): + """""" + raise NotImplementedError + + + +######################################################################## +class SniperAlgo(StAlgoTemplate): + """狙击算法(市价委托)""" + FINISHED_STATUS = [STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED] + + #---------------------------------------------------------------------- + def __init__(self, algoEngine): + """Constructor""" + super(SniperAlgo, self).__init__(algoEngine) + + self.algoName = u'Sniper' + self.hedgeInterval = 2 # 对冲腿撤单再发前的等待时间 + self.hedgeCount = 0 # 对冲计数 + + self.activeVtSymbol = spread.activeLeg.vtSymbol # 主动腿代码 + self.passiveVtSymbols = [leg.vtSymbol for leg in spread.passiveLegs] # 被动腿代码列表 + + # 缓存每条腿对象的字典 + self.legDict = {} + self.legDict[spread.activeLeg.vtSymbol] = spread.activeLeg + for leg in spread.passiveLegs: + self.legDict[leg.vtSymbol] = leg + + self.hedgingTaskDict = {} # 被动腿需要对冲的数量字典 vtSymbol:volume + self.legOrderDict = {} # vtSymbol: list of vtOrderID + + #---------------------------------------------------------------------- + def updateSpreadTick(self, spread): + """价差行情更新""" + self.spread = spread + + #---------------------------------------------------------------------- + def updateSpreadPos(self, spread): + """价差持仓更新""" + self.spread = spread + + #---------------------------------------------------------------------- + def updateTrade(self, trade): + """成交更新""" + if not self.active: + return + + if trade.vtSymbol == self.activeVtSymbol: + self.newActiveLegTrade(trade) + else: + self.newPassiveLegTrade(trade) + + #---------------------------------------------------------------------- + def updateOrder(self, order): + """委托更新""" + if not self.active: + return + + # 只处理完成委托 + if order.status in self.FINISHED_STATUS: + vtOrderID = order.vtOrderID + vtSymbol = order.vtSymbol + + # 从委托列表中移除该委托 + orderList = self.legOrderDict[vtSymbol] + + if vtOrderID in orderList: + orderList.remove(vtOrderID) + + # 检查若是被动腿,且已经没有未完成委托,则执行对冲 + if not orderList and vtSymbol in self.passiveVtSymbols: + self.hedgePassiveLeg(vtSymbol) + + #---------------------------------------------------------------------- + def updateTimer(self): + """计时更新""" + self.hedgeCount += 1 + + # 计时到达对冲间隔后,则对尚未成交的全部被动腿委托全部撤单 + # 收到撤单回报后,会自动发送新的对冲委托 + if self.hedgeCount > self.hedgeInterval: + self.cancelAllPassiveLegOrders() + self.hedgeCount = 0 + + #---------------------------------------------------------------------- + def start(self): + """启动""" + raise NotImplementedError + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + self.active = False + + self.hedgingTaskDict.clear() + self.cancelAllOrders() + + #---------------------------------------------------------------------- + def sendLegOrder(self, leg, legVolume): + """发送每条腿的委托""" + vtSymbol = leg.vtSymbol + volume = abs(legVolume) + payup = leg.payup + + # 发送委托 + if legVolume > 0: + price = leg.askPrice + + if leg.shortPos > 0: + orderList = self.algoEngine.cover(vtSymbol, price, volume, payup) + else: + orderList = self.algoEngine.buy(vtSymbol, price, volume, payup) + + elif legVolume < 0: + price = leg.bidPrice + + if leg.longPos > 0: + orderList = self.algoEngine.sell(vtSymbol, price, volume, payup) + else: + orderList = self.algoEngine.short(vtSymbol, price, volume, payup) + + # 保存到字典中 + if vtSymbol not in self.legOrderDict: + self.legOrderDict[vtSymbol] = orderList + else: + self.legOrderDict[vtSymbol].extend(orderList) + + #---------------------------------------------------------------------- + def quoteActiveLeg(self, direction): + """发出主动腿""" + spread = self.spread + + if direction == DIRECTION_LONG: + spreadVolume = min(spread.askVolume, + self.maxPosSize - spread.netPos, + self.maxOrderSize) + else: + spreadVolume = min(spread.bidVolume, + self.maxPosSize + spread.netPos, + self.maxOrderSize) + + if spreadVolume <= 0: + return + + leg = self.legDict[self.activeVtSymbol] + legVolume = spreadVolume * leg.ratio + + self.sendLegOrder(leg, legVolume) + + #---------------------------------------------------------------------- + def hedgePassiveLeg(self, vtSymbol): + """被动腿对冲""" + if vtSymbol not in self.hedgingTaskDict: + return + legVolume = self.hedgingTaskDict[vtSymbol] + + leg = self.legDict[vtSymbol] + + self.sendLegOrder(leg, legVolume) + + #---------------------------------------------------------------------- + def hedgeAllPassiveLegs(self): + """执行所有被动腿对冲""" + for vtSymbol in self.hedgingTaskDict.keys(): + self.hedgePassiveLeg(vtSymbol) + + #---------------------------------------------------------------------- + def newActiveLegTrade(self, trade): + """新的主动腿成交""" + spread = self.spread + + # 计算主动腿成交后,对应的价差仓位 + activeRatio = spread.activeLeg.ratio + spreadVolume = round(trade.volume / activeRatio) # 四舍五入求主动腿成交量对应的价差份数 + + # 计算价差新仓位,对应的被动腿需要对冲部分 + for leg in self.spread.passiveLegs: + newHedgingTask = leg.ratio * spreadVolume + + if leg.vtSymbol not in self.hedgingTaskDict: + self.hedgingTaskDict[leg.vtSymbol] = newHedgingTask + else: + self.hedgingTaskDict[leg.vtSymbol] += newHedgingTask + + #---------------------------------------------------------------------- + def newPassiveLegTrade(self, trade): + """新的被动腿成交""" + if trade.vtSymbol in self.hedgingTaskDict: + # 计算完成的对冲数量 + if trade.direction == DIRECTION_LONG: + hedgedVolume = trade.volume + else: + hedgedVolume = -trade.volume + + # 计算剩余尚未完成的数量 + self.hedgingTaskDict[trade.vtSymbol] -= hedgedVolume + + # 如果已全部完成,则从字典中移除 + if not self.hedgingTaskDict[trade.vtSymbol]: + del self.hedgingTaskDict[trade.vtSymbol] + + #---------------------------------------------------------------------- + def cancelLegOrder(self, vtSymbol): + """撤销某条腿的委托""" + if vtSymbol not in self.legOrderDict: + return + + orderList = self.legOrderDict[vtSymbol] + + for vtOrderID in orderList: + self.algoEngine.cancelOrder(vtOrderID) + + #---------------------------------------------------------------------- + def cancelAllOrders(self): + """撤销全部委托""" + for orderList in self.legOrderDict.values(): + for vtOrderID in orderList: + self.algoEngine.cancelOrder(vtOrderID) + + #---------------------------------------------------------------------- + def cancelAllPassiveLegOrders(self): + """撤销全部被动腿委托""" + for vtSymbol in self.passiveVtSymbols: + self.cancelLegOrder(vtSymbol) \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index 4ce43a52..c93bb3cd 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -6,8 +6,10 @@ 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, VtLogData +from vnpy.trader.vtEvent import (EVENT_TICK, EVENT_TRADE, EVENT_POSITION, + EVENT_TIMER, EVENT_ORDER) +from vnpy.trader.vtObject import (VtSubscribeReq, VtOrderReq, + VtCancelOrderReq, VtLogData) from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN, OFFSET_CLOSE) @@ -16,8 +18,8 @@ from .stBase import (StLeg, StSpread, EVENT_SPREADTRADING_TICK, ######################################################################## -class StEngine(object): - """""" +class StDataEngine(object): + """价差数据计算引擎""" settingFileName = 'ST_setting.json' settingFilePath = getJsonPath(settingFileName, __file__) @@ -143,15 +145,13 @@ class StEngine(object): spread = self.vtSymbolSpreadDict[tick.vtSymbol] spread.calculatePrice() - # 推送价差行情更新 - newSpread = copy(spread) - + # 推送价差行情更新 event1 = Event(EVENT_SPREADTRADING_TICK+spread.name) - event1.dict_['data'] = newSpread + event1.dict_['data'] = spread self.eventEngine.put(event1) event2 = Event(EVENT_SPREADTRADING_TICK) - event2.dict_['data'] = newSpread + event2.dict_['data'] = spread self.eventEngine.put(event2) #---------------------------------------------------------------------- @@ -184,18 +184,16 @@ class StEngine(object): spread.calculatePos() # 推送价差持仓更新 - newSpread = copy(spread) - event1 = Event(EVENT_SPREADTRADING_POS+spread.name) - event1.dict_['data'] = newSpread + event1.dict_['data'] = spread self.eventEngine.put(event1) event2 = Event(EVENT_SPREADTRADING_POS) - event2.dict_['data'] = newSpread + event2.dict_['data'] = spread self.eventEngine.put(event2) #---------------------------------------------------------------------- - def processPositionEvent(self, event): + def processPosEvent(self, event): """处理持仓推送""" # 检查持仓是否需要处理 pos = event.dict_['data'] @@ -217,14 +215,12 @@ class StEngine(object): spread.calculatePos() # 推送价差持仓更新 - newSpread = copy(spread) - event1 = Event(EVENT_SPREADTRADING_POS+spread.name) - event1.dict_['data'] = newSpread + event1.dict_['data'] = spread self.eventEngine.put(event1) event2 = Event(EVENT_SPREADTRADING_POS) - event2.dict_['data'] = newSpread + event2.dict_['data'] = spread self.eventEngine.put(event2) #---------------------------------------------------------------------- @@ -232,7 +228,7 @@ class StEngine(object): """""" self.eventEngine.register(EVENT_TICK, self.processTickEvent) self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) - self.eventEngine.register(EVENT_POSITION, self.processPositionEvent) + self.eventEngine.register(EVENT_POSITION, self.processPosEvent) #---------------------------------------------------------------------- def subscribeMarketData(self, vtSymbol): @@ -262,4 +258,155 @@ class StEngine(object): """停止""" pass + +######################################################################## +class StAlgoEngine(object): + """价差算法交易引擎""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine): + """Constructor""" + self.mainEngine = mainEngine + self.eventEngine = eventEngine + + self.algoDict = {} # spreadName:algo + self.vtSymbolAlgoDict = {} # vtSymbol:algo + + self.registerEvent() + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.eventEngine.register(EVENT_SPREADTRADING_TICK, self.processSpreadTickEvent) + self.eventEngine.register(EVENT_SPREADTRADING_POS, self.processSpreadPosEvent) + self.eventEngine.register(EVENT_TRADE, self.processTradeEvent) + self.eventEngine.register(EVENT_ORDER, self.processOrderEvent) + self.eventEngine.register(EVENT_TIMER, self.processTimerEvent) + + #---------------------------------------------------------------------- + def processSpreadTickEvent(self, event): + """处理价差行情事件""" + spread = event.dict_['data'] + + algo = self.algoDict.get(spread.name, None) + if algo: + algo.updateSpreadTick(spread) + + #---------------------------------------------------------------------- + def processSpreadPosEvent(self, event): + """处理价差持仓事件""" + spread = event.dict_['data'] + + algo = self.algoDict.get(spread.name, None) + if algo: + algo.updateSpreadPos(spread) + + #---------------------------------------------------------------------- + def processTradeEvent(self, event): + """处理成交事件""" + trade = event.dict_['data'] + + algo = self.algoDict.get(trade.vtSymbol, None) + if algo: + algo.updateTrade(trade) + + #---------------------------------------------------------------------- + def processOrderEvent(self, event): + """处理委托事件""" + order = event.dict_['data'] + + algo = self.algoDict.get(order.vtSymbol, None) + if algo: + algo.updateOrder(order) + + #---------------------------------------------------------------------- + def processTimerEvent(self, event): + """""" + for algo in self.algoDict.values(): + algo.updateTimer() + + #---------------------------------------------------------------------- + def sendOrder(self, vtSymbol, direction, offset, price, volume, payup=0): + """发单""" + contract = self.mainEngine.getContract(vtSymbol) + if not contract: + return '' + + req = VtOrderReq() + req.symbol = contract.symbol + req.exchange = contract.exchange + req.direction = direction + req.offset = offset + req.volume = volume + + if direction == DIRECTION_LONG: + req.price = price + payup * contract.priceTick + else: + req.price = price - payup * contract.priceTick + + vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) + return vtOrderID + + #---------------------------------------------------------------------- + def cancelOrder(self, vtOrderID): + """撤单""" + order = self.mainEngine.getOrder(vtOrderID) + if not order: + return + + req = VtCancelOrderReq() + req.symbol = order.symbol + req.exchange = order.exchange + req.frontID = order.frontID + req.sessionID = order.sessionID + req.orderID = order.orderID + + self.mainEngine.cancelOrder(req, order.gatewayName) + + #---------------------------------------------------------------------- + def buy(self, vtSymbol, price, volume, payup=0): + """买入""" + vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_OPEN, price, volume, payup) + return [vtOrderID] + + #---------------------------------------------------------------------- + def sell(self, vtSymbol, price, volume, payup=0): + """卖出""" + vtOrderID = self.sendOrder(vtSymbol, DIRECTION_SHORT, OFFSET_CLOSE, price, volume, payup) + return [vtOrderID] + + #---------------------------------------------------------------------- + def short(self, vtSymbol, price, volume, payup=0): + """卖空""" + vtOrderID = self.sendOrder(vtSymbol, DIRECTION_SHORT, OFFSET_OPEN, price, volume, payup) + return [vtOrderID] + + #---------------------------------------------------------------------- + def cover(self, vtSymbol, price, volume, payup=0): + """平空""" + vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_CLOSE, price, volume, payup) + return [vtOrderID] + + +######################################################################## +class StEngine(object): + """价差引擎""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine): + """Constructor""" + self.mainEngine = mainEngine + self.eventEngine = eventEngine + + self.dataEngine = StDataEngine(mainEngine, eventEngine) + self.algoEngine = StAlgoEngine(mainEngine, eventEngine) + + #---------------------------------------------------------------------- + def loadSetting(self): + """""" + self.dataEngine.loadSetting() + + + + \ No newline at end of file From 2578e1b41937a06e193a6a7cf2d62b42a2ba1aad Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 21 Jun 2017 23:12:49 +0800 Subject: [PATCH 09/29] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BB=B7=E5=B7=AE=E7=8B=99=E5=87=BB=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/spreadTrading/stAlgo.py | 79 +++++++++++++++++++++---- 1 file changed, 69 insertions(+), 10 deletions(-) diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index ba6e1a86..e3903407 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -12,9 +12,12 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, ######################################################################## class StAlgoTemplate(object): """价差算法交易模板""" - MODE_LONGSHORT = 'longshort' - MODE_LONGONLY = 'long' - MODE_SHORTONLY = 'short' + MODE_LONGSHORT = 1 + MODE_LONGONLY = 2 + MODE_SHORTONLY = 3 + + SPREAD_LONG = 1 + SPREAD_SHORT = 2 #---------------------------------------------------------------------- def __init__(self, algoEngine, spread): @@ -62,7 +65,7 @@ class StAlgoTemplate(object): raise NotImplementedError #---------------------------------------------------------------------- - def start(self): + def start(self, mode=MODE_LONGSHORT): """""" raise NotImplementedError @@ -84,7 +87,9 @@ class SniperAlgo(StAlgoTemplate): super(SniperAlgo, self).__init__(algoEngine) self.algoName = u'Sniper' - self.hedgeInterval = 2 # 对冲腿撤单再发前的等待时间 + self.quoteInterval = 2 # 主动腿报价撤单再发前等待的时间 + self.quoteCount = 0 # 报价计数 + self.hedgeInterval = 2 # 对冲腿对冲撤单再发前的等待时间 self.hedgeCount = 0 # 对冲计数 self.activeVtSymbol = spread.activeLeg.vtSymbol # 主动腿代码 @@ -103,6 +108,41 @@ class SniperAlgo(StAlgoTemplate): def updateSpreadTick(self, spread): """价差行情更新""" self.spread = spread + + # 若算法没有启动则直接返回 + if not self.active: + return + + # 若当前已有主动腿委托则直接返回 + if (self.activeVtSymbol in self.legOrderDict and + self.legOrderDict[self.activeVtSymbol]): + return + + # 允许做多 + if self.mode == self.MODE_LONGSHORT or self.mode == self.MODE_LONGONLY: + # 买入 + if (spread.netPos >= 0 and + spread.netPos < self.maxPosSize and + spread.askPrice <= self.buyPrice): + self.quoteActiveLeg(self.SPREAD_LONG) + + # 卖出 + elif (spread.netPos > 0 and + spread.bidPrice >= self.sellPrice): + self.quoteActiveLeg(self.SPREAD_SHORT) + + # 允许做空 + if self.mode == self.MODE_LONGSHORT or self.mode == self.MODE_SHORTONLY: + # 做空 + if (spread.netPos <= 0 and + spread.netPos > -self.maxPosSize and + spread.bidPrice >= self.shortPrice): + self.quoteActiveLeg(self.SPREAD_SHORT) + + # 平空 + elif (spread.netPos < 0 and + spread.askPrice <= self.coverPrice): + self.quoteActiveLeg(self.SPREAD_LONG) #---------------------------------------------------------------------- def updateSpreadPos(self, spread): @@ -144,8 +184,15 @@ class SniperAlgo(StAlgoTemplate): #---------------------------------------------------------------------- def updateTimer(self): """计时更新""" + self.quoteCount += 1 self.hedgeCount += 1 + # 计时到达报价间隔后,则对尚未成交的主动腿委托全部撤单 + # 收到撤单回报后清空委托列表,等待下次价差更新再发单 + if self.quoteCount > self.quoteInterval: + self.cancelLegOrder(self.activeVtSymbol) + self.quoteCount = 0 + # 计时到达对冲间隔后,则对尚未成交的全部被动腿委托全部撤单 # 收到撤单回报后,会自动发送新的对冲委托 if self.hedgeCount > self.hedgeInterval: @@ -153,9 +200,10 @@ class SniperAlgo(StAlgoTemplate): self.hedgeCount = 0 #---------------------------------------------------------------------- - def start(self): + def start(self, mode=MODE_LONGSHORT): """启动""" - raise NotImplementedError + self.mode = mode + self.active = True #---------------------------------------------------------------------- def stop(self): @@ -200,22 +248,31 @@ class SniperAlgo(StAlgoTemplate): """发出主动腿""" spread = self.spread - if direction == DIRECTION_LONG: + if direction == self.SPREAD_LONG: spreadVolume = min(spread.askVolume, self.maxPosSize - spread.netPos, self.maxOrderSize) + + # 有价差空头持仓的情况下,则本次委托最多平完空头 + if spread.shortPos > 0: + spreadVolume = min(spreadVolume, spread.shortPos) else: spreadVolume = min(spread.bidVolume, self.maxPosSize + spread.netPos, self.maxOrderSize) + # 有价差多头持仓的情况下,则本次委托最多平完多头 + if spread.longPos > 0: + spreadVolume = min(spreadVolume, spread.longPos) + if spreadVolume <= 0: return leg = self.legDict[self.activeVtSymbol] - legVolume = spreadVolume * leg.ratio - + legVolume = spreadVolume * leg.ratio self.sendLegOrder(leg, legVolume) + + self.quoteCount = 0 # 重置主动腿报价撤单等待计数 #---------------------------------------------------------------------- def hedgePassiveLeg(self, vtSymbol): @@ -234,6 +291,8 @@ class SniperAlgo(StAlgoTemplate): for vtSymbol in self.hedgingTaskDict.keys(): self.hedgePassiveLeg(vtSymbol) + self.hedgeCount = 0 # 重置被动腿对冲撤单等待计数 + #---------------------------------------------------------------------- def newActiveLegTrade(self, trade): """新的主动腿成交""" From 79a9ac2bfb33f81c1c32b351b41fc0bf712787f7 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Fri, 23 Jun 2017 16:27:05 +0800 Subject: [PATCH 10/29] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BB=B7=E5=B7=AE=E4=BA=A4=E6=98=93=E7=95=8C=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/spreadTrading/st.ico | Bin 45118 -> 66622 bytes vnpy/trader/app/spreadTrading/stAlgo.py | 122 +++++- vnpy/trader/app/spreadTrading/stBase.py | 2 + vnpy/trader/app/spreadTrading/stEngine.py | 171 ++++++++- vnpy/trader/app/spreadTrading/uiStWidget.py | 405 ++++++++++++++++++-- 5 files changed, 654 insertions(+), 46 deletions(-) diff --git a/vnpy/trader/app/spreadTrading/st.ico b/vnpy/trader/app/spreadTrading/st.ico index a66c245e0dc6c55842f923177515889ca5b9ce4e..4d0ad1991d3d17f3d649562dad09da2e23142166 100644 GIT binary patch literal 66622 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 diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index e3903407..3cb24c70 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -12,9 +12,9 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, ######################################################################## class StAlgoTemplate(object): """价差算法交易模板""" - MODE_LONGSHORT = 1 - MODE_LONGONLY = 2 - MODE_SHORTONLY = 3 + MODE_LONGSHORT = u'双向' + MODE_LONGONLY = u'做多' + MODE_SHORTONLY = u'做空' SPREAD_LONG = 1 SPREAD_SHORT = 2 @@ -65,7 +65,7 @@ class StAlgoTemplate(object): raise NotImplementedError #---------------------------------------------------------------------- - def start(self, mode=MODE_LONGSHORT): + def start(self): """""" raise NotImplementedError @@ -74,7 +74,79 @@ class StAlgoTemplate(object): """""" raise NotImplementedError + #---------------------------------------------------------------------- + def setBuyPrice(self, buyPrice): + """设置买开的价格""" + self.buyPrice = buyPrice + + #---------------------------------------------------------------------- + def setSellPrice(self, sellPrice): + """设置卖平的价格""" + self.sellPrice = sellPrice + + #---------------------------------------------------------------------- + def setShortPrice(self, shortPrice): + """设置卖开的价格""" + self.shortPrice = shortPrice + + #---------------------------------------------------------------------- + def setCoverPrice(self, coverPrice): + """设置买平的价格""" + self.coverPrice = coverPrice + + #---------------------------------------------------------------------- + def setMode(self, mode): + """设置算法交易方向""" + self.mode = mode + + #---------------------------------------------------------------------- + def setMaxOrderSize(self, maxOrderSize): + """设置最大单笔委托数量""" + self.maxOrderSize = maxOrderSize + + #---------------------------------------------------------------------- + def setMaxPosSize(self, maxPosSize): + """设置最大持仓数量""" + self.maxPosSize = maxPosSize + + #---------------------------------------------------------------------- + def putEvent(self): + """发出算法更新事件""" + self.algoEngine.putAlgoEvent(self) + + #---------------------------------------------------------------------- + def writeLog(self, content): + """输出算法日志""" + content = ':'.join([self.spreadName, content]) + self.algoEngine.writeLog(content) + #---------------------------------------------------------------------- + def getAlgoParams(self): + """获取算法参数""" + d = { + "spreadName": self.spreadName, + "algoName": self.algoName, + "buyPrice": self.buyPrice, + "sellPrice": self.sellPrice, + "shortPrice": self.shortPrice, + "coverPrice": self.coverPrice, + "maxOrderSize": self.maxOrderSize, + "maxPosSize": self.maxPosSize, + "mode": self.mode + } + return d + + #---------------------------------------------------------------------- + def setAlgoParams(self, d): + """设置算法参数""" + self.buyPrice = d.get('buyPrice', EMPTY_FLOAT) + self.sellPrice = d.get('sellPrice', EMPTY_FLOAT) + self.shortPrice = d.get('shortPrice', EMPTY_FLOAT) + self.coverPrice = d.get('coverPrice', EMPTY_FLOAT) + self.maxOrderSize = d.get('maxOrderSize', EMPTY_INT) + self.maxPosSize = d.get('maxPosSize', EMPTY_INT) + self.mode = d.get('mode', self.MODE_LONGSHORT) + ######################################################################## class SniperAlgo(StAlgoTemplate): @@ -82,9 +154,9 @@ class SniperAlgo(StAlgoTemplate): FINISHED_STATUS = [STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED] #---------------------------------------------------------------------- - def __init__(self, algoEngine): + def __init__(self, algoEngine, spread): """Constructor""" - super(SniperAlgo, self).__init__(algoEngine) + super(SniperAlgo, self).__init__(algoEngine, spread) self.algoName = u'Sniper' self.quoteInterval = 2 # 主动腿报价撤单再发前等待的时间 @@ -125,11 +197,13 @@ class SniperAlgo(StAlgoTemplate): spread.netPos < self.maxPosSize and spread.askPrice <= self.buyPrice): self.quoteActiveLeg(self.SPREAD_LONG) + self.writeLog(u'买入开仓') # 卖出 elif (spread.netPos > 0 and spread.bidPrice >= self.sellPrice): self.quoteActiveLeg(self.SPREAD_SHORT) + self.writeLog(u'卖出平仓') # 允许做空 if self.mode == self.MODE_LONGSHORT or self.mode == self.MODE_SHORTONLY: @@ -138,11 +212,13 @@ class SniperAlgo(StAlgoTemplate): spread.netPos > -self.maxPosSize and spread.bidPrice >= self.shortPrice): self.quoteActiveLeg(self.SPREAD_SHORT) + self.writeLog(u'卖出开仓') # 平空 elif (spread.netPos < 0 and spread.askPrice <= self.coverPrice): self.quoteActiveLeg(self.SPREAD_LONG) + self.writeLog(u'买入平仓') #---------------------------------------------------------------------- def updateSpreadPos(self, spread): @@ -180,10 +256,14 @@ class SniperAlgo(StAlgoTemplate): # 检查若是被动腿,且已经没有未完成委托,则执行对冲 if not orderList and vtSymbol in self.passiveVtSymbols: self.hedgePassiveLeg(vtSymbol) + self.writeLog(u'发出新的被动腿%s对冲单' %vtSymbol) #---------------------------------------------------------------------- def updateTimer(self): """计时更新""" + if not self.active: + return + self.quoteCount += 1 self.hedgeCount += 1 @@ -200,10 +280,14 @@ class SniperAlgo(StAlgoTemplate): self.hedgeCount = 0 #---------------------------------------------------------------------- - def start(self, mode=MODE_LONGSHORT): + def start(self): """启动""" - self.mode = mode self.active = True + + self.quoteCount = 0 + self.hedgeCount = 0 + + return self.active #---------------------------------------------------------------------- def stop(self): @@ -212,6 +296,8 @@ class SniperAlgo(StAlgoTemplate): self.hedgingTaskDict.clear() self.cancelAllOrders() + + return self.active #---------------------------------------------------------------------- def sendLegOrder(self, leg, legVolume): @@ -310,6 +396,9 @@ class SniperAlgo(StAlgoTemplate): self.hedgingTaskDict[leg.vtSymbol] = newHedgingTask else: self.hedgingTaskDict[leg.vtSymbol] += newHedgingTask + + # 输出日志 + self.writeLog(u'主动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) #---------------------------------------------------------------------- def newPassiveLegTrade(self, trade): @@ -328,6 +417,9 @@ class SniperAlgo(StAlgoTemplate): if not self.hedgingTaskDict[trade.vtSymbol]: del self.hedgingTaskDict[trade.vtSymbol] + # 输出日志 + self.writeLog(u'被动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) + #---------------------------------------------------------------------- def cancelLegOrder(self, vtSymbol): """撤销某条腿的委托""" @@ -339,15 +431,27 @@ class SniperAlgo(StAlgoTemplate): for vtOrderID in orderList: self.algoEngine.cancelOrder(vtOrderID) + self.writeLog(u'撤单%s的所有委托' %vtSymbol) + #---------------------------------------------------------------------- def cancelAllOrders(self): """撤销全部委托""" for orderList in self.legOrderDict.values(): for vtOrderID in orderList: self.algoEngine.cancelOrder(vtOrderID) + + self.writeLog(u'全部撤单') #---------------------------------------------------------------------- def cancelAllPassiveLegOrders(self): """撤销全部被动腿委托""" + cancelPassive = False + for vtSymbol in self.passiveVtSymbols: - self.cancelLegOrder(vtSymbol) \ No newline at end of file + if self.legOrderDict[vtSymbol]: + self.cancelLegOrder(vtSymbol) + cancelPassive = True + + # 只有确实发出撤单委托时,才输出信息 + if cancelPassive: + self.writeLog(u'被动腿全撤') diff --git a/vnpy/trader/app/spreadTrading/stBase.py b/vnpy/trader/app/spreadTrading/stBase.py index 64f0f00f..71f25f15 100644 --- a/vnpy/trader/app/spreadTrading/stBase.py +++ b/vnpy/trader/app/spreadTrading/stBase.py @@ -13,6 +13,8 @@ from vnpy.trader.vtConstant import (EMPTY_INT, EMPTY_FLOAT, EVENT_SPREADTRADING_TICK = 'eSpreadTradingTick.' EVENT_SPREADTRADING_POS = 'eSpreadTradingPos.' EVENT_SPREADTRADING_LOG = 'eSpreadTradingLog' +EVENT_SPREADTRADING_ALGO = 'eSpreadTradingAlgo.' +EVENT_SPREADTRADING_ALGOLOG = 'eSpreadTradingAlgoLog' diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index c93bb3cd..71e89c31 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -2,10 +2,10 @@ import json import traceback -from copy import copy +import shelve from vnpy.event import Event -from vnpy.trader.vtFunction import getJsonPath +from vnpy.trader.vtFunction import getJsonPath, getTempPath from vnpy.trader.vtEvent import (EVENT_TICK, EVENT_TRADE, EVENT_POSITION, EVENT_TIMER, EVENT_ORDER) from vnpy.trader.vtObject import (VtSubscribeReq, VtOrderReq, @@ -14,7 +14,9 @@ from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, OFFSET_OPEN, OFFSET_CLOSE) from .stBase import (StLeg, StSpread, EVENT_SPREADTRADING_TICK, - EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG) + EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG, + EVENT_SPREADTRADING_ALGO, EVENT_SPREADTRADING_ALGOLOG) +from .stAlgo import SniperAlgo ######################################################################## @@ -121,6 +123,9 @@ class StDataEngine(object): # 初始化价差 spread.initSpread() + self.putSpreadTickEvent(spread) + self.putSpreadPosEvent(spread) + # 返回结果 result = True msg = u'%s价差创建成功' %spread.name @@ -145,7 +150,12 @@ class StDataEngine(object): spread = self.vtSymbolSpreadDict[tick.vtSymbol] spread.calculatePrice() - # 推送价差行情更新 + # 发出事件 + self.putSpreadTickEvent(spread) + + #---------------------------------------------------------------------- + def putSpreadTickEvent(self, spread): + """发出价差行情更新事件""" event1 = Event(EVENT_SPREADTRADING_TICK+spread.name) event1.dict_['data'] = spread self.eventEngine.put(event1) @@ -215,13 +225,19 @@ class StDataEngine(object): spread.calculatePos() # 推送价差持仓更新 + self.putSpreadPosEvent(spread) + + #---------------------------------------------------------------------- + def putSpreadPosEvent(self, spread): + """发出价差持仓事件""" event1 = Event(EVENT_SPREADTRADING_POS+spread.name) event1.dict_['data'] = spread self.eventEngine.put(event1) - + event2 = Event(EVENT_SPREADTRADING_POS) event2.dict_['data'] = spread - self.eventEngine.put(event2) + self.eventEngine.put(event2) + #---------------------------------------------------------------------- def registerEvent(self): @@ -236,6 +252,7 @@ class StDataEngine(object): contract = self.mainEngine.getContract(vtSymbol) if not contract: self.writeLog(u'订阅行情失败,找不到该合约%s' %vtSymbol) + return req = VtSubscribeReq() req.symbol = contract.symbol @@ -254,18 +271,21 @@ class StDataEngine(object): self.eventEngine.put(event) #---------------------------------------------------------------------- - def stop(self): - """停止""" - pass + def getAllSpreads(self): + """获取所有的价差""" + return self.spreadDict.values() ######################################################################## class StAlgoEngine(object): """价差算法交易引擎""" + algoFileName = 'SpreadTradingAlgo.vt' + algoFilePath = getTempPath(algoFileName) #---------------------------------------------------------------------- - def __init__(self, mainEngine, eventEngine): + def __init__(self, dataEngine, mainEngine, eventEngine): """Constructor""" + self.dataEngine = dataEngine self.mainEngine = mainEngine self.eventEngine = eventEngine @@ -387,6 +407,122 @@ class StAlgoEngine(object): vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_CLOSE, price, volume, payup) return [vtOrderID] + #---------------------------------------------------------------------- + def putAlgoEvent(self, algo): + """发出算法状态更新事件""" + event = Event(EVENT_SPREADTRADING_ALGO+algo.name) + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def writeLog(self, content): + """输出日志""" + log = VtLogData() + log.logContent = content + + event = Event(EVENT_SPREADTRADING_ALGOLOG) + event.dict_['data'] = log + + self.eventEngine.put(event) + + #---------------------------------------------------------------------- + def saveSetting(self): + """保存算法配置""" + setting = {} + for algo in self.algoDict.values(): + setting[algo.spreadName] = algo.getAlgoParams() + + f = shelve.open(self.algoFilePath) + f['setting'] = setting + f.close() + + #---------------------------------------------------------------------- + def loadSetting(self): + """加载算法配置""" + # 创建算法对象 + l = self.dataEngine.getAllSpreads() + for spread in l: + self.algoDict[spread.name] = SniperAlgo(self, spread) + + # 加载配置 + f = shelve.open(self.algoFilePath) + setting = f.get('setting', None) + f.close() + + if not setting: + return + + for algo in self.algoDict.values(): + if algo.spreadName in setting: + d = setting[algo.spreadName] + algo.setAlgoParams(d) + + #---------------------------------------------------------------------- + def stopAll(self): + """停止全部算法""" + for algo in self.algoDict.values(): + algo.stop() + + #---------------------------------------------------------------------- + def startAlgo(self, spreadName): + """启动算法""" + algo = self.algoDict[spreadName] + algoActive = algo.start() + return algoActive + + #---------------------------------------------------------------------- + def stopAlgo(self, spreadName): + """停止算法""" + algo = self.algoDict[spreadName] + algoActive = algo.stop() + return algoActive + + #---------------------------------------------------------------------- + def getAllAlgoParams(self): + """获取所有算法的参数""" + return [algo.getAlgoParams() for algo in self.algoDict.values()] + + #---------------------------------------------------------------------- + def setAlgoBuyPrice(self, spreadName, buyPrice): + """设置算法买开价格""" + algo = self.algoDict[spreadName] + algo.setBuyPrice(buyPrice) + + #---------------------------------------------------------------------- + def setAlgoSellPrice(self, spreadName, sellPrice): + """设置算法卖平价格""" + algo = self.algoDict[spreadName] + algo.setSellPrice(sellPrice) + + #---------------------------------------------------------------------- + def setAlgoShortPrice(self, spreadName, shortPrice): + """设置算法卖开价格""" + algo = self.algoDict[spreadName] + algo.setShortPrice(shortPrice) + + #---------------------------------------------------------------------- + def setAlgoCoverPrice(self, spreadName, coverPrice): + """设置算法买平价格""" + algo = self.algoDict[spreadName] + algo.setCoverPrice(coverPrice) + + #---------------------------------------------------------------------- + def setAlgoMode(self, spreadName, mode): + """设置算法工作模式""" + algo = self.algoDict[spreadName] + algo.setMode(mode) + + #---------------------------------------------------------------------- + def setAlgoMaxOrderSize(self, spreadName, maxOrderSize): + """设置算法单笔委托限制""" + algo = self.algoDict[spreadName] + algo.setMaxOrderSize(maxOrderSize) + + #---------------------------------------------------------------------- + def setAlgoMaxPosSize(self, spreadName, maxPosSize): + """设置算法持仓限制""" + algo = self.algoDict[spreadName] + algo.setMaxPosSize(maxPosSize) + ######################################################################## class StEngine(object): @@ -399,12 +535,21 @@ class StEngine(object): self.eventEngine = eventEngine self.dataEngine = StDataEngine(mainEngine, eventEngine) - self.algoEngine = StAlgoEngine(mainEngine, eventEngine) + self.algoEngine = StAlgoEngine(self.dataEngine, mainEngine, eventEngine) #---------------------------------------------------------------------- - def loadSetting(self): - """""" + def init(self): + """初始化""" self.dataEngine.loadSetting() + self.algoEngine.loadSetting() + + #---------------------------------------------------------------------- + def stop(self): + """停止""" + self.dataEngine.saveSetting() + + self.algoEngine.stopAll() + self.algoEngine.saveSetting() diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index 9244fc4d..76fd714e 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -2,14 +2,20 @@ from collections import OrderedDict -from vnpy.trader.uiQt import QtWidgets +from vnpy.event import Event +from vnpy.trader.uiQt import QtWidgets, QtCore from vnpy.trader.uiBasicWidget import (BasicMonitor, BasicCell, PnlCell, AskCell, BidCell, BASIC_FONT) from .stBase import (EVENT_SPREADTRADING_TICK, EVENT_SPREADTRADING_POS, - EVENT_SPREADTRADING_LOG) + EVENT_SPREADTRADING_LOG, EVENT_SPREADTRADING_ALGO, + EVENT_SPREADTRADING_ALGOLOG) +from .stAlgo import StAlgoTemplate +STYLESHEET_START = 'background-color: rgb(111,255,244); color: black' +STYLESHEET_STOP = 'background-color: rgb(255,201,111); color: black' + ######################################################################## class StTickMonitor(BasicMonitor): @@ -64,25 +70,365 @@ class StPosMonitor(BasicMonitor): ######################################################################## -class StLogMonitor(BasicMonitor): +class StLogMonitor(QtWidgets.QTextEdit): + """价差日志监控""" + signal = QtCore.pyqtSignal(type(Event())) + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, eventEngine, parent=None): + """Constructor""" + super(StLogMonitor, self).__init__(parent) + + self.eventEngine = eventEngine + + self.registerEvent() + + #---------------------------------------------------------------------- + def processLogEvent(self, event): + """处理日志事件""" + log = event.dict_['data'] + content = '%s:%s' %(log.logTime, log.logContent) + self.append(content) + + #---------------------------------------------------------------------- + def registerEvent(self): + """注册事件监听""" + self.signal.connect(self.processLogEvent) + + self.eventEngine.register(EVENT_SPREADTRADING_LOG, self.signal.emit) + + +######################################################################## +class StAlgoLogMonitor(BasicMonitor): """价差日志监控""" #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine, parent=None): """Constructor""" - super(StLogMonitor, self).__init__(mainEngine, eventEngine, parent) + super(StAlgoLogMonitor, self).__init__(mainEngine, eventEngine, parent) d = OrderedDict() d['logTime'] = {'chinese':u'时间', 'cellType':BasicCell} - d['logContent'] = {'chinese':u'日志', 'cellType':BasicCell} + d['logContent'] = {'chinese':u'信息', 'cellType':BasicCell} self.setHeaderDict(d) - self.setEventType(EVENT_SPREADTRADING_LOG) + self.setEventType(EVENT_SPREADTRADING_ALGOLOG) self.setFont(BASIC_FONT) self.initTable() - self.registerEvent() + self.registerEvent() + +######################################################################## +class StBuyPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StBuyPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoBuyPrice(self.spreadName, value) + + +######################################################################## +class StSellPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StSellPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoSellPrice(self.spreadName, value) + + +######################################################################## +class StShortPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StShortPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoShortPrice(self.spreadName, value) + + +######################################################################## +class StCoverPriceSpinBox(QtWidgets.QDoubleSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, price, parent=None): + """Constructor""" + super(StCoverPriceSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setDecimals(4) + self.setRange(-10000, 10000) + self.setValue(price) + + self.valueChanged.connect(self.setPrice) + + #---------------------------------------------------------------------- + def setPrice(self, value): + """设置价格""" + self.algoEngine.setAlgoCoverPrice(self.spreadName, value) + + +######################################################################## +class StMaxPosSizeSpinBox(QtWidgets.QSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, size, parent=None): + """Constructor""" + super(StMaxPosSizeSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setRange(-10000, 10000) + self.setValue(size) + + self.valueChanged.connect(self.setSize) + + #---------------------------------------------------------------------- + def setSize(self, size): + """设置价格""" + self.algoEngine.setAlgoMaxPosSize(self.spreadName, size) + + +######################################################################## +class StMaxOrderSizeSpinBox(QtWidgets.QSpinBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, size, parent=None): + """Constructor""" + super(StMaxOrderSizeSpinBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.setRange(-10000, 10000) + self.setValue(size) + + self.valueChanged.connect(self.setSize) + + #---------------------------------------------------------------------- + def setSize(self, size): + """设置价格""" + self.algoEngine.setAlgoMaxOrderSize(self.spreadName, size) + + +######################################################################## +class StModeComboBox(QtWidgets.QComboBox): + """""" + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, mode, parent=None): + """Constructor""" + super(StModeComboBox, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + l = [StAlgoTemplate.MODE_LONGSHORT, + StAlgoTemplate.MODE_LONGONLY, + StAlgoTemplate.MODE_SHORTONLY] + self.addItems(l) + self.setCurrentIndex(l.index(mode)) + + self.currentIndexChanged.connect(self.setMode) + + #---------------------------------------------------------------------- + def setMode(self): + """设置模式""" + mode = unicode(self.currentText()) + self.algoEngine.setAlgoMode(self.spreadName, mode) + + #---------------------------------------------------------------------- + def algoActiveChanged(self, active): + """算法运行状态改变""" + # 只允许算法停止时修改运行模式 + if active: + self.setEnabled(False) + else: + self.setEnabled(True) + + +######################################################################## +class StActiveButton(QtWidgets.QPushButton): + """""" + signalActive = QtCore.pyqtSignal(bool) + + #---------------------------------------------------------------------- + def __init__(self, algoEngine, spreadName, parent=None): + """Constructor""" + super(StActiveButton, self).__init__(parent) + + self.algoEngine = algoEngine + self.spreadName = spreadName + + self.active = False + self.setStopped() + + self.clicked.connect(self.buttonClicked) + + #---------------------------------------------------------------------- + def buttonClicked(self): + """改变运行模式""" + if self.active: + algoActive = self.algoEngine.stopAlgo(self.spreadName) + + if not algoActive: + self.setStopped() + else: + algoActive = self.algoEngine.startAlgo(self.spreadName) + + if algoActive: + self.setStarted() + + #---------------------------------------------------------------------- + def setStarted(self): + """算法启动""" + self.setText(u'运行中') + self.setStyleSheet(STYLESHEET_START) + + self.active = True + self.signalActive.emit(self.active) + + #---------------------------------------------------------------------- + def setStopped(self): + """算法停止""" + self.setText(u'已停止') + self.setStyleSheet(STYLESHEET_STOP) + + self.active = False + self.signalActive.emit(self.active) + + +######################################################################## +class StAlgoManager(QtWidgets.QTableWidget): + """""" + + #---------------------------------------------------------------------- + def __init__(self, stEngine, parent=None): + """Constructor""" + super(StAlgoManager, self).__init__(parent) + + self.algoEngine = stEngine.algoEngine + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化表格""" + headers = [u'价差', + u'算法', + 'BuyPrice', + 'SellPrice', + 'CoverPrice', + 'ShortPrice', + u'委托上限', + u'持仓上限', + u'模式', + u'状态'] + self.setColumnCount(len(headers)) + self.setHorizontalHeaderLabels(headers) + self.horizontalHeader().setResizeMode(QtWidgets.QHeaderView.Stretch) + + self.verticalHeader().setVisible(False) + self.setEditTriggers(self.NoEditTriggers) + + #---------------------------------------------------------------------- + def initCells(self): + """初始化单元格""" + algoEngine = self.algoEngine + + l = self.algoEngine.getAllAlgoParams() + self.setRowCount(len(l)) + + for row, d in enumerate(l): + cellSpreadName = QtWidgets.QTableWidgetItem(d['spreadName']) + cellAlgoName = QtWidgets.QTableWidgetItem(d['algoName']) + spinBuyPrice = StBuyPriceSpinBox(algoEngine, d['spreadName'], d['buyPrice']) + spinSellPrice = StSellPriceSpinBox(algoEngine, d['spreadName'], d['sellPrice']) + spinShortPrice = StShortPriceSpinBox(algoEngine, d['spreadName'], d['shortPrice']) + spinCoverPrice = StCoverPriceSpinBox(algoEngine, d['spreadName'], d['coverPrice']) + spinMaxOrderSize = StMaxOrderSizeSpinBox(algoEngine, d['spreadName'], d['maxOrderSize']) + spinMaxPosSize = StMaxPosSizeSpinBox(algoEngine, d['spreadName'], d['maxPosSize']) + comboMode = StModeComboBox(algoEngine, d['spreadName'], d['mode']) + buttonActive = StActiveButton(algoEngine, d['spreadName']) + + self.setItem(row, 0, cellSpreadName) + self.setItem(row, 1, cellAlgoName) + self.setCellWidget(row, 2, spinBuyPrice) + self.setCellWidget(row, 3, spinSellPrice) + self.setCellWidget(row, 4, spinCoverPrice) + self.setCellWidget(row, 5, spinShortPrice) + self.setCellWidget(row, 6, spinMaxOrderSize) + self.setCellWidget(row, 7, spinMaxPosSize) + self.setCellWidget(row, 8, comboMode) + self.setCellWidget(row, 9, buttonActive) + + buttonActive.signalActive.connect(comboMode.algoActiveChanged) + + +######################################################################## +class StGroup(QtWidgets.QGroupBox): + """集合显示""" + + #---------------------------------------------------------------------- + def __init__(self, widget, title, parent=None): + """Constructor""" + super(StGroup, self).__init__(parent) + + self.setTitle(title) + vbox = QtWidgets.QVBoxLayout() + vbox.addWidget(widget) + self.setLayout(vbox) + ######################################################################## class StManager(QtWidgets.QWidget): @@ -105,37 +451,48 @@ class StManager(QtWidgets.QWidget): self.setWindowTitle(u'价差交易') # 创建按钮 - buttonLoadSetting = QtWidgets.QPushButton(u'加载配置') - - buttonLoadSetting.clicked.connect(self.stEngine.loadSetting) + buttonInit = QtWidgets.QPushButton(u'初始化') + buttonInit.clicked.connect(self.init) # 创建组件 tickMonitor = StTickMonitor(self.mainEngine, self.eventEngine) posMonitor = StPosMonitor(self.mainEngine, self.eventEngine) logMonitor = StLogMonitor(self.mainEngine, self.eventEngine) + self.algoManager = StAlgoManager(self.stEngine) + algoLogMonitor = StAlgoLogMonitor(self.mainEngine, self.eventEngine) + + # 创建集合 + groupTick = StGroup(tickMonitor, u'价差行情') + groupPos = StGroup(posMonitor, u'价差持仓') + groupLog = StGroup(logMonitor, u'日志信息') + groupAlgo = StGroup(self.algoManager, u'价差算法') + groupAlgoLog = StGroup(algoLogMonitor, u'算法信息') # 设置布局 - hbox1 = QtWidgets.QHBoxLayout() - hbox1.addWidget(buttonLoadSetting) - hbox1.addStretch() + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(buttonInit) + hbox.addStretch() - hbox2 = QtWidgets.QHBoxLayout() - hbox2.addWidget(tickMonitor) - hbox2.addWidget(posMonitor) - - vbox = QtWidgets.QVBoxLayout() - vbox.addLayout(hbox1) - vbox.addLayout(hbox2) - vbox.addWidget(logMonitor) - - self.setLayout(vbox) + grid = QtWidgets.QGridLayout() + grid.addLayout(hbox, 0, 0, 1, 2) + grid.addWidget(groupTick, 1, 0) + grid.addWidget(groupPos, 1, 1) + grid.addWidget(groupAlgo, 2, 0, 1, 2) + grid.addWidget(groupLog, 3, 0) + grid.addWidget(groupAlgoLog, 3, 1) + + self.setLayout(grid) #---------------------------------------------------------------------- def show(self): """重载显示""" self.showMaximized() - + #---------------------------------------------------------------------- + def init(self): + """初始化""" + self.stEngine.init() + self.algoManager.initCells() From 1aea18504a8da9826ef2306ead6f9c78fe14fbbc Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 13:39:21 +0800 Subject: [PATCH 11/29] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=8A=E6=B5=B7?= =?UTF-8?q?=E4=B8=AD=E6=9C=9F=E5=8E=86=E5=8F=B2=E6=95=B0=E6=8D=AE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/api/shcifco/__init__.py | 0 vnpy/api/shcifco/vnshcifco.py | 138 ++++++++++++++++++++++++++++++++++ 2 files changed, 138 insertions(+) create mode 100644 vnpy/api/shcifco/__init__.py create mode 100644 vnpy/api/shcifco/vnshcifco.py diff --git a/vnpy/api/shcifco/__init__.py b/vnpy/api/shcifco/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vnpy/api/shcifco/vnshcifco.py b/vnpy/api/shcifco/vnshcifco.py new file mode 100644 index 00000000..06626e97 --- /dev/null +++ b/vnpy/api/shcifco/vnshcifco.py @@ -0,0 +1,138 @@ +# encoding: UTF-8 + + +import requests + +HTTP_OK = 200 + + +######################################################################## +class DataApi(object): + """数据接口""" + + #---------------------------------------------------------------------- + def __init__(self, ip, port, token): + """Constructor""" + self.ip = ip + self.port = port + self.token = token + + self.service = 'ShcifcoApi' + self.domain = 'http://' + ':'.join([self.ip, self.port]) + + #---------------------------------------------------------------------- + def getData(self, path, params): + """下载数据""" + url = '/'.join([self.domain, self.service, path]) + params['token'] = self.token + r = requests.get(url=url, params=params) + + if r.status_code != HTTP_OK: + print u'http请求失败,状态代码%s' %r.status_code + return None + else: + return r.text + + #---------------------------------------------------------------------- + def getLastTick(self, symbol): + """获取最新Tick""" + path = 'lasttick' + params = {'ids': symbol} + data = self.getData(path, params) + + l = data.split(',') + d = { + 'symbol': l[0], + 'lastPrice': float(l[1]), + 'bidPrice': float(l[2]), + 'bidVolume': int(l[3]), + 'askPrice': float(l[4]), + 'askVolume': int(l[5]), + 'volume': int(l[6]), + 'openInterest': int(l[7]) + } + return d + + #---------------------------------------------------------------------- + def getLastPrice(self, symbol): + """获取最新成交价""" + path = 'lastprice' + params = {'ids': symbol} + data = self.getData(path, params) + + price = float(data) + return price + + #---------------------------------------------------------------------- + def getLastBar(self, symbol): + """获取最新的一分钟K线数据""" + path = 'lastbar' + params = {'ids': symbol} + data = self.getData(path, params) + + l = data.split(',') + d = { + 'symbol': l[0], + 'time': l[1], + 'open': float(l[2]), + 'high': float(l[3]), + 'low': float(l[4]), + 'close': float(l[5]), + 'volume': int([6]) + } + return d + + #---------------------------------------------------------------------- + def getHisBar(self, symbol, num, date='', period=''): + """获取历史K线数据""" + path = 'lastbar' + + # 默认参数 + params = { + 'ids': symbol, + 'num': num + } + # 可选参数 + if date: + params[date] = date + if period: + params[period] = period + + data = self.getData(path, params) + + barList = [] + l = data.split(';') + + for barStr in l: + barData = barStr.split(',') + d = { + 'symbol': barData[0], + 'time': barData[1], + 'open': float(barData[2]), + 'high': float(barData[3]), + 'low': float(barData[4]), + 'close': float(barData[5]), + 'volume': int([6]) + } + barList.append(d) + + return barList + + +if __name__ == "__main__": + ip = '101.231.179.199' + port = '10102' + token = 'testd2cda34b2d317779e812eb84ee4224a6_123456' + + api = DataApi(ip, port, token) + api.getData(path, params) + + print api.getLastTick('cu1709') + + print api.getLastPrice('cu1709') + + print api.getLastBar('cu1709') + + print api.getHisBar('cu1709', 50) + + \ No newline at end of file From b3cdb0e2c0060a71a43fa5fe68535559093b359f Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 16:55:37 +0800 Subject: [PATCH 12/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0vnpy.data=E7=94=A8?= =?UTF-8?q?=E4=BA=8E=E5=AD=98=E6=94=BE=E6=95=B0=E6=8D=AE=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E7=9A=84=E5=8A=9F=E8=83=BD=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {vnpy/api => archive}/datayes/README.md | 0 {vnpy/api => archive}/datayes/__init__.py | 0 {vnpy/api => archive}/datayes/api.py | 0 .../datayes/config/db_EQU_D1.csv | 0 {vnpy/api => archive}/datayes/download.sh | 0 {vnpy/api => archive}/datayes/errors.py | 0 {vnpy/api => archive}/datayes/fun/fetch.R | 0 .../datayes/names/equTicker.json | 0 .../datayes/names/fudTicker.json | 0 .../datayes/names/futTicker.json | 0 .../datayes/names/idxTicker.json | 0 .../datayes/names/optTicker.json | 0 .../api => archive}/datayes/names/secID.json | 0 {vnpy/api => archive}/datayes/prepare.sh | 0 .../datayes/static/figs/fig1.png | Bin .../datayes/static/figs/fig2.png | Bin .../datayes/static/figs/fig3.png | Bin .../datayes/static/figs/fig4.png | Bin .../datayes/static/figs/fig5.png | Bin .../datayes/static/figs/fig6.png | Bin .../datayes/static/tutorial.ipynb | 0 .../datayes/static/tutorial.md | 0 {vnpy/api => archive}/datayes/storage.py | 0 {vnpy/api => archive}/datayes/tests.py | 0 {vnpy/api => archive}/datayes/update.sh | 0 vnpy/data/README.md | 5 ++ vnpy/{api/shcifco => data}/__init__.py | 0 vnpy/data/datayes/__init__.py | 1 + vnpy/data/datayes/vndatayes.py | 52 ++++++++++++++++++ vnpy/data/shcifco/__init__.py | 0 vnpy/{api => data}/shcifco/vnshcifco.py | 4 +- vnpy/trader/app/ctaStrategy/ctaHistoryData.py | 6 +- vnpy/trader/app/spreadTrading/stEngine.py | 4 +- 33 files changed, 66 insertions(+), 6 deletions(-) rename {vnpy/api => archive}/datayes/README.md (100%) rename {vnpy/api => archive}/datayes/__init__.py (100%) rename {vnpy/api => archive}/datayes/api.py (100%) rename {vnpy/api => archive}/datayes/config/db_EQU_D1.csv (100%) rename {vnpy/api => archive}/datayes/download.sh (100%) rename {vnpy/api => archive}/datayes/errors.py (100%) rename {vnpy/api => archive}/datayes/fun/fetch.R (100%) rename {vnpy/api => archive}/datayes/names/equTicker.json (100%) rename {vnpy/api => archive}/datayes/names/fudTicker.json (100%) rename {vnpy/api => archive}/datayes/names/futTicker.json (100%) rename {vnpy/api => archive}/datayes/names/idxTicker.json (100%) rename {vnpy/api => archive}/datayes/names/optTicker.json (100%) rename {vnpy/api => archive}/datayes/names/secID.json (100%) rename {vnpy/api => archive}/datayes/prepare.sh (100%) rename {vnpy/api => archive}/datayes/static/figs/fig1.png (100%) rename {vnpy/api => archive}/datayes/static/figs/fig2.png (100%) rename {vnpy/api => archive}/datayes/static/figs/fig3.png (100%) rename {vnpy/api => archive}/datayes/static/figs/fig4.png (100%) rename {vnpy/api => archive}/datayes/static/figs/fig5.png (100%) rename {vnpy/api => archive}/datayes/static/figs/fig6.png (100%) rename {vnpy/api => archive}/datayes/static/tutorial.ipynb (100%) rename {vnpy/api => archive}/datayes/static/tutorial.md (100%) rename {vnpy/api => archive}/datayes/storage.py (100%) rename {vnpy/api => archive}/datayes/tests.py (100%) rename {vnpy/api => archive}/datayes/update.sh (100%) create mode 100644 vnpy/data/README.md rename vnpy/{api/shcifco => data}/__init__.py (100%) create mode 100644 vnpy/data/datayes/__init__.py create mode 100644 vnpy/data/datayes/vndatayes.py create mode 100644 vnpy/data/shcifco/__init__.py rename vnpy/{api => data}/shcifco/vnshcifco.py (98%) diff --git a/vnpy/api/datayes/README.md b/archive/datayes/README.md similarity index 100% rename from vnpy/api/datayes/README.md rename to archive/datayes/README.md diff --git a/vnpy/api/datayes/__init__.py b/archive/datayes/__init__.py similarity index 100% rename from vnpy/api/datayes/__init__.py rename to archive/datayes/__init__.py diff --git a/vnpy/api/datayes/api.py b/archive/datayes/api.py similarity index 100% rename from vnpy/api/datayes/api.py rename to archive/datayes/api.py diff --git a/vnpy/api/datayes/config/db_EQU_D1.csv b/archive/datayes/config/db_EQU_D1.csv similarity index 100% rename from vnpy/api/datayes/config/db_EQU_D1.csv rename to archive/datayes/config/db_EQU_D1.csv diff --git a/vnpy/api/datayes/download.sh b/archive/datayes/download.sh similarity index 100% rename from vnpy/api/datayes/download.sh rename to archive/datayes/download.sh diff --git a/vnpy/api/datayes/errors.py b/archive/datayes/errors.py similarity index 100% rename from vnpy/api/datayes/errors.py rename to archive/datayes/errors.py diff --git a/vnpy/api/datayes/fun/fetch.R b/archive/datayes/fun/fetch.R similarity index 100% rename from vnpy/api/datayes/fun/fetch.R rename to archive/datayes/fun/fetch.R diff --git a/vnpy/api/datayes/names/equTicker.json b/archive/datayes/names/equTicker.json similarity index 100% rename from vnpy/api/datayes/names/equTicker.json rename to archive/datayes/names/equTicker.json diff --git a/vnpy/api/datayes/names/fudTicker.json b/archive/datayes/names/fudTicker.json similarity index 100% rename from vnpy/api/datayes/names/fudTicker.json rename to archive/datayes/names/fudTicker.json diff --git a/vnpy/api/datayes/names/futTicker.json b/archive/datayes/names/futTicker.json similarity index 100% rename from vnpy/api/datayes/names/futTicker.json rename to archive/datayes/names/futTicker.json diff --git a/vnpy/api/datayes/names/idxTicker.json b/archive/datayes/names/idxTicker.json similarity index 100% rename from vnpy/api/datayes/names/idxTicker.json rename to archive/datayes/names/idxTicker.json diff --git a/vnpy/api/datayes/names/optTicker.json b/archive/datayes/names/optTicker.json similarity index 100% rename from vnpy/api/datayes/names/optTicker.json rename to archive/datayes/names/optTicker.json diff --git a/vnpy/api/datayes/names/secID.json b/archive/datayes/names/secID.json similarity index 100% rename from vnpy/api/datayes/names/secID.json rename to archive/datayes/names/secID.json diff --git a/vnpy/api/datayes/prepare.sh b/archive/datayes/prepare.sh similarity index 100% rename from vnpy/api/datayes/prepare.sh rename to archive/datayes/prepare.sh diff --git a/vnpy/api/datayes/static/figs/fig1.png b/archive/datayes/static/figs/fig1.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig1.png rename to archive/datayes/static/figs/fig1.png diff --git a/vnpy/api/datayes/static/figs/fig2.png b/archive/datayes/static/figs/fig2.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig2.png rename to archive/datayes/static/figs/fig2.png diff --git a/vnpy/api/datayes/static/figs/fig3.png b/archive/datayes/static/figs/fig3.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig3.png rename to archive/datayes/static/figs/fig3.png diff --git a/vnpy/api/datayes/static/figs/fig4.png b/archive/datayes/static/figs/fig4.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig4.png rename to archive/datayes/static/figs/fig4.png diff --git a/vnpy/api/datayes/static/figs/fig5.png b/archive/datayes/static/figs/fig5.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig5.png rename to archive/datayes/static/figs/fig5.png diff --git a/vnpy/api/datayes/static/figs/fig6.png b/archive/datayes/static/figs/fig6.png similarity index 100% rename from vnpy/api/datayes/static/figs/fig6.png rename to archive/datayes/static/figs/fig6.png diff --git a/vnpy/api/datayes/static/tutorial.ipynb b/archive/datayes/static/tutorial.ipynb similarity index 100% rename from vnpy/api/datayes/static/tutorial.ipynb rename to archive/datayes/static/tutorial.ipynb diff --git a/vnpy/api/datayes/static/tutorial.md b/archive/datayes/static/tutorial.md similarity index 100% rename from vnpy/api/datayes/static/tutorial.md rename to archive/datayes/static/tutorial.md diff --git a/vnpy/api/datayes/storage.py b/archive/datayes/storage.py similarity index 100% rename from vnpy/api/datayes/storage.py rename to archive/datayes/storage.py diff --git a/vnpy/api/datayes/tests.py b/archive/datayes/tests.py similarity index 100% rename from vnpy/api/datayes/tests.py rename to archive/datayes/tests.py diff --git a/vnpy/api/datayes/update.sh b/archive/datayes/update.sh similarity index 100% rename from vnpy/api/datayes/update.sh rename to archive/datayes/update.sh diff --git a/vnpy/data/README.md b/vnpy/data/README.md new file mode 100644 index 00000000..b00cb83f --- /dev/null +++ b/vnpy/data/README.md @@ -0,0 +1,5 @@ +# vn.data - 数据相关工具 + +### 历史数据 +* datayes:通联数据接口 +* shcifco:上海中期接口 \ No newline at end of file diff --git a/vnpy/api/shcifco/__init__.py b/vnpy/data/__init__.py similarity index 100% rename from vnpy/api/shcifco/__init__.py rename to vnpy/data/__init__.py diff --git a/vnpy/data/datayes/__init__.py b/vnpy/data/datayes/__init__.py new file mode 100644 index 00000000..e06b8545 --- /dev/null +++ b/vnpy/data/datayes/__init__.py @@ -0,0 +1 @@ +from vndatayes import DatayesApi \ No newline at end of file diff --git a/vnpy/data/datayes/vndatayes.py b/vnpy/data/datayes/vndatayes.py new file mode 100644 index 00000000..f64aaf68 --- /dev/null +++ b/vnpy/data/datayes/vndatayes.py @@ -0,0 +1,52 @@ +# encoding: UTF-8 + +'''一个简单的通联数据客户端,主要使用requests开发,比通联官网的python例子更为简洁。''' + +import os +import requests +import json + + +HTTP_OK = 200 + + +######################################################################## +class DatayesApi(object): + """通联数据API""" + + #---------------------------------------------------------------------- + def __init__(self, token, + domain="http://api.wmcloud.com/data", + version="v1"): + """Constructor""" + self.domain = domain # 主域名 + self.version = version # API版本 + self.token = token # 授权码 + + self.header = {} # http请求头部 + self.header['Connection'] = 'keep_alive' + self.header['Authorization'] = 'Bearer ' + self.token + + #---------------------------------------------------------------------- + def downloadData(self, path, params): + """下载数据""" + url = '/'.join([self.domain, self.version, path]) + r = requests.get(url=url, headers=self.header, params=params) + + if r.status_code != HTTP_OK: + print u'http请求失败,状态代码%s' %r.status_code + return None + else: + result = r.json() + if 'retMsg' in result and result['retMsg'] == 'Success': + return result['data'] + else: + if 'retMsg' in result: + print u'查询失败,返回信息%s' %result['retMsg'] + elif 'message' in result: + print u'查询失败,返回信息%s' %result['message'] + return None + + + + \ No newline at end of file diff --git a/vnpy/data/shcifco/__init__.py b/vnpy/data/shcifco/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/vnpy/api/shcifco/vnshcifco.py b/vnpy/data/shcifco/vnshcifco.py similarity index 98% rename from vnpy/api/shcifco/vnshcifco.py rename to vnpy/data/shcifco/vnshcifco.py index 06626e97..94927d9c 100644 --- a/vnpy/api/shcifco/vnshcifco.py +++ b/vnpy/data/shcifco/vnshcifco.py @@ -7,7 +7,7 @@ HTTP_OK = 200 ######################################################################## -class DataApi(object): +class ShcifcoApi(object): """数据接口""" #---------------------------------------------------------------------- @@ -124,7 +124,7 @@ if __name__ == "__main__": port = '10102' token = 'testd2cda34b2d317779e812eb84ee4224a6_123456' - api = DataApi(ip, port, token) + api = ShcifcoApi(ip, port, token) api.getData(path, params) print api.getLastTick('cu1709') diff --git a/vnpy/trader/app/ctaStrategy/ctaHistoryData.py b/vnpy/trader/app/ctaStrategy/ctaHistoryData.py index 5366468d..d9c97375 100644 --- a/vnpy/trader/app/ctaStrategy/ctaHistoryData.py +++ b/vnpy/trader/app/ctaStrategy/ctaHistoryData.py @@ -13,10 +13,10 @@ from multiprocessing.pool import ThreadPool import pymongo +from vnpy.data.datayes import DatayesApi from vnpy.trader.vtGlobal import globalSetting from vnpy.trader.vtConstant import * from vnpy.trader.vtObject import VtBarData -from vnpy.trader.app.ctaStrategy.datayesClient import DatayesClient # 以下为vn.trader和通联数据规定的交易所代码映射 @@ -33,10 +33,10 @@ class HistoryDataEngine(object): """CTA模块用的历史数据引擎""" #---------------------------------------------------------------------- - def __init__(self): + def __init__(self, token): """Constructor""" self.dbClient = pymongo.MongoClient(globalSetting['mongoHost'], globalSetting['mongoPort']) - self.datayesClient = DatayesClient() + self.datayesClient = DatayesApi(token) #---------------------------------------------------------------------- def lastTradeDate(self): diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index 71e89c31..6789da12 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -11,7 +11,8 @@ from vnpy.trader.vtEvent import (EVENT_TICK, EVENT_TRADE, EVENT_POSITION, from vnpy.trader.vtObject import (VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData) from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT, - OFFSET_OPEN, OFFSET_CLOSE) + OFFSET_OPEN, OFFSET_CLOSE, + PRICETYPE_LIMITPRICE) from .stBase import (StLeg, StSpread, EVENT_SPREADTRADING_TICK, EVENT_SPREADTRADING_POS, EVENT_SPREADTRADING_LOG, @@ -358,6 +359,7 @@ class StAlgoEngine(object): req.direction = direction req.offset = offset req.volume = volume + req.priceType = PRICETYPE_LIMITPRICE if direction == DIRECTION_LONG: req.price = price + payup * contract.priceTick From 788aa4acb7795387d4e309c6b4f0434ceb4fa5a7 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 17:14:35 +0800 Subject: [PATCH 13/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E4=BB=B7=E5=B7=AE?= =?UTF-8?q?=E4=BA=A4=E6=98=93=E6=A8=A1=E5=9D=97=E7=9A=84=E4=B8=80=E9=94=AE?= =?UTF-8?q?=E5=85=A8=E5=81=9C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/spreadTrading/stAlgo.py | 18 +++---- vnpy/trader/app/spreadTrading/uiStWidget.py | 49 ++++++++++++++----- .../gateway/ctpGateway/CTP_connect.json | 4 +- 3 files changed, 47 insertions(+), 24 deletions(-) diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index 3cb24c70..afd4f743 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -282,21 +282,21 @@ class SniperAlgo(StAlgoTemplate): #---------------------------------------------------------------------- def start(self): """启动""" + if not self.active: + self.quoteCount = 0 + self.hedgeCount = 0 + self.active = True - - self.quoteCount = 0 - self.hedgeCount = 0 - return self.active #---------------------------------------------------------------------- def stop(self): """停止""" - self.active = False - - self.hedgingTaskDict.clear() - self.cancelAllOrders() - + if self.active: + self.hedgingTaskDict.clear() + self.cancelAllOrders() + + self.active = False return self.active #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index 76fd714e..d2613146 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -319,16 +319,25 @@ class StActiveButton(QtWidgets.QPushButton): def buttonClicked(self): """改变运行模式""" if self.active: - algoActive = self.algoEngine.stopAlgo(self.spreadName) - - if not algoActive: - self.setStopped() + self.stop else: - algoActive = self.algoEngine.startAlgo(self.spreadName) - - if algoActive: - self.setStarted() + self.start() + #---------------------------------------------------------------------- + def stop(self): + """停止""" + algoActive = self.algoEngine.stopAlgo(self.spreadName) + if not algoActive: + self.setStopped() + + #---------------------------------------------------------------------- + def start(self): + """启动""" + algoActive = self.algoEngine.startAlgo(self.spreadName) + + if algoActive: + self.setStarted() + #---------------------------------------------------------------------- def setStarted(self): """算法启动""" @@ -350,7 +359,7 @@ class StActiveButton(QtWidgets.QPushButton): ######################################################################## class StAlgoManager(QtWidgets.QTableWidget): - """""" + """价差算法管理组件""" #---------------------------------------------------------------------- def __init__(self, stEngine, parent=None): @@ -359,6 +368,8 @@ class StAlgoManager(QtWidgets.QTableWidget): self.algoEngine = stEngine.algoEngine + self.buttonActiveDict = {} # spreadName: buttonActive + self.initUi() #---------------------------------------------------------------------- @@ -413,6 +424,14 @@ class StAlgoManager(QtWidgets.QTableWidget): self.setCellWidget(row, 9, buttonActive) buttonActive.signalActive.connect(comboMode.algoActiveChanged) + + self.buttonActiveDict[d['spreadName']] = buttonActive + + #---------------------------------------------------------------------- + def stopAll(self): + """停止所有算法""" + for button in self.buttonActiveDict.values(): + button.stop() ######################################################################## @@ -450,10 +469,6 @@ class StManager(QtWidgets.QWidget): """初始化界面""" self.setWindowTitle(u'价差交易') - # 创建按钮 - buttonInit = QtWidgets.QPushButton(u'初始化') - buttonInit.clicked.connect(self.init) - # 创建组件 tickMonitor = StTickMonitor(self.mainEngine, self.eventEngine) posMonitor = StPosMonitor(self.mainEngine, self.eventEngine) @@ -461,6 +476,13 @@ class StManager(QtWidgets.QWidget): self.algoManager = StAlgoManager(self.stEngine) algoLogMonitor = StAlgoLogMonitor(self.mainEngine, self.eventEngine) + # 创建按钮 + buttonInit = QtWidgets.QPushButton(u'初始化') + buttonInit.clicked.connect(self.init) + + buttonStopAll = QtWidgets.QPushButton(u'全部停止') + buttonStopAll.clicked.connect(self.algoManager.stopAll) + # 创建集合 groupTick = StGroup(tickMonitor, u'价差行情') groupPos = StGroup(posMonitor, u'价差持仓') @@ -472,6 +494,7 @@ class StManager(QtWidgets.QWidget): hbox = QtWidgets.QHBoxLayout() hbox.addWidget(buttonInit) hbox.addStretch() + hbox.addWidget(buttonStopAll) grid = QtWidgets.QGridLayout() grid.addLayout(hbox, 0, 0, 1, 2) diff --git a/vnpy/trader/gateway/ctpGateway/CTP_connect.json b/vnpy/trader/gateway/ctpGateway/CTP_connect.json index e4bfa6b8..1b4d5a42 100644 --- a/vnpy/trader/gateway/ctpGateway/CTP_connect.json +++ b/vnpy/trader/gateway/ctpGateway/CTP_connect.json @@ -2,6 +2,6 @@ "brokerID": "9999", "mdAddress": "tcp://180.168.146.187:10011", "tdAddress": "tcp://180.168.146.187:10001", - "userID": "simnow申请", - "password": "simnow申请" + "userID": "000300", + "password": "19890624" } \ No newline at end of file From 654c7d0e8a4f7faa3dc805d11643588a27464ca9 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 17:29:22 +0800 Subject: [PATCH 14/29] =?UTF-8?q?=E7=A7=BB=E9=99=A4=E5=8F=AF=E8=83=BD?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=9F=90=E4=BA=9B=E6=9C=9F=E6=9D=83=E5=92=8C?= =?UTF-8?q?=E4=BB=B7=E5=B7=AE=E8=A1=8C=E6=83=85Tick=E4=B8=A2=E5=A4=B1?= =?UTF-8?q?=E7=9A=84=E8=BF=87=E6=BB=A4=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/gateway/ctpGateway/ctpGateway.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/vnpy/trader/gateway/ctpGateway/ctpGateway.py b/vnpy/trader/gateway/ctpGateway/ctpGateway.py index 2294cd21..4354080b 100644 --- a/vnpy/trader/gateway/ctpGateway/ctpGateway.py +++ b/vnpy/trader/gateway/ctpGateway/ctpGateway.py @@ -329,10 +329,6 @@ class CtpMdApi(MdApi): #---------------------------------------------------------------------- def onRtnDepthMarketData(self, data): """行情推送""" - # 忽略成交量为0的无效tick数据 - if not data['Volume']: - return - # 创建对象 tick = VtTickData() tick.gatewayName = self.gatewayName @@ -710,7 +706,7 @@ class CtpTdApi(TdApi): pos.positionProfit += data['PositionProfit'] # 计算持仓均价 - if pos.position: + if pos.position and pos.symbol in self.symbolSizeDict: size = self.symbolSizeDict[pos.symbol] pos.price = (cost + data['PositionCost']) / (pos.position * size) From ed7e7a772818ab4c6a666e6f5abfb8b4927e5cab Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 18:00:07 +0800 Subject: [PATCH 15/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0DataRecording=E8=A1=8C?= =?UTF-8?q?=E6=83=85=E8=AE=B0=E5=BD=95=E4=BD=BF=E7=94=A8=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/DataRecording/runDataRecording.py | 88 +++++++++++++++++++ .../gateway/ctpGateway/CTP_connect.json | 4 +- 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 examples/DataRecording/runDataRecording.py diff --git a/examples/DataRecording/runDataRecording.py b/examples/DataRecording/runDataRecording.py new file mode 100644 index 00000000..73c77f6f --- /dev/null +++ b/examples/DataRecording/runDataRecording.py @@ -0,0 +1,88 @@ +# encoding: UTF-8 + +import multiprocessing +from time import sleep +from datetime import datetime, time + +from vnpy.event import EventEngine2 +from vnpy.trader.vtEvent import EVENT_LOG +from vnpy.trader.vtEngine import MainEngine + + +#---------------------------------------------------------------------- +def printLog(content): + """输出日志""" + t = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + print '%s\t%s' %(t, content) + +#---------------------------------------------------------------------- +def processLogEvent(event): + """处理日志事件""" + log = event.dict_['data'] + content = '%s:%s' %(log.gatewayName, log.logContent) + printLog(content) + +#---------------------------------------------------------------------- +def runChildProcess(): + """子进程运行函数""" + print '-'*20 + printLog(u'启动行情记录运行子进程') + + ee = EventEngine2() + printLog(u'事件引擎创建成功') + + me = MainEngine(ee) + printLog(u'主引擎创建成功') + + ee.register(EVENT_LOG, processLogEvent) + printLog(u'注册日志事件监听') + + me.connect('CTP') + printLog(u'连接CTP接口') + + while True: + sleep(1) + +#---------------------------------------------------------------------- +def runParentProcess(): + """父进程运行函数""" + printLog(u'启动行情记录守护父进程') + + DAY_START = time(8, 45) # 日盘启动和停止时间 + DAY_END = time(15, 30) + + NIGHT_START = time(20, 45) # 夜盘启动和停止时间 + NIGHT_END = time(2, 45) + + p = None # 子进程句柄 + + while True: + currentTime = datetime.now().time() + recording = False + + # 判断当前处于的时间段 + if ((currentTime >= DAY_START and currentTime <= DAY_END) or + (currentTime >= NIGHT_START) or + (currentTime <= NIGHT_END)): + recording = True + + # 记录时间则需要启动子进程 + if recording and p is None: + printLog(u'启动子进程') + p = multiprocessing.Process(target=runChildProcess) + p.start() + printLog(u'子进程启动成功') + + # 非记录时间则退出子进程 + if not recording and p is not None: + printLog(u'关闭子进程') + p.terminate() + p.join() + p = None + printLog(u'子进程关闭成功') + + sleep(5) + + +if __name__ == '__main__': + runParentProcess() \ No newline at end of file diff --git a/vnpy/trader/gateway/ctpGateway/CTP_connect.json b/vnpy/trader/gateway/ctpGateway/CTP_connect.json index 1b4d5a42..e4bfa6b8 100644 --- a/vnpy/trader/gateway/ctpGateway/CTP_connect.json +++ b/vnpy/trader/gateway/ctpGateway/CTP_connect.json @@ -2,6 +2,6 @@ "brokerID": "9999", "mdAddress": "tcp://180.168.146.187:10011", "tdAddress": "tcp://180.168.146.187:10001", - "userID": "000300", - "password": "19890624" + "userID": "simnow申请", + "password": "simnow申请" } \ No newline at end of file From f58f2be4ee16efca688a96b10de5db16f275f3be Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 27 Jun 2017 21:52:36 +0800 Subject: [PATCH 16/29] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E8=A1=8C=E6=83=85?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E5=B7=A5=E5=85=B7=EF=BC=8C=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=97=A0=E5=9B=BE=E5=BD=A2=E7=95=8C=E9=9D=A2CTA=E7=AD=96?= =?UTF-8?q?=E7=95=A5=E8=BF=90=E8=A1=8C=E7=A4=BA=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/CtaTrading/runCtaTrading.py | 104 +++++++++++++++++++++ examples/DataRecording/runDataRecording.py | 5 +- examples/README.md | 11 +++ vnpy/trader/app/ctaStrategy/ctaEngine.py | 20 +++- vnpy/trader/app/ctaStrategy/uiCtaWidget.py | 9 +- 5 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 examples/CtaTrading/runCtaTrading.py create mode 100644 examples/README.md diff --git a/examples/CtaTrading/runCtaTrading.py b/examples/CtaTrading/runCtaTrading.py new file mode 100644 index 00000000..70fa4c22 --- /dev/null +++ b/examples/CtaTrading/runCtaTrading.py @@ -0,0 +1,104 @@ +# encoding: UTF-8 + +import multiprocessing +from time import sleep +from datetime import datetime, time + +from vnpy.event import EventEngine2 +from vnpy.trader.vtEvent import EVENT_LOG +from vnpy.trader.vtEngine import MainEngine +from vnpy.trader.gateway import ctpGateway +from vnpy.trader.app import ctaStrategy +from vnpy.trader.app.ctaStrategy.ctaBase import EVENT_CTA_LOG + +#---------------------------------------------------------------------- +def printLog(content): + """输出日志""" + t = datetime.now().strftime('%Y-%m-%d %H:%M:%S') + print '%s\t%s' %(t, content) + +#---------------------------------------------------------------------- +def processLogEvent(event): + """处理日志事件""" + log = event.dict_['data'] + content = '%s:%s' %(log.gatewayName, log.logContent) + printLog(content) + +#---------------------------------------------------------------------- +def runChildProcess(): + """子进程运行函数""" + print '-'*20 + printLog(u'启动CTA策略运行子进程') + + ee = EventEngine2() + printLog(u'事件引擎创建成功') + + me = MainEngine(ee) + me.addGateway(ctpGateway) + me.addApp(ctaStrategy) + printLog(u'主引擎创建成功') + + ee.register(EVENT_LOG, processLogEvent) + ee.register(EVENT_CTA_LOG, processLogEvent) + printLog(u'注册日志事件监听') + + me.connect('CTP') + printLog(u'连接CTP接口') + + cta = me.appDict[ctaStrategy.appName] + + cta.loadSetting() + printLog(u'CTA策略载入成功') + + cta.initAll() + printLog(u'CTA策略初始化成功') + + cta.startAll() + printLog(u'CTA策略启动成功') + + while True: + sleep(1) + +#---------------------------------------------------------------------- +def runParentProcess(): + """父进程运行函数""" + printLog(u'启动CTA策略守护父进程') + + DAY_START = time(8, 45) # 日盘启动和停止时间 + DAY_END = time(15, 30) + + NIGHT_START = time(20, 45) # 夜盘启动和停止时间 + NIGHT_END = time(2, 45) + + p = None # 子进程句柄 + + while True: + currentTime = datetime.now().time() + recording = False + + # 判断当前处于的时间段 + if ((currentTime >= DAY_START and currentTime <= DAY_END) or + (currentTime >= NIGHT_START) or + (currentTime <= NIGHT_END)): + recording = True + + # 记录时间则需要启动子进程 + if recording and p is None: + printLog(u'启动子进程') + p = multiprocessing.Process(target=runChildProcess) + p.start() + printLog(u'子进程启动成功') + + # 非记录时间则退出子进程 + if not recording and p is not None: + printLog(u'关闭子进程') + p.terminate() + p.join() + p = None + printLog(u'子进程关闭成功') + + sleep(5) + + +if __name__ == '__main__': + runParentProcess() \ No newline at end of file diff --git a/examples/DataRecording/runDataRecording.py b/examples/DataRecording/runDataRecording.py index 73c77f6f..dc6846b8 100644 --- a/examples/DataRecording/runDataRecording.py +++ b/examples/DataRecording/runDataRecording.py @@ -7,7 +7,8 @@ from datetime import datetime, time from vnpy.event import EventEngine2 from vnpy.trader.vtEvent import EVENT_LOG from vnpy.trader.vtEngine import MainEngine - +from vnpy.trader.gateway import ctpGateway +from vnpy.trader.app import dataRecorder #---------------------------------------------------------------------- def printLog(content): @@ -32,6 +33,8 @@ def runChildProcess(): printLog(u'事件引擎创建成功') me = MainEngine(ee) + me.addGateway(ctpGateway) + me.addApp(dataRecorder) printLog(u'主引擎创建成功') ee.register(EVENT_LOG, processLogEvent) diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..148cecf1 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,11 @@ +# vn.py项目的应用示例 + +本文件夹中的内容主要是关于如何在交易业务中使用vn.py的示例 + +* VnTrader:最常用的vn.py图形交易界面 + +* DataRecording:全自动行情记录工具(无需用户每日定时重启) + +* CtaTrading:纯命令行模式的CTA策略交易(尽管同样实现了无人值守,但强烈建议每天启动时人工检查,为自己的PNL负责) + +* CtaBacktesting:CTA策略的回测和优化 \ No newline at end of file diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index 2a2178b5..319209eb 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -463,7 +463,25 @@ class CtaEngine(object): if so.strategy is strategy: self.cancelStopOrder(stopOrderID) else: - self.writeCtaLog(u'策略实例不存在:%s' %name) + self.writeCtaLog(u'策略实例不存在:%s' %name) + + #---------------------------------------------------------------------- + def initAll(self): + """全部初始化""" + for name in self.strategyDict.keys(): + self.initStrategy(name) + + #---------------------------------------------------------------------- + def startAll(self): + """全部启动""" + for name in self.strategyDict.keys(): + self.startStrategy(name) + + #---------------------------------------------------------------------- + def stopAll(self): + """全部停止""" + for name in self.strategyDict.keys(): + self.stopStrategy(name) #---------------------------------------------------------------------- def saveSetting(self): diff --git a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py index 62366a89..7223a673 100644 --- a/vnpy/trader/app/ctaStrategy/uiCtaWidget.py +++ b/vnpy/trader/app/ctaStrategy/uiCtaWidget.py @@ -228,20 +228,17 @@ class CtaEngineManager(QtWidgets.QWidget): #---------------------------------------------------------------------- def initAll(self): """全部初始化""" - for name in self.ctaEngine.strategyDict.keys(): - self.ctaEngine.initStrategy(name) + self.ctaEngine.initAll() #---------------------------------------------------------------------- def startAll(self): """全部启动""" - for name in self.ctaEngine.strategyDict.keys(): - self.ctaEngine.startStrategy(name) + self.ctaEngine.startAll() #---------------------------------------------------------------------- def stopAll(self): """全部停止""" - for name in self.ctaEngine.strategyDict.keys(): - self.ctaEngine.stopStrategy(name) + self.ctaEngine.stopAll() #---------------------------------------------------------------------- def load(self): From bed06834e3d1f65be3bfba577c5d0ac3cd371c3f Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 28 Jun 2017 15:36:24 +0800 Subject: [PATCH 17/29] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=97=A0=E7=95=8C?= =?UTF-8?q?=E9=9D=A2CTA=E7=AD=96=E7=95=A5=E4=BA=A4=E6=98=93=E7=9A=84Exampl?= =?UTF-8?q?e=EF=BC=8C=E4=BF=AE=E6=94=B9DataRecorder=E7=9A=84=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E6=96=87=E4=BB=B6=E4=B8=BAcsv=E6=A0=BC=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/CtaTrading/runCtaTrading.py | 21 +++- examples/DataRecording/runDataRecording.py | 8 +- examples/README.md | 2 +- vnpy/trader/app/dataRecorder/DR_setting.csv | 7 ++ vnpy/trader/app/dataRecorder/DR_setting.json | 32 ------ vnpy/trader/app/dataRecorder/drEngine.py | 105 +++++++------------ 6 files changed, 72 insertions(+), 103 deletions(-) create mode 100644 vnpy/trader/app/dataRecorder/DR_setting.csv delete mode 100644 vnpy/trader/app/dataRecorder/DR_setting.json diff --git a/examples/CtaTrading/runCtaTrading.py b/examples/CtaTrading/runCtaTrading.py index 70fa4c22..bd5eb84b 100644 --- a/examples/CtaTrading/runCtaTrading.py +++ b/examples/CtaTrading/runCtaTrading.py @@ -21,7 +21,17 @@ def printLog(content): def processLogEvent(event): """处理日志事件""" log = event.dict_['data'] - content = '%s:%s' %(log.gatewayName, log.logContent) + if log.gatewayName: + content = '%s:%s' %(log.gatewayName, log.logContent) + else: + content = '%s:%s' %('MainEngine', log.logContent) + printLog(content) + +#---------------------------------------------------------------------- +def processCtaLogEvent(event): + """处理CTA模块日志事件""" + log = event.dict_['data'] + content = '%s:%s' %('CTA Engine', log.logContent) printLog(content) #---------------------------------------------------------------------- @@ -39,12 +49,14 @@ def runChildProcess(): printLog(u'主引擎创建成功') ee.register(EVENT_LOG, processLogEvent) - ee.register(EVENT_CTA_LOG, processLogEvent) + ee.register(EVENT_CTA_LOG, processCtaLogEvent) printLog(u'注册日志事件监听') me.connect('CTP') printLog(u'连接CTP接口') + sleep(5) # 等待CTP接口初始化 + cta = me.appDict[ctaStrategy.appName] cta.loadSetting() @@ -101,4 +113,7 @@ def runParentProcess(): if __name__ == '__main__': - runParentProcess() \ No newline at end of file + runChildProcess() + + # 尽管同样实现了无人值守,但强烈建议每天启动时人工检查,为自己的PNL负责 + # runParentProcess() \ No newline at end of file diff --git a/examples/DataRecording/runDataRecording.py b/examples/DataRecording/runDataRecording.py index dc6846b8..b4997c14 100644 --- a/examples/DataRecording/runDataRecording.py +++ b/examples/DataRecording/runDataRecording.py @@ -20,7 +20,10 @@ def printLog(content): def processLogEvent(event): """处理日志事件""" log = event.dict_['data'] - content = '%s:%s' %(log.gatewayName, log.logContent) + if log.gatewayName: + content = '%s:%s' %(log.gatewayName, log.logContent) + else: + content = '%s:%s' %('MainEngine', log.logContent) printLog(content) #---------------------------------------------------------------------- @@ -88,4 +91,5 @@ def runParentProcess(): if __name__ == '__main__': - runParentProcess() \ No newline at end of file + runChildProcess() + #runParentProcess() \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 148cecf1..c95316f3 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,6 +6,6 @@ * DataRecording:全自动行情记录工具(无需用户每日定时重启) -* CtaTrading:纯命令行模式的CTA策略交易(尽管同样实现了无人值守,但强烈建议每天启动时人工检查,为自己的PNL负责) +* CtaTrading:无图形界面模式的CTA策略交易 * CtaBacktesting:CTA策略的回测和优化 \ No newline at end of file diff --git a/vnpy/trader/app/dataRecorder/DR_setting.csv b/vnpy/trader/app/dataRecorder/DR_setting.csv new file mode 100644 index 00000000..fa5f396c --- /dev/null +++ b/vnpy/trader/app/dataRecorder/DR_setting.csv @@ -0,0 +1,7 @@ +gateway,symbol,exchange,currency,product,tick,bar,active +CTP,IF1709,,,,y,y,IF0000 +CTP,IC1709,,,,y,, +CTP,m1709,,,,y,, +SGIT,IH1709,,,,y,y,IH0000 +LTS,600036,SZSE,,,y,, +IB,EUR.USD,IDEALPRO,USD,,y,y, diff --git a/vnpy/trader/app/dataRecorder/DR_setting.json b/vnpy/trader/app/dataRecorder/DR_setting.json deleted file mode 100644 index f7c297c5..00000000 --- a/vnpy/trader/app/dataRecorder/DR_setting.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "working": false, - - "tick": - [ - ["m1609", "XSPEED"], - ["IF1606", "SGIT"], - ["IH1606", "SGIT"], - ["IH1606", "SGIT"], - ["IC1606", "SGIT"], - ["IC1606", "SGIT"], - ["600036", "LTS", "SZSE"], - ["EUR.USD", "IB", "IDEALPRO", "USD", "外汇"] - ], - - "bar": - [ - ["IF1605", "SGIT"], - ["IF1606", "SGIT"], - ["IH1606", "SGIT"], - ["IH1606", "SGIT"], - ["IC1606", "SGIT"], - ["IC1606", "SGIT"] - ], - - "active": - { - "IF0000": "IF1605", - "IH0000": "IH1605", - "IC0000": "IC1605" - } -} \ No newline at end of file diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index 56d8eba2..431c41c3 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -6,7 +6,8 @@ 使用DR_setting.json来配置需要收集的合约,以及主力合约代码。 ''' -import json +#import json +import csv import os import copy from collections import OrderedDict @@ -27,7 +28,7 @@ from vnpy.trader.app.dataRecorder.language import text class DrEngine(object): """数据记录引擎""" - settingFileName = 'DR_setting.json' + settingFileName = 'DR_setting.csv' path = os.path.abspath(os.path.dirname(__file__)) settingFileName = os.path.join(path, settingFileName) @@ -57,84 +58,58 @@ class DrEngine(object): # 载入设置,订阅行情 self.loadSetting() + # 启动数据插入线程 + self.start() + + # 注册事件监听 + self.registerEvent() + #---------------------------------------------------------------------- def loadSetting(self): - """载入设置""" + """加载配置""" with open(self.settingFileName) as f: - drSetting = json.load(f) + drSetting = csv.DictReader(f) - # 如果working设为False则不启动行情记录功能 - working = drSetting['working'] - if not working: - return - - if 'tick' in drSetting: - l = drSetting['tick'] + for d in drSetting: + # 读取配置 + gatewayName = d['gateway'] + symbol = d['symbol'] + exchange = d['symbol'] + currency = d['currency'] + productClass = d['product'] + recordTick = d['tick'] + recordBar = d['bar'] + activeSymbol = d['active'] - for setting in l: - symbol = setting[0] + if exchange: + vtSymbol = '.'.join([symbol, exchange]) + else: vtSymbol = symbol - - req = VtSubscribeReq() - req.symbol = setting[0] - - # 针对LTS和IB接口,订阅行情需要交易所代码 - if len(setting)>=3: - req.exchange = setting[2] - vtSymbol = '.'.join([symbol, req.exchange]) - - # 针对IB接口,订阅行情需要货币和产品类型 - if len(setting)>=5: - req.currency = setting[3] - req.productClass = setting[4] - - self.mainEngine.subscribe(req, setting[1]) - - tick = VtTickData() # 该tick实例可以用于缓存部分数据(目前未使用) - self.tickDict[vtSymbol] = tick - - if 'bar' in drSetting: - l = drSetting['bar'] - for setting in l: - symbol = setting[0] - vtSymbol = symbol - - req = VtSubscribeReq() - req.symbol = symbol - - if len(setting)>=3: - req.exchange = setting[2] - vtSymbol = '.'.join([symbol, req.exchange]) - - if len(setting)>=5: - req.currency = setting[3] - req.productClass = setting[4] - - self.mainEngine.subscribe(req, setting[1]) - - bar = VtBarData() - self.barDict[vtSymbol] = bar - - if 'active' in drSetting: - d = drSetting['active'] + # 订阅行情 + req = VtSubscribeReq() + req.symbol = symbol + req.exchange = exchange + req.currency = currency + req.productClass = productClass + self.mainEngine.subscribe(req, gatewayName) - # 注意这里的vtSymbol对于IB和LTS接口,应该后缀.交易所 - for activeSymbol, vtSymbol in d.items(): + # 设置需要记录的数据 + if recordTick: + self.tickDict[vtSymbol] = VtTickData() + + if recordBar: + self.barDict[vtSymbol] = VtBarData() + + if activeSymbol: self.activeSymbolDict[vtSymbol] = activeSymbol - - # 启动数据插入线程 - self.start() - - # 注册事件监听 - self.registerEvent() #---------------------------------------------------------------------- def procecssTickEvent(self, event): """处理行情推送""" tick = event.dict_['data'] vtSymbol = tick.vtSymbol - + # 转化Tick格式 if not tick.datetime: tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') From 676ce4a649b2a8be7745e873262d8932c832cb06 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 28 Jun 2017 17:40:57 +0800 Subject: [PATCH 18/29] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=8C=E6=83=85?= =?UTF-8?q?=E8=AE=B0=E5=BD=95UI=E7=9A=84=E7=95=8C=E9=9D=A2=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E5=8C=96Bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/dataRecorder/drEngine.py | 12 +++++ vnpy/trader/app/dataRecorder/uiDrWidget.py | 55 +++++++++------------- 2 files changed, 33 insertions(+), 34 deletions(-) diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index 431c41c3..31f1b5a3 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -50,6 +50,9 @@ class DrEngine(object): # K线对象字典 self.barDict = {} + # 配置字典 + self.settingDict = OrderedDict() + # 负责执行数据库插入的单独线程相关 self.active = False # 工作状态 self.queue = Queue() # 队列 @@ -96,6 +99,7 @@ class DrEngine(object): # 设置需要记录的数据 if recordTick: + tick = VtTickData() self.tickDict[vtSymbol] = VtTickData() if recordBar: @@ -103,6 +107,14 @@ class DrEngine(object): if activeSymbol: self.activeSymbolDict[vtSymbol] = activeSymbol + + # 保存配置到缓存中 + self.settingDict[vtSymbol] = d + + #---------------------------------------------------------------------- + def getSetting(self): + """获取配置""" + return self.settingDict #---------------------------------------------------------------------- def procecssTickEvent(self, event): diff --git a/vnpy/trader/app/dataRecorder/uiDrWidget.py b/vnpy/trader/app/dataRecorder/uiDrWidget.py index 49833179..575702b3 100644 --- a/vnpy/trader/app/dataRecorder/uiDrWidget.py +++ b/vnpy/trader/app/dataRecorder/uiDrWidget.py @@ -4,14 +4,10 @@ 行情记录模块相关的GUI控制组件 ''' -import json - -from qtpy import QtWidgets, QtGui, QtCore - from vnpy.event import Event -from vnpy.trader.vtEvent import * - -from vnpy.trader.app.dataRecorder.language import text +from vnpy.trader.uiQt import QtWidgets, QtCore +from .drBase import EVENT_DATARECORDER_LOG +from .language import text ######################################################################## @@ -119,33 +115,24 @@ class DrEngineManager(QtWidgets.QWidget): #---------------------------------------------------------------------- def updateSetting(self): """显示引擎行情记录配置""" - with open(self.drEngine.settingFileName) as f: - drSetting = json.load(f) - - if 'tick' in drSetting: - l = drSetting['tick'] - - for setting in l: - self.tickTable.insertRow(0) - self.tickTable.setItem(0, 0, TableCell(setting[0])) - self.tickTable.setItem(0, 1, TableCell(setting[1])) - - if 'bar' in drSetting: - l = drSetting['bar'] - - for setting in l: - self.barTable.insertRow(0) - self.barTable.setItem(0, 0, TableCell(setting[0])) - self.barTable.setItem(0, 1, TableCell(setting[1])) - - if 'active' in drSetting: - d = drSetting['active'] - - for activeSymbol, symbol in d.items(): - self.activeTable.insertRow(0) - self.activeTable.setItem(0, 0, TableCell(activeSymbol)) - self.activeTable.setItem(0, 1, TableCell(symbol)) - + setting = self.drEngine.getSetting() + + for d in setting.values(): + if d['tick']: + self.tickTable.insertRow(0) + self.tickTable.setItem(0, 0, TableCell(d['symbol'])) + self.tickTable.setItem(0, 1, TableCell(d['gateway'])) + + if d['bar']: + self.barTable.insertRow(0) + self.barTable.setItem(0, 0, TableCell(d['symbol'])) + self.barTable.setItem(0, 1, TableCell(d['gateway'])) + + if d['active']: + self.activeTable.insertRow(0) + self.activeTable.setItem(0, 0, TableCell(d['active'])) + self.activeTable.setItem(0, 1, TableCell(d['symbol'])) + self.tickTable.resizeColumnsToContents() self.barTable.resizeColumnsToContents() self.activeTable.resizeColumnsToContents() From 9eee8ea166c62443897be61cbb54bb07053a73a5 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Fri, 30 Jun 2017 11:22:53 +0800 Subject: [PATCH 19/29] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=B8=8A=E6=B5=B7?= =?UTF-8?q?=E4=B8=AD=E6=9C=9F=E5=8E=86=E5=8F=B2=E8=A1=8C=E6=83=85=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3vn.shcifco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/VnTrader/run.py | 4 +- vnpy/data/shcifco/test.py | 27 +++++++ vnpy/data/shcifco/vnshcifco.py | 70 +++++++++++-------- vnpy/trader/app/dataRecorder/drEngine.py | 2 +- vnpy/trader/app/spreadTrading/ST_setting.json | 21 ++++++ vnpy/trader/app/spreadTrading/stAlgo.py | 11 ++- vnpy/trader/app/spreadTrading/stEngine.py | 35 ++++++---- vnpy/trader/app/spreadTrading/uiStWidget.py | 3 +- vnpy/trader/uiMainWindow.py | 32 +++++---- 9 files changed, 139 insertions(+), 66 deletions(-) create mode 100644 vnpy/data/shcifco/test.py diff --git a/examples/VnTrader/run.py b/examples/VnTrader/run.py index 22c5a54a..0af7dabe 100644 --- a/examples/VnTrader/run.py +++ b/examples/VnTrader/run.py @@ -17,8 +17,7 @@ from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, shzdGateway, huobiGateway, okcoinGateway) # 加载上层应用 -from vnpy.trader.app import (riskManager, dataRecorder, - ctaStrategy, spreadTrading) +from vnpy.trader.app import (riskManager, ctaStrategy, spreadTrading) #---------------------------------------------------------------------- @@ -43,7 +42,6 @@ def main(): # 添加上层应用 me.addApp(riskManager) - me.addApp(dataRecorder) me.addApp(ctaStrategy) me.addApp(spreadTrading) diff --git a/vnpy/data/shcifco/test.py b/vnpy/data/shcifco/test.py new file mode 100644 index 00000000..15d8e192 --- /dev/null +++ b/vnpy/data/shcifco/test.py @@ -0,0 +1,27 @@ +# encoding: UTF-8 + +from vnshcifco import ShcifcoApi, PERIOD_1MIN + + +if __name__ == "__main__": + ip = '101.231.179.199' + port = '10102' + token = 'testd2cda34b2d317779e812eb84ee4224a6_qpweqf1' + symbol = 'cu1709' + + # 创建API对象 + api = ShcifcoApi(ip, port, token) + + # 获取最新tick + print api.getLastTick(symbol) + + # 获取最新价格 + print api.getLastPrice(symbol) + + # 获取最新分钟线 + print api.getLastBar(symbol) + + # 获取历史分钟线 + print api.getHisBar(symbol, 502, period=PERIOD_1MIN) + + \ No newline at end of file diff --git a/vnpy/data/shcifco/vnshcifco.py b/vnpy/data/shcifco/vnshcifco.py index 94927d9c..568cd0d0 100644 --- a/vnpy/data/shcifco/vnshcifco.py +++ b/vnpy/data/shcifco/vnshcifco.py @@ -5,6 +5,12 @@ import requests HTTP_OK = 200 +PERIOD_1MIN = '1m' +PERIOD_5MIN = '5m' +PERIOD_15MIN = '15m' +PERIOD_60MIN = '60m' +PERIOD_1DAY = '1d' + ######################################################################## class ShcifcoApi(object): @@ -38,8 +44,12 @@ class ShcifcoApi(object): """获取最新Tick""" path = 'lasttick' params = {'ids': symbol} - data = self.getData(path, params) + data = self.getData(path, params) + if not data: + return None + + data = data.split(';')[0] l = data.split(',') d = { 'symbol': l[0], @@ -58,8 +68,12 @@ class ShcifcoApi(object): """获取最新成交价""" path = 'lastprice' params = {'ids': symbol} - data = self.getData(path, params) + data = self.getData(path, params) + if not data: + return None + + data = data.split(';')[0] price = float(data) return price @@ -67,9 +81,13 @@ class ShcifcoApi(object): def getLastBar(self, symbol): """获取最新的一分钟K线数据""" path = 'lastbar' - params = {'ids': symbol} - data = self.getData(path, params) + params = {'id': symbol} + data = self.getData(path, params) + if not data: + return None + + data = data.split(';')[0] l = data.split(',') d = { 'symbol': l[0], @@ -78,18 +96,19 @@ class ShcifcoApi(object): 'high': float(l[3]), 'low': float(l[4]), 'close': float(l[5]), - 'volume': int([6]) + 'volume': int(l[6]), + 'openInterest': int(l[7]) } return d #---------------------------------------------------------------------- def getHisBar(self, symbol, num, date='', period=''): """获取历史K线数据""" - path = 'lastbar' + path = 'hisbar' # 默认参数 params = { - 'ids': symbol, + 'id': symbol, 'num': num } # 可选参数 @@ -99,40 +118,31 @@ class ShcifcoApi(object): params[period] = period data = self.getData(path, params) + if not data: + return None barList = [] l = data.split(';') for barStr in l: + # 过滤某些空数据 + if ',' not in barStr: + continue + barData = barStr.split(',') d = { 'symbol': barData[0], - 'time': barData[1], - 'open': float(barData[2]), - 'high': float(barData[3]), - 'low': float(barData[4]), - 'close': float(barData[5]), - 'volume': int([6]) + 'date': barData[1], + 'time': barData[2], + 'open': float(barData[3]), + 'high': float(barData[4]), + 'low': float(barData[5]), + 'close': float(barData[6]), + 'volume': int(barData[7]), + 'openInterest': int(barData[8]) } barList.append(d) return barList -if __name__ == "__main__": - ip = '101.231.179.199' - port = '10102' - token = 'testd2cda34b2d317779e812eb84ee4224a6_123456' - - api = ShcifcoApi(ip, port, token) - api.getData(path, params) - - print api.getLastTick('cu1709') - - print api.getLastPrice('cu1709') - - print api.getLastBar('cu1709') - - print api.getHisBar('cu1709', 50) - - \ No newline at end of file diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index 31f1b5a3..c9af1522 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -77,7 +77,7 @@ class DrEngine(object): # 读取配置 gatewayName = d['gateway'] symbol = d['symbol'] - exchange = d['symbol'] + exchange = d['exchange'] currency = d['currency'] productClass = d['product'] recordTick = d['tick'] diff --git a/vnpy/trader/app/spreadTrading/ST_setting.json b/vnpy/trader/app/spreadTrading/ST_setting.json index b2edf2c1..ba2c1da2 100644 --- a/vnpy/trader/app/spreadTrading/ST_setting.json +++ b/vnpy/trader/app/spreadTrading/ST_setting.json @@ -1,4 +1,25 @@ [ + { + "name": "m.09-01", + + "activeLeg": + { + "vtSymbol": "m1709", + "ratio": 1, + "multiplier": 1.0, + "payup": 2 + }, + + "passiveLegs": [ + { + "vtSymbol": "m1801", + "ratio": -1, + "multiplier": -1.0, + "payup": 2 + } + ] + }, + { "name": "IF.07-09", diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index afd4f743..8c35698b 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -117,7 +117,8 @@ class StAlgoTemplate(object): #---------------------------------------------------------------------- def writeLog(self, content): """输出算法日志""" - content = ':'.join([self.spreadName, content]) + prefix = ' '.join([self.spreadName, self.algoName]) + content = ':'.join([prefix, content]) self.algoEngine.writeLog(content) #---------------------------------------------------------------------- @@ -287,6 +288,8 @@ class SniperAlgo(StAlgoTemplate): self.hedgeCount = 0 self.active = True + self.writeLog(u'算法启动') + return self.active #---------------------------------------------------------------------- @@ -296,7 +299,9 @@ class SniperAlgo(StAlgoTemplate): self.hedgingTaskDict.clear() self.cancelAllOrders() - self.active = False + self.active = False + self.writeLog(u'算法停止') + return self.active #---------------------------------------------------------------------- @@ -448,7 +453,7 @@ class SniperAlgo(StAlgoTemplate): cancelPassive = False for vtSymbol in self.passiveVtSymbols: - if self.legOrderDict[vtSymbol]: + if vtSymbol in self.legOrderDict and self.legOrderDict[vtSymbol]: self.cancelLegOrder(vtSymbol) cancelPassive = True diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index 6789da12..1ba5e9b8 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -93,10 +93,10 @@ class StDataEngine(object): activeSetting = setting['activeLeg'] activeLeg = StLeg() - activeLeg.vtSymbol = activeSetting['vtSymbol'] - activeLeg.ratio = activeSetting['ratio'] - activeLeg.multiplier = activeSetting['multiplier'] - activeLeg.payup = activeSetting['payup'] + activeLeg.vtSymbol = str(activeSetting['vtSymbol']) + activeLeg.ratio = float(activeSetting['ratio']) + activeLeg.multiplier = float(activeSetting['multiplier']) + activeLeg.payup = int(activeSetting['payup']) spread.addActiveLeg(activeLeg) self.legDict[activeLeg.vtSymbol] = activeLeg @@ -110,10 +110,10 @@ class StDataEngine(object): for d in passiveSettingList: passiveLeg = StLeg() - passiveLeg.vtSymbol = d['vtSymbol'] - passiveLeg.ratio = d['ratio'] - passiveLeg.multiplier = d['multiplier'] - passiveLeg.payup = d['payup'] + passiveLeg.vtSymbol = str(d['vtSymbol']) + passiveLeg.ratio = float(d['ratio']) + passiveLeg.multiplier = float(d['multiplier']) + passiveLeg.payup = int(d['payup']) spread.addPassiveLeg(passiveLeg) self.legDict[passiveLeg.vtSymbol] = passiveLeg @@ -176,7 +176,7 @@ class StDataEngine(object): # 更新腿持仓 leg = self.legDict[trade.vtSymbol] direction = trade.direction - offset = trade.offst + offset = trade.offset if direction == DIRECTION_LONG: if offset == OFFSET_OPEN: @@ -212,7 +212,7 @@ class StDataEngine(object): return # 更新腿持仓 - leg = self.legDict[trade.vtSymbol] + leg = self.legDict[pos.vtSymbol] direction = pos.direction if direction == DIRECTION_LONG: @@ -222,7 +222,7 @@ class StDataEngine(object): leg.netPos = leg.longPos - leg.shortPos # 更新价差持仓 - spread = self.vtSymbolSpreadDict[trade.vtSymbol] + spread = self.vtSymbolSpreadDict[pos.vtSymbol] spread.calculatePos() # 推送价差持仓更新 @@ -327,7 +327,7 @@ class StAlgoEngine(object): """处理成交事件""" trade = event.dict_['data'] - algo = self.algoDict.get(trade.vtSymbol, None) + algo = self.vtSymbolAlgoDict.get(trade.vtSymbol, None) if algo: algo.updateTrade(trade) @@ -335,8 +335,8 @@ class StAlgoEngine(object): def processOrderEvent(self, event): """处理委托事件""" order = event.dict_['data'] + algo = self.vtSymbolAlgoDict.get(order.vtSymbol, None) - algo = self.algoDict.get(order.vtSymbol, None) if algo: algo.updateOrder(order) @@ -358,7 +358,7 @@ class StAlgoEngine(object): req.exchange = contract.exchange req.direction = direction req.offset = offset - req.volume = volume + req.volume = int(volume) req.priceType = PRICETYPE_LIMITPRICE if direction == DIRECTION_LONG: @@ -443,7 +443,12 @@ class StAlgoEngine(object): # 创建算法对象 l = self.dataEngine.getAllSpreads() for spread in l: - self.algoDict[spread.name] = SniperAlgo(self, spread) + algo = SniperAlgo(self, spread) + self.algoDict[spread.name] = algo + + # 保存腿代码和算法对象的映射 + for leg in spread.allLegs: + self.vtSymbolAlgoDict[leg.vtSymbol] = algo # 加载配置 f = shelve.open(self.algoFilePath) diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index d2613146..91f9c48b 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -319,7 +319,7 @@ class StActiveButton(QtWidgets.QPushButton): def buttonClicked(self): """改变运行模式""" if self.active: - self.stop + self.stop() else: self.start() @@ -334,7 +334,6 @@ class StActiveButton(QtWidgets.QPushButton): def start(self): """启动""" algoActive = self.algoEngine.startAlgo(self.spreadName) - if algoActive: self.setStarted() diff --git a/vnpy/trader/uiMainWindow.py b/vnpy/trader/uiMainWindow.py index 27d92ad9..27c3f5e7 100644 --- a/vnpy/trader/uiMainWindow.py +++ b/vnpy/trader/uiMainWindow.py @@ -1,6 +1,7 @@ # encoding: UTF-8 import psutil +import traceback from vnpy.trader.vtFunction import loadIconPath from vnpy.trader.vtGlobal import globalSetting @@ -257,18 +258,25 @@ class MainWindow(QtWidgets.QMainWindow): #---------------------------------------------------------------------- def loadWindowSettings(self, settingName): """载入窗口设置""" - settings = QtCore.QSettings('vn.trader', settingName) - # 这里由于PyQt4的版本不同,settings.value('state')调用返回的结果可能是: - # 1. None(初次调用,注册表里无相应记录,因此为空) - # 2. QByteArray(比较新的PyQt4) - # 3. QVariant(以下代码正确执行所需的返回结果) - # 所以为了兼容考虑,这里加了一个try...except,如果是1、2的情况就pass - # 可能导致主界面的设置无法载入(每次退出时的保存其实是成功了) - try: - self.restoreState(settings.value('state').toByteArray()) - self.restoreGeometry(settings.value('geometry').toByteArray()) - except AttributeError: - pass + settings = QtCore.QSettings('vn.trader', settingName) + state = settings.value('state') + geometry = settings.value('geometry') + + # 尚未初始化 + if state is None: + return + # 老版PyQt + elif isinstance(state, QtCore.QVariant): + self.restoreState(state.toByteArray()) + self.restoreGeometry(geometry.toByteArray()) + # 新版PyQt + elif isinstance(state, QtCore.QByteArray): + self.restoreState(state) + self.restoreGeometry(geometry) + # 异常 + else: + content = u'载入窗口配置异常,请检查' + self.mainEngine.writeLog(content) #---------------------------------------------------------------------- def restoreWindow(self): From 302b6f75d776b6984de48aa327679de65aa9d031 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 3 Jul 2017 16:15:29 +0800 Subject: [PATCH 20/29] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=8C=E6=88=90?= =?UTF-8?q?=E4=BB=B7=E5=B7=AE=E4=BA=A4=E6=98=93=E6=A8=A1=E5=9D=97=E7=9A=84?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=EF=BC=8C=E4=B8=BB=E5=BC=95=E6=93=8E=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E6=95=B0=E6=8D=AE=E5=BA=93=E5=8A=A0=E8=BD=BD=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E6=97=B6=E7=9A=84=E6=8E=92=E5=BA=8F=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/DataRecording/runDataRecording.py | 8 +- vnpy/data/shcifco/vnshcifco.py | 3 +- vnpy/trader/app/ctaStrategy/ctaBacktesting.py | 4 +- vnpy/trader/app/ctaStrategy/ctaEngine.py | 4 +- vnpy/trader/app/riskManager/RM_setting.json | 4 +- vnpy/trader/app/spreadTrading/stAlgo.py | 111 +++++++++++++----- vnpy/trader/app/spreadTrading/stBase.py | 2 + vnpy/trader/app/spreadTrading/stEngine.py | 28 ++++- vnpy/trader/app/spreadTrading/uiStWidget.py | 2 +- .../gateway/okcoinGateway/okcoinGateway.py | 1 + vnpy/trader/vtEngine.py | 11 +- 11 files changed, 130 insertions(+), 48 deletions(-) diff --git a/examples/DataRecording/runDataRecording.py b/examples/DataRecording/runDataRecording.py index b4997c14..c05425ea 100644 --- a/examples/DataRecording/runDataRecording.py +++ b/examples/DataRecording/runDataRecording.py @@ -54,11 +54,11 @@ def runParentProcess(): """父进程运行函数""" printLog(u'启动行情记录守护父进程') - DAY_START = time(8, 45) # 日盘启动和停止时间 - DAY_END = time(15, 30) + DAY_START = time(8, 57) # 日盘启动和停止时间 + DAY_END = time(15, 18) - NIGHT_START = time(20, 45) # 夜盘启动和停止时间 - NIGHT_END = time(2, 45) + NIGHT_START = time(20, 57) # 夜盘启动和停止时间 + NIGHT_END = time(2, 33) p = None # 子进程句柄 diff --git a/vnpy/data/shcifco/vnshcifco.py b/vnpy/data/shcifco/vnshcifco.py index 568cd0d0..84f8331e 100644 --- a/vnpy/data/shcifco/vnshcifco.py +++ b/vnpy/data/shcifco/vnshcifco.py @@ -144,5 +144,4 @@ class ShcifcoApi(object): barList.append(d) return barList - - + diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 01b29280..9f3073de 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -139,7 +139,7 @@ class BacktestingEngine(object): # 载入初始化需要用的数据 flt = {'datetime':{'$gte':self.dataStartDate, '$lt':self.strategyStartDate}} - initCursor = collection.find(flt) + initCursor = collection.find(flt).sort('datetime') # 将数据从查询指针中读取出,并生成列表 self.initData = [] # 清空initData列表 @@ -154,7 +154,7 @@ class BacktestingEngine(object): else: flt = {'datetime':{'$gte':self.strategyStartDate, '$lte':self.dataEndDate}} - self.dbCursor = collection.find(flt) + self.dbCursor = collection.find(flt).sort('datetime') self.output(u'载入完成,数据量:%s' %(initCursor.count() + self.dbCursor.count())) diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index 319209eb..77464b18 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -337,7 +337,7 @@ class CtaEngine(object): startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} - barData = self.mainEngine.dbQuery(dbName, collectionName, d) + barData = self.mainEngine.dbQuery(dbName, collectionName, d, 'datetime') l = [] for d in barData: @@ -352,7 +352,7 @@ class CtaEngine(object): startDate = self.today - timedelta(days) d = {'datetime':{'$gte':startDate}} - tickData = self.mainEngine.dbQuery(dbName, collectionName, d) + tickData = self.mainEngine.dbQuery(dbName, collectionName, d, 'datetime') l = [] for d in tickData: diff --git a/vnpy/trader/app/riskManager/RM_setting.json b/vnpy/trader/app/riskManager/RM_setting.json index 1e452dd7..25c98921 100644 --- a/vnpy/trader/app/riskManager/RM_setting.json +++ b/vnpy/trader/app/riskManager/RM_setting.json @@ -2,8 +2,8 @@ "orderFlowClear": 1, "orderCancelLimit": 10, "workingOrderLimit": 20, - "tradeLimit": 100, - "orderSizeLimit": 10, + "tradeLimit": 1000, + "orderSizeLimit": 100, "active": true, "orderFlowLimit": 50 } \ No newline at end of file diff --git a/vnpy/trader/app/spreadTrading/stAlgo.py b/vnpy/trader/app/spreadTrading/stAlgo.py index 8c35698b..aa9b4184 100644 --- a/vnpy/trader/app/spreadTrading/stAlgo.py +++ b/vnpy/trader/app/spreadTrading/stAlgo.py @@ -175,7 +175,8 @@ class SniperAlgo(StAlgoTemplate): self.legDict[leg.vtSymbol] = leg self.hedgingTaskDict = {} # 被动腿需要对冲的数量字典 vtSymbol:volume - self.legOrderDict = {} # vtSymbol: list of vtOrderID + self.legOrderDict = {} # vtSymbol: list of vtOrderID + self.orderTradedDict = {} # vtOrderID: tradedVolume #---------------------------------------------------------------------- def updateSpreadTick(self, spread): @@ -229,21 +230,30 @@ class SniperAlgo(StAlgoTemplate): #---------------------------------------------------------------------- def updateTrade(self, trade): """成交更新""" - if not self.active: - return - - if trade.vtSymbol == self.activeVtSymbol: - self.newActiveLegTrade(trade) - else: - self.newPassiveLegTrade(trade) + pass #---------------------------------------------------------------------- def updateOrder(self, order): """委托更新""" if not self.active: return + + vtOrderID = order.vtOrderID + vtSymbol = order.vtSymbol + newTradedVolume = order.tradedVolume + lastTradedVolume = self.orderTradedDict.get(vtOrderID, 0) - # 只处理完成委托 + # 检查是否有新的成交 + if newTradedVolume > lastTradedVolume: + self.orderTradedDict[vtOrderID] = newTradedVolume # 缓存委托已经成交数量 + volume = newTradedVolume - lastTradedVolume # 计算本次成交数量 + + if vtSymbol == self.activeVtSymbol: + self.newActiveLegTrade(vtSymbol, order.direction, volume) + else: + self.newPassiveLegTrade(vtSymbol, order.direction, volume) + + # 处理完成委托 if order.status in self.FINISHED_STATUS: vtOrderID = order.vtOrderID vtSymbol = order.vtSymbol @@ -257,7 +267,6 @@ class SniperAlgo(StAlgoTemplate): # 检查若是被动腿,且已经没有未完成委托,则执行对冲 if not orderList and vtSymbol in self.passiveVtSymbols: self.hedgePassiveLeg(vtSymbol) - self.writeLog(u'发出新的被动腿%s对冲单' %vtSymbol) #---------------------------------------------------------------------- def updateTimer(self): @@ -283,9 +292,35 @@ class SniperAlgo(StAlgoTemplate): #---------------------------------------------------------------------- def start(self): """启动""" - if not self.active: - self.quoteCount = 0 - self.hedgeCount = 0 + # 如果已经运行则直接返回状态 + if self.active: + return self.active + + # 做多检查 + if self.mode != self.MODE_SHORTONLY: + if self.buyPrice >= self.sellPrice: + self.writeLog(u'启动失败,允许多头交易时BuyPrice必须小于SellPrice') + return self.active + + # 做空检查 + if self.mode != self.MODE_LONGONLY: + if self.shortPrice <= self.coverPrice: + self.writeLog(u'启动失败,允许空头交易时ShortPrice必须大于CoverPrice') + return self.active + + # 多空检查 + if self.mode == self.MODE_LONGSHORT: + if self.buyPrice >= self.coverPrice: + self.writeLog(u'启动失败,允许双向交易时BuyPrice必须小于CoverPrice') + return self.active + + if self.shortPrice <= self.sellPrice: + self.writeLog(u'启动失败,允许双向交易时ShortPrice必须大于SellPrice') + return self.active + + # 启动算法 + self.quoteCount = 0 + self.hedgeCount = 0 self.active = True self.writeLog(u'算法启动') @@ -339,6 +374,7 @@ class SniperAlgo(StAlgoTemplate): """发出主动腿""" spread = self.spread + # 首先计算不带正负号的价差委托量 if direction == self.SPREAD_LONG: spreadVolume = min(spread.askVolume, self.maxPosSize - spread.netPos, @@ -359,9 +395,15 @@ class SniperAlgo(StAlgoTemplate): if spreadVolume <= 0: return + # 加上价差方向 + if direction == self.SPREAD_SHORT: + spreadVolume = -spreadVolume + + # 计算主动腿委托量 leg = self.legDict[self.activeVtSymbol] legVolume = spreadVolume * leg.ratio self.sendLegOrder(leg, legVolume) + self.writeLog(u'发出新的主动腿%s狙击单' %self.activeVtSymbol) self.quoteCount = 0 # 重置主动腿报价撤单等待计数 @@ -370,11 +412,16 @@ class SniperAlgo(StAlgoTemplate): """被动腿对冲""" if vtSymbol not in self.hedgingTaskDict: return - legVolume = self.hedgingTaskDict[vtSymbol] + orderList = self.legOrderDict.get(vtSymbol, []) + if orderList: + return + + legVolume = self.hedgingTaskDict[vtSymbol] leg = self.legDict[vtSymbol] self.sendLegOrder(leg, legVolume) + self.writeLog(u'发出新的被动腿%s对冲单' %vtSymbol) #---------------------------------------------------------------------- def hedgeAllPassiveLegs(self): @@ -385,13 +432,19 @@ class SniperAlgo(StAlgoTemplate): self.hedgeCount = 0 # 重置被动腿对冲撤单等待计数 #---------------------------------------------------------------------- - def newActiveLegTrade(self, trade): + def newActiveLegTrade(self, vtSymbol, direction, volume): """新的主动腿成交""" - spread = self.spread + # 输出日志 + self.writeLog(u'主动腿%s成交,方向%s,数量%s' %(vtSymbol, direction, volume)) + + # 将主动腿成交带上方向 + if direction == DIRECTION_SHORT: + volume = -volume # 计算主动腿成交后,对应的价差仓位 + spread = self.spread activeRatio = spread.activeLeg.ratio - spreadVolume = round(trade.volume / activeRatio) # 四舍五入求主动腿成交量对应的价差份数 + spreadVolume = round(volume / activeRatio) # 四舍五入求主动腿成交量对应的价差份数 # 计算价差新仓位,对应的被动腿需要对冲部分 for leg in self.spread.passiveLegs: @@ -402,28 +455,28 @@ class SniperAlgo(StAlgoTemplate): else: self.hedgingTaskDict[leg.vtSymbol] += newHedgingTask - # 输出日志 - self.writeLog(u'主动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) + # 发出被动腿对冲委托 + self.hedgeAllPassiveLegs() #---------------------------------------------------------------------- - def newPassiveLegTrade(self, trade): + def newPassiveLegTrade(self, vtSymbol, direction, volume): """新的被动腿成交""" - if trade.vtSymbol in self.hedgingTaskDict: + if vtSymbol in self.hedgingTaskDict: # 计算完成的对冲数量 - if trade.direction == DIRECTION_LONG: - hedgedVolume = trade.volume + if direction == DIRECTION_LONG: + hedgedVolume = volume else: - hedgedVolume = -trade.volume + hedgedVolume = -volume # 计算剩余尚未完成的数量 - self.hedgingTaskDict[trade.vtSymbol] -= hedgedVolume + self.hedgingTaskDict[vtSymbol] -= hedgedVolume # 如果已全部完成,则从字典中移除 - if not self.hedgingTaskDict[trade.vtSymbol]: - del self.hedgingTaskDict[trade.vtSymbol] + if not self.hedgingTaskDict[vtSymbol]: + del self.hedgingTaskDict[vtSymbol] # 输出日志 - self.writeLog(u'被动腿%s成交,方向%s,数量%s' %(trade.vtSymbol, trade.direction, trade.volume)) + self.writeLog(u'被动腿%s成交,方向%s,数量%s' %(vtSymbol, direction, volume)) #---------------------------------------------------------------------- def cancelLegOrder(self, vtSymbol): @@ -432,6 +485,8 @@ class SniperAlgo(StAlgoTemplate): return orderList = self.legOrderDict[vtSymbol] + if not orderList: + return for vtOrderID in orderList: self.algoEngine.cancelOrder(vtOrderID) diff --git a/vnpy/trader/app/spreadTrading/stBase.py b/vnpy/trader/app/spreadTrading/stBase.py index 71f25f15..bead63f4 100644 --- a/vnpy/trader/app/spreadTrading/stBase.py +++ b/vnpy/trader/app/spreadTrading/stBase.py @@ -149,6 +149,8 @@ class StSpread(object): self.shortPos = min(self.shortPos, legAdjustedShortPos) # 计算净仓位 + self.longPos = int(self.longPos) + self.shortPos = int(self.shortPos) self.netPos = self.longPos - self.shortPos #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/spreadTrading/stEngine.py b/vnpy/trader/app/spreadTrading/stEngine.py index 1ba5e9b8..808bf565 100644 --- a/vnpy/trader/app/spreadTrading/stEngine.py +++ b/vnpy/trader/app/spreadTrading/stEngine.py @@ -389,25 +389,45 @@ class StAlgoEngine(object): def buy(self, vtSymbol, price, volume, payup=0): """买入""" vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_OPEN, price, volume, payup) - return [vtOrderID] + l = [] + + if vtOrderID: + l.append(vtOrderID) + + return l #---------------------------------------------------------------------- def sell(self, vtSymbol, price, volume, payup=0): """卖出""" vtOrderID = self.sendOrder(vtSymbol, DIRECTION_SHORT, OFFSET_CLOSE, price, volume, payup) - return [vtOrderID] + l = [] + + if vtOrderID: + l.append(vtOrderID) + + return l #---------------------------------------------------------------------- def short(self, vtSymbol, price, volume, payup=0): """卖空""" vtOrderID = self.sendOrder(vtSymbol, DIRECTION_SHORT, OFFSET_OPEN, price, volume, payup) - return [vtOrderID] + l = [] + + if vtOrderID: + l.append(vtOrderID) + + return l #---------------------------------------------------------------------- def cover(self, vtSymbol, price, volume, payup=0): """平空""" vtOrderID = self.sendOrder(vtSymbol, DIRECTION_LONG, OFFSET_CLOSE, price, volume, payup) - return [vtOrderID] + l = [] + + if vtOrderID: + l.append(vtOrderID) + + return l #---------------------------------------------------------------------- def putAlgoEvent(self, algo): diff --git a/vnpy/trader/app/spreadTrading/uiStWidget.py b/vnpy/trader/app/spreadTrading/uiStWidget.py index 91f9c48b..178b4e55 100644 --- a/vnpy/trader/app/spreadTrading/uiStWidget.py +++ b/vnpy/trader/app/spreadTrading/uiStWidget.py @@ -33,7 +33,7 @@ class StTickMonitor(BasicMonitor): d['askPrice'] = {'chinese':u'卖价', 'cellType':AskCell} d['askVolume'] = {'chinese':u'卖量', 'cellType':AskCell} d['time'] = {'chinese':u'时间', 'cellType':BasicCell} - d['symbol'] = {'chinese':u'代码', 'cellType':BasicCell} + d['symbol'] = {'chinese':u'价差公式', 'cellType':BasicCell} self.setHeaderDict(d) self.setDataKey('name') diff --git a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py index 2791c49f..788ceede 100644 --- a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py +++ b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py @@ -11,6 +11,7 @@ vn.okcoin的gateway接入 import os import json from datetime import datetime +from time import sleep from copy import copy from threading import Condition from Queue import Queue diff --git a/vnpy/trader/vtEngine.py b/vnpy/trader/vtEngine.py index 70b087e5..ab52c066 100644 --- a/vnpy/trader/vtEngine.py +++ b/vnpy/trader/vtEngine.py @@ -5,7 +5,7 @@ import shelve from collections import OrderedDict from datetime import datetime -from pymongo import MongoClient +from pymongo import MongoClient, ASCENDING from pymongo.errors import ConnectionFailure from vnpy.event import Event @@ -209,12 +209,17 @@ class MainEngine(object): self.writeLog(text.DATA_INSERT_FAILED) #---------------------------------------------------------------------- - def dbQuery(self, dbName, collectionName, d): + def dbQuery(self, dbName, collectionName, d, sortKey='', sortDirection=ASCENDING): """从MongoDB中读取数据,d是查询要求,返回的是数据库查询的指针""" if self.dbClient: db = self.dbClient[dbName] collection = db[collectionName] - cursor = collection.find(d) + + if sortKey: + cursor = collection.find(d).sort(sortKey, sortDirection) # 对查询出来的数据进行排序 + else: + cursor = collection.find(d) + if cursor: return list(cursor) else: From 22d7795cb29188539990bf278bb5c1b8a6ecd8af Mon Sep 17 00:00:00 2001 From: Happiness Date: Mon, 3 Jul 2017 20:59:40 +0800 Subject: [PATCH 21/29] =?UTF-8?q?1.okcoin=20=E6=B7=BB=E5=8A=A0eth=202.?= =?UTF-8?q?=E4=BF=AE=E6=94=B9okcoin=20websocket=20=E6=96=AD=E5=BC=80?= =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=90=8E=E7=B3=BB=E7=BB=9F=E6=89=BE=E4=B8=8D?= =?UTF-8?q?=E5=88=B0sleep=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/VnTrader/run.py | 22 +++++---- vnpy/api/okcoin/vnokcoin.py | 2 + vnpy/trader/app/dataRecorder/DR_setting.json | 22 ++------- .../gateway/okcoinGateway/okcoinGateway.py | 47 ++++++++++++++----- 4 files changed, 54 insertions(+), 39 deletions(-) diff --git a/examples/VnTrader/run.py b/examples/VnTrader/run.py index e174bd53..5aa78198 100644 --- a/examples/VnTrader/run.py +++ b/examples/VnTrader/run.py @@ -12,9 +12,11 @@ from vnpy.trader.uiQt import qApp from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 -from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, - sgitGateway, oandaGateway, ibGateway, - shzdGateway, huobiGateway, okcoinGateway) +# from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, +# sgitGateway, oandaGateway, ibGateway, +# shzdGateway, huobiGateway, okcoinGateway) + +from vnpy.trader.gateway import ( huobiGateway, okcoinGateway) # 加载上层应用 from vnpy.trader.app import (riskManager, dataRecorder, @@ -31,13 +33,13 @@ def main(): me = MainEngine(ee) # 添加交易接口 - me.addGateway(ctpGateway) - me.addGateway(femasGateway) - me.addGateway(xspeedGateway) - me.addGateway(sgitGateway) - me.addGateway(oandaGateway) - me.addGateway(ibGateway) - me.addGateway(shzdGateway) + # me.addGateway(ctpGateway) + # me.addGateway(femasGateway) + # me.addGateway(xspeedGateway) + # me.addGateway(sgitGateway) + # me.addGateway(oandaGateway) + # me.addGateway(ibGateway) + # me.addGateway(shzdGateway) me.addGateway(huobiGateway) me.addGateway(okcoinGateway) diff --git a/vnpy/api/okcoin/vnokcoin.py b/vnpy/api/okcoin/vnokcoin.py index 38565825..75c09c05 100644 --- a/vnpy/api/okcoin/vnokcoin.py +++ b/vnpy/api/okcoin/vnokcoin.py @@ -20,6 +20,7 @@ CURRENCY_USD = 'usd' # 电子货币代码 SYMBOL_BTC = 'btc' SYMBOL_LTC = 'ltc' +SYMBOL_ETH = 'eth' # 行情深度 DEPTH_20 = 20 @@ -42,6 +43,7 @@ INTERVAL_1W = 'week' # 交易代码,需要后缀货币名才能完整 TRADING_SYMBOL_BTC = 'btc_' TRADING_SYMBOL_LTC = 'ltc_' +TRADING_SYMBOL_ETH = 'eth_' # 委托类型 TYPE_BUY = 'buy' diff --git a/vnpy/trader/app/dataRecorder/DR_setting.json b/vnpy/trader/app/dataRecorder/DR_setting.json index f7c297c5..07030299 100644 --- a/vnpy/trader/app/dataRecorder/DR_setting.json +++ b/vnpy/trader/app/dataRecorder/DR_setting.json @@ -1,32 +1,18 @@ { - "working": false, + "working": true, "tick": [ - ["m1609", "XSPEED"], - ["IF1606", "SGIT"], - ["IH1606", "SGIT"], - ["IH1606", "SGIT"], - ["IC1606", "SGIT"], - ["IC1606", "SGIT"], - ["600036", "LTS", "SZSE"], - ["EUR.USD", "IB", "IDEALPRO", "USD", "外汇"] ], "bar": [ - ["IF1605", "SGIT"], - ["IF1606", "SGIT"], - ["IH1606", "SGIT"], - ["IH1606", "SGIT"], - ["IC1606", "SGIT"], - ["IC1606", "SGIT"] + ["BTC_CNY_SPOT", "OKCOIN"], + ["LTC_CNY_SPOT", "OKCOIN"], + ["ETH_CNY_SPOT", "OKCOIN"] ], "active": { - "IF0000": "IF1605", - "IH0000": "IH1605", - "IC0000": "IC1605" } } \ No newline at end of file diff --git a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py index 2791c49f..4128592d 100644 --- a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py +++ b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py @@ -15,6 +15,7 @@ from copy import copy from threading import Condition from Queue import Queue from threading import Thread +from time import sleep from vnpy.api.okcoin import vnokcoin from vnpy.trader.vtGateway import * @@ -54,16 +55,24 @@ LTC_USD_THISWEEK = 'LTC_USD_THISWEEK' LTC_USD_NEXTWEEK = 'LTC_USD_NEXTWEEK' LTC_USD_QUARTER = 'LTC_USD_QUARTER' +ETH_USD_SPOT = 'ETH_USD_SPOT' +ETH_USD_THISWEEK = 'ETH_USD_THISWEEK' +ETH_USD_NEXTWEEK = 'ETH_USD_NEXTWEEK' +ETH_USD_QUARTER = 'ETH_USD_QUARTER' + # CNY BTC_CNY_SPOT = 'BTC_CNY_SPOT' LTC_CNY_SPOT = 'LTC_CNY_SPOT' +ETH_CNY_SPOT = 'ETH_CNY_SPOT' # 印射字典 spotSymbolMap = {} spotSymbolMap['ltc_usd'] = LTC_USD_SPOT spotSymbolMap['btc_usd'] = BTC_USD_SPOT +spotSymbolMap['ETH_usd'] = ETH_USD_SPOT spotSymbolMap['ltc_cny'] = LTC_CNY_SPOT spotSymbolMap['btc_cny'] = BTC_CNY_SPOT +spotSymbolMap['eth_cny'] = ETH_CNY_SPOT spotSymbolMapReverse = {v: k for k, v in spotSymbolMap.items()} @@ -75,16 +84,20 @@ channelSymbolMap = {} # USD channelSymbolMap['ok_sub_spotusd_btc_ticker'] = BTC_USD_SPOT channelSymbolMap['ok_sub_spotusd_ltc_ticker'] = LTC_USD_SPOT +channelSymbolMap['ok_sub_spotusd_eth_ticker'] = ETH_USD_SPOT channelSymbolMap['ok_sub_spotusd_btc_depth_20'] = BTC_USD_SPOT channelSymbolMap['ok_sub_spotusd_ltc_depth_20'] = LTC_USD_SPOT +channelSymbolMap['ok_sub_spotusd_eth_depth_20'] = ETH_USD_SPOT # CNY channelSymbolMap['ok_sub_spotcny_btc_ticker'] = BTC_CNY_SPOT channelSymbolMap['ok_sub_spotcny_ltc_ticker'] = LTC_CNY_SPOT +channelSymbolMap['ok_sub_spotcny_eth_ticker'] = ETH_CNY_SPOT channelSymbolMap['ok_sub_spotcny_btc_depth_20'] = BTC_CNY_SPOT channelSymbolMap['ok_sub_spotcny_ltc_depth_20'] = LTC_CNY_SPOT +channelSymbolMap['ok_sub_spotcny_eth_depth_20'] = ETH_CNY_SPOT @@ -305,17 +318,20 @@ class Api(vnokcoin.OkCoinApi): self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_LTC, '-1') self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_BTC, '-1') - + self.spotOrderInfo(vnokcoin.TRADING_SYMBOL_ETH, '-1') + # 连接后订阅现货的成交和账户数据 self.subscribeSpotTrades() self.subscribeSpotUserInfo() self.subscribeSpotTicker(vnokcoin.SYMBOL_BTC) self.subscribeSpotTicker(vnokcoin.SYMBOL_LTC) - + self.subscribeSpotTicker(vnokcoin.SYMBOL_ETH) + self.subscribeSpotDepth(vnokcoin.SYMBOL_BTC, vnokcoin.DEPTH_20) self.subscribeSpotDepth(vnokcoin.SYMBOL_LTC, vnokcoin.DEPTH_20) - + self.subscribeSpotDepth(vnokcoin.SYMBOL_ETH, vnokcoin.DEPTH_20) + # 如果连接的是USD网站则订阅期货相关回报数据 if self.currency == vnokcoin.CURRENCY_USD: self.subscribeFutureTrades() @@ -346,10 +362,12 @@ class Api(vnokcoin.OkCoinApi): # USD_SPOT self.cbDict['ok_sub_spotusd_btc_ticker'] = self.onTicker self.cbDict['ok_sub_spotusd_ltc_ticker'] = self.onTicker - + self.cbDict['ok_sub_spotusd_eth_ticker'] = self.onTicker + self.cbDict['ok_sub_spotusd_btc_depth_20'] = self.onDepth self.cbDict['ok_sub_spotusd_ltc_depth_20'] = self.onDepth - + self.cbDict['ok_sub_spotusd_eth_depth_20'] = self.onDepth + self.cbDict['ok_spotusd_userinfo'] = self.onSpotUserInfo self.cbDict['ok_spotusd_orderinfo'] = self.onSpotOrderInfo @@ -362,10 +380,12 @@ class Api(vnokcoin.OkCoinApi): # CNY_SPOT self.cbDict['ok_sub_spotcny_btc_ticker'] = self.onTicker self.cbDict['ok_sub_spotcny_ltc_ticker'] = self.onTicker - + self.cbDict['ok_sub_spotcny_eth_ticker'] = self.onTicker + self.cbDict['ok_sub_spotcny_btc_depth_20'] = self.onDepth self.cbDict['ok_sub_spotcny_ltc_depth_20'] = self.onDepth - + self.cbDict['ok_sub_spotcny_eth_depth_20'] = self.onDepth + self.cbDict['ok_spotcny_userinfo'] = self.onSpotUserInfo self.cbDict['ok_spotcny_orderinfo'] = self.onSpotOrderInfo @@ -452,7 +472,7 @@ class Api(vnokcoin.OkCoinApi): funds = rawData['info']['funds'] # 持仓信息 - for symbol in ['btc', 'ltc', self.currency]: + for symbol in ['btc', 'ltc','eth', self.currency]: if symbol in funds['free']: pos = VtPositionData() pos.gatewayName = self.gatewayName @@ -485,7 +505,7 @@ class Api(vnokcoin.OkCoinApi): info = rawData['info'] # 持仓信息 - for symbol in ['btc', 'ltc', self.currency]: + for symbol in ['btc', 'ltc','eth', self.currency]: if symbol in info['free']: pos = VtPositionData() pos.gatewayName = self.gatewayName @@ -616,7 +636,8 @@ class Api(vnokcoin.OkCoinApi): contractList.append(self.generateSpecificContract(contract, BTC_CNY_SPOT)) contractList.append(self.generateSpecificContract(contract, LTC_CNY_SPOT)) - + contractList.append(self.generateSpecificContract(contract, ETH_CNY_SPOT)) + return contractList #---------------------------------------------------------------------- @@ -633,7 +654,8 @@ class Api(vnokcoin.OkCoinApi): contractList.append(self.generateSpecificContract(contract, BTC_USD_SPOT)) contractList.append(self.generateSpecificContract(contract, LTC_USD_SPOT)) - + contractList.append(self.generateSpecificContract(contract, ETH_USD_SPOT)) + # 期货 contract.productClass = PRODUCT_FUTURES @@ -643,6 +665,9 @@ class Api(vnokcoin.OkCoinApi): contractList.append(self.generateSpecificContract(contract, LTC_USD_THISWEEK)) contractList.append(self.generateSpecificContract(contract, LTC_USD_NEXTWEEK)) contractList.append(self.generateSpecificContract(contract, LTC_USD_QUARTER)) + contractList.append(self.generateSpecificContract(contract, ETH_USD_THISWEEK)) + contractList.append(self.generateSpecificContract(contract, ETH_USD_NEXTWEEK)) + contractList.append(self.generateSpecificContract(contract, ETH_USD_QUARTER)) return contractList From 62b2565d7f8c51b5bf93216ec75849150d6afa06 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Thu, 6 Jul 2017 16:59:45 +0800 Subject: [PATCH 22/29] =?UTF-8?q?=E4=BF=AE=E5=A4=8DctaHistoryData=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E6=95=B0=E6=8D=AE=E5=BA=93=E5=90=8D=E5=B8=B8=E9=87=8F?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/ctaStrategy/ctaHistoryData.py | 1 + 1 file changed, 1 insertion(+) diff --git a/vnpy/trader/app/ctaStrategy/ctaHistoryData.py b/vnpy/trader/app/ctaStrategy/ctaHistoryData.py index d9c97375..34b6a284 100644 --- a/vnpy/trader/app/ctaStrategy/ctaHistoryData.py +++ b/vnpy/trader/app/ctaStrategy/ctaHistoryData.py @@ -17,6 +17,7 @@ from vnpy.data.datayes import DatayesApi from vnpy.trader.vtGlobal import globalSetting from vnpy.trader.vtConstant import * from vnpy.trader.vtObject import VtBarData +from .ctaBase import SETTING_DB_NAME, TICK_DB_NAME, MINUTE_DB_NAME # 以下为vn.trader和通联数据规定的交易所代码映射 From 2189cdef62e67b04c3146832177e5909fe6256b5 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Fri, 7 Jul 2017 17:59:31 +0800 Subject: [PATCH 23/29] =?UTF-8?q?Examples=E4=B8=AD=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E4=B8=8A=E6=B5=B7=E4=B8=AD=E6=9C=9F=E5=8E=86=E5=8F=B2=E8=A1=8C?= =?UTF-8?q?=E6=83=85=E4=B8=8B=E8=BD=BD=E6=9C=8D=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/CtaBacktesting/backtesting.ipynb | 14 ++-- examples/ShcifcoDataService/config.json | 11 +++ examples/ShcifcoDataService/dataService.py | 91 +++++++++++++++++++++ examples/ShcifcoDataService/downloadData.py | 11 +++ examples/ShcifcoDataService/runService.py | 30 +++++++ vnpy/data/shcifco/test.py | 8 +- 6 files changed, 154 insertions(+), 11 deletions(-) create mode 100644 examples/ShcifcoDataService/config.json create mode 100644 examples/ShcifcoDataService/dataService.py create mode 100644 examples/ShcifcoDataService/downloadData.py create mode 100644 examples/ShcifcoDataService/runService.py diff --git a/examples/CtaBacktesting/backtesting.ipynb b/examples/CtaBacktesting/backtesting.ipynb index 1de18e1d..0540c100 100644 --- a/examples/CtaBacktesting/backtesting.ipynb +++ b/examples/CtaBacktesting/backtesting.ipynb @@ -79,13 +79,13 @@ "name": "stdout", "output_type": "stream", "text": [ - "2017-06-02 16:07:31.265000\t开始载入数据\n", - "2017-06-02 16:07:31.423000\t载入完成,数据量:331890\n", - "2017-06-02 16:07:31.423000\t开始回测\n", - "2017-06-02 16:07:31.441000\t策略初始化完成\n", - "2017-06-02 16:07:31.441000\t策略启动完成\n", - "2017-06-02 16:07:31.442000\t开始回放数据\n", - "2017-06-02 16:07:54.738000\t数据回放结束\n" + "2017-07-06 23:15:17.471000\t开始载入数据\n", + "2017-07-06 23:15:17.485000\t载入完成,数据量:0\n", + "2017-07-06 23:15:17.485000\t开始回测\n", + "2017-07-06 23:15:17.485000\t策略初始化完成\n", + "2017-07-06 23:15:17.485000\t策略启动完成\n", + "2017-07-06 23:15:17.485000\t开始回放数据\n", + "2017-07-06 23:15:17.486000\t数据回放结束\n" ] } ], diff --git a/examples/ShcifcoDataService/config.json b/examples/ShcifcoDataService/config.json new file mode 100644 index 00000000..5d7715c9 --- /dev/null +++ b/examples/ShcifcoDataService/config.json @@ -0,0 +1,11 @@ +{ + "MONGO_HOST": "localhost", + "MONGO_PORT": 27017, + + "SHCIFCO_IP": "180.169.126.123", + "SHCIFCO_PORT": "45065", + "SHCIFCO_TOKEN": "请联系上海中期申请", + + "SYMBOLS": ["cu1707", "cu1708", "cu1709", "cu1712", + "m1707", "m1708", "m1709", "m1712"] +} \ No newline at end of file diff --git a/examples/ShcifcoDataService/dataService.py b/examples/ShcifcoDataService/dataService.py new file mode 100644 index 00000000..270cbde9 --- /dev/null +++ b/examples/ShcifcoDataService/dataService.py @@ -0,0 +1,91 @@ +# encoding: UTF-8 + +import json +import time +import datetime +import random + +from pymongo import MongoClient, ASCENDING + +from vnpy.data.shcifco.vnshcifco import ShcifcoApi, PERIOD_1MIN +from vnpy.trader.vtObject import VtBarData +from vnpy.trader.app.ctaStrategy.ctaBase import MINUTE_DB_NAME + + +# 加载配置 +config = open('config.json') +setting = json.load(config) + +MONGO_HOST = setting['MONGO_HOST'] +MONGO_PORT = setting['MONGO_PORT'] +SHCIFCO_IP = setting['SHCIFCO_IP'] +SHCIFCO_PORT = setting['SHCIFCO_PORT'] +SHCIFCO_TOKEN = setting['SHCIFCO_TOKEN'] +SYMBOLS = setting['SYMBOLS'] + +api = ShcifcoApi(SHCIFCO_IP, SHCIFCO_PORT, SHCIFCO_TOKEN) # 历史行情服务API对象 +mc = MongoClient(MONGO_HOST, MONGO_PORT) # Mongo连接 +db = mc[MINUTE_DB_NAME] # 数据库 + + +#---------------------------------------------------------------------- +def generateVtBar(d): + """生成K线""" + bar = VtBarData() + + bar.symbol = d['symbol'] + bar.vtSymbol = d['symbol'] + bar.date = d['date'] + bar.time = ':'.join([d['time'][:2], d['time'][2:]]) + bar.open = d['open'] + bar.high = d['high'] + bar.low = d['low'] + bar.close = d['close'] + bar.volume = d['volume'] + bar.openInterest = d['openInterest'] + bar.datetime = datetime.datetime.strptime(' '.join([bar.date, bar.time]), '%Y%m%d %H:%M') + + return bar + +#---------------------------------------------------------------------- +def downMinuteBarBySymbol(symbol, num): + """下载某一合约的分钟线数据""" + start = time.time() + + cl = db[symbol] # 集合 + cl.ensure_index([('datetime', ASCENDING)], unique=True) # 添加索引 + + l = api.getHisBar(symbol, num, period=PERIOD_1MIN) + if not l: + print u'%s数据下载失败' %symbol + return + + for d in l: + bar = generateVtBar(d) + d = bar.__dict__ + flt = {'datetime': bar.datetime} + cl.replace_one(flt, d, True) + + end = time.time() + cost = (end - start) * 1000 + + print u'合约%s数据下载完成%s - %s,耗时%s毫秒' %(symbol, generateVtBar(l[0]).datetime, + generateVtBar(l[-1]).datetime, cost) + +#---------------------------------------------------------------------- +def downloadAllMinuteBar(num): + """下载所有配置中的合约的分钟线数据""" + print '-' * 50 + print u'开始下载合约分钟线数据' + print '-' * 50 + + for symbol in SYMBOLS: + downMinuteBarBySymbol(symbol, num) + time.sleep(1) + + print '-' * 50 + print u'合约分钟线数据下载完成' + print '-' * 50 + + + \ No newline at end of file diff --git a/examples/ShcifcoDataService/downloadData.py b/examples/ShcifcoDataService/downloadData.py new file mode 100644 index 00000000..3cf6f3cc --- /dev/null +++ b/examples/ShcifcoDataService/downloadData.py @@ -0,0 +1,11 @@ +# encoding: UTF-8 + +""" +立即下载数据到数据库中,用于手动执行更新操作。 +""" + +from dataService import * + + +if __name__ == '__main__': + downloadAllMinuteBar(1000) \ No newline at end of file diff --git a/examples/ShcifcoDataService/runService.py b/examples/ShcifcoDataService/runService.py new file mode 100644 index 00000000..2b5ac936 --- /dev/null +++ b/examples/ShcifcoDataService/runService.py @@ -0,0 +1,30 @@ +# encoding: UTF-8 + +""" +定时服务,可无人值守运行,实现每日自动下载更新历史行情数据到数据库中。 +""" + +from dataService import * + + +if __name__ == '__main__': + taskCompletedDate = None + + # 生成一个随机的任务下载时间,用于避免所有用户在同一时间访问数据服务器 + taskTime = datetime.time(hour=17, minute=random.randint(1,59)) + + # 进入主循环 + while True: + t = datetime.datetime.now() + + # 每天到达任务下载时间后,执行数据下载的操作 + if t.time() > taskTime and (taskCompletedDate is None or t.date() != taskCompletedDate): + # 下载1000根分钟线数据,足以覆盖过去两天的行情 + downloadAllMinuteBar(1000) + + # 更新任务完成的日期 + taskCompletedDate = t.date() + else: + print u'当前时间%s,任务定时%s' %(t, taskTime) + + time.sleep(60) \ No newline at end of file diff --git a/vnpy/data/shcifco/test.py b/vnpy/data/shcifco/test.py index 15d8e192..eb2f88d8 100644 --- a/vnpy/data/shcifco/test.py +++ b/vnpy/data/shcifco/test.py @@ -4,9 +4,9 @@ from vnshcifco import ShcifcoApi, PERIOD_1MIN if __name__ == "__main__": - ip = '101.231.179.199' - port = '10102' - token = 'testd2cda34b2d317779e812eb84ee4224a6_qpweqf1' + ip = '180.169.126.123' + port = '45065' + token = '请联系上海中期申请' symbol = 'cu1709' # 创建API对象 @@ -22,6 +22,6 @@ if __name__ == "__main__": print api.getLastBar(symbol) # 获取历史分钟线 - print api.getHisBar(symbol, 502, period=PERIOD_1MIN) + print api.getHisBar(symbol, 500, period=PERIOD_1MIN) \ No newline at end of file From b43f70e48ed78c51fb77adb1fd1f660d3d4a8162 Mon Sep 17 00:00:00 2001 From: XueShan Date: Sat, 8 Jul 2017 15:02:45 +0800 Subject: [PATCH 24/29] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=AD=E6=9C=9F?= =?UTF-8?q?=E8=8E=B7=E5=8F=96=E5=8E=86=E5=8F=B2=E6=95=B0=E6=8D=AE=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3=E4=B8=ADdate=E5=92=8Cperiod=E7=9A=84key=E8=B5=8B?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/data/shcifco/vnshcifco.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnpy/data/shcifco/vnshcifco.py b/vnpy/data/shcifco/vnshcifco.py index 84f8331e..425d96b8 100644 --- a/vnpy/data/shcifco/vnshcifco.py +++ b/vnpy/data/shcifco/vnshcifco.py @@ -113,9 +113,9 @@ class ShcifcoApi(object): } # 可选参数 if date: - params[date] = date + params['date'] = date if period: - params[period] = period + params['period'] = period data = self.getData(path, params) if not data: From a26cb7e09d7a4405863b3104ed67b5afb94b0742 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Sun, 9 Jul 2017 21:05:23 +0800 Subject: [PATCH 25/29] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E4=BC=98=E5=85=88=E4=BB=8E=E5=BD=93=E5=89=8D?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E5=A4=B9=E5=8A=A0=E8=BD=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/CtaTrading/CTA_setting.json | 19 +++ examples/CtaTrading/CTP_connect.json | 7 + examples/DataRecording/CTP_connect.json | 7 + examples/DataRecording/DR_setting.json | 18 +++ examples/VnTrader/CTA_setting.json | 19 +++ examples/VnTrader/CTP_connect.json | 7 + examples/VnTrader/DR_setting.json | 18 +++ examples/VnTrader/FEMAS_connect.json | 7 + examples/VnTrader/HUOBI_connect.json | 7 + examples/VnTrader/IB_connect.json | 6 + examples/VnTrader/OANDA_connect.json | 5 + examples/VnTrader/OKCOIN_connect.json | 7 + examples/VnTrader/RM_setting.json | 9 ++ examples/VnTrader/SGIT_connect.json | 7 + examples/VnTrader/SHZD_connect.json | 8 + examples/VnTrader/ST_setting.json | 85 ++++++++++ examples/VnTrader/XSPEED_connect.json | 6 + examples/VnTrader/run.py | 22 ++- vnpy/trader/app/ctaStrategy/ctaEngine.py | 13 +- vnpy/trader/app/dataRecorder/drEngine.py | 152 +++++++++++++----- vnpy/trader/app/riskManager/rmEngine.py | 8 +- .../gateway/cshshlpGateway/cshshlpGateway.py | 7 +- vnpy/trader/gateway/ctpGateway/ctpGateway.py | 9 +- .../gateway/femasGateway/femasGateway.py | 7 +- .../gateway/huobiGateway/huobiGateway.py | 7 +- vnpy/trader/gateway/ibGateway/ibGateway.py | 9 +- .../gateway/ksgoldGateway/ksgoldGateway.py | 6 +- .../gateway/ksotpGateway/ksotpGateway.py | 7 +- .../gateway/lhangGateway/lhangGateway.py | 6 +- vnpy/trader/gateway/ltsGateway/ltsGateway.py | 7 +- .../gateway/oandaGateway/oandaGateway.py | 6 +- .../gateway/okcoinGateway/okcoinGateway.py | 6 +- vnpy/trader/gateway/qdpGateway/qdpGateway.py | 6 +- .../trader/gateway/sgitGateway/sgitGateway.py | 7 +- .../trader/gateway/shzdGateway/shzdGateway.py | 10 +- .../gateway/xspeedGateway/xspeedGateway.py | 7 +- 36 files changed, 423 insertions(+), 121 deletions(-) create mode 100644 examples/CtaTrading/CTA_setting.json create mode 100644 examples/CtaTrading/CTP_connect.json create mode 100644 examples/DataRecording/CTP_connect.json create mode 100644 examples/DataRecording/DR_setting.json create mode 100644 examples/VnTrader/CTA_setting.json create mode 100644 examples/VnTrader/CTP_connect.json create mode 100644 examples/VnTrader/DR_setting.json create mode 100644 examples/VnTrader/FEMAS_connect.json create mode 100644 examples/VnTrader/HUOBI_connect.json create mode 100644 examples/VnTrader/IB_connect.json create mode 100644 examples/VnTrader/OANDA_connect.json create mode 100644 examples/VnTrader/OKCOIN_connect.json create mode 100644 examples/VnTrader/RM_setting.json create mode 100644 examples/VnTrader/SGIT_connect.json create mode 100644 examples/VnTrader/SHZD_connect.json create mode 100644 examples/VnTrader/ST_setting.json create mode 100644 examples/VnTrader/XSPEED_connect.json diff --git a/examples/CtaTrading/CTA_setting.json b/examples/CtaTrading/CTA_setting.json new file mode 100644 index 00000000..19884be3 --- /dev/null +++ b/examples/CtaTrading/CTA_setting.json @@ -0,0 +1,19 @@ +[ + { + "name": "double ema", + "className": "EmaDemoStrategy", + "vtSymbol": "IF1706" + }, + + { + "name": "atr rsi", + "className": "AtrRsiStrategy", + "vtSymbol": "IC1706" + }, + + { + "name": "king keltner", + "className": "KkStrategy", + "vtSymbol": "IH1706" + } +] \ No newline at end of file diff --git a/examples/CtaTrading/CTP_connect.json b/examples/CtaTrading/CTP_connect.json new file mode 100644 index 00000000..e4bfa6b8 --- /dev/null +++ b/examples/CtaTrading/CTP_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "9999", + "mdAddress": "tcp://180.168.146.187:10011", + "tdAddress": "tcp://180.168.146.187:10001", + "userID": "simnow申请", + "password": "simnow申请" +} \ No newline at end of file diff --git a/examples/DataRecording/CTP_connect.json b/examples/DataRecording/CTP_connect.json new file mode 100644 index 00000000..e4bfa6b8 --- /dev/null +++ b/examples/DataRecording/CTP_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "9999", + "mdAddress": "tcp://180.168.146.187:10011", + "tdAddress": "tcp://180.168.146.187:10001", + "userID": "simnow申请", + "password": "simnow申请" +} \ No newline at end of file diff --git a/examples/DataRecording/DR_setting.json b/examples/DataRecording/DR_setting.json new file mode 100644 index 00000000..07030299 --- /dev/null +++ b/examples/DataRecording/DR_setting.json @@ -0,0 +1,18 @@ +{ + "working": true, + + "tick": + [ + ], + + "bar": + [ + ["BTC_CNY_SPOT", "OKCOIN"], + ["LTC_CNY_SPOT", "OKCOIN"], + ["ETH_CNY_SPOT", "OKCOIN"] + ], + + "active": + { + } +} \ No newline at end of file diff --git a/examples/VnTrader/CTA_setting.json b/examples/VnTrader/CTA_setting.json new file mode 100644 index 00000000..19884be3 --- /dev/null +++ b/examples/VnTrader/CTA_setting.json @@ -0,0 +1,19 @@ +[ + { + "name": "double ema", + "className": "EmaDemoStrategy", + "vtSymbol": "IF1706" + }, + + { + "name": "atr rsi", + "className": "AtrRsiStrategy", + "vtSymbol": "IC1706" + }, + + { + "name": "king keltner", + "className": "KkStrategy", + "vtSymbol": "IH1706" + } +] \ No newline at end of file diff --git a/examples/VnTrader/CTP_connect.json b/examples/VnTrader/CTP_connect.json new file mode 100644 index 00000000..1b4d5a42 --- /dev/null +++ b/examples/VnTrader/CTP_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "9999", + "mdAddress": "tcp://180.168.146.187:10011", + "tdAddress": "tcp://180.168.146.187:10001", + "userID": "000300", + "password": "19890624" +} \ No newline at end of file diff --git a/examples/VnTrader/DR_setting.json b/examples/VnTrader/DR_setting.json new file mode 100644 index 00000000..07030299 --- /dev/null +++ b/examples/VnTrader/DR_setting.json @@ -0,0 +1,18 @@ +{ + "working": true, + + "tick": + [ + ], + + "bar": + [ + ["BTC_CNY_SPOT", "OKCOIN"], + ["LTC_CNY_SPOT", "OKCOIN"], + ["ETH_CNY_SPOT", "OKCOIN"] + ], + + "active": + { + } +} \ No newline at end of file diff --git a/examples/VnTrader/FEMAS_connect.json b/examples/VnTrader/FEMAS_connect.json new file mode 100644 index 00000000..e2bb938e --- /dev/null +++ b/examples/VnTrader/FEMAS_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "0110", + "tdAddress": "tcp://118.126.16.229:17111", + "password": "飞马账户请自行联系期货公司申请", + "mdAddress": "tcp://118.126.16.229:17101", + "userID": "飞马账户请自行联系期货公司申请" +} \ No newline at end of file diff --git a/examples/VnTrader/HUOBI_connect.json b/examples/VnTrader/HUOBI_connect.json new file mode 100644 index 00000000..3c427281 --- /dev/null +++ b/examples/VnTrader/HUOBI_connect.json @@ -0,0 +1,7 @@ +{ + "accessKey": "火币网站申请", + "secretKey": "火币网站申请", + "interval": 0.5, + "market": "cny", + "debug": false +} \ No newline at end of file diff --git a/examples/VnTrader/IB_connect.json b/examples/VnTrader/IB_connect.json new file mode 100644 index 00000000..1e62cab3 --- /dev/null +++ b/examples/VnTrader/IB_connect.json @@ -0,0 +1,6 @@ +{ + "host": "localhost", + "port": 7497, + "clientId": 888, + "accountCode": "DU545254" +} \ No newline at end of file diff --git a/examples/VnTrader/OANDA_connect.json b/examples/VnTrader/OANDA_connect.json new file mode 100644 index 00000000..21dd2cd9 --- /dev/null +++ b/examples/VnTrader/OANDA_connect.json @@ -0,0 +1,5 @@ +{ + "token": "请在OANDA网站申请", + "accountId": "请在OANDA网站申请", + "settingName": "practice" +} \ No newline at end of file diff --git a/examples/VnTrader/OKCOIN_connect.json b/examples/VnTrader/OKCOIN_connect.json new file mode 100644 index 00000000..8240e55e --- /dev/null +++ b/examples/VnTrader/OKCOIN_connect.json @@ -0,0 +1,7 @@ +{ + "host": "CNY", + "apiKey": "OKCOIN网站申请", + "secretKey": "OKCOIN网站申请", + "trace": false, + "leverage": 20 +} \ No newline at end of file diff --git a/examples/VnTrader/RM_setting.json b/examples/VnTrader/RM_setting.json new file mode 100644 index 00000000..25c98921 --- /dev/null +++ b/examples/VnTrader/RM_setting.json @@ -0,0 +1,9 @@ +{ + "orderFlowClear": 1, + "orderCancelLimit": 10, + "workingOrderLimit": 20, + "tradeLimit": 1000, + "orderSizeLimit": 100, + "active": true, + "orderFlowLimit": 50 +} \ No newline at end of file diff --git a/examples/VnTrader/SGIT_connect.json b/examples/VnTrader/SGIT_connect.json new file mode 100644 index 00000000..a6925448 --- /dev/null +++ b/examples/VnTrader/SGIT_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "9999", + "tdAddress": "tcp://140.206.81.6:37776", + "password": "888888", + "mdAddress": "tcp://140.206.81.6:37777", + "userID": "0600035" +} \ No newline at end of file diff --git a/examples/VnTrader/SHZD_connect.json b/examples/VnTrader/SHZD_connect.json new file mode 100644 index 00000000..0bf3746e --- /dev/null +++ b/examples/VnTrader/SHZD_connect.json @@ -0,0 +1,8 @@ +{ + "frontAddress": "222.73.119.230", + "frontPort": 7003, + "marketAddress": "222.73.119.230", + "marketPort": 9003, + "userId": "demo000604", + "userPwd": "888888" +} \ No newline at end of file diff --git a/examples/VnTrader/ST_setting.json b/examples/VnTrader/ST_setting.json new file mode 100644 index 00000000..ba2c1da2 --- /dev/null +++ b/examples/VnTrader/ST_setting.json @@ -0,0 +1,85 @@ +[ + { + "name": "m.09-01", + + "activeLeg": + { + "vtSymbol": "m1709", + "ratio": 1, + "multiplier": 1.0, + "payup": 2 + }, + + "passiveLegs": [ + { + "vtSymbol": "m1801", + "ratio": -1, + "multiplier": -1.0, + "payup": 2 + } + ] + }, + + { + "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/examples/VnTrader/XSPEED_connect.json b/examples/VnTrader/XSPEED_connect.json new file mode 100644 index 00000000..71f0b84a --- /dev/null +++ b/examples/VnTrader/XSPEED_connect.json @@ -0,0 +1,6 @@ +{ + "tdAddress": "tcp://203.187.171.250:10910", + "password": "请联系飞创申请", + "mdAddress": "tcp://203.187.171.250:10915", + "accountID": "请联系飞创申请" +} \ No newline at end of file diff --git a/examples/VnTrader/run.py b/examples/VnTrader/run.py index 2140d8ae..0af7dabe 100644 --- a/examples/VnTrader/run.py +++ b/examples/VnTrader/run.py @@ -12,11 +12,9 @@ from vnpy.trader.uiQt import qApp from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 -# from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, -# sgitGateway, oandaGateway, ibGateway, -# shzdGateway, huobiGateway, okcoinGateway) - -from vnpy.trader.gateway import ( huobiGateway, okcoinGateway) +from vnpy.trader.gateway import (ctpGateway, femasGateway, xspeedGateway, + sgitGateway, oandaGateway, ibGateway, + shzdGateway, huobiGateway, okcoinGateway) # 加载上层应用 from vnpy.trader.app import (riskManager, ctaStrategy, spreadTrading) @@ -32,13 +30,13 @@ def main(): me = MainEngine(ee) # 添加交易接口 - # me.addGateway(ctpGateway) - # me.addGateway(femasGateway) - # me.addGateway(xspeedGateway) - # me.addGateway(sgitGateway) - # me.addGateway(oandaGateway) - # me.addGateway(ibGateway) - # me.addGateway(shzdGateway) + me.addGateway(ctpGateway) + me.addGateway(femasGateway) + me.addGateway(xspeedGateway) + me.addGateway(sgitGateway) + me.addGateway(oandaGateway) + me.addGateway(ibGateway) + me.addGateway(shzdGateway) me.addGateway(huobiGateway) me.addGateway(okcoinGateway) diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index 77464b18..cca62f6e 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -29,10 +29,10 @@ from vnpy.trader.vtEvent import * from vnpy.trader.vtConstant import * from vnpy.trader.vtObject import VtTickData, VtBarData from vnpy.trader.vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData -from vnpy.trader.vtFunction import todayDate +from vnpy.trader.vtFunction import todayDate, getJsonPath -from vnpy.trader.app.ctaStrategy.ctaBase import * -from vnpy.trader.app.ctaStrategy.strategy import STRATEGY_CLASS +from .ctaBase import * +from .strategy import STRATEGY_CLASS @@ -41,8 +41,7 @@ from vnpy.trader.app.ctaStrategy.strategy import STRATEGY_CLASS class CtaEngine(object): """CTA策略引擎""" settingFileName = 'CTA_setting.json' - path = os.path.abspath(os.path.dirname(__file__)) - settingFileName = os.path.join(path, settingFileName) + settingfilePath = getJsonPath(settingFileName, __file__) #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): @@ -486,7 +485,7 @@ class CtaEngine(object): #---------------------------------------------------------------------- def saveSetting(self): """保存策略配置""" - with open(self.settingFileName, 'w') as f: + with open(self.settingfilePath, 'w') as f: l = [] for strategy in self.strategyDict.values(): @@ -501,7 +500,7 @@ class CtaEngine(object): #---------------------------------------------------------------------- def loadSetting(self): """读取策略配置""" - with open(self.settingFileName) as f: + with open(self.settingfilePath) as f: l = json.load(f) for setting in l: diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index c9af1522..ec4641c2 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -17,7 +17,7 @@ from threading import Thread from vnpy.event import Event from vnpy.trader.vtEvent import * -from vnpy.trader.vtFunction import todayDate +from vnpy.trader.vtFunction import todayDate, getJsonPath from vnpy.trader.vtObject import VtSubscribeReq, VtLogData, VtBarData, VtTickData from vnpy.trader.app.dataRecorder.drBase import * @@ -28,9 +28,8 @@ from vnpy.trader.app.dataRecorder.language import text class DrEngine(object): """数据记录引擎""" - settingFileName = 'DR_setting.csv' - path = os.path.abspath(os.path.dirname(__file__)) - settingFileName = os.path.join(path, settingFileName) + settingFileName = 'DR_setting.json' + settingFilePath = getJsonPath(settingFileName, __file__) #---------------------------------------------------------------------- def __init__(self, mainEngine, eventEngine): @@ -66,49 +65,122 @@ class DrEngine(object): # 注册事件监听 self.registerEvent() - + #---------------------------------------------------------------------- def loadSetting(self): """加载配置""" with open(self.settingFileName) as f: - drSetting = csv.DictReader(f) - - for d in drSetting: - # 读取配置 - gatewayName = d['gateway'] - symbol = d['symbol'] - exchange = d['exchange'] - currency = d['currency'] - productClass = d['product'] - recordTick = d['tick'] - recordBar = d['bar'] - activeSymbol = d['active'] - - if exchange: - vtSymbol = '.'.join([symbol, exchange]) - else: + drSetting = json.load(f) + + # 如果working设为False则不启动行情记录功能 + working = drSetting['working'] + if not working: + return + + if 'tick' in drSetting: + l = drSetting['tick'] + + for setting in l: + symbol = setting[0] vtSymbol = symbol - - # 订阅行情 - req = VtSubscribeReq() - req.symbol = symbol - req.exchange = exchange - req.currency = currency - req.productClass = productClass - self.mainEngine.subscribe(req, gatewayName) - - # 设置需要记录的数据 - if recordTick: - tick = VtTickData() - self.tickDict[vtSymbol] = VtTickData() - - if recordBar: - self.barDict[vtSymbol] = VtBarData() - - if activeSymbol: + + req = VtSubscribeReq() + req.symbol = setting[0] + + # 针对LTS和IB接口,订阅行情需要交易所代码 + if len(setting)>=3: + req.exchange = setting[2] + vtSymbol = '.'.join([symbol, req.exchange]) + + # 针对IB接口,订阅行情需要货币和产品类型 + if len(setting)>=5: + req.currency = setting[3] + req.productClass = setting[4] + + self.mainEngine.subscribe(req, setting[1]) + + tick = VtTickData() # 该tick实例可以用于缓存部分数据(目前未使用) + self.tickDict[vtSymbol] = tick + + if 'bar' in drSetting: + l = drSetting['bar'] + + for setting in l: + symbol = setting[0] + vtSymbol = symbol + + req = VtSubscribeReq() + req.symbol = symbol + + if len(setting)>=3: + req.exchange = setting[2] + vtSymbol = '.'.join([symbol, req.exchange]) + + if len(setting)>=5: + req.currency = setting[3] + req.productClass = setting[4] + + self.mainEngine.subscribe(req, setting[1]) + + bar = VtBarData() + self.barDict[vtSymbol] = bar + + if 'active' in drSetting: + d = drSetting['active'] + + # 注意这里的vtSymbol对于IB和LTS接口,应该后缀.交易所 + for activeSymbol, vtSymbol in d.items(): self.activeSymbolDict[vtSymbol] = activeSymbol + + # 启动数据插入线程 + self.start() + + # 注册事件监听 + self.registerEvent() + + + ##---------------------------------------------------------------------- + #def loadCsvSetting(self): + #"""加载CSV配置""" + #with open(self.settingFileName) as f: + #drSetting = csv.DictReader(f) + + #for d in drSetting: + ## 读取配置 + #gatewayName = d['gateway'] + #symbol = d['symbol'] + #exchange = d['exchange'] + #currency = d['currency'] + #productClass = d['product'] + #recordTick = d['tick'] + #recordBar = d['bar'] + #activeSymbol = d['active'] + + #if exchange: + #vtSymbol = '.'.join([symbol, exchange]) + #else: + #vtSymbol = symbol + + ## 订阅行情 + #req = VtSubscribeReq() + #req.symbol = symbol + #req.exchange = exchange + #req.currency = currency + #req.productClass = productClass + #self.mainEngine.subscribe(req, gatewayName) + + ## 设置需要记录的数据 + #if recordTick: + #tick = VtTickData() + #self.tickDict[vtSymbol] = VtTickData() - # 保存配置到缓存中 + #if recordBar: + #self.barDict[vtSymbol] = VtBarData() + + #if activeSymbol: + #self.activeSymbolDict[vtSymbol] = activeSymbol + + ## 保存配置到缓存中 self.settingDict[vtSymbol] = d #---------------------------------------------------------------------- diff --git a/vnpy/trader/app/riskManager/rmEngine.py b/vnpy/trader/app/riskManager/rmEngine.py index 54ef606e..8816f2b0 100644 --- a/vnpy/trader/app/riskManager/rmEngine.py +++ b/vnpy/trader/app/riskManager/rmEngine.py @@ -15,14 +15,14 @@ from vnpy.event import Event from vnpy.trader.vtEvent import * from vnpy.trader.vtConstant import * from vnpy.trader.vtGateway import VtLogData +from vnpy.trader.vtFunction import getJsonPath ######################################################################## class RmEngine(object): """风控引擎""" settingFileName = 'RM_setting.json' - path = os.path.abspath(os.path.dirname(__file__)) - settingFileName = os.path.join(path, settingFileName) + settingFilePath = getJsonPath(settingFileName, __file__) name = u'风控模块' @@ -64,7 +64,7 @@ class RmEngine(object): #---------------------------------------------------------------------- def loadSetting(self): """读取配置""" - with open(self.settingFileName) as f: + with open(self.settingFilePath) as f: d = json.load(f) # 设置风控参数 @@ -84,7 +84,7 @@ class RmEngine(object): #---------------------------------------------------------------------- def saveSetting(self): """保存风控参数""" - with open(self.settingFileName, 'w') as f: + with open(self.settingFilePath, 'w') as f: # 保存风控参数 d = {} diff --git a/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py b/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py index 49a7968e..63fdf361 100644 --- a/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py +++ b/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py @@ -8,7 +8,7 @@ from time import sleep from vnpy.api.cshshlp import CsHsHlp from vnpy.api.ctp import MdApi from vnpy.trader.vtGateway import * -from vnpy.trader.vtFunction import getTempPath +from vnpy.trader.vtFunction import getTempPath, getJsonPath # 接口常量 @@ -97,11 +97,10 @@ class CshshlpGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ctpGateway/ctpGateway.py b/vnpy/trader/gateway/ctpGateway/ctpGateway.py index 4354080b..129bcd30 100644 --- a/vnpy/trader/gateway/ctpGateway/ctpGateway.py +++ b/vnpy/trader/gateway/ctpGateway/ctpGateway.py @@ -15,9 +15,9 @@ from datetime import datetime from vnpy.api.ctp import MdApi, TdApi, defineDict from vnpy.trader.vtGateway import * -from vnpy.trader.vtFunction import getTempPath -from vnpy.trader.gateway.ctpGateway.language import text +from vnpy.trader.vtFunction import getJsonPath, getTempPath from vnpy.trader.vtConstant import GATEWAYTYPE_FUTURES +from .language import text # 以下为一些VT类型和CTP类型的映射字典 @@ -97,11 +97,10 @@ class CtpGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/femasGateway/femasGateway.py b/vnpy/trader/gateway/femasGateway/femasGateway.py index 35051d3f..497f146b 100644 --- a/vnpy/trader/gateway/femasGateway/femasGateway.py +++ b/vnpy/trader/gateway/femasGateway/femasGateway.py @@ -11,7 +11,7 @@ import os import json from vnpy.api.femas import MdApi, TdApi, defineDict -from vnpy.trader.vtFunction import getTempPath +from vnpy.trader.vtFunction import getTempPath, getJsonPath from vnpy.trader.vtGateway import * # 以下为一些VT类型和CTP类型的映射字典 @@ -77,11 +77,10 @@ class FemasGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/huobiGateway/huobiGateway.py b/vnpy/trader/gateway/huobiGateway/huobiGateway.py index d84fee10..dd7b6224 100644 --- a/vnpy/trader/gateway/huobiGateway/huobiGateway.py +++ b/vnpy/trader/gateway/huobiGateway/huobiGateway.py @@ -15,7 +15,7 @@ from threading import Thread from vnpy.api.huobi import vnhuobi from vnpy.trader.vtGateway import * - +from vnpy.trader.vtFunction import getJsonPath SYMBOL_BTCCNY = 'BTCCNY' SYMBOL_LTCCNY = 'LTCCNY' @@ -65,11 +65,10 @@ class HuobiGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ibGateway/ibGateway.py b/vnpy/trader/gateway/ibGateway/ibGateway.py index 880768b0..51c12e5e 100644 --- a/vnpy/trader/gateway/ibGateway/ibGateway.py +++ b/vnpy/trader/gateway/ibGateway/ibGateway.py @@ -19,7 +19,9 @@ from copy import copy from vnpy.api.ib import * from vnpy.trader.vtGateway import * -from vnpy.trader.gateway.ibGateway.language import text +from vnpy.trader.vtFunction import getJsonPath +from .language import text + # 以下为一些VT类型和CTP类型的映射字典 @@ -142,11 +144,10 @@ class IbGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py b/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py index 80f22f91..a23fa1cf 100644 --- a/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py +++ b/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py @@ -13,6 +13,7 @@ import time from vnpy.api.ksgold import TdApi, defineDict from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath # 以下类型映射参考的是原生API里的Constant.h @@ -50,11 +51,10 @@ class KsgoldGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py b/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py index f6dd286b..fdfead52 100644 --- a/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py +++ b/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py @@ -9,7 +9,7 @@ import os import json from vnpy.api.ksotp import MdApi, TdApi, defineDict -from vnpy.trader.vtFunction import getTempPath +from vnpy.trader.vtFunction import getTempPath, getJsonPath from vnpy.trader.vtGateway import * # 以下为一些VT类型和CTP类型的映射字典 @@ -73,11 +73,10 @@ class KsotpGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/lhangGateway/lhangGateway.py b/vnpy/trader/gateway/lhangGateway/lhangGateway.py index d8d250b8..3948482a 100644 --- a/vnpy/trader/gateway/lhangGateway/lhangGateway.py +++ b/vnpy/trader/gateway/lhangGateway/lhangGateway.py @@ -12,6 +12,7 @@ from time import sleep from vnpy.api.lhang import LhangApi from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath SYMBOL_BTCCNY = 'BTCCNY' @@ -51,11 +52,10 @@ class LhangGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ltsGateway/ltsGateway.py b/vnpy/trader/gateway/ltsGateway/ltsGateway.py index 5616c5c5..693e9542 100644 --- a/vnpy/trader/gateway/ltsGateway/ltsGateway.py +++ b/vnpy/trader/gateway/ltsGateway/ltsGateway.py @@ -8,7 +8,7 @@ import os import json from vnpy.api.lts import MdApi, QryApi, TdApi, defineDict -from vnpy.trader.vtFunction import getTempPath +from vnpy.trader.vtFunction import getTempPath, getJsonPath from vnpy.trader.vtGateway import * @@ -74,11 +74,10 @@ class LtsGateway(VtGateway): """连接""" # 载入json 文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/oandaGateway/oandaGateway.py b/vnpy/trader/gateway/oandaGateway/oandaGateway.py index f4e52bac..e6cb9aff 100644 --- a/vnpy/trader/gateway/oandaGateway/oandaGateway.py +++ b/vnpy/trader/gateway/oandaGateway/oandaGateway.py @@ -26,6 +26,7 @@ import datetime from vnpy.api.oanda import OandaApi from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath # 价格类型映射 priceTypeMap = {} @@ -58,11 +59,10 @@ class OandaGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py index f41265f9..1b73dc3c 100644 --- a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py +++ b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py @@ -20,6 +20,7 @@ from time import sleep from vnpy.api.okcoin import vnokcoin from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath # 价格类型映射 priceTypeMap = {} @@ -122,11 +123,10 @@ class OkcoinGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/qdpGateway/qdpGateway.py b/vnpy/trader/gateway/qdpGateway/qdpGateway.py index fe00f708..d9443c75 100644 --- a/vnpy/trader/gateway/qdpGateway/qdpGateway.py +++ b/vnpy/trader/gateway/qdpGateway/qdpGateway.py @@ -15,6 +15,7 @@ from copy import copy from vnpy.api.qdp import MdApi, TdApi, defineDict from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath # 以下为一些VT类型和QDP类型的映射字典 @@ -82,11 +83,10 @@ class QdpGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/sgitGateway/sgitGateway.py b/vnpy/trader/gateway/sgitGateway/sgitGateway.py index 4e009e10..ecee3026 100644 --- a/vnpy/trader/gateway/sgitGateway/sgitGateway.py +++ b/vnpy/trader/gateway/sgitGateway/sgitGateway.py @@ -14,7 +14,7 @@ from copy import copy from datetime import datetime from vnpy.api.sgit import MdApi, TdApi, defineDict -from vnpy.trader.vtFunction import getTempPath +from vnpy.trader.vtFunction import getTempPath, getJsonPath from vnpy.trader.vtGateway import * @@ -94,11 +94,10 @@ class SgitGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/shzdGateway/shzdGateway.py b/vnpy/trader/gateway/shzdGateway/shzdGateway.py index a56d2d42..ae192271 100644 --- a/vnpy/trader/gateway/shzdGateway/shzdGateway.py +++ b/vnpy/trader/gateway/shzdGateway/shzdGateway.py @@ -17,6 +17,7 @@ from datetime import datetime from vnpy.api.shzd import ShzdApi from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath # 以下为一些VT类型和SHZD类型的映射字典 @@ -34,10 +35,6 @@ directionMapReverse = {v: k for k, v in directionMap.items()} # 交易所类型映射 exchangeMap = {} -#exchangeMap[EXCHANGE_CFFEX] = 'CFFEX' -#exchangeMap[EXCHANGE_SHFE] = 'SHFE' -#exchangeMap[EXCHANGE_CZCE] = 'CZCE' -#exchangeMap[EXCHANGE_DCE] = 'DCE' exchangeMap[EXCHANGE_HKEX] = 'HKEX' exchangeMap[EXCHANGE_CME] = 'CME' exchangeMap[EXCHANGE_ICE] = 'ICE' @@ -77,11 +74,10 @@ class ShzdGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py b/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py index ae913eab..091d4693 100644 --- a/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py +++ b/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py @@ -11,6 +11,8 @@ from copy import copy from vnpy.api.xspeed import MdApi, TdApi, defineDict from vnpy.trader.vtGateway import * +from vnpy.trader.vtFunction import getJsonPath + # 以下为一些VT类型和XSPEED类型的映射字典 # 价格类型映射 @@ -81,11 +83,10 @@ class XspeedGateway(VtGateway): """连接""" # 载入json文件 fileName = self.gatewayName + '_connect.json' - path = os.path.abspath(os.path.dirname(__file__)) - fileName = os.path.join(path, fileName) + filePath = getJsonPath(fileName, __file__) try: - f = file(fileName) + f = file(filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName From 08fc1565956d6155f10f44eadae9ddc6c5137e50 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Sun, 9 Jul 2017 21:11:00 +0800 Subject: [PATCH 26/29] =?UTF-8?q?CTA=E5=BC=95=E6=93=8E=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=A1=8C=E6=83=85tick=E6=97=B6=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AF=B9=E5=BC=82=E5=B8=B8=E6=95=B0=E6=8D=AE=E7=9A=84=E6=8D=95?= =?UTF-8?q?=E6=8D=89=E5=92=8C=E8=BF=87=E6=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/VnTrader/CTP_connect.json | 4 ++-- vnpy/trader/app/ctaStrategy/ctaEngine.py | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/examples/VnTrader/CTP_connect.json b/examples/VnTrader/CTP_connect.json index 1b4d5a42..e4bfa6b8 100644 --- a/examples/VnTrader/CTP_connect.json +++ b/examples/VnTrader/CTP_connect.json @@ -2,6 +2,6 @@ "brokerID": "9999", "mdAddress": "tcp://180.168.146.187:10011", "tdAddress": "tcp://180.168.146.187:10001", - "userID": "000300", - "password": "19890624" + "userID": "simnow申请", + "password": "simnow申请" } \ No newline at end of file diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index cca62f6e..edc34197 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -254,10 +254,15 @@ class CtaEngine(object): # 推送tick到对应的策略实例进行处理 if tick.vtSymbol in self.tickStrategyDict: - # 添加datetime字段 - if not tick.datetime: - tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') - + # tick时间可能出现异常数据,使用try...except实现捕捉和过滤 + try: + # 添加datetime字段 + if not tick.datetime: + tick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') + except ValueError: + self.writeCtaLog(traceback.format_exc()) + return + # 逐个推送到策略实例中 l = self.tickStrategyDict[tick.vtSymbol] for strategy in l: From fe92850996bd7546687cfe85bd0b5678d5aa48cf Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Sun, 9 Jul 2017 23:54:52 +0800 Subject: [PATCH 27/29] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E7=BC=96=E8=BE=91=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/VnTrader/VT_setting.json | 11 ++ vnpy/trader/app/dataRecorder/drEngine.py | 4 +- .../gateway/cshshlpGateway/cshshlpGateway.py | 8 +- vnpy/trader/gateway/ctpGateway/ctpGateway.py | 9 +- .../gateway/femasGateway/femasGateway.py | 8 +- .../gateway/huobiGateway/huobiGateway.py | 8 +- vnpy/trader/gateway/ibGateway/ibGateway.py | 8 +- .../gateway/ksgoldGateway/ksgoldGateway.py | 8 +- .../gateway/ksotpGateway/ksotpGateway.py | 8 +- .../gateway/lhangGateway/lhangGateway.py | 8 +- vnpy/trader/gateway/ltsGateway/ltsGateway.py | 8 +- .../gateway/oandaGateway/oandaGateway.py | 8 +- .../gateway/okcoinGateway/okcoinGateway.py | 8 +- vnpy/trader/gateway/qdpGateway/qdpGateway.py | 11 +- .../trader/gateway/sgitGateway/sgitGateway.py | 9 +- .../trader/gateway/shzdGateway/shzdGateway.py | 9 +- .../gateway/xspeedGateway/xspeedGateway.py | 11 +- vnpy/trader/ico/editor.ico | Bin 0 -> 67646 bytes vnpy/trader/language/chinese/text.py | 3 + vnpy/trader/language/english/text.py | 3 + vnpy/trader/uiBasicWidget.py | 98 +++++++++++++++++- vnpy/trader/uiMainWindow.py | 10 ++ vnpy/trader/vtFunction.py | 10 +- vnpy/trader/vtGlobal.py | 5 +- 24 files changed, 196 insertions(+), 77 deletions(-) create mode 100644 examples/VnTrader/VT_setting.json create mode 100644 vnpy/trader/ico/editor.ico diff --git a/examples/VnTrader/VT_setting.json b/examples/VnTrader/VT_setting.json new file mode 100644 index 00000000..c9bdcc0b --- /dev/null +++ b/examples/VnTrader/VT_setting.json @@ -0,0 +1,11 @@ +{ + "fontFamily": "微软雅黑", + "fontSize": 12, + + "mongoHost": "localhost", + "mongoPort": 27017, + "mongoLogging": true, + + "darkStyle": true, + "language": "chinese" +} \ No newline at end of file diff --git a/vnpy/trader/app/dataRecorder/drEngine.py b/vnpy/trader/app/dataRecorder/drEngine.py index ec4641c2..63a20e57 100644 --- a/vnpy/trader/app/dataRecorder/drEngine.py +++ b/vnpy/trader/app/dataRecorder/drEngine.py @@ -218,7 +218,9 @@ class DrEngine(object): bar = self.barDict[vtSymbol] # 如果第一个TICK或者新的一分钟 - if not bar.datetime or bar.datetime.minute != tick.datetime.minute: + if (not bar.datetime or + bar.datetime.minute != tick.datetime.minute or + bar.datetime.hour != tick.datetime.hour): if bar.vtSymbol: newBar = copy.copy(bar) self.insertData(MINUTE_DB_NAME, vtSymbol, newBar) diff --git a/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py b/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py index 63fdf361..8e8689cb 100644 --- a/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py +++ b/vnpy/trader/gateway/cshshlpGateway/cshshlpGateway.py @@ -92,15 +92,15 @@ class CshshlpGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ctpGateway/ctpGateway.py b/vnpy/trader/gateway/ctpGateway/ctpGateway.py index 129bcd30..f9390b2a 100644 --- a/vnpy/trader/gateway/ctpGateway/ctpGateway.py +++ b/vnpy/trader/gateway/ctpGateway/ctpGateway.py @@ -92,15 +92,14 @@ class CtpGateway(VtGateway): self.qryEnabled = False # 循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" - # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/femasGateway/femasGateway.py b/vnpy/trader/gateway/femasGateway/femasGateway.py index 497f146b..c5962a49 100644 --- a/vnpy/trader/gateway/femasGateway/femasGateway.py +++ b/vnpy/trader/gateway/femasGateway/femasGateway.py @@ -72,15 +72,15 @@ class FemasGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/huobiGateway/huobiGateway.py b/vnpy/trader/gateway/huobiGateway/huobiGateway.py index dd7b6224..cb36f3c2 100644 --- a/vnpy/trader/gateway/huobiGateway/huobiGateway.py +++ b/vnpy/trader/gateway/huobiGateway/huobiGateway.py @@ -60,15 +60,15 @@ class HuobiGateway(VtGateway): self.tradeApi = HuobiTradeApi(self) self.dataApi = HuobiDataApi(self) + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ibGateway/ibGateway.py b/vnpy/trader/gateway/ibGateway/ibGateway.py index 51c12e5e..6104f002 100644 --- a/vnpy/trader/gateway/ibGateway/ibGateway.py +++ b/vnpy/trader/gateway/ibGateway/ibGateway.py @@ -138,16 +138,16 @@ class IbGateway(VtGateway): self.connected = False # 连接状态 self.api = IbWrapper(self) # API接口 + + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py b/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py index a23fa1cf..d7ebb69e 100644 --- a/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py +++ b/vnpy/trader/gateway/ksgoldGateway/ksgoldGateway.py @@ -46,15 +46,15 @@ class KsgoldGateway(VtGateway): self.orderInited = False # 委托初始化查询 self.tradeInited = False # 成交初始化查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py b/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py index fdfead52..c5b0a465 100644 --- a/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py +++ b/vnpy/trader/gateway/ksotpGateway/ksotpGateway.py @@ -68,15 +68,15 @@ class KsotpGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/lhangGateway/lhangGateway.py b/vnpy/trader/gateway/lhangGateway/lhangGateway.py index 3948482a..174906e6 100644 --- a/vnpy/trader/gateway/lhangGateway/lhangGateway.py +++ b/vnpy/trader/gateway/lhangGateway/lhangGateway.py @@ -47,15 +47,15 @@ class LhangGateway(VtGateway): self.api = LhangApi(self) + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/ltsGateway/ltsGateway.py b/vnpy/trader/gateway/ltsGateway/ltsGateway.py index 693e9542..83610ac2 100644 --- a/vnpy/trader/gateway/ltsGateway/ltsGateway.py +++ b/vnpy/trader/gateway/ltsGateway/ltsGateway.py @@ -68,16 +68,16 @@ class LtsGateway(VtGateway): self.qryConnected = False self.qryEnabled = False # 是否要启动循环查询 + + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json 文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/oandaGateway/oandaGateway.py b/vnpy/trader/gateway/oandaGateway/oandaGateway.py index e6cb9aff..642c81bf 100644 --- a/vnpy/trader/gateway/oandaGateway/oandaGateway.py +++ b/vnpy/trader/gateway/oandaGateway/oandaGateway.py @@ -54,15 +54,15 @@ class OandaGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py index 1b73dc3c..0fd23e7d 100644 --- a/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py +++ b/vnpy/trader/gateway/okcoinGateway/okcoinGateway.py @@ -118,15 +118,15 @@ class OkcoinGateway(VtGateway): self.leverage = 0 self.connected = False + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/qdpGateway/qdpGateway.py b/vnpy/trader/gateway/qdpGateway/qdpGateway.py index d9443c75..1c621518 100644 --- a/vnpy/trader/gateway/qdpGateway/qdpGateway.py +++ b/vnpy/trader/gateway/qdpGateway/qdpGateway.py @@ -78,15 +78,14 @@ class QdpGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): - """连接""" - # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - + """连接""" try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/sgitGateway/sgitGateway.py b/vnpy/trader/gateway/sgitGateway/sgitGateway.py index ecee3026..d46501a3 100644 --- a/vnpy/trader/gateway/sgitGateway/sgitGateway.py +++ b/vnpy/trader/gateway/sgitGateway/sgitGateway.py @@ -89,15 +89,14 @@ class SgitGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" - # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/shzdGateway/shzdGateway.py b/vnpy/trader/gateway/shzdGateway/shzdGateway.py index ae192271..3ed9f305 100644 --- a/vnpy/trader/gateway/shzdGateway/shzdGateway.py +++ b/vnpy/trader/gateway/shzdGateway/shzdGateway.py @@ -69,15 +69,14 @@ class ShzdGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): """连接""" - # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py b/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py index 091d4693..dd46ffef 100644 --- a/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py +++ b/vnpy/trader/gateway/xspeedGateway/xspeedGateway.py @@ -78,15 +78,14 @@ class XspeedGateway(VtGateway): self.qryEnabled = False # 是否要启动循环查询 + self.fileName = self.gatewayName + '_connect.json' + self.filePath = getJsonPath(self.fileName, __file__) + #---------------------------------------------------------------------- def connect(self): - """连接""" - # 载入json文件 - fileName = self.gatewayName + '_connect.json' - filePath = getJsonPath(fileName, __file__) - + """连接""" try: - f = file(filePath) + f = file(self.filePath) except IOError: log = VtLogData() log.gatewayName = self.gatewayName diff --git a/vnpy/trader/ico/editor.ico b/vnpy/trader/ico/editor.ico new file mode 100644 index 0000000000000000000000000000000000000000..e52273768ba59b89403ae24282c21560ef00e4e0 GIT binary patch literal 67646 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 literal 0 HcmV?d00001 diff --git a/vnpy/trader/language/chinese/text.py b/vnpy/trader/language/chinese/text.py index 4627da96..6029c21a 100644 --- a/vnpy/trader/language/chinese/text.py +++ b/vnpy/trader/language/chinese/text.py @@ -121,6 +121,9 @@ RESTORE = u'还原窗口' ABOUT = u'关于' TEST = u'测试' CONNECT = u'连接' +EDIT_SETTING = u'编辑配置' +LOAD = u'读取' +SAVE = u'保存' CPU_MEMORY_INFO = u'CPU使用率:{cpu}% 内存使用率:{memory}%' CONFIRM_EXIT = u'确认退出?' diff --git a/vnpy/trader/language/english/text.py b/vnpy/trader/language/english/text.py index bf2c14b3..17b307d6 100644 --- a/vnpy/trader/language/english/text.py +++ b/vnpy/trader/language/english/text.py @@ -121,6 +121,9 @@ RESTORE = u'Restore Window' ABOUT = u'About' TEST = u'Test' CONNECT = u'Connect ' +EDIT_SETTING = 'Edit Setting' +LOAD = 'Load' +SAVE = 'Save' CPU_MEMORY_INFO = u'CPU Usage:{cpu}% Memory Usage:{memory}%' CONFIRM_EXIT = u'Confirm Exit?' diff --git a/vnpy/trader/uiBasicWidget.py b/vnpy/trader/uiBasicWidget.py index 0a793642..c88cadb9 100644 --- a/vnpy/trader/uiBasicWidget.py +++ b/vnpy/trader/uiBasicWidget.py @@ -7,11 +7,12 @@ import platform from collections import OrderedDict from vnpy.event import * -from vnpy.trader.vtEvent import * -from vnpy.trader.vtFunction import * -from vnpy.trader.vtGateway import * -from vnpy.trader import vtText -from vnpy.trader.uiQt import QtGui, QtWidgets, QtCore, BASIC_FONT +from .vtEvent import * +from .vtFunction import * +from .vtGateway import * +from . import vtText +from .uiQt import QtGui, QtWidgets, QtCore, BASIC_FONT +from .vtFunction import jsonPathDict COLOR_RED = QtGui.QColor('red') @@ -1229,3 +1230,90 @@ class ContractManager(QtWidgets.QWidget): self.monitor.refresh() + +######################################################################## +class SettingEditor(QtWidgets.QWidget): + """配置编辑器""" + + #---------------------------------------------------------------------- + def __init__(self, mainEngine, parent=None): + """Constructor""" + super(SettingEditor, self).__init__(parent) + + self.mainEngine = mainEngine + self.currentFileName = '' + + self.initUi() + + #---------------------------------------------------------------------- + def initUi(self): + """初始化界面""" + self.setWindowTitle(vtText.EDIT_SETTING) + + self.comboFileName = QtWidgets.QComboBox() + self.comboFileName.addItems(jsonPathDict.keys()) + + buttonLoad = QtWidgets.QPushButton(vtText.LOAD) + buttonSave = QtWidgets.QPushButton(vtText.SAVE) + buttonLoad.clicked.connect(self.loadSetting) + buttonSave.clicked.connect(self.saveSetting) + + self.editSetting = QtWidgets.QTextEdit() + self.labelPath = QtWidgets.QLabel() + + hbox = QtWidgets.QHBoxLayout() + hbox.addWidget(self.comboFileName) + hbox.addWidget(buttonLoad) + hbox.addWidget(buttonSave) + hbox.addStretch() + + vbox = QtWidgets.QVBoxLayout() + vbox.addLayout(hbox) + vbox.addWidget(self.editSetting) + vbox.addWidget(self.labelPath) + + self.setLayout(vbox) + + #---------------------------------------------------------------------- + def loadSetting(self): + """加载配置""" + self.currentFileName = str(self.comboFileName.currentText()) + filePath = jsonPathDict[self.currentFileName] + self.labelPath.setText(filePath) + + with open(filePath) as f: + self.editSetting.clear() + + for line in f: + line = line.replace('\n', '') # 移除换行符号 + line = line.decode('UTF-8') + self.editSetting.append(line) + + #---------------------------------------------------------------------- + def saveSetting(self): + """保存配置""" + if not self.currentFileName: + return + + filePath = jsonPathDict[self.currentFileName] + + with open(filePath, 'w') as f: + content = self.editSetting.toPlainText() + content = content.encode('UTF-8') + f.write(content) + + #---------------------------------------------------------------------- + def show(self): + """显示""" + self.comboFileName.clear() + self.comboFileName.addItems(jsonPathDict.keys()) + + super(SettingEditor, self).showMaximized() + + + + + + + + diff --git a/vnpy/trader/uiMainWindow.py b/vnpy/trader/uiMainWindow.py index 27c3f5e7..2fd2769f 100644 --- a/vnpy/trader/uiMainWindow.py +++ b/vnpy/trader/uiMainWindow.py @@ -117,6 +117,7 @@ class MainWindow(QtWidgets.QMainWindow): # 帮助 helpMenu = menubar.addMenu(vtText.HELP) helpMenu.addAction(self.createAction(vtText.CONTRACT_SEARCH, self.openContract, loadIconPath('contract.ico'))) + helpMenu.addAction(self.createAction(vtText.EDIT_SETTING, self.openSettingEditor, loadIconPath('editor.ico'))) helpMenu.addSeparator() helpMenu.addAction(self.createAction(vtText.RESTORE, self.restoreWindow, loadIconPath('restore.ico'))) helpMenu.addAction(self.createAction(vtText.ABOUT, self.openAbout, loadIconPath('about.ico'))) @@ -219,6 +220,15 @@ class MainWindow(QtWidgets.QMainWindow): except KeyError: self.widgetDict['contractM'] = ContractManager(self.mainEngine) self.widgetDict['contractM'].show() + + #---------------------------------------------------------------------- + def openSettingEditor(self): + """打开配置编辑""" + try: + self.widgetDict['settingEditor'].show() + except KeyError: + self.widgetDict['settingEditor'] = SettingEditor(self.mainEngine) + self.widgetDict['settingEditor'].show() #---------------------------------------------------------------------- def closeEvent(self, event): diff --git a/vnpy/trader/vtFunction.py b/vnpy/trader/vtFunction.py index 32bc99a4..acd7405c 100644 --- a/vnpy/trader/vtFunction.py +++ b/vnpy/trader/vtFunction.py @@ -63,7 +63,11 @@ def getTempPath(name): path = os.path.join(tempPath, name) return path - + + +# JSON配置文件路径 +jsonPathDict = {} + #---------------------------------------------------------------------- def getJsonPath(name, moduleFile): """ @@ -74,10 +78,14 @@ def getJsonPath(name, moduleFile): currentFolder = os.getcwd() currentJsonPath = os.path.join(currentFolder, name) if os.path.isfile(currentJsonPath): + jsonPathDict[name] = currentJsonPath return currentJsonPath moduleFolder = os.path.abspath(os.path.dirname(moduleFile)) moduleJsonPath = os.path.join(moduleFolder, '.', name) + jsonPathDict[name] = moduleJsonPath return moduleJsonPath + + diff --git a/vnpy/trader/vtGlobal.py b/vnpy/trader/vtGlobal.py index ab5a6f8d..0b4bc72c 100644 --- a/vnpy/trader/vtGlobal.py +++ b/vnpy/trader/vtGlobal.py @@ -7,14 +7,13 @@ import os import traceback import json - +from vtFunction import getJsonPath globalSetting = {} # 全局配置字典 settingFileName = "VT_setting.json" -path = os.path.abspath(os.path.dirname(__file__)) -settingFileName = os.path.join(path, settingFileName) +settingFilePath = getJsonPath(settingFileName, __file__) try: f = file(settingFileName) From 801e3edd1e78a357c5c64a8f6a0fe0367ef9816f Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 10 Jul 2017 20:22:31 +0800 Subject: [PATCH 28/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0CTA=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E7=9A=84=E5=9B=9E=E6=B5=8B=E5=BC=95=E6=93=8E?= =?UTF-8?q?=E5=9C=A8=E6=94=B6=E5=88=B0=E9=99=90=E4=BB=B7=E5=A7=94=E6=89=98?= =?UTF-8?q?=E5=90=8E=E5=85=88=E6=8E=A8=E9=80=81=E6=9C=AA=E6=88=90=E4=BA=A4?= =?UTF-8?q?=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/ctaStrategy/ctaBacktesting.py | 6 +++++- vnpy/trader/uiBasicWidget.py | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 9f3073de..10759b70 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -228,7 +228,6 @@ class BacktestingEngine(object): order.vtSymbol = vtSymbol order.price = self.roundToPriceTick(price) order.totalVolume = volume - order.status = STATUS_NOTTRADED # 刚提交尚未成交 order.orderID = orderID order.vtOrderID = orderID order.orderTime = str(self.dt) @@ -321,6 +320,11 @@ class BacktestingEngine(object): # 遍历限价单字典中的所有限价单 for orderID, order in self.workingLimitOrderDict.items(): + # 推送委托进入队列(未成交)的状态更新 + if not order.status: + order.status = STATUS_NOTTRADED + self.strategy.onOrder(order) + # 判断是否会成交 buyCross = (order.direction==DIRECTION_LONG and order.price>=buyCrossPrice and diff --git a/vnpy/trader/uiBasicWidget.py b/vnpy/trader/uiBasicWidget.py index c88cadb9..aff93177 100644 --- a/vnpy/trader/uiBasicWidget.py +++ b/vnpy/trader/uiBasicWidget.py @@ -1305,10 +1305,12 @@ class SettingEditor(QtWidgets.QWidget): #---------------------------------------------------------------------- def show(self): """显示""" + # 更新配置文件下拉框 self.comboFileName.clear() self.comboFileName.addItems(jsonPathDict.keys()) - super(SettingEditor, self).showMaximized() + # 显示界面 + super(SettingEditor, self).show() From e1ca7de271ddfd28f71aec9814f816b5d199f000 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Mon, 10 Jul 2017 20:39:13 +0800 Subject: [PATCH 29/29] =?UTF-8?q?=E5=A2=9E=E5=8A=A0CTA=E7=AD=96=E7=95=A5?= =?UTF-8?q?=E6=9C=AB=E7=8F=AD=E7=9A=84=E5=81=9C=E6=AD=A2=E5=8D=95=E7=8A=B6?= =?UTF-8?q?=E6=80=81=E6=9B=B4=E6=96=B0=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/ctaStrategy/ctaBacktesting.py | 25 +++++++++++-------- vnpy/trader/app/ctaStrategy/ctaEngine.py | 5 ++++ vnpy/trader/app/ctaStrategy/ctaTemplate.py | 5 ++++ .../ctaStrategy/strategy/strategyAtrRsi.py | 4 +++ .../strategy/strategyDualThrust.py | 5 ++++ .../ctaStrategy/strategy/strategyEmaDemo.py | 10 ++++++++ .../strategy/strategyKingKeltner.py | 5 ++++ 7 files changed, 49 insertions(+), 10 deletions(-) diff --git a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py index 10759b70..c3d63f6f 100644 --- a/vnpy/trader/app/ctaStrategy/ctaBacktesting.py +++ b/vnpy/trader/app/ctaStrategy/ctaBacktesting.py @@ -272,8 +272,8 @@ class BacktestingEngine(object): so.price = self.roundToPriceTick(price) so.volume = volume so.strategy = strategy - so.stopOrderID = stopOrderID so.status = STOPORDER_WAITING + so.stopOrderID = stopOrderID if orderType == CTAORDER_BUY: so.direction = DIRECTION_LONG @@ -292,6 +292,9 @@ class BacktestingEngine(object): self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so + # 推送停止单初始更新 + self.strategy.onStopOrder(so) + return stopOrderID #---------------------------------------------------------------------- @@ -302,6 +305,7 @@ class BacktestingEngine(object): so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] + self.strategy.onStopOrder(so) #---------------------------------------------------------------------- def crossLimitOrder(self): @@ -395,6 +399,11 @@ class BacktestingEngine(object): # 如果发生了成交 if buyCross or sellCross: + # 更新停止单状态,并从字典中删除该停止单 + so.status = STOPORDER_TRIGGERED + if stopOrderID in self.workingStopOrderDict: + del self.workingStopOrderDict[stopOrderID] + # 推送成交数据 self.tradeCount += 1 # 成交编号自增1 tradeID = str(self.tradeCount) @@ -414,19 +423,15 @@ class BacktestingEngine(object): orderID = str(self.limitOrderCount) trade.orderID = orderID trade.vtOrderID = orderID - trade.direction = so.direction trade.offset = so.offset trade.volume = so.volume trade.tradeTime = str(self.dt) trade.dt = self.dt - self.strategy.onTrade(trade) self.tradeDict[tradeID] = trade # 推送委托数据 - so.status = STOPORDER_TRIGGERED - order = VtOrderData() order.vtSymbol = so.vtSymbol order.symbol = so.vtSymbol @@ -439,14 +444,14 @@ class BacktestingEngine(object): order.tradedVolume = so.volume order.status = STATUS_ALLTRADED order.orderTime = trade.tradeTime - self.strategy.onOrder(order) self.limitOrderDict[orderID] = order - # 从字典中删除该限价单 - if stopOrderID in self.workingStopOrderDict: - del self.workingStopOrderDict[stopOrderID] - + # 按照顺序推送数据 + self.strategy.onStopOrder(so) + self.strategy.onOrder(order) + self.strategy.onTrade(trade) + #---------------------------------------------------------------------- def insertData(self, dbName, collectionName, data): """考虑到回测中不允许向数据库插入数据,防止实盘交易中的一些代码出错""" diff --git a/vnpy/trader/app/ctaStrategy/ctaEngine.py b/vnpy/trader/app/ctaStrategy/ctaEngine.py index edc34197..fc6f69d9 100644 --- a/vnpy/trader/app/ctaStrategy/ctaEngine.py +++ b/vnpy/trader/app/ctaStrategy/ctaEngine.py @@ -210,6 +210,9 @@ class CtaEngine(object): self.stopOrderDict[stopOrderID] = so self.workingStopOrderDict[stopOrderID] = so + # 推送停止单状态 + strategy.onStopOrder(so) + return stopOrderID #---------------------------------------------------------------------- @@ -220,6 +223,7 @@ class CtaEngine(object): so = self.workingStopOrderDict[stopOrderID] so.status = STOPORDER_CANCELLED del self.workingStopOrderDict[stopOrderID] + so.strategy.onStopOrder(so) #---------------------------------------------------------------------- def processStopOrder(self, tick): @@ -244,6 +248,7 @@ class CtaEngine(object): so.status = STOPORDER_TRIGGERED self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy) del self.workingStopOrderDict[so.stopOrderID] + so.strategy.onStopOrder(so) #---------------------------------------------------------------------- def processTickEvent(self, event): diff --git a/vnpy/trader/app/ctaStrategy/ctaTemplate.py b/vnpy/trader/app/ctaStrategy/ctaTemplate.py index f9cf9459..b4213d1f 100644 --- a/vnpy/trader/app/ctaStrategy/ctaTemplate.py +++ b/vnpy/trader/app/ctaStrategy/ctaTemplate.py @@ -90,6 +90,11 @@ class CtaTemplate(object): """收到Bar推送(必须由用户继承实现)""" raise NotImplementedError + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """收到停止单推送(必须由用户继承实现)""" + raise NotImplementedError + #---------------------------------------------------------------------- def buy(self, price, volume, stop=False): """买开""" diff --git a/vnpy/trader/app/ctaStrategy/strategy/strategyAtrRsi.py b/vnpy/trader/app/ctaStrategy/strategy/strategyAtrRsi.py index 3669a66b..c9606b96 100644 --- a/vnpy/trader/app/ctaStrategy/strategy/strategyAtrRsi.py +++ b/vnpy/trader/app/ctaStrategy/strategy/strategyAtrRsi.py @@ -237,3 +237,7 @@ class AtrRsiStrategy(CtaTemplate): # 发出状态更新事件 self.putEvent() + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """停止单推送""" + pass \ No newline at end of file diff --git a/vnpy/trader/app/ctaStrategy/strategy/strategyDualThrust.py b/vnpy/trader/app/ctaStrategy/strategy/strategyDualThrust.py index bc5b99b5..c7f7815a 100644 --- a/vnpy/trader/app/ctaStrategy/strategy/strategyDualThrust.py +++ b/vnpy/trader/app/ctaStrategy/strategy/strategyDualThrust.py @@ -221,3 +221,8 @@ class DualThrustStrategy(CtaTemplate): def onTrade(self, trade): # 发出状态更新事件 self.putEvent() + + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """停止单推送""" + pass \ No newline at end of file diff --git a/vnpy/trader/app/ctaStrategy/strategy/strategyEmaDemo.py b/vnpy/trader/app/ctaStrategy/strategy/strategyEmaDemo.py index 5047c444..e1fee112 100644 --- a/vnpy/trader/app/ctaStrategy/strategy/strategyEmaDemo.py +++ b/vnpy/trader/app/ctaStrategy/strategy/strategyEmaDemo.py @@ -188,6 +188,11 @@ class EmaDemoStrategy(CtaTemplate): # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """停止单推送""" + pass + ######################################################################################## class OrderManagementDemoStrategy(CtaTemplate): @@ -294,3 +299,8 @@ class OrderManagementDemoStrategy(CtaTemplate): """收到成交推送(必须由用户继承实现)""" # 对于无需做细粒度委托控制的策略,可以忽略onOrder pass + + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """停止单推送""" + pass diff --git a/vnpy/trader/app/ctaStrategy/strategy/strategyKingKeltner.py b/vnpy/trader/app/ctaStrategy/strategy/strategyKingKeltner.py index 5681a56d..84163ea3 100644 --- a/vnpy/trader/app/ctaStrategy/strategy/strategyKingKeltner.py +++ b/vnpy/trader/app/ctaStrategy/strategy/strategyKingKeltner.py @@ -278,3 +278,8 @@ class KkStrategy(CtaTemplate): # 将委托号记录到列表中 self.orderList.append(self.buyOrderID) self.orderList.append(self.shortOrderID) + + #---------------------------------------------------------------------- + def onStopOrder(self, so): + """停止单推送""" + pass \ No newline at end of file