初步完成了vn.trader的CTA策略模块,和vn.strategy相比的主要变化包括:

1. 重新设计的策略引擎API
2. 重新设计的策略模板,策略方面的开发更直观
3. 设计了一个基于EMA双均线的演示策略
4. 基于新的策略模板重写了行情记录工具DataRecorder
This commit is contained in:
chenxy123 2016-02-04 20:41:37 +08:00
parent a6cc6cb339
commit 42df562e60
22 changed files with 743 additions and 448 deletions

View File

@ -1,10 +0,0 @@
{
"DR_IF1512": {
"strategyClassName": "DataRecorder",
"vtSymbol": "IF1512"
},
"DR_IH1512": {
"strategyClassName": "DataRecorder",
"vtSymbol": "IH1512"
}
}

Binary file not shown.

View File

@ -0,0 +1,7 @@
[
{
"name": "double ema",
"className": "DoubleEmaDemo",
"vtSymbol": "IF1602"
}
]

View File

Can't render this file because it is too large.

View File

View File

@ -1,22 +1,21 @@
# encoding: UTF-8
from datetime import datetime, timedelta
import json
from collections import OrderedDict
'''
本文件中包含的是CTA模块的回测引擎回测引擎的API和CTA引擎一致
可以使用和实盘相同的代码进行回测
'''
from datetime import datetime, timedelta
from collections import OrderedDict
import json
import pymongo
from ctaBase import *
from ctaSetting import *
from vtConstant import *
from vtGateway import VtOrderData, VtTradeData
from ctaConstant import *
from ctaObject import *
from ctaStrategies import strategyClassDict
from ctaStrategyTemplate import TestStrategy
from ctaHistoryData import MINUTE_DB_NAME
########################################################################
class BacktestingEngine(object):
@ -45,22 +44,24 @@ class BacktestingEngine(object):
self.strategy = None # 回测策略
self.mode = self.BAR_MODE # 回测模式默认为K线
self.dbClient = None # 数据库客户端
self.dbCursor = None # 数据库指针
self.dbClient = None # 数据库客户端
self.dbCursor = None # 数据库指针
self.historyData = [] # 历史数据的列表,回测用
self.initData = [] # 初始化用的数据
self.historyData = [] # 历史数据的列表,回测用
self.initData = [] # 初始化用的数据
self.backtestingData = [] # 回测用的数据
self.dataStartDate = None # 回测数据开始日期datetime对象
self.strategyStartDate = None # 策略启动日期(即前面的数据用于初始化),同上
self.strategyStartDate = None # 策略启动日期(即前面的数据用于初始化),datetime对象
self.limitOrderDict = {} # 限价单字典
self.workingLimitOrderDict = {} # 活动限价单字典,用于进行撮合用
self.limitOrderCount = 0 # 限价单编号
self.limitOrderDict = OrderedDict() # 限价单字典
self.workingLimitOrderDict = OrderedDict() # 活动限价单字典,用于进行撮合用
self.limitOrderCount = 0 # 限价单编号
self.tradeCount = 0 # 成交编号
self.tradeDict = {} # 成交字典
self.tradeCount = 0 # 成交编号
self.tradeDict = OrderedDict() # 成交字典
self.logList = [] # 日志记录
# 当前最新数据,用于模拟成交用
self.tick = None
@ -68,7 +69,7 @@ class BacktestingEngine(object):
self.dt = None # 最新的时间
#----------------------------------------------------------------------
def setStartDate(self, startDate='20100416', initDays=30):
def setStartDate(self, startDate='20100416', initDays=10):
"""设置回测的启动日期"""
self.dataStartDate = datetime.strptime(startDate, '%Y%m%d')
@ -107,16 +108,26 @@ class BacktestingEngine(object):
else:
self.backtestingData.append(data)
self.output(u'载入完成,数据量%s' %len(self.backtestingData))
self.output(u'载入完成,数据量%s' %len(self.backtestingData))
#----------------------------------------------------------------------
def runBacktesting(self):
"""运行回测"""
self.strategy.start()
self.output(u'开始回测')
self.strategy.inited = True
self.strategy.onInit()
self.output(u'策略初始化完成')
self.strategy.trading = True
self.strategy.onStart()
self.output(u'策略启动完成')
self.output(u'开始回放数据')
if self.mode == self.BAR_MODE:
for data in self.backtestingData:
self.newBar(data)
#print str(data.datetime)
else:
for data in self.backtestingData:
self.newTick(data)
@ -125,9 +136,10 @@ class BacktestingEngine(object):
def newBar(self, bar):
"""新的K线"""
self.bar = bar
self.crossLimitOrder() # 先撮合限价单
self.crossStopOrder() # 再撮合停止单
self.strategy.onBar(bar)
self.dt = bar.datetime
self.crossLimitOrder() # 先撮合限价单
self.crossStopOrder() # 再撮合停止单
self.strategy.onBar(bar) # 推送K线到策略中
#----------------------------------------------------------------------
def newTick(self, tick):
@ -138,9 +150,13 @@ class BacktestingEngine(object):
self.strategy.onTick(tick)
#----------------------------------------------------------------------
def initStrategy(self, name, strategyClass, paramDict=None):
"""初始化策略"""
self.strategy = strategyClass(self, name, paramDict)
def initStrategy(self, strategyClass, setting=None):
"""
初始化策略
setting是策略的参数设置如果使用类中写好的默认设置则可以不传该参数
"""
self.strategy = strategyClass(self, setting)
self.strategy.name = self.strategy.className
#----------------------------------------------------------------------
def sendOrder(self, vtSymbol, orderType, price, volume, strategy):
@ -261,6 +277,7 @@ class BacktestingEngine(object):
trade.price = order.price
trade.volume = order.totalVolume
trade.tradeTime = str(self.dt)
trade.dt = self.dt
self.strategy.onTrade(trade)
self.tradeDict[tradeID] = trade
@ -284,7 +301,7 @@ class BacktestingEngine(object):
buyCrossPrice = self.tick.lastPrice
sellCrossPrice = self.tick.lastPrice
# 遍历限价单字典中的所有限价
# 遍历停止单字典中的所有停止
for stopOrderID, so in self.workingStopOrderDict.items():
# 判断是否会成交
buyCross = so.direction==DIRECTION_LONG and so.price<=buyCrossPrice
@ -310,6 +327,7 @@ class BacktestingEngine(object):
trade.price = so.price
trade.volume = so.volume
trade.tradeTime = str(self.dt)
trade.dt = self.dt
self.strategy.onTrade(trade)
self.tradeDict[tradeID] = trade
@ -331,6 +349,8 @@ class BacktestingEngine(object):
order.orderTime = trade.tradeTime
self.strategy.onOrder(order)
self.limitOrderDict[orderID] = order
# 从字典中删除该限价单
del self.workingStopOrderDict[stopOrderID]
@ -349,33 +369,129 @@ class BacktestingEngine(object):
"""直接返回初始化数据列表中的Tick"""
return self.initData
#----------------------------------------------------------------------
def getToday(self):
"""获取代表今日的datetime对象"""
# 这个方法本身主要用于在每日初始化时确定日期,从而知道该读取之前从某日起的数据
# 这里选择策略启动的日期
return self.strategyStartDate
#----------------------------------------------------------------------
def writeCtaLog(self, content):
"""记录日志"""
print content
log = str(self.dt) + ' ' + content
self.logList.append(log)
#----------------------------------------------------------------------
def output(self, content):
"""输出内容"""
print content
#----------------------------------------------------------------------
def showBacktestingResult(self):
"""
显示回测结果
"""
self.output(u'显示回测结果')
# 首先基于回测后的成交记录,计算每笔交易的盈亏
pnlDict = OrderedDict() # 每笔盈亏的记录
longTrade = [] # 未平仓的多头交易
shortTrade = [] # 未平仓的空头交易
for trade in self.tradeDict.values():
# 多头交易
if trade.direction == DIRECTION_LONG:
# 如果尚无空头交易
if not shortTrade:
longTrade.append(trade)
# 当前多头交易为平空
else:
entryTrade = shortTrade.pop(0)
pnl = (trade.price - entryTrade.price) * trade.volume * (-1)
pnlDict[trade.dt] = pnl
# 空头交易
else:
# 如果尚无多头交易
if not longTrade:
shortTrade.append(trade)
# 当前空头交易为平多
else:
entryTrade = longTrade.pop(0)
pnl = (trade.price - entryTrade.price) * trade.volume
pnlDict[trade.dt] = pnl
# 然后基于每笔交易的结果,我们可以计算具体的盈亏曲线和最大回撤等
timeList = pnlDict.keys()
pnlList = pnlDict.values()
capital = 0
maxCapital = 0
drawdown = 0
capitalList = [] # 盈亏汇总的时间序列
maxCapitalList = [] # 最高盈利的时间序列
drawdownList = [] # 回撤的时间序列
for pnl in pnlList:
capital += pnl
maxCapital = max(capital, maxCapital)
drawdown = capital - maxCapital
capitalList.append(capital)
maxCapitalList.append(maxCapital)
drawdownList.append(drawdown)
# 绘图
import matplotlib.pyplot as plt
pCapital = plt.subplot(3, 1, 1)
pCapital.set_ylabel("capital")
pCapital.plot(capitalList)
pDD = plt.subplot(3, 1, 2)
pDD.set_ylabel("DD")
pDD.bar(range(len(drawdownList)), drawdownList)
pPnl = plt.subplot(3, 1, 3)
pPnl.set_ylabel("pnl")
pPnl.hist(pnlList, bins=20)
# 输出
self.output('-' * 50)
self.output(u'第一笔交易时间:%s' % timeList[0])
self.output(u'最后一笔交易时间:%s' % timeList[-1])
self.output(u'总交易次数:%s' % len(pnlList))
self.output(u'总盈亏:%s' % capitalList[-1])
self.output(u'最大回撤: %s' % min(drawdownList))
#----------------------------------------------------------------------
def putStrategyEvent(self, name):
"""发送策略更新事件,回测中忽略"""
pass
#----------------------------------------------------------------------
def test():
""""""
if __name__ == '__main__':
# 以下内容是一段回测脚本的演示,用户可以根据自己的需求修改
# 建议使用ipython notebook或者spyder来做回测
# 同样可以在命令模式下进行回测(一行一行输入运行)
from ctaDemo import *
# 创建回测引擎
engine = BacktestingEngine()
# 设置引擎的回测模式为K线
engine.setBacktestingMode(engine.BAR_MODE)
engine.initStrategy(u'测试', TestStrategy)
engine.setStartDate()
# 设置回测用的数据起始日期
engine.setStartDate('20100416')
# 载入历史数据到引擎中
engine.loadHistoryData(MINUTE_DB_NAME, 'IF0000')
# 在引擎中创建策略对象
engine.initStrategy(DoubleEmaDemo, {})
# 开始跑回测
engine.runBacktesting()
# 显示回测结果
# spyder或者ipython notebook中运行时会弹出盈亏曲线图
# 直接在cmd中回测则只会打印一些回测数值
engine.showBacktestingResult()

