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 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/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