Home >  > Vn.py策略回测

Vn.py策略回测

0

一、插入数据到MangoDB
代码如下:

# 加载模块
%matplotlib inline

import tushare as ts
import pymongo
from datetime import datetime

from vnpy.trader.vtObject import VtBarData
from vnpy.trader.app.ctaStrategy.ctaBase import DAILY_DB_NAME

# 定义合约代码
symbol = '510050'
exchange = 'SSE'
vtSymbol = '.'.join([symbol, exchange])

# 下载历史数据
data = ts.get_hist_data(symbol, '2017-01-01')
data = data.sort_values("date")

print u'数据下载完成'

# 创建MongoDB连接
client = pymongo.MongoClient('localhost', 27017)
collection = client[DAILY_DB_NAME][vtSymbol]
collection.ensure_index('datetime')

print u'MongoDB连接成功'

# 将数据插入历史数据库
for row in data.iterrows():
    date = row[0]
    data = row[1]
    
    bar = VtBarData()
    bar.vtSymbol = vtSymbol
    bar.symbol = symbol
    bar.exchange = exchange
    bar.date = date
    bar.datetime = datetime.strptime(date, '%Y-%m-%d')
    bar.open = data['open']
    bar.high = data['high']
    bar.low = data['low']
    bar.close = data['close']
    bar.volume = data['volume']
    
    flt = {'datetime': bar.datetime}
    collection.update_one(flt, {'$set':bar.__dict__}, upsert=True)

print u'数据插入完成'

upset = True,表示有数据,则进行更新。

运行成功后会提示:

数据下载完成
MongoDB连接成功
数据插入完成

不过我又发现如下错误信息:

C:\ProgramData\Anaconda2\lib\site-packages\ipykernel_launcher.py:25: DeprecationWarning: ensure_index is deprecated. Use create_index instead.

二、Mango DB

1.下载Robomongo
官方有两个版本下载,我下载的是Robo 3T

2.初次使用
初次使用会弹出如下的界面。

3.连接数据库
点击上图中的create按钮,会弹出下面的对话框,点击test看看是否连接成功。

如果连接成功的话,点击“save”就可以看到mangoDB的数据库了。

小提示:
其实这里还可以给MongoDB添加管理员账户,不过要先切换到一个数据库,可以看这里的教程。

三、开发交易策略

# 开发交易策略
import numpy as np

from vnpy.trader.app.ctaStrategy.ctaTemplate import CtaTemplate