View File

@ -1,7 +1,40 @@
# encoding: UTF-8
from vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT
'''
本文件中包含了CTA模块中用到的一些基础设置类和常量等
'''
from __future__ import division
# 把vn.trader根目录添加到python环境变量中
import sys
sys.path.append('..')
# 常量定义
# CTA引擎中涉及到的交易方向类型
CTAORDER_BUY = u'买开'
CTAORDER_SELL = u'卖平'
CTAORDER_SHORT = u'卖开'
CTAORDER_COVER = u'买平'
# 本地停止单状态
STOPORDER_WAITING = u'等待中'
STOPORDER_CANCELLED = u'已撤销'
STOPORDER_TRIGGERED = u'已触发'
# 本地停止单前缀
STOPORDERPREFIX = 'CtaStopOrder.'
# 数据库名称
TICK_DB_NAME = 'VtTrader_Tick_Db'
DAILY_DB_NAME = 'VtTrader_Daily_Db'
MINUTE_DB_NAME = 'VtTrader_1Min_Db'
# CTA引擎中涉及的数据类定义
from vtConstant import EMPTY_UNICODE, EMPTY_STRING, EMPTY_FLOAT, EMPTY_INT
########################################################################
class StopOrder(object):
@ -92,5 +125,4 @@ class CtaTickData(object):
self.askVolume2 = EMPTY_INT
self.askVolume3 = EMPTY_INT
self.askVolume4 = EMPTY_INT
self.askVolume5 = EMPTY_INT
self.askVolume5 = EMPTY_INT

View File

