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/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/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 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 5888c475..00000000 Binary files a/tutorial/performance/test.pyd and /dev/null differ 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/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: # 合并更新数据字典 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): 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) # 设置数据 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(): diff --git a/vnpy/trader/archive/app.ico b/vnpy/trader/archive/app.ico deleted file mode 100644 index 152292aa..00000000 Binary files a/vnpy/trader/archive/app.ico and /dev/null differ diff --git a/vnpy/trader/archive/help.ico b/vnpy/trader/archive/help.ico deleted file mode 100644 index 2cff09c9..00000000 Binary files a/vnpy/trader/archive/help.ico and /dev/null differ diff --git a/vnpy/trader/archive/system.ico b/vnpy/trader/archive/system.ico deleted file mode 100644 index 0b23e1b3..00000000 Binary files a/vnpy/trader/archive/system.ico and /dev/null differ diff --git a/vnpy/trader/archive/vtClient.py b/vnpy/trader/archive/vtClient.py deleted file mode 100644 index 88d62cfe..00000000 --- a/vnpy/trader/archive/vtClient.py +++ /dev/null @@ -1,178 +0,0 @@ -# encoding: utf-8 - -# 重载sys模块,设置默认字符串编码方式为utf8 -import sys -reload(sys) -sys.setdefaultencoding('utf8') - -# vn.trader模块 -from vnpy.event import EventEngine2 -from vnpy.rpc import RpcClient - -from vnpy.trader.vtGlobal import globalSetting -from vnpy.trader.vtEngine import MainEngine -from vnpy.trader.uiQt import createQApp -from vnpy.trader.uiMainWindow import MainWindow - - - -######################################################################## -class VtClient(RpcClient): - """vn.trader客户端""" - - #---------------------------------------------------------------------- - def __init__(self, reqAddress, subAddress, eventEngine): - """Constructor""" - super(VtClient, self).__init__(reqAddress, subAddress) - - self.eventEngine = eventEngine - - self.usePickle() - - #---------------------------------------------------------------------- - def callback(self, topic, data): - """回调函数""" - self.eventEngine.put(data) - - -######################################################################## -class ClientEngine(MainEngine): - """客户端引擎,提供和MainEngine完全相同的API接口""" - - #---------------------------------------------------------------------- - def __init__(self, client, eventEngine): - """Constructor""" - super(MainEngine, self).__init__(eventEngine) - - self.client = client - self.eventEngine = eventEngine - - # 扩展模块 - self.ctaEngine = CtaEngine(self, self.eventEngine) - self.drEngine = DrEngine(self, self.eventEngine) - self.rmEngine = RmEngine(self, self.eventEngine) - - #---------------------------------------------------------------------- - def connect(self, gatewayName): - """连接特定名称的接口""" - self.client.connect(gatewayName) - - #---------------------------------------------------------------------- - def subscribe(self, subscribeReq, gatewayName): - """订阅特定接口的行情""" - self.client.subscribe(subscribeReq, gatewayName) - - #---------------------------------------------------------------------- - def sendOrder(self, orderReq, gatewayName): - """对特定接口发单""" - return self.client.sendOrder(orderReq, gatewayName) - - #---------------------------------------------------------------------- - def cancelOrder(self, cancelOrderReq, gatewayName): - """对特定接口撤单""" - self.client.cancelOrder(cancelOrderReq, gatewayName) - - #---------------------------------------------------------------------- - def qryAccont(self, gatewayName): - """查询特定接口的账户""" - self.client.qryAccount(gatewayName) - - #---------------------------------------------------------------------- - def qryPosition(self, gatewayName): - """查询特定接口的持仓""" - self.client.qryPosition(gatewayName) - - #---------------------------------------------------------------------- - def exit(self): - """退出程序前调用,保证正常退出""" - # 停止事件引擎 - self.eventEngine.stop() - - # 关闭客户端的推送数据接收 - self.client.stop() - - # 停止数据记录引擎 - self.drEngine.stop() - - #---------------------------------------------------------------------- - def writeLog(self, content): - """快速发出日志事件""" - self.client.writeLog(content) - - #---------------------------------------------------------------------- - def dbConnect(self): - """连接MongoDB数据库""" - self.client.dbConnect() - - #---------------------------------------------------------------------- - def dbInsert(self, dbName, collectionName, d): - """向MongoDB中插入数据,d是具体数据""" - self.client.dbInsert(dbName, collectionName, d) - - #---------------------------------------------------------------------- - def dbQuery(self, dbName, collectionName, d): - """从MongoDB中读取数据,d是查询要求,返回的是数据库查询的数据列表""" - return self.client.dbQuery(dbName, collectionName, d) - - #---------------------------------------------------------------------- - def dbUpdate(self, dbName, collectionName, d, flt, upsert=False): - """向MongoDB中更新数据,d是具体数据,flt是过滤条件,upsert代表若无是否要插入""" - self.client.dbUpdate(dbName, collectionName, d, flt, upsert) - - #---------------------------------------------------------------------- - def getContract(self, vtSymbol): - """查询合约""" - return self.client.getContract(vtSymbol) - - #---------------------------------------------------------------------- - def getAllContracts(self): - """查询所有合约(返回列表)""" - return self.client.getAllContracts() - - #---------------------------------------------------------------------- - def getOrder(self, vtOrderID): - """查询委托""" - return self.client.getOrder(vtOrderID) - - #---------------------------------------------------------------------- - def getAllWorkingOrders(self): - """查询所有的活跃的委托(返回列表)""" - return self.client.getAllWorkingOrders() - - #---------------------------------------------------------------------- - def getAllGatewayDetails(self): - """查询所有的接口名称""" - return self.client.getAllGatewayDetails() - - -#---------------------------------------------------------------------- -def main(): - """客户端主程序入口""" - # 创建Qt对象 - qApp = createQApp() - - # 创建事件引擎 - eventEngine = EventEngine2() - eventEngine.start(timer=False) - - # 创建客户端 - reqAddress = 'tcp://localhost:2014' - subAddress = 'tcp://localhost:0602' - client = VtClient(reqAddress, subAddress, eventEngine) - - client.subscribeTopic('') - client.start() - - # 初始化主引擎和主窗口对象 - mainEngine = ClientEngine(client, eventEngine) - mainWindow = MainWindow(mainEngine, mainEngine.eventEngine) - mainWindow.showMaximized() - - # 在主线程中启动Qt事件循环 - sys.exit(qApp.exec_()) - - -if __name__ == '__main__': - main() - - \ No newline at end of file diff --git a/vnpy/trader/archive/vtServer.py b/vnpy/trader/archive/vtServer.py deleted file mode 100644 index f590aad8..00000000 --- a/vnpy/trader/archive/vtServer.py +++ /dev/null @@ -1,100 +0,0 @@ -# encoding: utf-8 - -import sys -import os - -from datetime import datetime -from time import sleep -from threading import Thread - -from vnpy.event import EventEngine2 -from vnpy.rpc import RpcServer -from vnpy.trader.vtEngine import MainEngine - - -######################################################################## -class VtServer(RpcServer): - """vn.trader服务器""" - - #---------------------------------------------------------------------- - def __init__(self, repAddress, pubAddress): - """Constructor""" - super(VtServer, self).__init__(repAddress, pubAddress) - self.usePickle() - - # 创建事件引擎 - self.ee = EventEngine2() - - # 创建主引擎对象 - self.engine = MainEngine(self.ee) - - # 注册主引擎的方法到服务器的RPC函数 - self.register(self.engine.connect) - self.register(self.engine.subscribe) - self.register(self.engine.sendOrder) - self.register(self.engine.cancelOrder) - self.register(self.engine.qryAccount) - self.register(self.engine.qryPosition) - self.register(self.engine.exit) - self.register(self.engine.writeLog) - self.register(self.engine.dbConnect) - self.register(self.engine.dbInsert) - self.register(self.engine.dbQuery) - self.register(self.engine.dbUpdate) - self.register(self.engine.getContract) - self.register(self.engine.getAllContracts) - self.register(self.engine.getOrder) - self.register(self.engine.getAllWorkingOrders) - self.register(self.engine.getAllGatewayDetails) - - # 注册事件引擎发送的事件处理监听 - self.engine.eventEngine.registerGeneralHandler(self.eventHandler) - - #---------------------------------------------------------------------- - def eventHandler(self, event): - """事件处理""" - self.publish(event.type_, event) - - #---------------------------------------------------------------------- - def stopServer(self): - """停止服务器""" - # 关闭引擎 - self.engine.exit() - - # 停止服务器线程 - self.stop() - - -#---------------------------------------------------------------------- -def printLog(content): - """打印日志""" - print datetime.now().strftime("%H:%M:%S"), '\t', content - - -#---------------------------------------------------------------------- -def runServer(): - """运行服务器""" - repAddress = 'tcp://*:2014' - pubAddress = 'tcp://*:0602' - - # 创建并启动服务器 - server = VtServer(repAddress, pubAddress) - server.start() - - printLog('-'*50) - printLog(u'vn.trader服务器已启动') - - # 进入主循环 - while True: - printLog(u'请输入exit来关闭服务器') - if raw_input() != 'exit': - continue - - printLog(u'确认关闭服务器?yes|no') - if raw_input() == 'yes': - break - - server.stopServer() - -if __name__ == '__main__': - runServer() \ No newline at end of file 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()}