class DoubleMaStrategy(CtaTemplate):
    """双均线策略Demo"""
    className = 'DoubleMaStrategy'
    author = u'用Python的交易员'
    
    # 策略参数
    initDays = 25   # 初始化数据所用的天数
    
    # 策略变量
    barCount = 0
    closeArray = np.zeros(20)
    ma5 = 0
    ma20 = 0    
    lastMa5 = 0
    lastMa20 = 0

    # 参数列表,保存了参数的名称
    paramList = ['name',
                 'className',
                 'author',
                 'vtSymbol']    
    
    # 变量列表,保存了变量的名称
    varList = ['inited',
               'trading',
               'pos']  

    def __init__(self, ctaEngine, setting):
        """构造函数"""
        super(DoubleMaStrategy, self).__init__(ctaEngine, setting)
        
        # 针对可变对象类型的变量,需要在这里初始化
        self.closeArray = np.zeros(20)
        
    def onInit(self):
        """初始化策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双均线策略初始化')
        
        initData = self.loadBar(self.initDays)
        for bar in initData:
            self.onBar(bar)
        
        self.putEvent()
        
    def onStart(self):
        """启动策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双均线策略启动')
        self.putEvent()
    
    def onStop(self):
        """停止策略(必须由用户继承实现)"""
        self.writeCtaLog(u'双均线策略停止')
        self.putEvent()
        
    def onTick(self, tick):
        """收到行情TICK推送(必须由用户继承实现)"""
        # 因为只是展示如何使用框架,这里直接跳过,实盘需要用户基于Tick自行合成K线
        pass
        
    def onBar(self, bar):
        """收到Bar推送(必须由用户继承实现)"""
        # 缓存数据
        self.closeArray[0:19] = self.closeArray[1:20]
        self.closeArray[-1] = bar.close
        
        self.barCount += 1
        if self.barCount < self.initDays:
            return
        
        # 计算快慢均线
        self.ma5 = self.closeArray[15:20].mean()
        self.ma20 = self.closeArray.mean()
        
        # 判断买卖
        crossOver = self.ma5>self.ma20 and self.lastMa5<=self.lastMa20     # 金叉上穿
        crossBelow = self.ma5<self.ma20 and self.lastMa5>=self.lastMa20    # 死叉下穿
        
        # 金叉和死叉的条件是互斥
        # 所有的委托均以K线收盘价委托,为了保证回测成交超价5%发单
        if crossOver:
            # 如果金叉时手头没有持仓,则直接做多
            if self.pos == 0:
                self.buy(bar.close*1.05, 10000)
            # 如果有空头持仓,则先平空,再做多
            elif self.pos < 0:
                self.cover(bar.close*1.05, 10000)
                self.buy(bar.close*1.05, 10000)
        # 死叉和金叉相反
        elif crossBelow:
            if self.pos == 0:
                self.short(bar.close*0.95, 10000)
            elif self.pos > 0:
                self.sell(bar.close*0.95, 10000)
                self.short(bar.close*0.95, 10000)
                
        # 发出状态更新事件
        self.putEvent()
        
    def onOrder(self, order):
        """收到委托变化推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass
    
    def onTrade(self, trade):
        """收到成交推送(必须由用户继承实现)"""
        # 对于无需做细粒度委托控制的策略,可以忽略onOrder
        pass
    
    def onStopOrder(self, so):
        """停止单推送"""
        pass    

这一步需要在jupyter里运行一下。

四、正式回测
代码

# 加载回测引擎
from vnpy.trader.app.ctaStrategy.ctaBacktesting import BacktestingEngine

# 创建回测引擎实例
engine = BacktestingEngine()

# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)

# 设置回测用的数据起始日期
engine.setStartDate('20170101', initDays=20)

# 设置产品相关参数
engine.setSlippage(0)         # 滑点设为0
engine.setRate(1.5/10000)     # 万1.5 ETF手续费
engine.setSize(1)             # ETF每股为1
engine.setPriceTick(0.001)    # ETF最小价格变动
engine.setCapital(1)          # 为了只统计净盈亏,设置初始资金为1

# 设置使用的历史数据库
engine.setDatabase(DAILY_DB_NAME, vtSymbol)

# 在引擎中创建策略对象
engine.initStrategy(DoubleMaStrategy, {})

# 开始跑回测
engine.runBacktesting()

# 显示回测结果
engine.showDailyResult()

不过我遇到了以下的报错信息:

C:\ProgramData\Anaconda2\lib\site-packages\vnpy\trader\app\ctaStrategy\ctaBacktesting.py:1017: RuntimeWarning: invalid value encountered in log
df['return'] = (np.log(df['balance']) - np.log(df['balance'].shift(1))).fillna(0)

下面是回测结果:

五、再次回测

因上次回测出现错误,隔几天后,再次回测.
1. 执行jpyter上的“kernel --restart & clear output”。
2. 将第一段代码中的相关代码注释掉:

# 下载历史数据
# data = ts.get_hist_data(symbol, '2017-01-01')
# data = data.sort_values("date")

print u'数据下载完成'

# 创建MongoDB连接
client = pymongo.MongoClient('localhost', 27017)
collection = client[DAILY_DB_NAME][vtSymbol]
collection.ensure_index('datetime')

print u'MongoDB连接成功'

# 将数据插入历史数据库
# for row in data.iterrows():
#     date = row[0]
#     data = row[1]
    
#     bar = VtBarData()
#     bar.vtSymbol = vtSymbol
#     bar.symbol = symbol
#     bar.exchange = exchange
#     bar.date = date
#     bar.datetime = datetime.strptime(date, '%Y-%m-%d')
#     bar.open = data['open']
#     bar.high = data['high']
#     bar.low = data['low']
#     bar.close = data['close']
#     bar.volume = data['volume']
    
#     flt = {'datetime': bar.datetime}
#     collection.update_one(flt, {'$set':bar.__dict__}, upsert=True)

print u'数据插入完成'

3.执行代码
开始也同样出现上面的错误提示,不过后来我想自己编辑ctaBacktesting.py这个文件,没想到这个错误自己消失了。

暧昧帖

本文暂无标签

发表评论

*

*