@ -0,0 +1,184 @@
# encoding: UTF-8
"""
这里的Demo是一个最简单的策略实现并未考虑太多实盘中的交易细节
1. 委托价格超出涨跌停价导致的委托失败
2. 委托未成交需要撤单后重新委托
3. 断网后恢复交易状态
4. 等等
这些点是作者选择特意忽略不去实现因此想实盘的朋友请自己多多研究CTA交易的一些细节
做到了然于胸后再去交易对自己的money和时间负责
也希望社区能做出一个解决了以上潜在风险的Demo出来
"""
from ctaBase import *
from ctaTemplate import CtaTemplate
########################################################################
class DoubleEmaDemo(CtaTemplate):
"""双指数均线策略Demo"""
className = 'DoubleEmaDemo'
author = u'用Python的交易员'
# 策略参数
fastK = 0.9 # 快速EMA参数
slowK = 0.1 # 慢速EMA参数
initDays = 10 # 初始化数据所用的天数
# 策略变量
bar = None
barMinute = EMPTY_STRING
fastMa = [] # 快速EMA均线数组
fastMa0 = EMPTY_FLOAT # 当前最新的快速EMA
fastMa1 = EMPTY_FLOAT # 上一根的快速EMA
slowMa = [] # 与上面相同
slowMa0 = EMPTY_FLOAT
slowMa1 = EMPTY_FLOAT
# 参数列表,保存了参数的名称
paramList = ['name',
'className',
'author',
'vtSymbol',
'fastK',
'slowK']
# 变量列表,保存了变量的名称
varList = ['inited',
'trading',
'pos',
'fastMa0',
'fastMa1',
'slowMa0',
'slowMa1']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, setting):
"""Constructor"""
super(DoubleEmaDemo, self).__init__(ctaEngine, setting)
#----------------------------------------------------------------------
def onInit(self):
"""初始化策略(必须由用户继承实现)"""
self.writeCtaLog(u'双EMA演示策略初始化')
initData = self.loadBar(self.initDays)
for bar in initData:
self.onBar(bar)
self.putEvent()
#----------------------------------------------------------------------
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'双EMA演示策略启动')
self.putEvent()
#----------------------------------------------------------------------
def onStop(self):
"""停止策略(必须由用户继承实现)"""
self.writeCtaLog(u'双EMA演示策略停止')
self.putEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送必须由用户继承实现"""
# 计算K线
tickMinute = tick.datetime.minute
if tickMinute != self.barMinute:
if self.bar:
self.onBar(self.bar)
bar = CtaBarData()
bar.vtSymbol = tick.vtSymbol
bar.symbol = tick.symbol
bar.exchange = tick.exchange
bar.open = tick.lastPrice
bar.high = tick.lastPrice
bar.low = tick.lastPrice
bar.close = tick.lastPrice
bar.date = tick.date
bar.time = tick.time
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
# 实盘中用不到的数据可以选择不算,从而加快速度
#bar.volume = tick.volume
#bar.openInterest = tick.openInterest
self.bar = bar # 这种写法为了减少一层访问,加快速度
self.barMinute = tickMinute # 更新当前的分钟
else: # 否则继续累加新的K线
bar = self.bar # 写法同样为了加快速度
bar.high = max(bar.high, tick.lastPrice)
bar.low = min(bar.low, tick.lastPrice)
bar.close = tick.lastPrice
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送必须由用户继承实现"""
# 计算快慢均线
if not self.fastMa0:
self.fastMa0 = bar.close
self.fastMa.append(self.fastMa0)
else:
self.fastMa1 = self.fastMa0
self.fastMa0 = bar.close * self.fastK + self.fastMa0 * (1 - self.fastK)
self.fastMa.append(self.fastMa0)
if not self.slowMa0:
self.slowMa0 = bar.close
self.slowMa.append(self.slowMa0)
else:
self.slowMa1 = self.slowMa0
self.slowMa0 = bar.close * self.slowK + self.slowMa0 * (1 - self.slowK)
self.slowMa.append(self.slowMa0)
# 判断买卖
crossOver = self.fastMa0>self.slowMa0 and self.fastMa1<self.slowMa1 # 金叉上穿
crossBelow = self.fastMa0<self.slowMa0 and self.fastMa1>self.slowMa1 # 死叉下穿
# 金叉和死叉的条件是互斥
# 所有的委托均以K线收盘价委托这里有一个实盘中无法成交的风险考虑添加对模拟市价单类型的支持
if crossOver:
# 如果金叉时手头没有持仓,则直接做多
if self.pos == 0:
self.buy(bar.close, 1)
# 如果有空头持仓,则先平空,再做多
elif self.pos < 0:
self.cover(bar.close, 1)
self.buy(bar.close, 1)
# 死叉和金叉相反
elif crossBelow:
if self.pos == 0:
self.short(bar.close, 1)
elif self.pos > 0:
self.sell(bar.close, 1)
self.short(bar.close, 1)
# 发出状态更新事件
self.putEvent()
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
# 对于无需做细粒度委托控制的策略可以忽略onOrder
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送(必须由用户继承实现)"""
# 对于无需做细粒度委托控制的策略可以忽略onOrder
pass

View File

@ -1,22 +1,26 @@
# encoding: UTF-8
from datetime import datetime
import json
from collections import OrderedDict
'''
本文件中实现了CTA策略引擎针对CTA类型的策略抽象简化了部分底层接口的功能
'''
import json
import os
from collections import OrderedDict
from datetime import datetime, timedelta
from ctaBase import *
from ctaSetting import STRATEGY_CLASS
from eventEngine import *
from vtConstant import *
from vtGateway import VtSubscribeReq, VtOrderReq, VtCancelOrderReq, VtLogData
from ctaConstant import *
from ctaObject import *
from ctaStrategies import strategyClassDict
########################################################################
class CtaEngine(object):
"""CTA策略引擎"""
settingFileName = 'CTA_setting.json'
settingFileName = os.getcwd() + '\\ctaAlgo\\' + settingFileName
#----------------------------------------------------------------------
def __init__(self, mainEngine, eventEngine):
@ -24,11 +28,14 @@ class CtaEngine(object):
self.mainEngine = mainEngine
self.eventEngine = eventEngine
# 保存策略对象的字典
# key为策略名称value为策略对象注意策略名称不允许重复
# 当前日期
self.today = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
# 保存策略实例的字典
# key为策略名称value为策略实例注意策略名称不允许重复
self.strategyDict = {}
# 保存vtSymbol和策略对象映射的字典用于推送tick数据
# 保存vtSymbol和策略实例映射的字典用于推送tick数据
# 由于可能多个strategy交易同一个vtSymbol因此key为vtSymbol
# value为包含所有相关strategy对象的list
self.tickStrategyDict = {}
@ -48,7 +55,7 @@ class CtaEngine(object):
# 注册事件监听
self.registerEvent()
#----------------------------------------------------------------------
def sendOrder(self, vtSymbol, orderType, price, volume, strategy):
"""发单"""
@ -79,6 +86,9 @@ class CtaEngine(object):
vtOrderID = self.mainEngine.sendOrder(req, contract.gatewayName) # 发单
self.orderStrategyDict[vtOrderID] = strategy # 保存vtOrderID和策略的映射关系
#self.writeCtaLog(u'发送委托:' + str(req.__dict__))
return vtOrderID
#----------------------------------------------------------------------
@ -99,7 +109,7 @@ class CtaEngine(object):
req.sessionID = order.sessionID
req.orderID = order.orderID
self.mainEngine.cancelOrder(req, order.gatewayName)
#----------------------------------------------------------------------
def sendStopOrder(self, vtSymbol, orderType, price, volume, strategy):
"""发停止单(本地实现)"""
@ -141,7 +151,7 @@ class CtaEngine(object):
so = self.workingStopOrderDict[stopOrderID]
so.status = STOPORDER_CANCELLED
del self.workingStopOrderDict[stopOrderID]
#----------------------------------------------------------------------
def processStopOrder(self, tick):
"""收到行情后处理本地停止单(检查是否要立即发出)"""
@ -165,7 +175,7 @@ class CtaEngine(object):
so.status = STOPORDER_TRIGGERED
self.sendOrder(so.vtSymbol, so.orderType, price, so.volume, so.strategy)
del self.workingStopOrderDict[so.stopOrderID]
#----------------------------------------------------------------------
def procecssTickEvent(self, event):
"""处理行情推送"""
@ -173,7 +183,7 @@ class CtaEngine(object):
# 收到tick行情后先处理本地停止单检查是否要立即发出
self.processStopOrder(tick)
# 推送tick到对应的策略对象进行处理
# 推送tick到对应的策略实例进行处理
if tick.vtSymbol in self.tickStrategyDict:
# 将vtTickData数据转化为ctaTickData
ctaTick = CtaTickData()
@ -184,7 +194,7 @@ class CtaEngine(object):
# 添加datetime字段
ctaTick.datetime = datetime.strptime(' '.join([tick.date, tick.time]), '%Y%m%d %H:%M:%S.%f')
# 逐个推送到策略对象
# 逐个推送到策略实例
l = self.tickStrategyDict[tick.vtSymbol]
for strategy in l:
strategy.onTick(ctaTick)
@ -204,7 +214,14 @@ class CtaEngine(object):
trade = event.dict_['data']
if trade.vtOrderID in self.orderStrategyDict:
strategy = self.orderStrategyDict[order.vtOrderID]
strategy = self.orderStrategyDict[trade.vtOrderID]
# 计算策略持仓
if trade.direction == DIRECTION_LONG:
strategy.pos += trade.volume
else:
strategy.pos -= trade.volume
strategy.onTrade(trade)
#----------------------------------------------------------------------
@ -213,47 +230,46 @@ class CtaEngine(object):
self.eventEngine.register(EVENT_TICK, self.procecssTickEvent)
self.eventEngine.register(EVENT_ORDER, self.processOrderEvent)
self.eventEngine.register(EVENT_TRADE, self.processTradeEvent)
#----------------------------------------------------------------------
def insertData(self, dbName, collectionName, data):
"""插入数据到数据库这里的data可以是CtaTickData或者CtaBarData"""
self.mainEngine.dbInsert(dbName, collectionName, data.__dict__)
#----------------------------------------------------------------------
def loadBar(self, dbName, collectionName, startDate):
def loadBar(self, dbName, collectionName, days):
"""从数据库中读取Bar数据startDate是datetime对象"""
startDate = self.today - timedelta(days)
d = {'datetime':{'$gte':startDate}}
cursor = self.mainEngine.dbQuery(dbName, collectionName, d)
l = []
for d in cursor:
bar = CtaBarData()
bar.__dict__ = d
l.append(bar)
if cursor:
for d in cursor:
bar = CtaBarData()
bar.__dict__ = d
l.append(bar)
return l
#----------------------------------------------------------------------
def loadTick(self, dbName, collectionName, startDate):
def loadTick(self, dbName, collectionName, days):
"""从数据库中读取Tick数据startDate是datetime对象"""
startDate = self.today - timedelta(days)
d = {'datetime':{'$gte':startDate}}
cursor = self.mainEngine.dbQuery(dbName, collectionName, d)
l = []
for d in cursor:
tick = CtaTickData()
tick.__dict__ = d
l.append(tick)
if cursor:
for d in cursor:
tick = CtaTickData()
tick.__dict__ = d
l.append(tick)
return l
#----------------------------------------------------------------------
def getToday(self):
"""获取代表今日的datetime对象"""
today = datetime.today()
today = today.replace(hour=0, minute=0, second=0, microsecond=0)
return today
#----------------------------------------------------------------------
def writeCtaLog(self, content):
"""快速发出CTA模块日志事件"""
@ -264,12 +280,27 @@ class CtaEngine(object):
self.eventEngine.put(event)
#----------------------------------------------------------------------
def initStrategy(self, name, strategyClass, paramDict=None):
"""初始化策略"""
def loadStrategy(self, setting):
"""载入策略"""
try:
name = setting['name']
className = setting['className']
except Exception, e:
self.writeCtaLog(u'载入策略出错:%s' %e)
return
# 获取策略类
strategyClass = STRATEGY_CLASS.get(className, None)
if not strategyClass:
self.writeCtaLog(u'找不到策略类:%s' %className)
return
# 防止策略重名
if name not in self.strategyDict:
# 创建策略对象
strategy = strategyClass(self, name, paramDict)
if name in self.strategyDict:
self.writeCtaLog(u'策略实例重名:%s' %name)
else:
# 创建策略实例
strategy = strategyClass(self, setting)
self.strategyDict[name] = strategy
# 保存Tick映射关系
@ -289,8 +320,16 @@ class CtaEngine(object):
self.mainEngine.subscribe(req, contract.gatewayName)
else:
self.writeCtaLog(u'%s的交易合约%s无法找到' %(name, strategy.vtSymbol))
#----------------------------------------------------------------------
def initStrategy(self, name):
"""初始化策略"""
if name in self.strategyDict:
strategy = self.strategyDict[name]
strategy.inited = True
strategy.onInit()
else:
self.writeCtaLog(u'存在策略对象重名:' + name)
self.writeCtaLog(u'策略实例不存在:%s' %name)
#---------------------------------------------------------------------
def startStrategy(self, name):
@ -298,11 +337,11 @@ class CtaEngine(object):
if name in self.strategyDict:
strategy = self.strategyDict[name]
if not strategy.trading:
if strategy.inited and not strategy.trading:
strategy.trading = True
strategy.start()
strategy.onStart()
else:
self.writeCtaLog(u'策略对象不存在:' + name)
self.writeCtaLog(u'策略实例不存在:%s' %name)
#----------------------------------------------------------------------
def stopStrategy(self, name):
@ -312,7 +351,7 @@ class CtaEngine(object):
if strategy.trading:
strategy.trading = False
strategy.stop()
strategy.onStop()
# 对该策略发出的所有限价单进行撤单
for vtOrderID, s in self.orderStrategyDict.items():
@ -324,55 +363,45 @@ class CtaEngine(object):
if so.strategy is strategy:
self.cancelStopOrder(stopOrderID)
else:
self.writeCtaLog(u'策略对象不存在:' + name)
self.writeCtaLog(u'策略实例不存在:%s' %name)
#----------------------------------------------------------------------
def saveStrategySetting(self):
"""保存引擎中的策略配置"""
def saveSetting(self):
"""保存策略配置"""
with open(self.settingFileName, 'w') as f:
d = {}
l = []
for name, strategy in self.strategyDict.items():
for strategy in self.strategyDict.values():
setting = {}
setting['strategyClassName'] = strategy.strategyClassName
for param in strategy.paramList:
setting[param] = strategy.__getattribute__(param)
d[name] = setting
l.append(setting)
jsonD = json.dumps(d, indent=4)
f.write(jsonD)
jsonL = json.dumps(l, indent=4)
f.write(jsonL)
#----------------------------------------------------------------------
def loadStrategySetting(self):
"""读取引擎中的策略配置"""
def loadSetting(self):
"""读取策略配置"""
with open(self.settingFileName) as f:
d = json.load(f)
l = json.load(f)
for name, setting in d.items():
strategyClassName = setting['strategyClassName']
if strategyClassName in strategyClassDict:
strategyClass = strategyClassDict[strategyClassName]
self.initStrategy(name, strategyClass, setting)
else:
self.writeCtaLog(u'无法找到策略类:' + strategyClassName)
break
for setting in l:
self.loadStrategy(setting)
#----------------------------------------------------------------------
def getStrategyVar(self, name):
"""获取策略当前的变量字典"""
if name in self.strategyDict:
strategy = self.strategyDict[name]
d = strategy.__dict__
varDict = OrderedDict()
for key in strategy.varList:
if key in d:
varDict[key] = d[key]
varDict[key] = strategy.__getattribute__(key)
return varDict
else:
self.writeCtaLog(u'策略对象不存在:' + name)
self.writeCtaLog(u'策略实例不存在:' + name)
return None
#----------------------------------------------------------------------
@ -380,16 +409,20 @@ class CtaEngine(object):
"""获取策略的参数字典"""
if name in self.strategyDict:
strategy = self.strategyDict[name]
d = strategy.__dict__
paramDict = OrderedDict()
for key in strategy.paramList:
if key in d:
paramDict[key] = d[key]
for key in strategy.paramList:
paramDict[key] = strategy.__getattribute__(key)
return paramDict
else:
self.writeCtaLog(u'策略对象不存在:' + name)
return None
self.writeCtaLog(u'策略实例不存在:' + name)
return None
#----------------------------------------------------------------------
def putStrategyEvent(self, name):
"""触发策略状态变化事件通常用于通知GUI更新"""
event = Event(EVENT_CTA_STRATEGY+name)
self.eventEngine.put(event)

View File

@ -1,13 +1,20 @@
# encoding: UTF-8
"""
本模块中主要包含
1. 从通联数据下载历史行情的引擎
2. 用来把MultiCharts导出的历史数据载入到MongoDB中用的函数
"""
from datetime import datetime, timedelta
import pymongo
from time import time
from multiprocessing.pool import ThreadPool
from vtConstant import EXCHANGE_CFFEX, EXCHANGE_DCE, EXCHANGE_CZCE, EXCHANGE_SHFE
from ctaBase import *
from vtConstant import *
from datayesClient import DatayesClient
from ctaObject import CtaBarData
# 以下为vn.trader和通联数据规定的交易所代码映射
VT_TO_DATAYES_EXCHANGE = {}
@ -15,14 +22,8 @@ VT_TO_DATAYES_EXCHANGE[EXCHANGE_CFFEX] = 'CCFX' # 中金所
VT_TO_DATAYES_EXCHANGE[EXCHANGE_SHFE] = 'XSGE' # 上期所
VT_TO_DATAYES_EXCHANGE[EXCHANGE_CZCE] = 'XZCE' # 郑商所
VT_TO_DATAYES_EXCHANGE[EXCHANGE_DCE] = 'XDCE' # 大商所
DATAYES_TO_VT_EXCHANGE = {v:k for k,v in VT_TO_DATAYES_EXCHANGE.items()}
# 数据库名称
DAILY_DB_NAME = 'VtTrader_Daily_Db'
MINUTE_DB_NAME = 'VtTrader_1Min_Db'
SETTING_DB_NAME = 'VtTrader_Setting_Db'
########################################################################
class HistoryDataEngine(object):

View File

@ -8,9 +8,9 @@
在CTA_setting.json中写入具体每个策略对象的类和合约设置
'''
from ctaStrategyTemplate import TestStrategy
from ctaDataRecorder import DataRecorder
from ctaTemplate import DataRecorder
from ctaDemo import DoubleEmaDemo
strategyClassDict = {}
strategyClassDict['TestStrategy'] = TestStrategy
strategyClassDict['DataRecorder'] = DataRecorder
STRATEGY_CLASS = {}
STRATEGY_CLASS['DataRecorder'] = DataRecorder
STRATEGY_CLASS['DoubleEmaDemo'] = DoubleEmaDemo

View File

@ -1,59 +1,77 @@
# encoding: UTF-8
'''
本文件包含了CTA引擎中的策略开发用模板开发策略时需要继承CtaTemplate类
'''
from ctaBase import *
from vtConstant import *
from ctaConstant import *
########################################################################
class CtaStrategyTemplate(object):
class CtaTemplate(object):
"""CTA策略模板"""
# 策略类的名称
strategyClassName = 'Template'
# 策略类的名称和作者
className = 'CtaTemplate'
author = EMPTY_UNICODE
# MongoDB数据库的名称K线数据库默认为1分钟
tickDbName = TICK_DB_NAME
barDbName = MINUTE_DB_NAME
# 策略的基本参数
name = EMPTY_UNICODE # 策略实例名称
vtSymbol = EMPTY_STRING # 交易的合约vt系统代码
# 策略的基本变量,由引擎管理
inited = False # 是否进行了初始化
trading = False # 是否启动交易,由引擎管理
pos = 0 # 持仓情况
# 参数列表,保存了参数的名称
paramList = ['vtSymbol']
paramList = ['name',
'className',
'author',
'vtSymbol']
# 变量列表,保存了变量的名称
varList = ['trading']
varList = ['inited',
'trading',
'pos']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, name, setting=None):
def __init__(self, ctaEngine, setting):
"""Constructor"""
self.ctaEngine = ctaEngine
self.name = name
self.vtSymbol = EMPTY_STRING # 交易的合约vt系统代码
self.tickDbName = EMPTY_STRING # tick数据库名称
self.barDbName = EMPTY_STRING # bar数据库名称
self.trading = False # 控制是否启动交易
self.init() # 初始化策略
# 设置策略的参数
if setting:
self.setParam(setting)
d = self.__dict__
for key in self.paramList:
if key in setting:
d[key] = setting[key]
#----------------------------------------------------------------------
def init(self):
def onInit(self):
"""初始化策略(必须由用户继承实现)"""
raise NotImplementedError
#----------------------------------------------------------------------
def start(self):
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.trading = True
raise NotImplementedError
#----------------------------------------------------------------------
def stop(self):
def onStop(self):
"""停止策略(必须由用户继承实现)"""
raise NotImplementedError
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送必须由用户继承实现"""
raise NotImplementedError
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
@ -72,51 +90,32 @@ class CtaStrategyTemplate(object):
#----------------------------------------------------------------------
def buy(self, price, volume, stop=False):
"""买开"""
# 如果stop为True则意味着发本地停止单
if self.trading:
if stop:
orderID = self.ctaEngine.sendStopOrder(self.vtSymbol, CTAORDER_BUY, price, volume, self)
else:
orderID = self.ctaEngine.sendOrder(self.vtSymbol, CTAORDER_BUY, price, volume, self)
return orderID
else:
return None
return self.sendOrder(CTAORDER_BUY, price, volume, stop)
#----------------------------------------------------------------------
def sell(self, price, volume, stop=False):
"""卖平"""
# 如果stop为True则意味着发本地停止单
if self.trading:
if stop:
orderID = self.ctaEngine.sendStopOrder(self.vtSymbol, CTAORDER_SELL, price, volume, self)
else:
orderID = self.ctaEngine.sendOrder(self.vtSymbol, CTAORDER_SELL, price, volume, self)
return orderID
else:
return None
return self.sendOrder(CTAORDER_SELL, price, volume, stop)
#----------------------------------------------------------------------
def short(self, price, volume, stop=False):
"""卖开"""
# 如果stop为True则意味着发本地停止单
if self.trading:
if stop:
orderID = self.ctaEngine.sendStopOrder(self.vtSymbol, CTAORDER_SHORT, price, volume, self)
else:
orderID = self.ctaEngine.sendOrder(self.vtSymbol, CTAORDER_SHORT, price, volume, self)
return orderID
else:
return None
return self.sendOrder(CTAORDER_SHORT, price, volume, stop)
#----------------------------------------------------------------------
def cover(self, price, volume, stop=False):
"""买平"""
return self.sendOrder(CTAORDER_COVER, price, volume, stop)
#----------------------------------------------------------------------
def sendOrder(self, orderType, price, volume, stop=False):
"""发送委托"""
if self.trading:
# 如果stop为True则意味着发本地停止单
if stop:
orderID = self.ctaEngine.sendStopOrder(self.vtSymbol, CTAORDER_COVER, price, volume, self)
orderID = self.ctaEngine.sendStopOrder(self.vtSymbol, orderType, price, volume, self)
else:
orderID = self.ctaEngine.sendOrder(self.vtSymbol, CTAORDER_COVER, price, volume, self)
orderID = self.ctaEngine.sendOrder(self.vtSymbol, orderType, price, volume, self)
return orderID
else:
return None
@ -140,105 +139,131 @@ class CtaStrategyTemplate(object):
self.ctaEngine.insertData(self.barDbName, self.vtSymbol, bar)
#----------------------------------------------------------------------
def loadTick(self, startDate):
def loadTick(self, days):
"""读取tick数据"""
return self.ctaEngine.loadTick(self.tickDbName, self.vtSymbol, startDate)
return self.ctaEngine.loadTick(self.tickDbName, self.vtSymbol, days)
#----------------------------------------------------------------------
def loadBar(self, startDate):
def loadBar(self, days):
"""读取bar数据"""
return self.ctaEngine.loadBar(self.barDbName, self.vtSymbol, startDate)
#----------------------------------------------------------------------
def setParam(self, setting):
"""设置参数"""
d = self.__dict__
for key in self.paramList:
if key in setting:
d[key] = setting[key]
#----------------------------------------------------------------------
def getToday(self):
"""查询当前日期"""
return self.ctaEngine.getToday()
return self.ctaEngine.loadBar(self.barDbName, self.vtSymbol, days)
#----------------------------------------------------------------------
def writeCtaLog(self, content):
"""记录CTA日志"""
content = self.name + ':' + content
self.ctaEngine.writeCtaLog(content)
#----------------------------------------------------------------------
def putEvent(self):
"""发出策略状态变化事件"""
self.ctaEngine.putStrategyEvent(self.name)
########################################################################
class TestStrategy(CtaStrategyTemplate):
"""测试策略"""
class DataRecorder(CtaTemplate):
"""
纯粹用来记录历史数据的工具基于CTA策略
建议运行在实际交易程序外的一个vn.trader实例中
本工具会记录Tick和1分钟K线数据
"""
className = 'DataRecorder'
author = u'用Python的交易员'
# 策略的基本参数
name = EMPTY_UNICODE # 策略实例名称
vtSymbol = EMPTY_STRING # 交易的合约vt系统代码
# 策略的变量
bar = None # K线数据对象
barMinute = EMPTY_STRING # 当前的分钟,初始化设为-1
# 变量列表,保存了变量的名称
varList = ['inited',
'trading',
'pos',
'barMinute']
#----------------------------------------------------------------------
def __init__(self, ctaEngine, name, setting=None):
def __init__(self, ctaEngine, setting):
"""Constructor"""
super(TestStrategy, self).__init__(ctaEngine, name, setting)
self.strategyClassName = 'TestStrategy'
self.author = u'用Python的交易员' # 作者
self.pos = EMPTY_INT # 持仓
self.lastPrice = EMPTY_FLOAT # 最新价
# 参数和变量列表设置
self.paramList.append('author')
self.varList.append('pos')
self.varList.append('lastPrice')
# 测试用计数
self.count = 0
super(DataRecorder, self).__init__(ctaEngine, setting)
#----------------------------------------------------------------------
def init(self):
"""初始化策略(必须由用户继承实现)"""
self.writeCtaLog(u'测试策略%s初始化' %self.name)
def onInit(self):
"""初始化"""
self.writeCtaLog(u'数据记录工具初始化')
#----------------------------------------------------------------------
def start(self):
def onStart(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'测试策略%s启动' %self.name)
self.writeCtaLog(u'数据记录工具启动')
self.putEvent()
#----------------------------------------------------------------------
def stop(self):
def onStop(self):
"""停止策略(必须由用户继承实现)"""
self.writeCtaLog(u'测试策略%s停止' %self.name)
self.writeCtaLog(u'数据记录工具停止')
self.putEvent()
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送必须由用户继承实现"""
self.writeCtaLog(u'测试策略%s收到Tick' %self.name)
self.lastPrice = tick.lastPrice
"""收到行情TICK推送"""
# 收到Tick后首先插入到数据库里
self.insertTick(tick)
# 计算K线
tickMinute = tick.datetime.minute
if tickMinute != self.barMinute: # 如果分钟变了则把旧的K线插入数据库并生成新的K线
if self.bar:
self.onBar(self.bar)
bar = CtaBarData() # 创建新的K线目的在于防止之前K线对象在插入Mongo中被再次修改导致出错
bar.vtSymbol = tick.vtSymbol
bar.symbol = tick.symbol
bar.exchange = tick.exchange
bar.open = tick.lastPrice
bar.high = tick.lastPrice
bar.low = tick.lastPrice
bar.close = tick.lastPrice
bar.date = tick.date
bar.time = tick.time
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
bar.volume = tick.volume
bar.openInterest = tick.openInterest
self.bar = bar # 这种写法为了减少一层访问,加快速度
self.barMinute = tickMinute # 更新当前的分钟
else: # 否则继续累加新的K线
bar = self.bar # 写法同样为了加快速度
bar.high = max(bar.high, tick.lastPrice)
bar.low = min(bar.low, tick.lastPrice)
bar.close = tick.lastPrice
bar.volume = bar.volume + tick.volume # 成交量是累加的
bar.openInterest = tick.openInterest # 持仓量直接更新
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送(必须由用户继承实现)"""
print u'收到委托回报,委托编号%s' %order.orderID
"""收到委托变化推送"""
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送(必须由用户继承实现)"""
print u'收到成交回报,成交编号%s' %order.orderID
"""收到成交推送"""
pass
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送必须由用户继承实现"""
self.count += 1
if self.count == 10:
self.buy(bar.close, 1)
if self.count == 20:
self.sell(bar.close, 1)
self.count = 0
#print u'收到推送'
"""收到Bar推送"""
self.insertBar(bar)

