From e7b56439f93548a291d71258e0d03c74062e86dd Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 5 Dec 2017 12:48:25 +0800 Subject: [PATCH 1/7] =?UTF-8?q?[Add]=E6=96=B0=E5=A2=9EQuantosDataService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/QuantosDataService/README.md | 3 + examples/QuantosDataService/config.json | 10 ++ examples/QuantosDataService/dataService.py | 121 ++++++++++++++++++++ examples/QuantosDataService/downloadData.py | 22 ++++ examples/QuantosDataService/runService.py | 39 +++++++ examples/README.md | 6 +- 6 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 examples/QuantosDataService/README.md create mode 100644 examples/QuantosDataService/config.json create mode 100644 examples/QuantosDataService/dataService.py create mode 100644 examples/QuantosDataService/downloadData.py create mode 100644 examples/QuantosDataService/runService.py diff --git a/examples/QuantosDataService/README.md b/examples/QuantosDataService/README.md new file mode 100644 index 00000000..18d119e0 --- /dev/null +++ b/examples/QuantosDataService/README.md @@ -0,0 +1,3 @@ +# quantOS历史行情服务 + +请在[www.quantos.org](www.quantos.org)注册后,将用户名和TOKEN输入到配置文件config.json中,即可使用该服务。 \ No newline at end of file diff --git a/examples/QuantosDataService/config.json b/examples/QuantosDataService/config.json new file mode 100644 index 00000000..c046ab3f --- /dev/null +++ b/examples/QuantosDataService/config.json @@ -0,0 +1,10 @@ +{ + "MONGO_HOST": "localhost", + "MONGO_PORT": 27017, + + "DATA_SERVER": "tcp://data.tushare.org:8910", + "USERNAME": "", + "TOKEN": "", + + "SYMBOLS": ["510050.SSE", "510300.SSE"] +} \ No newline at end of file diff --git a/examples/QuantosDataService/dataService.py b/examples/QuantosDataService/dataService.py new file mode 100644 index 00000000..0d76fc70 --- /dev/null +++ b/examples/QuantosDataService/dataService.py @@ -0,0 +1,121 @@ +# encoding: UTF-8 + +import sys +import json +from datetime import datetime, timedelta +from time import time, sleep + +from pymongo import MongoClient, ASCENDING + +from vnpy.trader.vtObject import VtBarData +from vnpy.trader.app.ctaStrategy.ctaBase import MINUTE_DB_NAME +from vnpy.trader.gateway.tkproGateway.DataApi import DataApi + + +# 交易所类型映射 +exchangeMap = {} +exchangeMap['CFFEX'] = 'CFE' +exchangeMap['SHFE'] = 'SHF' +exchangeMap['CZCE'] = 'CZC' +exchangeMap['DCE'] = 'DCE' +exchangeMap['SSE'] = 'SH' +exchangeMap['SZSE'] = 'SZ' +exchangeMapReverse = {v:k for k,v in exchangeMap.items()} + +# 加载配置 +config = open('config.json') +setting = json.load(config) +config.close() + +MONGO_HOST = setting['MONGO_HOST'] +MONGO_PORT = setting['MONGO_PORT'] +SYMBOLS = setting['SYMBOLS'] +USERNAME = setting['USERNAME'] +TOKEN = setting['TOKEN'] +DATA_SERVER = setting['DATA_SERVER'] + +# 创建API对象 +mc = MongoClient(MONGO_HOST, MONGO_PORT) # Mongo连接 +db = mc[MINUTE_DB_NAME] # 数据库 + + +#---------------------------------------------------------------------- +def generateVtBar(row): + """生成K线""" + bar = VtBarData() + + symbol, exchange = row['symbol'].split('.') + + bar.symbol = symbol + bar.exchange = exchangeMapReverse[exchange] + bar.vtSymbol = '.'.join([bar.symbol, bar.exchange]) + bar.open = row['open'] + bar.high = row['high'] + bar.low = row['low'] + bar.close = row['close'] + bar.volume = row['volume'] + + bar.date = str(row['trade_date']) + bar.time = str(row['time']) + bar.datetime = datetime.strptime(' '.join([bar.date, bar.time]), '%Y%m%d %H%M%S') + + return bar + +#---------------------------------------------------------------------- +def downMinuteBarBySymbol(api, vtSymbol, startDate): + """下载某一合约的分钟线数据""" + start = time() + + cl = db[vtSymbol] + cl.ensure_index([('datetime', ASCENDING)], unique=True) # 添加索引 + + dt = datetime.strptime(startDate, '%Y%m%d') + today = datetime.now() + delta = timedelta(1) + + code, exchange = vtSymbol.split('.') + symbol = '.'.join([code, exchangeMap[exchange]]) + + while dt <= today: + d = int(dt.strftime('%Y%m%d')) + df, msg = api.bar(symbol, freq='1M', trade_date=d) + dt += delta + + if df is None: + continue + + for ix, row in df.iterrows(): + bar = generateVtBar(row) + d = bar.__dict__ + flt = {'datetime': bar.datetime} + cl.replace_one(flt, d, True) + + + end = time() + cost = (end - start) * 1000 + + print u'合约%s数据下载完成%s - %s,耗时%s毫秒' %(vtSymbol, startDate, today.strftime('%Y%m%d'), cost) + + +#---------------------------------------------------------------------- +def downloadAllMinuteBar(api): + """下载所有配置中的合约的分钟线数据""" + print '-' * 50 + print u'开始下载合约分钟线数据' + print '-' * 50 + + startDt = datetime.today() - 10 * timedelta(1) + startDate = startDt.strftime('%Y%m%d') + + # 添加下载任务 + for symbol in SYMBOLS: + downMinuteBarBySymbol(api, str(symbol), startDate) + + print '-' * 50 + print u'合约分钟线数据下载完成' + print '-' * 50 + + +if __name__ == '__main__': + downloadAllMinuteBar() + \ No newline at end of file diff --git a/examples/QuantosDataService/downloadData.py b/examples/QuantosDataService/downloadData.py new file mode 100644 index 00000000..5ed97326 --- /dev/null +++ b/examples/QuantosDataService/downloadData.py @@ -0,0 +1,22 @@ +# encoding: UTF-8 + +""" +立即下载数据到数据库中,用于手动执行更新操作。 +""" + +import json + +from vnpy.trader.gateway.tkproGateway.DataApi import DataApi +from dataService import * + + +if __name__ == '__main__': + # 创建API对象 + api = DataApi(DATA_SERVER) + info, msg = api.login(USERNAME, TOKEN) + + if not info: + print u'数据服务器登录失败,原因:%s' %msg + + # 下载数据 + downloadAllMinuteBar(api) \ No newline at end of file diff --git a/examples/QuantosDataService/runService.py b/examples/QuantosDataService/runService.py new file mode 100644 index 00000000..34132e33 --- /dev/null +++ b/examples/QuantosDataService/runService.py @@ -0,0 +1,39 @@ +# encoding: UTF-8 + +""" +定时服务,可无人值守运行,实现每日自动下载更新历史行情数据到数据库中。 +""" + +import datetime as ddt + +from dataService import * + + +if __name__ == '__main__': + taskCompletedDate = None + + # 生成一个随机的任务下载时间,用于避免所有用户在同一时间访问数据服务器 + taskTime = ddt.time(hour=17, minute=0) + + # 进入主循环 + while True: + t = ddt.datetime.now() + + # 每天到达任务下载时间后,执行数据下载的操作 + if t.time() > taskTime and (taskCompletedDate is None or t.date() != taskCompletedDate): + # 创建API对象 + api = DataApi(DATA_SERVER) + info, msg = api.login(USERNAME, TOKEN) + + if not info: + print u'数据服务器登录失败,原因:%s' %msg + + # 下载数据 + downloadAllMinuteBar(api) + + # 更新任务完成的日期 + taskCompletedDate = t.date() + else: + print u'当前时间%s,任务定时%s' %(t, taskTime) + + sleep(60) \ No newline at end of file diff --git a/examples/README.md b/examples/README.md index 10befbda..cb7a61bf 100644 --- a/examples/README.md +++ b/examples/README.md @@ -4,6 +4,8 @@ * VnTrader:最常用的vn.py图形交易界面 +* OptionMaster: 期权量化交易系统 + * DataRecording:全自动行情记录工具(无需用户每日定时重启) * CtaTrading:无图形界面模式的CTA策略交易 @@ -18,4 +20,6 @@ * TushareDataService:TuShare历史行情服务(A股) -* FutuDataService:富途证券历史行情服务(美股、港股) \ No newline at end of file +* FutuDataService:富途证券历史行情服务(美股、港股) + +* QuantosDataService: quantOS历史行情服务(A股、期货) \ No newline at end of file From f67cb4086475c3ff169db46144da0906ffd503b1 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Tue, 5 Dec 2017 13:24:33 +0800 Subject: [PATCH 2/7] =?UTF-8?q?[Add]=E6=B7=BB=E5=8A=A0OptionMaster?= =?UTF-8?q?=E4=B8=8B=E7=9A=84CTP=E8=AF=81=E5=88=B8=E6=8E=A5=E5=8F=A3ctpsec?= =?UTF-8?q?Gateway?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/OptionMaster/CTPSEC_connect.json | 7 +++++++ examples/OptionMaster/CTP_connect.json | 10 +++++----- examples/OptionMaster/ctpsecGateway/__init__.py | 10 ++++++++++ .../OptionMaster/data/TRADE_MARKET_110100001088sop.dat | 1 - examples/OptionMaster/run.py | 3 +++ vnpy/trader/gateway/ctpGateway/ctpGateway.py | 1 + 6 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 examples/OptionMaster/CTPSEC_connect.json create mode 100644 examples/OptionMaster/ctpsecGateway/__init__.py delete mode 100644 examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat diff --git a/examples/OptionMaster/CTPSEC_connect.json b/examples/OptionMaster/CTPSEC_connect.json new file mode 100644 index 00000000..85eacb25 --- /dev/null +++ b/examples/OptionMaster/CTPSEC_connect.json @@ -0,0 +1,7 @@ +{ + "brokerID": "2001", + "mdAddress": "tcp://125.64.36.26:51213", + "tdAddress": "tcp://125.64.36.26:51205", + "userID": "请联系经纪商申请", + "password": "请联系经纪商申请" +} \ No newline at end of file diff --git a/examples/OptionMaster/CTP_connect.json b/examples/OptionMaster/CTP_connect.json index e4bfa6b8..85eacb25 100644 --- a/examples/OptionMaster/CTP_connect.json +++ b/examples/OptionMaster/CTP_connect.json @@ -1,7 +1,7 @@ { - "brokerID": "9999", - "mdAddress": "tcp://180.168.146.187:10011", - "tdAddress": "tcp://180.168.146.187:10001", - "userID": "simnow申请", - "password": "simnow申请" + "brokerID": "2001", + "mdAddress": "tcp://125.64.36.26:51213", + "tdAddress": "tcp://125.64.36.26:51205", + "userID": "请联系经纪商申请", + "password": "请联系经纪商申请" } \ No newline at end of file diff --git a/examples/OptionMaster/ctpsecGateway/__init__.py b/examples/OptionMaster/ctpsecGateway/__init__.py new file mode 100644 index 00000000..46b1e399 --- /dev/null +++ b/examples/OptionMaster/ctpsecGateway/__init__.py @@ -0,0 +1,10 @@ +# encoding: UTF-8 + +from vnpy.trader import vtConstant +from vnpy.trader.gateway.ctpGateway import CtpGateway + +gatewayClass = CtpGateway +gatewayName = 'CTPSEC' +gatewayDisplayName = 'CTP证券' +gatewayType = vtConstant.GATEWAYTYPE_FUTURES +gatewayQryEnabled = True diff --git a/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat b/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat deleted file mode 100644 index dff3957f..00000000 --- a/examples/OptionMaster/data/TRADE_MARKET_110100001088sop.dat +++ /dev/null @@ -1 +0,0 @@ -tBr8RMewRABqiW7HBOkrkg== \ No newline at end of file diff --git a/examples/OptionMaster/run.py b/examples/OptionMaster/run.py index fac0164f..16926371 100644 --- a/examples/OptionMaster/run.py +++ b/examples/OptionMaster/run.py @@ -18,6 +18,8 @@ from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 from vnpy.trader.gateway import (secGateway, ctpGateway) +import ctpsecGateway + # 加载上层应用 from vnpy.trader.app import (riskManager, optionMaster) @@ -37,6 +39,7 @@ def main(): # 添加交易接口 me.addGateway(secGateway) me.addGateway(ctpGateway) + me.addGateway(ctpsecGateway) # 添加上层应用 me.addApp(riskManager) diff --git a/vnpy/trader/gateway/ctpGateway/ctpGateway.py b/vnpy/trader/gateway/ctpGateway/ctpGateway.py index 20f98c79..21f8c118 100644 --- a/vnpy/trader/gateway/ctpGateway/ctpGateway.py +++ b/vnpy/trader/gateway/ctpGateway/ctpGateway.py @@ -48,6 +48,7 @@ exchangeMap[EXCHANGE_SHFE] = 'SHFE' exchangeMap[EXCHANGE_CZCE] = 'CZCE' exchangeMap[EXCHANGE_DCE] = 'DCE' exchangeMap[EXCHANGE_SSE] = 'SSE' +exchangeMap[EXCHANGE_SZSE] = 'SZSE' exchangeMap[EXCHANGE_INE] = 'INE' exchangeMap[EXCHANGE_UNKNOWN] = '' exchangeMapReverse = {v:k for k,v in exchangeMap.items()} From 03381c216c498aff377ed494c1b1b14e06839042 Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 6 Dec 2017 09:14:53 +0800 Subject: [PATCH 3/7] [Fix]Close #620 --- vnpy/data/tq/vntq.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vnpy/data/tq/vntq.py b/vnpy/data/tq/vntq.py index 4c08390d..a123a0d8 100644 --- a/vnpy/data/tq/vntq.py +++ b/vnpy/data/tq/vntq.py @@ -211,7 +211,11 @@ class TqApi(object): def on_receive_msg(self, msg): """收到数据推送""" pack = json.loads(msg) - l = pack["data"] + + if 'data' in pack: + l = pack["data"] + else: + print u'on_receive_msg收到的数据中没有data字段,数据内容%s' %str(pack) for data in l: # 合并更新数据字典 From 7e7ef73be45deb318f2ea14bfddb85a5266fa53d Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 6 Dec 2017 21:49:24 +0800 Subject: [PATCH 4/7] =?UTF-8?q?[Fix]=E4=BF=AE=E5=A4=8D=E5=B8=8C=E8=85=8A?= =?UTF-8?q?=E5=80=BC=E8=AE=A1=E7=AE=97=E7=9A=84=E4=B9=98=E6=95=B0bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/optionMaster/omBase.py | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/vnpy/trader/app/optionMaster/omBase.py b/vnpy/trader/app/optionMaster/omBase.py index e82e021a..d5a4f1c6 100644 --- a/vnpy/trader/app/optionMaster/omBase.py +++ b/vnpy/trader/app/optionMaster/omBase.py @@ -145,7 +145,7 @@ class OmUnderlying(OmInstrument): #---------------------------------------------------------------------- def calculatePosGreeks(self): """计算持仓希腊值""" - self.posDelta = self.theoDelta * self.netPos * self.size + self.posDelta = self.theoDelta * self.netPos ######################################################################## @@ -218,21 +218,26 @@ class OmOption(OmInstrument): if not underlyingPrice or not self.pricingImpv: return - self.theoPrice, self.theoDelta, self.theoGamma, self.theoTheta, self.theoVega = self.calculateGreeks(underlyingPrice, - self.k, - self.r, - self.t, - self.pricingImpv, - self.cp) + self.theoPrice, delta, gamma, theta, vega = self.calculateGreeks(underlyingPrice, + self.k, + self.r, + self.t, + self.pricingImpv, + self.cp) + + self.theoDelta = delta * self.size + self.theoGamma = gamma * self.size + self.theoTheta = theta * self.size + self.theoVega = vega * self.size #---------------------------------------------------------------------- def calculatePosGreeks(self): """计算持仓希腊值""" self.posValue = self.theoPrice * self.netPos * self.size - self.posDelta = self.theoDelta * self.netPos * self.size - self.posGamma = self.theoGamma * self.netPos * self.size - self.posTheta = self.theoTheta * self.netPos * self.size - self.posVega = self.theoVega * self.netPos * self.size + self.posDelta = self.theoDelta * self.netPos + self.posGamma = self.theoGamma * self.netPos + self.posTheta = self.theoTheta * self.netPos + self.posVega = self.theoVega * self.netPos #---------------------------------------------------------------------- def newTick(self, tick): From f3cb22e6edf04298fb58be7ec5d39857ce59503b Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 6 Dec 2017 21:50:02 +0800 Subject: [PATCH 5/7] =?UTF-8?q?[Fix]=E4=BF=AE=E5=A4=8D=E6=9C=9F=E6=9D=83?= =?UTF-8?q?=E6=89=8B=E5=8A=A8=E4=BA=A4=E6=98=93=E7=BB=84=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E4=BA=8B=E4=BB=B6=E8=AE=A2=E9=98=85bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/optionMaster/uiOmManualTrader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vnpy/trader/app/optionMaster/uiOmManualTrader.py b/vnpy/trader/app/optionMaster/uiOmManualTrader.py index 2b9c96cb..1652be06 100644 --- a/vnpy/trader/app/optionMaster/uiOmManualTrader.py +++ b/vnpy/trader/app/optionMaster/uiOmManualTrader.py @@ -201,7 +201,7 @@ class ChainMonitor(QtWidgets.QTableWidget): for underlying in portfolio.underlyingDict.values(): self.eventEngine.register(EVENT_TICK + underlying.vtSymbol, self.signalTick.emit) - self.eventEngine.register(EVENT_TRADE + underlying.vtSymbol, self.signalTick.emit) + self.eventEngine.register(EVENT_TRADE + underlying.vtSymbol, self.signalTrade.emit) for chain in portfolio.chainDict.values(): for option in chain.optionDict.values(): From ef6014c6f85ca20fd4cfbf257dfcbd8c227516cb Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 6 Dec 2017 21:52:14 +0800 Subject: [PATCH 6/7] =?UTF-8?q?[Mod]=E6=B7=BB=E5=8A=A0=E6=83=85=E6=99=AF?= =?UTF-8?q?=E5=88=86=E6=9E=90=E7=9A=84=E8=BD=B4=E6=A0=87=E7=AD=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- vnpy/trader/app/optionMaster/uiOmAnalysisManager.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vnpy/trader/app/optionMaster/uiOmAnalysisManager.py b/vnpy/trader/app/optionMaster/uiOmAnalysisManager.py index e5bbacad..156486dd 100644 --- a/vnpy/trader/app/optionMaster/uiOmAnalysisManager.py +++ b/vnpy/trader/app/optionMaster/uiOmAnalysisManager.py @@ -35,11 +35,11 @@ class ScenarioValueMonitor(QtWidgets.QTableWidget): # 设置表头 self.setColumnCount(len(priceChangeArray)) - priceChangeHeaders = [('%s%%' %(priceChange*100)) for priceChange in priceChangeArray] + priceChangeHeaders = [('price %s%%' %(priceChange*100)) for priceChange in priceChangeArray] self.setHorizontalHeaderLabels(priceChangeHeaders) self.setRowCount(len(impvChangeArray)) - impvChangeHeaders = [('%s%%' %(impvChange*100)) for impvChange in impvChangeArray] + impvChangeHeaders = [('impv %s%%' %(impvChange*100)) for impvChange in impvChangeArray] self.setVerticalHeaderLabels(impvChangeHeaders) # 设置数据 From 3c0309993d3ba1b246f2b8bde3c59c9515fb6aad Mon Sep 17 00:00:00 2001 From: "vn.py" Date: Wed, 6 Dec 2017 22:04:04 +0800 Subject: [PATCH 7/7] =?UTF-8?q?[Mod]=E4=BF=AE=E6=94=B9=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E5=8F=B7=E5=88=B0v1.7.2=E4=BB=A5=E5=8F=8A=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 18 +- tutorial/README.md | 5 - .../Performance of Receiving Tick Data.ipynb | 498 ----------------- tutorial/performance/Python Performance.ipynb | 511 ------------------ tutorial/performance/README.md | 16 - tutorial/performance/test.pyd | Bin 20480 -> 0 bytes tutorial/performance/test.pyx | 48 -- tutorial/performance/test_setup.py | 7 - vnpy/__init__.py | 2 +- vnpy/trader/archive/app.ico | Bin 67646 -> 0 bytes vnpy/trader/archive/help.ico | Bin 60478 -> 0 bytes vnpy/trader/archive/system.ico | Bin 67646 -> 0 bytes vnpy/trader/archive/vtClient.py | 178 ------ vnpy/trader/archive/vtServer.py | 100 ---- 14 files changed, 10 insertions(+), 1373 deletions(-) delete mode 100644 tutorial/README.md delete mode 100644 tutorial/performance/Performance of Receiving Tick Data.ipynb delete mode 100644 tutorial/performance/Python Performance.ipynb delete mode 100644 tutorial/performance/README.md delete mode 100644 tutorial/performance/test.pyd delete mode 100644 tutorial/performance/test.pyx delete mode 100644 tutorial/performance/test_setup.py delete mode 100644 vnpy/trader/archive/app.ico delete mode 100644 vnpy/trader/archive/help.ico delete mode 100644 vnpy/trader/archive/system.ico delete mode 100644 vnpy/trader/archive/vtClient.py delete mode 100644 vnpy/trader/archive/vtServer.py diff --git a/README.md b/README.md index 0e3d56fc..c76b259c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ vn.py是基于Python的开源量化交易程序开发框架,起源于国内私 ### 项目结构 -1. 丰富的Python交易和数据API接口(vnpy.api),基本覆盖了国内外所有常规交易品种(股票、期货、期权、外汇、外盘、比特币),具体包括: +1. 丰富的Python交易API接口(vnpy.api),基本覆盖了国内外所有常规交易品种(股票、期货、期权、外汇、外盘、比特币),具体包括: - CTP(ctp) @@ -41,9 +41,7 @@ vn.py是基于Python的开源量化交易程序开发框架,起源于国内私 - 火币(huobi) - - 链行(lhang) - - - 通联数据(datayes) + - LBank(lbank) 2. 简洁易用的事件驱动引擎(vnpy.event),作为事件驱动型交易程序的核心 @@ -53,7 +51,7 @@ vn.py是基于Python的开源量化交易程序开发框架,起源于国内私 * 同时登录多个交易接口,在一套界面上监控多种市场的行情和多种资产账户的资金、持仓、委托、成交情况 - * 支持跨市场套利(CTP期货和LTS证券)、境内外套利(CTP期货和IB外盘)、多市场数据整合实时预测走势(CTP的股指期货数据、IB的外盘A50数据、Wind的行业指数数据)等策略应用 + * 支持跨市场套利(CTP期货和XTP证券)、境内外套利(CTP期货和IB外盘)、多市场数据整合实时预测走势(CTP的股指期货数据、IB的外盘A50数据、Wind的行业指数数据)等策略应用 * CTA策略引擎模块,在保持易用性的同时,允许用户针对CTA类策略运行过程中委托的报撤行为进行细粒度控制(降低交易滑点、实现高频策略) @@ -148,10 +146,11 @@ from vnpy.trader.uiMainWindow import MainWindow # 加载底层接口 from vnpy.trader.gateway import (ctpGateway, oandaGateway, ibGateway, - huobiGateway, okcoinGateway) + tkproGateway) if system == 'Windows': - from vnpy.trader.gateway import femasGateway, xspeedGateway + from vnpy.trader.gateway import (femasGateway, xspeedGateway, + futuGateway, secGateway) if system == 'Linux': from vnpy.trader.gateway import xtpGateway @@ -174,14 +173,15 @@ def main(): # 添加交易接口 me.addGateway(ctpGateway) + me.addGateway(tkproGateway) me.addGateway(oandaGateway) me.addGateway(ibGateway) - me.addGateway(huobiGateway) - me.addGateway(okcoinGateway) if system == 'Windows': me.addGateway(femasGateway) me.addGateway(xspeedGateway) + me.addGateway(secGateway) + me.addGateway(futuGateway) if system == 'Linux': me.addGateway(xtpGateway) diff --git a/tutorial/README.md b/tutorial/README.md deleted file mode 100644 index f3bbea75..00000000 --- a/tutorial/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# vn.py项目的实战应用指南 - -本文件夹下的内容主要是围绕vn.py在实际交易中的一系列具体应用,包括说明文档和代码例子。 - -* performance:[《百倍加速!Python量化策略的算法性能提升指南》](http://zhuanlan.zhihu.com/p/24168485) diff --git a/tutorial/performance/Performance of Receiving Tick Data.ipynb b/tutorial/performance/Performance of Receiving Tick Data.ipynb deleted file mode 100644 index da78784a..00000000 --- a/tutorial/performance/Performance of Receiving Tick Data.ipynb +++ /dev/null @@ -1,498 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#vnpy接收行情数据性能测试与改进优化" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "by Jerry He, 2016.12,\n", - "讨论:https://zhuanlan.zhihu.com/p/24662087" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "近来,量化交易平台vnpy因其开源、功能强大、开发容易、可定制性强的特点,目前已经被广泛应用在量化交易中。\n", - "行情数据落地是量化交易平台必须解决的一个基础问题,它有两个方面的作用:一是供策略开发时进行分析、回测;二是为实盘程序时提供近期的历史数据。前者可以通过传统效率更高的实现方式(比如我们有基于C++和leveldb实现的行情数据接收、转发、历史数据获取程序)实现,也可以通过向数据提供方购买获取。但是对于后者,直接基于vnpy落地近期的数据是更为简易的方式。\n", - "\n", - "vnpy包含行情落地模块dataRecorder,已经实现了tick数据、分钟bar数据保存功能。\n", - "本工作主要包括:\n", - "- vnpy原落地函数的性能考查\n", - "- 针对CTP接口,原落地函数的修正与优化\n", - "\n", - "以下所有性能测试时间单位均为毫秒。\n", - "\n", - "测试基于windows 7, i7 3.4GHz." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "from datetime import datetime, time\n", - "import time as gtime\n", - "import pymongo\n", - "from dateutil.parser import parse" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 重构vnpy接收行情数据代码,以用于测试" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "TICK_DB_NAME='Test'\n", - "\n", - "EMPTY_STRING = ''\n", - "EMPTY_UNICODE = u''\n", - "EMPTY_INT = 0\n", - "EMPTY_FLOAT = 0.0\n", - "\n", - "class DrTickData(object):\n", - " \"\"\"Tick数据\"\"\"\n", - "\n", - " #----------------------------------------------------------------------\n", - " def __init__(self):\n", - " \"\"\"Constructor\"\"\" \n", - " self.vtSymbol = EMPTY_STRING # vt系统代码\n", - " self.symbol = EMPTY_STRING # 合约代码\n", - " self.exchange = EMPTY_STRING # 交易所代码\n", - "\n", - " # 成交数据\n", - " self.lastPrice = EMPTY_FLOAT # 最新成交价\n", - " self.volume = EMPTY_INT # 最新成交量\n", - " self.openInterest = EMPTY_INT # 持仓量\n", - " \n", - " self.upperLimit = EMPTY_FLOAT # 涨停价\n", - " self.lowerLimit = EMPTY_FLOAT # 跌停价\n", - " \n", - " # tick的时间\n", - " self.date = EMPTY_STRING # 日期\n", - " self.time = EMPTY_STRING # 时间\n", - " self.datetime = None # python的datetime时间对象\n", - " \n", - " # 五档行情\n", - " self.bidPrice1 = EMPTY_FLOAT\n", - " self.bidPrice2 = EMPTY_FLOAT\n", - " self.bidPrice3 = EMPTY_FLOAT\n", - " self.bidPrice4 = EMPTY_FLOAT\n", - " self.bidPrice5 = EMPTY_FLOAT\n", - " \n", - " self.askPrice1 = EMPTY_FLOAT\n", - " self.askPrice2 = EMPTY_FLOAT\n", - " self.askPrice3 = EMPTY_FLOAT\n", - " self.askPrice4 = EMPTY_FLOAT\n", - " self.askPrice5 = EMPTY_FLOAT \n", - " \n", - " self.bidVolume1 = EMPTY_INT\n", - " self.bidVolume2 = EMPTY_INT\n", - " self.bidVolume3 = EMPTY_INT\n", - " self.bidVolume4 = EMPTY_INT\n", - " self.bidVolume5 = EMPTY_INT\n", - " \n", - " self.askVolume1 = EMPTY_INT\n", - " self.askVolume2 = EMPTY_INT\n", - " self.askVolume3 = EMPTY_INT\n", - " self.askVolume4 = EMPTY_INT\n", - " self.askVolume5 = EMPTY_INT \n", - " \n", - "def insertData(db,collection,data):\n", - " client[db][collection].insert(data.__dict__)\n", - "\n", - "def procecssTickEvent(tick, insertDB=False):\n", - " \"\"\"处理行情推送\"\"\"\n", - " vtSymbol = tick.vtSymbol\n", - "\n", - " # 转化Tick格式\n", - " drTick = DrTickData()\n", - " d = drTick.__dict__\n", - " for key in d.keys():\n", - " if key != 'datetime':\n", - " d[key] = tick.__dict__[key]\n", - " drTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f') \n", - " \n", - " # 更新Tick数据\n", - " if insertDB:\n", - " insertData(TICK_DB_NAME, vtSymbol, drTick) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 创建一个用于测试的Tick数据" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{u'askPrice2': 0.0, u'lastPrice': 2977.0, u'exchange': u'UNKNOWN', u'bidVolume5': 0, u'bidVolume4': 0, u'bidVolume3': 0, u'bidVolume2': 0, u'bidVolume1': 1551, u'datetime': datetime.datetime(2016, 12, 28, 21, 27, 36, 500000), u'askVolume1': 120, u'askVolume3': 0, u'askVolume2': 0, u'askVolume5': 0, u'askVolume4': 0, u'date': u'20161228', u'askPrice5': 0.0, u'volume': 392068, u'lowerLimit': 2725.0, u'bidPrice5': 0.0, u'bidPrice4': 0.0, u'bidPrice1': 2976.0, u'bidPrice3': 0.0, u'bidPrice2': 0.0, u'vtSymbol': u'rb1705', u'time': u'21:27:36.5', u'openInterest': 2304294.0, u'askPrice4': 0.0, u'askPrice3': 0.0, u'symbol': u'rb1705', u'askPrice1': 2977.0, u'upperLimit': 3136.0}\n" - ] - } - ], - "source": [ - "client=pymongo.MongoClient()\n", - "data=client['VnTrader_Tick_Db']['rb1705'].find_one({})\n", - "del data['_id']\n", - "\n", - "class InputTick: pass\n", - "tick=InputTick()\n", - "tick.__dict__.update(data)\n", - "print tick.__dict__" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 测试原版函数性能" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def profiling(count,func=None):\n", - " if func==None: func=lambda: procecssTickEvent(tick)\n", - " t0=gtime.time()\n", - " for i in range(count):\n", - " func()\n", - " total_time=(gtime.time()-t0)\n", - " return total_time*1000/count\n", - "\n", - "test_count=10000" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "原版不保存数据到mongodb单次耗时:0.0255\n", - "原版含保存数据到mongodb单次耗时:0.2334\n" - ] - } - ], - "source": [ - "original_nodb=profiling(test_count)\n", - "client.drop_database(TICK_DB_NAME)\n", - "original_db=profiling(test_count,func=lambda: procecssTickEvent(tick,insertDB=True))\n", - "print '原版不保存数据到mongodb单次耗时:%.4f' %original_nodb\n", - "print '原版含保存数据到mongodb单次耗时:%.4f' %original_db" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "##改进版本\n", - "\n", - "原版程序使用CTP接口保存期货数据时,存在几个问题:\n", - "- 非交易时间收到的野数据没有被过滤掉\n", - "- 当前各交易所提供的date字段混乱,有的使用真实日期,有的使用交易日,导致计算的datetime字段也是有问题的\n", - "\n", - "针对以上问题的改进版本如下:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "#过滤掉的时间区间,注意集合竞价tick被过滤了。\n", - "invalid_sections=[(time(2,30,59),time(9,0,0)),\n", - " (time(11,30,59),time(13,0,0)),\n", - " (time(15,15,0),time(21,0,0))]\n", - "\n", - "#本地时间在此区间时对收到的Tick数据不处理,避免有时期货公司会抽风把数据重推一次。\n", - "invalid_local_section=(time(5,0,0),time(8,30,0))\n", - "\n", - "def procecssTickEvent(tick, insertDB=False):\n", - " \"\"\"处理行情推送\"\"\"\n", - " # 1. 本地时间检查\n", - " local_datetime=datetime.now()\n", - " local_time=local_datetime.time()\n", - " if local_time>invalid_local_section[0] and local_timesec[0] and tmpTime\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
mongodb写入text文件写入无数据写入
原版0.2334NaN0.0255
新版0.21740.03620.0160
\n", - "" - ], - "text/plain": [ - " mongodb写入 text文件写入 无数据写入\n", - "原版 0.2334 NaN 0.0255\n", - "新版 0.2174 0.0362 0.0160" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "df=pd.DataFrame([{u'无数据写入':original_nodb,u'mongodb写入':original_db},\n", - " {u'无数据写入': new_nodb, u'mongodb写入': new_db, u'text文件写入':new_db_text}\n", - " ],index=['原版','新版'])\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "总的来看,行情数据落地原版与新版一次落地耗时都为0.2ms左右。函数中,耗时主要来源于mongodb的插入,占约为90%的耗时。通过尝试简单的text写入作为数据存储方式,耗时得到了大幅降低,获得了单次0.04ms耗时的效果,采取其它更高效的格式有望进一步降低耗时。但考虑到无数据写入时的耗时为约0.02ms,所以期望的最优耗时也就在0.02ms左右。\n", - "\n", - "总的来说,基于mongodb的方案能够实时存储的条目数在每秒几百条量级;进一步优化可能达到几千条量级。此水平应该己能满足绝大多数的需求。" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.10" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/tutorial/performance/Python Performance.ipynb b/tutorial/performance/Python Performance.ipynb deleted file mode 100644 index ec3e8152..00000000 --- a/tutorial/performance/Python Performance.ipynb +++ /dev/null @@ -1,511 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "# 这个测试目标在于仿造一个类似于实盘中,不断有新的数据推送过来,\n", - "# 然后需要计算移动平均线数值,这么一个比较常见的任务。\n", - "\n", - "from __future__ import division\n", - "import time\n", - "import random\n", - "\n", - "# 生成测试用的数据\n", - "data = []\n", - "data_length = 100000 # 总数据量\n", - "ma_length = 500 # 移动均线的窗口\n", - "test_times = 10 # 测试次数\n", - "\n", - "for i in range(data_length):\n", - " data.append(random.randint(1, 100))" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:1.16959998608秒\n", - "单个数据点耗时:11.7547737294微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 计算500期的移动均线,并将结果保存到一个列表里返回\n", - "def ma_basic(data, ma_length):\n", - " \n", - " # 用于保存均线输出结果的列表\n", - " ma = []\n", - " \n", - " # 计算均线用的数据窗口\n", - " data_window = data[:ma_length]\n", - " \n", - " # 测试用数据(去除了之前初始化用的部分)\n", - " test_data = data[ma_length:]\n", - " \n", - " # 模拟实盘不断收到新数据推送的情景,遍历历史数据计算均线\n", - " for new_tick in test_data:\n", - " # 移除最老的数据点并增加最新的数据点\n", - " data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " # 遍历求均线\n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - " \n", - " # 返回数据\n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_basic(data, ma_length)\n", - "\n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - " \n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:2.11879999638秒\n", - "单个数据点耗时:21.2944723254微秒\n", - "最后10个移动平均值: [49.804000000000002, 49.832000000000001, 49.799999999999997, 49.899999999999999, 49.892000000000003, 49.887999999999998, 49.927999999999997, 50.052, 50.106000000000002, 49.981999999999999]\n" - ] - } - ], - "source": [ - "# 改用numpy(首先是一种常见的错误用法)\n", - "import numpy as np\n", - "\n", - "def ma_numpy_wrong(data, ma_length):\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " \n", - " for new_tick in test_data:\n", - " data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " # 使用numpy求均线,注意这里本质上每次循环\n", - " # 都在创建一个新的numpy数组对象,开销很大\n", - " data_array = np.array(data_window)\n", - " ma.append(data_array.mean())\n", - " \n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_numpy_wrong(data, ma_length)\n", - " \n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - " \n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.614300012589秒\n", - "单个数据点耗时:6.17386947325微秒\n", - "最后10个移动平均值: [49.804000000000002, 49.832000000000001, 49.799999999999997, 49.899999999999999, 49.892000000000003, 49.887999999999998, 49.927999999999997, 50.052, 50.106000000000002, 49.981999999999999]\n" - ] - } - ], - "source": [ - "# numpy的正确用法\n", - "def ma_numpy_right(data, ma_length):\n", - " ma = []\n", - " \n", - " # 用numpy数组来缓存计算窗口内的数据\n", - " data_window = np.array(data[:ma_length])\n", - " \n", - " test_data = data[ma_length:]\n", - " \n", - " for new_tick in test_data:\n", - " # 使用numpy数组的底层数据偏移来实现数据更新\n", - " data_window[0:ma_length-1] = data_window[1:ma_length]\n", - " data_window[-1] = new_tick\n", - " ma.append(data_window.mean())\n", - " \n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_numpy_right(data, ma_length)\n", - " \n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - " \n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.043700003624秒\n", - "单个数据点耗时:0.439196016321微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 使用numba加速,ma_numba函数和ma_basic完全一样\n", - "import numba\n", - "\n", - "@numba.jit\n", - "def ma_numba(data, ma_length):\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " \n", - " for new_tick in test_data:\n", - " data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - "\n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_numba(data, ma_length)\n", - "\n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - " \n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.0348000049591秒\n", - "单个数据点耗时:0.349748793559微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 将均线计算改写为高速算法\n", - "def ma_online(data, ma_length):\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " \n", - " # 缓存的窗口内数据求和结果\n", - " sum_buffer = 0\n", - " \n", - " for new_tick in test_data:\n", - " old_tick = data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " # 如果缓存结果为空,则先通过遍历求第一次结果\n", - " if not sum_buffer:\n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - " \n", - " # 将求和结果缓存下来\n", - " sum_buffer = sum_tick\n", - " else:\n", - " # 这里的算法将计算复杂度从O(n)降低到了O(1)\n", - " sum_buffer = sum_buffer - old_tick + new_tick\n", - " ma.append(sum_buffer/ma_length)\n", - " \n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_online(data, ma_length)\n", - " \n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - "\n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.0290000200272秒\n", - "单个数据点耗时:0.29145748771微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 高速算法和numba结合,ma_online_numba函数和ma_online完全一样\n", - "@numba.jit\n", - "def ma_online_numba(data, ma_length):\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " \n", - " sum_buffer = 0\n", - " \n", - " for new_tick in test_data:\n", - " old_tick = data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " if not sum_buffer:\n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - " sum_buffer = sum_tick\n", - " else:\n", - " sum_buffer = sum_buffer - old_tick + new_tick\n", - " ma.append(sum_buffer/ma_length)\n", - "\n", - " return ma\n", - "\n", - "# 运行测试\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_online_numba(data, ma_length)\n", - " \n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - "\n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "\"\"\"\n", - "# 基础的cython加速\n", - "def ma_cython(data, ma_length):\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " \n", - " for new_tick in test_data:\n", - " data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - " \n", - " return ma\n", - " \n", - "\n", - "# cython和高速算法\n", - "def ma_cython_online(data, ma_length):\n", - " # 静态声明变量\n", - " cdef int sum_buffer, sum_tick, old_tick, new_tick\n", - "\n", - " ma = []\n", - " data_window = data[:ma_length]\n", - " test_data = data[ma_length:]\n", - " sum_buffer = 0\n", - " \n", - " for new_tick in test_data:\n", - " old_tick = data_window.pop(0)\n", - " data_window.append(new_tick)\n", - " \n", - " if not sum_buffer:\n", - " sum_tick = 0\n", - " for tick in data_window:\n", - " sum_tick += tick\n", - " ma.append(sum_tick/ma_length)\n", - " \n", - " sum_buffer = sum_tick\n", - " else:\n", - " sum_buffer = sum_buffer - old_tick + new_tick\n", - " ma.append(sum_buffer/ma_length)\n", - " \n", - " return ma\n", - "\"\"\"" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.600800013542秒\n", - "单个数据点耗时:6.03819109088微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 基础cython加速\n", - "from test import ma_cython\n", - "\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_cython(data, ma_length)\n", - " \n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - "\n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "单次耗时:0.00980000495911秒\n", - "单个数据点耗时:0.0984925121518微秒\n", - "最后10个移动平均值: [49.804, 49.832, 49.8, 49.9, 49.892, 49.888, 49.928, 50.052, 50.106, 49.982]\n" - ] - } - ], - "source": [ - "# 高速算法和cython结合\n", - "from test import ma_cython_online\n", - "\n", - "start = time.time()\n", - "\n", - "for i in range(test_times):\n", - " result = ma_cython_online(data, ma_length)\n", - "\n", - "time_per_test = (time.time()-start)/test_times\n", - "time_per_point = time_per_test/(data_length - ma_length)\n", - "\n", - "print u'单次耗时:%s秒' %time_per_test\n", - "print u'单个数据点耗时:%s微秒' %(time_per_point*1000000)\n", - "print u'最后10个移动平均值:', result[-10:]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.11" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/tutorial/performance/README.md b/tutorial/performance/README.md deleted file mode 100644 index 3b1edff7..00000000 --- a/tutorial/performance/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# 使用说明 - -### 使用步骤 -1. 在当前文件夹下打开cmd窗口 -2. 输入ipython notebook运行 -3. 打开Python Performance笔记本,使用Shift+回车逐个Cell运行 - -### 编译Cython -打开cmd,输入运行: -> python setup.py build_ext --inplace - -### 文件说明 -* Python Performance.ipynb:Jupyter Notebook笔记本 -* test.pyx:Cython模块的源代码 -* test_setup.py:编译test.pyx所需的配置文件 -* test.pyd:编译好的Cython模块,可以在Python里直接import diff --git a/tutorial/performance/test.pyd b/tutorial/performance/test.pyd deleted file mode 100644 index 5888c475165281e6bc18c92a03bc90156ddf8c15..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 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 P=CtO3{l9p diff --git a/tutorial/performance/test.pyx b/tutorial/performance/test.pyx deleted file mode 100644 index b5c0a11c..00000000 --- a/tutorial/performance/test.pyx +++ /dev/null @@ -1,48 +0,0 @@ -#encoding:utf-8 - -from __future__ import division - -# 基础的cython加速 -def ma_cython(data, ma_length): - ma = [] - data_window = data[:ma_length] - test_data = data[ma_length:] - - for new_tick in test_data: - data_window.pop(0) - data_window.append(new_tick) - - sum_tick = 0 - for tick in data_window: - sum_tick += tick - ma.append(sum_tick/ma_length) - - return ma - - -# cython和高速算法 -def ma_cython_online(data, ma_length): - # 静态声明变量 - cdef int sum_buffer, sum_tick, old_tick, new_tick - - ma = [] - data_window = data[:ma_length] - test_data = data[ma_length:] - sum_buffer = 0 - - for new_tick in test_data: - old_tick = data_window.pop(0) - data_window.append(new_tick) - - if not sum_buffer: - sum_tick = 0 - for tick in data_window: - sum_tick += tick - ma.append(sum_tick/ma_length) - - sum_buffer = sum_tick - else: - sum_buffer = sum_buffer - old_tick + new_tick - ma.append(sum_buffer/ma_length) - - return ma \ No newline at end of file diff --git a/tutorial/performance/test_setup.py b/tutorial/performance/test_setup.py deleted file mode 100644 index e0b2737f..00000000 --- a/tutorial/performance/test_setup.py +++ /dev/null @@ -1,7 +0,0 @@ -from distutils.core import setup -from Cython.Build import cythonize - -setup( - name = 'cython test', - ext_modules = cythonize("test.pyx"), -) \ No newline at end of file diff --git a/vnpy/__init__.py b/vnpy/__init__.py index 1b644b2f..f33d253f 100644 --- a/vnpy/__init__.py +++ b/vnpy/__init__.py @@ -1,4 +1,4 @@ # encoding: UTF-8 -__version__ = '1.7.1' +__version__ = '1.7.2' __author__ = 'Xiaoyou Chen' \ No newline at end of file diff --git a/vnpy/trader/archive/app.ico b/vnpy/trader/archive/app.ico deleted file mode 100644 index 152292aa7a52714d0b302f4c0275c4016e1fdef9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67646 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 F{{aYmoG1VQ diff --git a/vnpy/trader/archive/help.ico b/vnpy/trader/archive/help.ico deleted file mode 100644 index 2cff09c9d5ab19b6804997f4564a4d7cef792c44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 60478 zcmeI5eQ*?a8OJXz{-HDCjAPyt5|R}2N=FhxNFhoqv}(P}<&E$bND)FYr3`P@nrWdO z8XyS;YLh_F(joz>&NMHKP8o#S0%6Nf&Z^qYr=n%P3e6mQ&($C_9p8v{kaBnrFm`zkJ{qq0~bi9sgDc{ECbjQmx! z{g5JX`WWgU>N=_qb%Uj93@FAFYcondG>MY5{g5hgO7#LOq%p8zyvtD%bmXm~ZHJVG z(_WOouy|rLm~$ghQHoSNF~+G4Sn_Cl<@G52UVW91gyOtt$2bjO+=In&xt(DQ)L8Oi zXHy;Q-M$IhWs1tKteOFqq2E|mmgF^hTrDRotwdeece#ZgT-+a*4IgO zQX82+BO5-x((6|&Tk6+1alCM*$FF*fzR|w6M%6hkcoaEaWsYjLCFZDRbVFCS5jftx z`FFVeNe}8z#@D}3g026iTLUoy$G+2B;o|OZ!KFQUhS!z-MR4aoXAH^l#>pn=-IWO! z-xzOj<-q0k0=RwsG;`E7>w6sUFh`yHl{p%t&t;CxQC@yrEQL87%9A_gbJWfQgxhgW zxbGh??H&)89puTQj^$|HQ#r@Fyp{8`z4Gii25G;$Z%?csR5v zL-40#>^^)g2kK@f3FRuWZ0!#c;dE;@IQorz`1XbjsQOO4P#4wt^QEayWgP1a-aK<8 z4x1OHfH{w@!NkJM!ZC$7vme=yqSNF}*^hzv&DXZDd3!cA{wM{WpPf8BZiB{TXid+}N`}`~KHz0Mf=rH+kz>o--Z*yZk>mTXWDqhVeYr% zVIGbl)~eQRMemJl4^LJf1r$IL@KG+`5(y%*$;= zUX+`26y@ovQM$^@(Xq`L%;(fE7z;nGNP=fItY^xTVCV9*!1Fozu>;oJ$g=W9HC}V% z$Wk}?RpKb-bIjqA&moRO@6#bx-sB0S)~q=zYUWRAX$Y@9#W+HsCC_=$Z5`_ULY6>yyR^%Cp%pEp?- zeCAcoF0?PPA4Tt|F_p_P&Sssyc&&9I6d}iHE_xW3b5Ic|J2;m)=BNfgu}+yBCyfDX z>0ABQ>d$W@D_7mcb-zK4Vvb^5Lp@c%v8)rU)wcjyNvTt>9O=2#dN_ylz8?>7j>NC~ z#dK&`m?GTAO82sAO%3>)wk}D96R$eIo4}cCcypw80yNjAYWn_FdUpi9FNEIfLhlE0 z<|i&Q$Cjtkg!@J&)r-sLVm}cD%+U{y1@UnF@ByjEy@q^UOZ{pv=SDI| zjJ#q$BFCeLxI<9KuTp_y5?IT+yq!OG>+$^2tzR`f$HYOabx$wmbB-gg9v7X! z_>ZR7@0Ztqdo5INA{z=HH^%hntsIRf0*z(rdN474&w6;W$i&NjunM*mFUt4 z-=&SN4p53wd?8s2i8-Py$O`bDR_p zf9T#1cRs%bw{CtqqT0H4SF1#O!^2*3dN(XTLD3m9Rnta})Yn~kYeyFkJ z!^(NnVa42$Rn_!Nd`?+p0fek4T>_^XST=KYF>R4R^>)4OX z(W$-a^1QEGlz2^bCFebXo1B4sLl1Z_)SC*!>U2A`^2LJXaUG!sI{vPT+l&6m4!HX3N8svjXBb}BIxKLf@0=ky+WJ3(|K0j0>R(}?PhfDM-;f;L{-`iq5t@EA z2R^>q>sNGJ>eqmILL^=jh=IzY6u5Av$FF*fzLAO?JA~^ocwMGydKO%}{E=UwWRCK} zwy&*8jr)-4dU6|aB$ZB1fX?k;)3&YyRv-|@S6eyEMB5FhFX0~$By!jX8Uqqd;Vp{}F)P&Zhr#em{VaWM_W~7>`ED#pSge)x#Ru7ic}{A6@sSuKQc1`)k+o{|6v2OKkuE diff --git a/vnpy/trader/archive/system.ico b/vnpy/trader/archive/system.ico deleted file mode 100644 index 0b23e1b3068d873b2455fd8f660041319988bff3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 67646 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