[Mod]修改版本号到v1.7.2以及相关文档
This commit is contained in:
parent
ef6014c6f8
commit
3c0309993d
18
README.md
18
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)
|
||||
|
@ -1,5 +0,0 @@
|
||||
# vn.py项目的实战应用指南
|
||||
|
||||
本文件夹下的内容主要是围绕vn.py在实际交易中的一系列具体应用,包括说明文档和代码例子。
|
||||
|
||||
* performance:[《百倍加速!Python量化策略的算法性能提升指南》](http://zhuanlan.zhihu.com/p/24168485)
|
@ -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_time<invalid_local_section[1]:\n",
|
||||
" return\n",
|
||||
"\n",
|
||||
" # 2. 转化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",
|
||||
"\n",
|
||||
" #防御时间格式变为 ”9:00:00.5\"\n",
|
||||
" if tick.time[2] != ':': \n",
|
||||
" tick.time = '0' + tick.time\n",
|
||||
" \n",
|
||||
" tick_hour = int(tick.time[0:2]) \n",
|
||||
" local_hour = local_time.hour\n",
|
||||
" real_date=local_datetime\n",
|
||||
" if tick_hour == 23 and local_hour == 0:#行情时间慢于系统时间\n",
|
||||
" real_date+=timedelta(-1)\n",
|
||||
" elif tick_hour == 0 and local_hour == 23:#系统时间慢于行情时间\n",
|
||||
" real_date+=timedelta(1)\n",
|
||||
"\n",
|
||||
" tick.time = tick.time.ljust(12,'0')\n",
|
||||
" drTick.datetime = datetime(real_date.year,real_date.month,real_date.day,\n",
|
||||
" int(tick.time[0:2]), int(tick.time[3:5]), int(tick.time[6:8]), int(tick.time[9:12])*1000)\n",
|
||||
"\n",
|
||||
" tmpTime=drTick.datetime.time()\n",
|
||||
" for sec in invalid_sections:\n",
|
||||
" if tmpTime>sec[0] and tmpTime<sec[1]:\n",
|
||||
" return\n",
|
||||
" \n",
|
||||
" # 3. 更新Tick数据\n",
|
||||
" if insertDB:\n",
|
||||
" insertData(TICK_DB_NAME, tick.vtSymbol, drTick) \n",
|
||||
"\n",
|
||||
"procecssTickEvent(tick)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"新版不保存数据到mongodb单次耗时:0.0255\n",
|
||||
"新版含保存数据到mongodb单次耗时:0.2334\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"new_nodb=profiling(test_count)\n",
|
||||
"client.drop_database(TICK_DB_NAME)\n",
|
||||
"new_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": {},
|
||||
"source": [
|
||||
"## 保存为文本文件效率"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"def insertData(db,collection,data):\n",
|
||||
" for key in data.__dict__:\n",
|
||||
" fout.write(str(data.__dict__[key])+',')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"新版含保存数据到text file单次耗时:0.2334\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"fout=open('D:/test.txt','w')\n",
|
||||
"new_db_text=profiling(test_count,func=lambda: procecssTickEvent(tick,insertDB=True))\n",
|
||||
"print '新版含保存数据到text file单次耗时:%.4f' %original_db\n",
|
||||
"fout.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## 时间类型转化效率\n",
|
||||
"\n",
|
||||
"注意到不保存数据到数据的版本中,新版相比老版耗时反而降低了,这主要是由于时间转化函数的改写。\n",
|
||||
"\n",
|
||||
"如下三种时间转化方法效率差别巨大:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"转化方法1耗时:0.0560\n",
|
||||
"转化方法2耗时:0.0122\n",
|
||||
"转化方法3耗时:0.0032\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"time_convert1=profiling(10000,lambda:parse('20161212 21:21:21.5'))\n",
|
||||
"time_convert2=profiling(10000,lambda:datetime.strptime('20161212 21:21:21.5', '%Y%m%d %H:%M:%S.%f'))\n",
|
||||
"def customized_parse(s):\n",
|
||||
" s=s.ljust(21,'0')\n",
|
||||
" return datetime(int(s[0:4]),int(s[4:6]),int(s[6:8]),int(s[9:11]), int(s[12:14]), int(s[15:17]), int(s[18:21])*1000 )\n",
|
||||
"time_convert3=profiling(10000,lambda:customized_parse('20161212 21:21:21.5')) \n",
|
||||
"print '转化方法1耗时:%.4f' %time_convert1\n",
|
||||
"print '转化方法2耗时:%.4f' %time_convert2\n",
|
||||
"print '转化方法3耗时:%.4f' %time_convert3"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"source": [
|
||||
"#总结"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div>\n",
|
||||
"<table border=\"1\" class=\"dataframe\">\n",
|
||||
" <thead>\n",
|
||||
" <tr style=\"text-align: right;\">\n",
|
||||
" <th></th>\n",
|
||||
" <th>mongodb写入</th>\n",
|
||||
" <th>text文件写入</th>\n",
|
||||
" <th>无数据写入</th>\n",
|
||||
" </tr>\n",
|
||||
" </thead>\n",
|
||||
" <tbody>\n",
|
||||
" <tr>\n",
|
||||
" <th>原版</th>\n",
|
||||
" <td>0.2334</td>\n",
|
||||
" <td>NaN</td>\n",
|
||||
" <td>0.0255</td>\n",
|
||||
" </tr>\n",
|
||||
" <tr>\n",
|
||||
" <th>新版</th>\n",
|
||||
" <td>0.2174</td>\n",
|
||||
" <td>0.0362</td>\n",
|
||||
" <td>0.0160</td>\n",
|
||||
" </tr>\n",
|
||||
" </tbody>\n",
|
||||
"</table>\n",
|
||||
"</div>"
|
||||
],
|
||||
"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
|
||||
}
|
@ -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
|
||||
}
|
@ -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
|
Binary file not shown.
@ -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
|
@ -1,7 +0,0 @@
|
||||
from distutils.core import setup
|
||||
from Cython.Build import cythonize
|
||||
|
||||
setup(
|
||||
name = 'cython test',
|
||||
ext_modules = cythonize("test.pyx"),
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
# encoding: UTF-8
|
||||
|
||||
__version__ = '1.7.1'
|
||||
__version__ = '1.7.2'
|
||||
__author__ = 'Xiaoyou Chen'
|
Binary file not shown.
Before Width: | Height: | Size: 66 KiB |
Binary file not shown.
Before Width: | Height: | Size: 59 KiB |
Binary file not shown.
Before Width: | Height: | Size: 66 KiB |
@ -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()
|
||||
|
||||
|
@ -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()
|
Loading…
Reference in New Issue
Block a user