View File

@ -1,5 +1,8 @@
# encoding: UTF-8
'''一个简单的通联数据客户端主要使用requests开发比通联官网的python例子更为简洁。'''
import requests
import json

View File

@ -1,68 +1,63 @@
# encoding: UTF-8
'''CTA模块相关的GUI控制组件'''
'''
CTA模块相关的GUI控制组件
'''
from uiBasicWidget import QtGui, QtCore, BasicCell
from eventEngine import *
########################################################################
class ValueMonitor(QtGui.QTableWidget):
"""数值监控"""
signal = QtCore.pyqtSignal()
class CtaValueMonitor(QtGui.QTableWidget):
"""参数监控"""
#----------------------------------------------------------------------
def __init__(self, parent=None):
"""Constructor"""
super(ValueMonitor , self).__init__(parent)
super(CtaValueMonitor, self).__init__(parent)
self.keyCellDict = {}
self.row = 0
self.data = None
self.inited = False
self.initUi()
self.signal.connect(self.updateTable)
#----------------------------------------------------------------------
def initUi(self):
"""初始化界面"""
self.setColumnCount(2)
self.verticalHeader().setVisible(False)
self.horizontalHeader().setVisible(False)
self.setRowCount(1)
self.verticalHeader().setVisible(False)
self.setEditTriggers(self.NoEditTriggers)
self.setAlternatingRowColors(True)
self.setMaximumHeight(self.sizeHint().height())
#----------------------------------------------------------------------
def updateData(self, data):
"""更新数据"""
self.data = data
self.signal.emit()
#----------------------------------------------------------------------
def updateTable(self):
"""更新表格"""
for key, value in self.data.items():
if key in self.keyCellDict:
cell = self.keyCellDict[key]
cell.setText(unicode(value))
else:
# 创建并保存单元格
keyCell = BasicCell(unicode(key))
cell = BasicCell(unicode(value))
self.keyCellDict[key] = cell
# 移动到下一行
self.insertRow(self.row)
self.setItem(self.row, 0, keyCell)
self.setItem(self.row, 1, cell)
self.row += 1
if not self.inited:
self.setColumnCount(len(data))
self.setHorizontalHeaderLabels(data.keys())
col = 0
for k, v in data.items():
cell = QtGui.QTableWidgetItem(unicode(v))
self.keyCellDict[k] = cell
self.setItem(0, col, cell)
col += 1
self.inited = True
else:
for k, v in data.items():
cell = self.keyCellDict[k]
cell.setText(unicode(v))
########################################################################
class CtaStrategyManager(QtGui.QGroupBox):
"""策略管理组件"""
signal = QtCore.pyqtSignal(type(Event()))
#----------------------------------------------------------------------
def __init__(self, ctaEngine, eventEngine, name, parent=None):
@ -82,28 +77,37 @@ class CtaStrategyManager(QtGui.QGroupBox):
"""初始化界面"""
self.setTitle(self.name)
paramLabel = QtGui.QLabel(u'参数')
varLabel = QtGui.QLabel(u'变量')
self.paramMonitor = CtaValueMonitor(self)
self.varMonitor = CtaValueMonitor(self)
self.paramMonitor = ValueMonitor(self)
self.varMonitor = ValueMonitor(self)
maxHeight = 60
self.paramMonitor.setMaximumHeight(maxHeight)
self.varMonitor.setMaximumHeight(maxHeight)
buttonInit = QtGui.QPushButton(u'初始化')
buttonStart = QtGui.QPushButton(u'启动')
buttonStop = QtGui.QPushButton(u'停止')
buttonInit.clicked.connect(self.init)
buttonStart.clicked.connect(self.start)
buttonStop.clicked.connect(self.stop)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(buttonStart)
hbox.addWidget(buttonStop)
hbox.addStretch()
hbox1 = QtGui.QHBoxLayout()
hbox1.addWidget(buttonInit)
hbox1.addWidget(buttonStart)
hbox1.addWidget(buttonStop)
hbox1.addStretch()
hbox2 = QtGui.QHBoxLayout()
hbox2.addWidget(self.paramMonitor)
hbox3 = QtGui.QHBoxLayout()
hbox3.addWidget(self.varMonitor)
vbox = QtGui.QVBoxLayout()
vbox.addLayout(hbox)
vbox.addWidget(paramLabel)
vbox.addWidget(self.paramMonitor)
vbox.addWidget(varLabel)
vbox.addWidget(self.varMonitor)
vbox.addLayout(hbox1)
vbox.addLayout(hbox2)
vbox.addLayout(hbox3)
self.setLayout(vbox)
#----------------------------------------------------------------------
@ -120,7 +124,13 @@ class CtaStrategyManager(QtGui.QGroupBox):
#----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
self.eventEngine.register(EVENT_TIMER, self.updateMonitor)
self.signal.connect(self.updateMonitor)
self.eventEngine.register(EVENT_CTA_STRATEGY+self.name, self.signal.emit)
#----------------------------------------------------------------------
def init(self):
"""初始化策略"""
self.ctaEngine.initStrategy(self.name)
#----------------------------------------------------------------------
def start(self):
@ -133,7 +143,6 @@ class CtaStrategyManager(QtGui.QGroupBox):
self.ctaEngine.stopStrategy(self.name)
########################################################################
class CtaEngineManager(QtGui.QWidget):
"""CTA引擎管理组件"""
@ -162,23 +171,28 @@ class CtaEngineManager(QtGui.QWidget):
# 按钮
loadButton = QtGui.QPushButton(u'加载策略')
initAllButton = QtGui.QPushButton(u'全部初始化')
startAllButton = QtGui.QPushButton(u'全部启动')
stopAllButton = QtGui.QPushButton(u'全部停止')
loadButton.clicked.connect(self.load)
initAllButton.clicked.connect(self.initAll)
startAllButton.clicked.connect(self.startAll)
stopAllButton.clicked.connect(self.stopAll)
# 滚动区域放置所有的CtaStrategyManager
self.scrollArea = QtGui.QScrollArea()
self.scrollArea.setWidgetResizable(True)
# CTA组件的日志监控
self.ctaLogMonitor = QtGui.QTextEdit()
self.ctaLogMonitor.setReadOnly(True)
self.ctaLogMonitor.setMaximumHeight(200)
# 设置布局
hbox2 = QtGui.QHBoxLayout()
hbox2.addWidget(loadButton)
hbox2.addWidget(initAllButton)
hbox2.addWidget(startAllButton)
hbox2.addWidget(stopAllButton)
hbox2.addStretch()
@ -193,14 +207,22 @@ class CtaEngineManager(QtGui.QWidget):
def initStrategyManager(self):
"""初始化策略管理组件界面"""
w = QtGui.QWidget()
hbox = QtGui.QHBoxLayout()
vbox = QtGui.QVBoxLayout()
for name in self.ctaEngine.strategyDict.keys():
strategyManager = CtaStrategyManager(self.ctaEngine, self.eventEngine, name)
hbox.addWidget(strategyManager)
vbox.addWidget(strategyManager)
w.setLayout(hbox)
self.scrollArea.setWidget(w)
vbox.addStretch()
w.setLayout(vbox)
self.scrollArea.setWidget(w)
#----------------------------------------------------------------------
def initAll(self):
"""全部初始化"""
for name in self.ctaEngine.strategyDict.keys():
self.ctaEngine.initStrategy(name)
#----------------------------------------------------------------------
def startAll(self):
@ -218,7 +240,7 @@ class CtaEngineManager(QtGui.QWidget):
def load(self):
"""加载策略"""
if not self.strategyLoaded:
self.ctaEngine.loadStrategySetting()
self.ctaEngine.loadSetting()
self.initStrategyManager()
self.strategyLoaded = True
self.ctaEngine.writeCtaLog(u'策略加载成功')

View File

@ -1,15 +0,0 @@
# encoding: UTF-8
# CTA引擎中涉及到的交易方向类型
CTAORDER_BUY = u'买开'
CTAORDER_SELL = u'卖平'
CTAORDER_SHORT = u'卖开'
CTAORDER_COVER = u'买平'
# 本地停止单状态
STOPORDER_WAITING = u'等待中'
STOPORDER_CANCELLED = u'已撤销'
STOPORDER_TRIGGERED = u'已触发'
# 本地停止单前缀
STOPORDERPREFIX = 'CtaStopOrder.'

View File

@ -1,106 +0,0 @@
# encoding: UTF-8
from ctaStrategyTemplate import *
from ctaObject import CtaBarData
########################################################################
class DataRecorder(CtaStrategyTemplate):
"""
纯粹用来记录历史数据的工具基于CTA策略
建议运行在实际交易程序外的一个vn.trader实例中
本工具会记录Tick和1分钟K线数据
"""
#----------------------------------------------------------------------
def __init__(self, ctaEngine, name, setting=None):
"""Constructor"""
super(DataRecorder, self).__init__(ctaEngine, name, setting)
self.strategyClassName = 'DataRecorder'
self.author = u'用Python的交易员'
self.tickDbName = 'VtTrader_Tick_Db'
self.barDbName = 'VtTrader_1Min_Db'
self.paramList.append('author')
# 数据记录相关
self.bar = None # K线数据对象
self.barMinute = -1 # 当前的分钟,初始化设为-1
#----------------------------------------------------------------------
def init(self):
"""初始化"""
self.writeCtaLog(u'数据记录工具%s初始化' %self.name)
#----------------------------------------------------------------------
def start(self):
"""启动策略(必须由用户继承实现)"""
self.writeCtaLog(u'数据记录工具%s启动' %self.name)
#----------------------------------------------------------------------
def stop(self):
"""停止策略(必须由用户继承实现)"""
self.writeCtaLog(u'数据记录工具%s停止' %self.name)
#----------------------------------------------------------------------
def onTick(self, tick):
"""收到行情TICK推送"""
# 收到Tick后首先插入到数据库里
self.insertTick(tick)
# 计算K线
tickMinute = tick.datetime.minute
if tickMinute != self.barMinute: # 如果分钟变了则把旧的K线插入数据库并生成新的K线
if self.bar:
self.onBar(self.bar)
bar = CtaBarData() # 创建新的K线目的在于防止之前K线对象在插入Mongo中被再次修改导致出错
bar.vtSymbol = tick.vtSymbol
bar.symbol = tick.symbol
bar.exchange = tick.exchange
bar.open = tick.lastPrice
bar.high = tick.lastPrice
bar.low = tick.lastPrice
bar.close = tick.lastPrice
bar.date = tick.date
bar.time = tick.time
bar.datetime = tick.datetime # K线的时间设为第一个Tick的时间
bar.volume = tick.volume
bar.openInterest = tick.openInterest
self.bar = bar # 这种写法为了减少一层访问,加快速度
self.barMinute = tickMinute # 更新当前的分钟
else: # 否则继续累加新的K线
bar = self.bar # 写法同样为了加快速度
bar.high = max(bar.high, tick.lastPrice)
bar.low = min(bar.low, tick.lastPrice)
bar.close = tick.lastPrice
bar.volume = bar.volume + tick.volume # 成交量是累加的
bar.openInterest = tick.openInterest # 持仓量直接更新
#----------------------------------------------------------------------
def onOrder(self, order):
"""收到委托变化推送"""
pass
#----------------------------------------------------------------------
def onTrade(self, trade):
"""收到成交推送"""
pass
#----------------------------------------------------------------------
def onBar(self, bar):
"""收到Bar推送"""
self.insertBar(bar)

View File

@ -26,6 +26,7 @@ EVENT_ERROR = 'eError.' # 错误回报事件
# CTA模块相关
EVENT_CTA_LOG = 'eCtaLog' # CTA相关的日志事件
EVENT_CTA_STRATEGY = 'eCtaStrategy.' # CTA策略状态变化事件
# Wind接口相关
EVENT_WIND_CONNECTREQ = 'eWindConnectReq' # Wind接口请求连接事件

View File

@ -276,7 +276,7 @@ class BasicMonitor(QtGui.QTableWidget):
for header in self.headerList:
content = safeUnicode(data.__getattribute__(header))
cell = d[header]
cell.setContent(content, self.mainEngine)
cell.setContent(content)
if self.saveData: # 如果设置了保存数据对象,则进行对象保存
cell.data = data
@ -575,10 +575,11 @@ class TradingWidget(QtGui.QFrame):
EXCHANGE_GLOBEX,
EXCHANGE_IDEALPRO]
currencyList = [CURRENCY_CNY,
currencyList = [CURRENCY_NONE,
CURRENCY_CNY,
CURRENCY_USD]
productClassList = [PRODUCT_UNKNOWN,
productClassList = [PRODUCT_NONE,
PRODUCT_EQUITY,
PRODUCT_FUTURES,
PRODUCT_OPTION]

View File

@ -3,7 +3,7 @@
import psutil
from uiBasicWidget import *
from uiCtaWidget import CtaEngineManager
from ctaAlgo.uiCtaWidget import CtaEngineManager
########################################################################

View File

@ -39,6 +39,7 @@ PRODUCT_FOREX = u'外汇'
PRODUCT_UNKNOWN = u'未知'
PRODUCT_SPOT = u'现货'
PRODUCT_DEFER = u'延期'
PRODUCT_NONE = ''
# 价格类型常量
PRICETYPE_LIMITPRICE = u'限价'
@ -68,4 +69,5 @@ EXCHANGE_IDEALPRO = 'IDEALPRO' # IB外汇ECN
# 货币类型
CURRENCY_USD = 'USD' # 美元
CURRENCY_CNY = 'CNY' # 人民币
CURRENCY_UNKNOWN = 'UNKNOWN' # 未知货币
CURRENCY_UNKNOWN = 'UNKNOWN' # 未知货币
CURRENCY_NONE = '' # 空货币

View File

@ -8,8 +8,7 @@ from pymongo.errors import ConnectionFailure
from eventEngine import *
from vtGateway import *
import uiBasicWidget
from ctaEngine import CtaEngine
from ctaAlgo.ctaEngine import CtaEngine
########################################################################