mark一下,parameters列表里面的参数能同步,那仓位同步是在哪控制的?
细颗粒度,考虑到挂单排队的回测,工作量巨大啊,必须mark
用Python的交易员 wrote:
- 每个CTA策略只能交易一个合约,你可以启动多个策略来交易多个合约
- risk_level是个参数,你可以提前计算好想要交易的最大手数,并反推出risk_level
- 加仓代码的写法没有固定范式,简单的话可以写在开仓代码里
- Github仓库中的examples代码里,有cta_backtesting目录,其中有组合回测说明
mark一下,组合回测说明,跨品种策略
目前看到的样例是轮询驱动
while engine.strategy_active:
......
sleep(1)
自己想到的接近on_tick的模式是,不断轮询,判断tick的datetime是否有更新,最大误差就是sleep的时间
while engine.strategy_active:
for i in range(10):
tick = engine.get_tick(vt_symbol, use_df=True)
if tick['datetime'][0] != tick_pre['datetime'][0]:
break # 如果是新tick数据,则跳出循环
sleep(0.1)
......
请问 jupyter notebook是否可以on_tick或on_trade事件驱动触发?可不可以举个简单例子?
非常感谢
最大的缺点就是:注释太少了
月总,能多加些注释么?
on_tick函数内撤单追单详解,实盘在用的代码
mark
留个爪,mark一下
VNPY 1.9.2版本支持看穿式终端的流程
必须mark一下,非常实用
vnpy版本1.9.2
onTick触发时,程序开始和结束的时候,都记录本地时间,并writeCtaLog出来
def onTick(self, tick):
self.writeCtaLog(u'本地时间: %s' %(datetime,datetime.now())
tickstarttime = datetime.datetime.now()
策略主体
tickendtime = datetime.datetime.now()
passtime = str(tickendtime - tickstarttime)
self.writeCtaLog(u'onTick程序运行时长: %s' %(passtime))
一、发现两个现象
有时候打印出来的Log时间差大于onTick程序实际的运行时间,有时候Log时间差又小于onTick程序实际的运行时间,如下:
1、onTick程序运行时间0.001s,Log记录的时间差有0.007s (即23,598 - 23,591)
2019-12-23 13:43:23,591 INFO: CTA_STRATEGY p2005 LongStrategy:本地时间: 2019-12-23 13:43:23.588000
2019-12-23 13:43:23,592 INFO: CTA_STRATEGY p2005 LongStrategy:pos **** :0
2019-12-23 13:43:23,592 INFO: CTA_STRATEGY p2005 LongStrategy:self.auto[self.vtSymbol] :on
2019-12-23 13:43:23,594 INFO: CTA_STRATEGY p2005 LongStrategy:askprice askvolume:6014.0 595
2019-12-23 13:43:23,595 INFO: CTA_STRATEGY p2005 LongStrategy:bidprice bidvolume:6012.0 525
2019-12-23 13:43:23,595 INFO: CTA_STRATEGY p2005 LongStrategy:拒单数 撤单数:0 0
2019-12-23 13:43:23,595 INFO: CTA_STRATEGY p2005 LongStrategy:仓位:0
2019-12-23 13:43:23,596 INFO: CTA_STRATEGY p2005 LongStrategy:self.lastTick.lastVolume:0
2019-12-23 13:43:23,596 INFO: CTA_STRATEGY p2005 LongStrategy:self.lastTick.volume:2501110
2019-12-23 13:43:23,596 INFO: CTA_STRATEGY p2005 LongStrategy:self.limitVolume[self.vtSymbol]:200
2019-12-23 13:43:23,596 INFO: CTA_STRATEGY p2005 LongStrategy:order.price:6000.0
2019-12-23 13:43:23,598 INFO: CTA_STRATEGY p2005 LongStrategy:onTick程序运行时长 :0:00:00.001000
2、onTick程序运行时间0.005s,Log记录的时间只有0.004s (即07,096 - 07,092),
且记录的起始时间比程序本身的时间要晚0.020s,即第一条程序时间13:51:07.072000,Log时间13:51:07,092
2019-12-23 13:51:07,092 INFO: CTA_STRATEGY p2005 LongStrategy:本地时间: 2019-12-23 13:51:07.072000
2019-12-23 13:51:07,092 INFO: CTA_STRATEGY p2005 LongStrategy:pos **** :0
2019-12-23 13:51:07,094 INFO: CTA_STRATEGY p2005 LongStrategy:self.auto[self.vtSymbol] :on
2019-12-23 13:51:07,094 INFO: CTA_STRATEGY p2005 LongStrategy:askprice askvolume:6024.0 415
2019-12-23 13:51:07,094 INFO: CTA_STRATEGY p2005 LongStrategy:bidprice bidvolume:6022.0 660
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:拒单数 撤单数:0 0
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:仓位:0
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:self.lastTick.lastVolume:0
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:self.lastTick.volume:2561906
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:self.limitVolume[self.vtSymbol]:200
2019-12-23 13:51:07,095 INFO: CTA_STRATEGY p2005 LongStrategy:order.price:6000.0
2019-12-23 13:51:07,096 INFO: CTA_STRATEGY p2005 LongStrategy:onTick程序运行时长 :0:00:00.005000
二、问题
1、writeCtaLog函数记录的时候和程序主体运行是什么样的关系?Log时间差一会大,一会小,感觉是相互独立的
2、如果onTick中运用了较多的writeCtaLog函数来记录,譬如20个策略,每个策略onTick中写出30个writeCtaLog函数,这样在效率上会影响onTick程序的运行么?
3、假如writeCtaLog函数较多会影响onTick程序的效率,怎么提高效率呢,Log的信息改用pandas输出?还是说用多进程multiprocessing包?
非常感谢!
测试账户是指什么?模拟账号?
徽商期货,客服回复:
1、徽商期货的IT 联系方式:0371-58670101
电话属于总部的 徽商期货负责郑州易盛,但期货公司不提供 测试账户,让直接联系易盛
2、易盛的联系方式
http://www.esunny.com.cn/index.php?a=lists&catid=9
3、易盛的程序化平台是极星 ,官方的 极星量化开发群 QQ群号是:472789093
4、易盛技术人员回复:极星仿真和易盛模拟不是一个后台(再具体我就不是很懂了)
5、关于易盛模拟账号:
http://www.esunny.com.cn/index.php?a=lists&catid=18
6、程序化在启动前,好像要同时先登录易盛的极星客户端(印象中是,没用过)
这些信息可以了么?
易盛 极星 内盘,在期货数据方面有些优势,譬如郑商所的商品期货,数据有免费五档行情,以及tick切片是0.25s,优势很明显,请问易盛 极星 内盘的数据api接口有没有上线的计划?谢谢
基础代码我再认真核对一下,找了好几圈了,目前还没找出哪里直接改了UI而没通过Singal/Slot
另外,从结构上,我看到一些有数据交互功能的UI,譬如CTA策略、价差交易,都被独立封装成了上层应用
# 添加上层应用
me.addApp(riskManager)
me.addApp(ctaStrategy)
me.addApp(spreadTrading)
交互功能如下,有按键修改策略状态初始化,有log输出到UI
我自己设计的UI也有类似的功能,就是按钮直接修改策略的参数和链接到策略的sendOrder发单
请问,也必须像价差交易、CTA策略等一样做成“上层应用”吗?
我参考的是没有实时交互功能的代码模式
如“打开配置编辑”模板,直接从菜单栏弹出:
def openSettingEditor(self):
"""打开配置编辑"""
try:
self.widgetDict['settingEditor'].show()
except KeyError:
self.widgetDict['settingEditor'] = SettingEditor(self.mainEngine)
self.widgetDict['settingEditor'].show()
自己设计的弹出窗口如下:
def sniperTrade(self):
"""打开手动交易"""
try:
self.widgetDict['sniperTrade'].show()
except KeyError:
self.widgetDict['sniperTrade'] = SniperTradingWidget(self.mainEngine, self.eventEngine, self.ctaEngine) # 无问西东 新建窗体 新增传入ctaEngine
self.widgetDict['sniperTrade'].show()
交互功能UI,结构上必须做成上层应用么?还是可以做成简单的弹出窗口就行了?
这可能是最后一个疑问了,非常感谢群主的悉心指导
非常感谢群主百忙之中的解答
signal.emit注册是有的,因为这个UI窗口是照搬“简单交易组件”来的,所以,注册机制跟MainWindow里的您写的那个手动下单一致
参考的源代码:
class TradingWidget(QtWidgets.QFrame):
"""简单交易组件"""
signal = QtCore.Signal(type(Event()))
......
#----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
self.signal.connect(self.updateTick)
self.eventEngine.register(EVENT_TICK, self.signal.emit)
实际代码如下,这两个class的注册是一模一样的
class SniperTradingWidget(QtWidgets.QFrame):
"""狙击交易组件"""
signal = QtCore.Signal(type(Event()))
......
#----------------------------------------------------------------------
def registerEvent(self):
"""注册事件监听"""
self.signal.connect(self.updateTick)
self.eventEngine.register(EVENT_TICK, self.signal.emit)
至于调用这个class的上层函数,我也是参考’功能应用‘菜单的模板
’功能应用‘菜单源码,参考’打开配置编辑‘代码:
def createOpenAppFunction(self, appDetail):
"""创建打开应用UI的函数"""
def openAppFunction():
appName = appDetail['appName']
try:
self.widgetDict[appName].show()
except KeyError:
appEngine = self.mainEngine.getApp(appName)
# self.widgetDict[appName] = appDetail['appWidget'](appEngine, self.eventEngine)
# 无问西东,这部分细节实现还不太清楚,传递的参数不是(self.mainEngine, self.eventEngine, self.ctaEngine)
# 譬如CtaEngineManager(ctaEngine, eventEngine, parent=None)
self.widgetDict[appName] = appDetail['appWidget'](appEngine, self.eventEngine)
self.widgetDict[appName].show()
return openAppFunction
def openSettingEditor(self):
"""打开配置编辑"""
try:
self.widgetDict['settingEditor'].show()
except KeyError:
self.widgetDict['settingEditor'] = SettingEditor(self.mainEngine)
self.widgetDict['settingEditor'].show()
调用自编UI的代码(多传了一个ctaEngine,在初始化时的_init_里面就传入了):
def sniperTrade(self):
"""打开手动交易"""
try:
self.widgetDict['sniperTrade'].show()
except KeyError:
self.widgetDict['sniperTrade'] = SniperTradingWidget(self.mainEngine, self.eventEngine, self.ctaEngine) # 无问西东 新建窗体 新增传入ctaEngine
self.widgetDict['sniperTrade'].show()
自己写的updateTick函数内容也挺简单,也就是参考“简单交易组件”更新一下数据
def updateTick(self, event):
"""更新行情"""
tick = event.dict_['data']
if tick.vtSymbol != self.symbol:
return
self.tick = tick
updateStart = datetime.datetime.now()
self.ctaEngine.writeCtaLog(u'updateStart时间: %s' % (updateStart))
# 新增
self.lastTick = tick
self.getVolume() # 成交量相关计算函数
if not self.checkFixed.isChecked():
self.spinPrice.setValue(tick.lastPrice)
# priceTick = self.mainEngine.getContract(self.vtSymbol).priceTick
self.labelBidVolume1.setText(str(tick.bidVolume1))
self.labelAskVolume1.setText(str(tick.askVolume1))
self.labelBidPrice1.setText(str(tick.bidPrice1))
self.labelBidPrice2.setText(str(tick.bidPrice1 - 1 * self.priceTick))
self.labelBidPrice3.setText(str(tick.bidPrice1 - 2 * self.priceTick))
self.labelBidPrice4.setText(str(tick.bidPrice1 - 3 * self.priceTick))
self.labelBidPrice5.setText(str(tick.bidPrice1 - 4 * self.priceTick))
self.labelAskPrice1.setText(str(tick.askPrice1))
self.labelAskPrice2.setText(str(tick.askPrice1 + 1 * self.priceTick))
self.labelAskPrice3.setText(str(tick.askPrice1 + 2 * self.priceTick))
self.labelAskPrice4.setText(str(tick.askPrice1 + 3 * self.priceTick))
self.labelAskPrice5.setText(str(tick.askPrice1 + 4 * self.priceTick))
# 新增
self.labelBidPrice1Middle.setText(str(tick.bidPrice1))
self.labelAskPrice1Middle.setText(str(tick.askPrice1))
self.labelBidVolume1Middle.setText(str(tick.bidVolume1))
self.labelAskVolume1Middle.setText(str(tick.askVolume1))
self.labelAskVolumeLast.setText(str(self.askVolumeLast))
self.labelBidVolumeLast.setText(str(self.bidVolumeLast))
self.labelAskVolumeSum.setText(str(self.askVolumeSum))
self.labelBidVolumeSum.setText(str(self.bidVolumeSum))
# 偏移与点差计算挂单价格
self.labelAskpriceDiff.setText(str(tick.askPrice1 + self.spinDiff.value() * self.priceTick))
self.labelBidpriceDiff.setText(str(tick.bidPrice1 - self.spinDiff.value() * self.priceTick))
if tick.bidPrice2:
self.labelBidPrice2.setText(str(tick.bidPrice2))
self.labelBidPrice3.setText(str(tick.bidPrice3))
self.labelBidPrice4.setText(str(tick.bidPrice4))
self.labelBidPrice5.setText(str(tick.bidPrice5))
self.labelAskPrice2.setText(str(tick.askPrice2))
self.labelAskPrice3.setText(str(tick.askPrice3))
self.labelAskPrice4.setText(str(tick.askPrice4))
self.labelAskPrice5.setText(str(tick.askPrice5))
self.labelBidVolume2.setText(str(tick.bidVolume2))
self.labelBidVolume3.setText(str(tick.bidVolume3))
self.labelBidVolume4.setText(str(tick.bidVolume4))
self.labelBidVolume5.setText(str(tick.bidVolume5))
self.labelAskVolume2.setText(str(tick.askVolume2))
self.labelAskVolume3.setText(str(tick.askVolume3))
self.labelAskVolume4.setText(str(tick.askVolume4))
self.labelAskVolume5.setText(str(tick.askVolume5))
self.labelLastPrice.setText(str(tick.lastPrice))
if tick.preClosePrice:
rt = (tick.lastPrice/tick.preClosePrice)-1
self.labelReturn.setText(('%.2f' %(rt*100))+'%')
else:
self.labelReturn.setText('')
# 新增
self.askPricePrevious = self.lastTick.askPrice1
self.bidPricePrevious = self.lastTick.bidPrice1
self.volumePrevious = self.lastTick.volume
updateEnd= datetime.datetime.now()
self.ctaEngine.writeCtaLog(u'updateEnd时间: %s' % (updateEnd))
self.ctaEngine.writeCtaLog(u'update运行时间: %s' % (updateEnd - updateStart))
感觉定义class 和调用class 都跟原版很接近的呀?好像不是注册事件的原因,还有什么其他的可能性么?或者我的调用class有问题?它的现象是可以正常启动,也可以正常运行,只是运行一个小时左右,就出现UI(未响应)。
感谢群主的指导
补充:
因为在updateTick函数的开始 和结尾都打印了时间戳
查看log发现,最后的时间戳是成对出现的,也就是最后一次是顺利的运行到了updateTick的结尾,不是死在了这个函数的内部计算过程中
2019-07-30 10:33:51,516 INFO: CTA_STRATEGY updateStart时间: 2019-07-30 10:33:51.400000
2019-07-30 10:33:51,571 INFO: CTA_STRATEGY updateEnd时间: 2019-07-30 10:33:51.409000
2019-07-30 10:33:51,572 INFO: CTA_STRATEGY update运行时间: 0:00:00.009000
目的是添加一个手动开仓的UI,按钮链接到策略的sendOrder,然后策略自动平仓(譬如止损),但失败了,启动半个小时左右,UI就 无响应了
版本 vnpy1.8.1
具体实施的步骤如下:
1、在主窗口增加了一个 “测试” 菜单
2、‘’测试‘下拉菜单里,添加按钮,连接到弹出窗口
测试按钮代码:
# 帮助
helpMenu = menubar.addMenu(vtText.HELP)
helpMenu.addAction(self.createAction(vtText.CONTRACT_SEARCH, self.openContract, loadIconPath('contract.ico')))
helpMenu.addAction(self.createAction(vtText.EDIT_SETTING, self.openSettingEditor, loadIconPath('editor.ico')))
helpMenu.addSeparator()
helpMenu.addAction(self.createAction(vtText.RESTORE, self.restoreWindow, loadIconPath('restore.ico')))
helpMenu.addAction(self.createAction(vtText.ABOUT, self.openAbout, loadIconPath('about.ico')))
helpMenu.addSeparator()
helpMenu.addAction(self.createAction(vtText.TEST, self.test, loadIconPath('test.ico')))
# 测试
testMenu = menubar.addMenu(vtText.TEST)
testMenu.addAction(self.createAction(u'参数配置', self.openSettingParameter, loadIconPath('editor.ico')))
testMenu.addAction(self.createAction(u'sniper', self.sniperTrade, loadIconPath('editor.ico')))**
弹出窗口函数
def sniperTrade(self):
"""打开手动交易"""
try:
self.widgetDict['sniperTrade'].show()
except KeyError:
self.widgetDict['sniperTrade'] = SniperTradingWidget(self.mainEngine, self.eventEngine, self.ctaEngine) # 无问西东 新建窗体 新增传入ctaEngine
self.widgetDict['sniperTrade'].show()
3、弹出窗口是参照“简单交易组件”照搬过来,增加了几个下单的按钮(可以连接到策略中的sendOrder)
class TradingWidget(QtWidgets.QFrame):
class SniperTradingWidget(QtWidgets.QFrame):
这个UI界面中没有耗时程序,基本updateTick函数,更新UI时间在10ms内
一般能正常启动和正常运行,半个小时到一个小时后,UI就无响应了(包括MainWindow),UI虽然无响应,但是后台的策略程序在正常运行。
请问这样加载一个新的弹出窗口的程序步骤是正确的么?无响应的问题会出在哪个环节?谢谢
知乎文章中 ,没找到底层调用 QueryPerformanceFrequency 函数 的位置,也写在头文件中了么?
应该还是在.h的头文件里有改动,请问这套代码的新链接在哪里?原来知乎上测试tick-to-trade的代码链接失效了
在头文件vnctpmd.h中的Task结构体中增加一行声明
//任务结构体
struct Task
{
int task_name; //回调函数名称对应的常量
any task_data; //数据结构体
any task_error; //错误结构体
int task_id; //请求id
bool task_last; //是否为最后返回
LONGLONG task_time; //时间
};
增加上面最后一行,“task_time”: 不是“Task”的成员 的错误没有了
下面的错误依然存在:
错误 3 error C2039: “t”: 不是“MdApi”的成员
错误 4 error C2228: “.QuadPart”的左边必须有类/结构/联合
对应的代码段如下:
void MdApi::processRtnDepthMarketData(Task task)
{
PyLock lock;
CThostFtdcDepthMarketDataField task_data = any_cast<CThostFtdcDepthMarketDataField>(task.task_data);
dict data;
data["HighestPrice"] = task_data.HighestPrice;
data["BidPrice5"] = task_data.BidPrice5;
data["BidPrice4"] = task_data.BidPrice4;
data["BidPrice1"] = task_data.BidPrice1;
data["BidPrice3"] = task_data.BidPrice3;
data["BidPrice2"] = task_data.BidPrice2;
data["LowerLimitPrice"] = task_data.LowerLimitPrice;
data["OpenPrice"] = task_data.OpenPrice;
data["AskPrice5"] = task_data.AskPrice5;
data["AskPrice4"] = task_data.AskPrice4;
data["AskPrice3"] = task_data.AskPrice3;
data["PreClosePrice"] = task_data.PreClosePrice;
data["AskPrice1"] = task_data.AskPrice1;
data["PreSettlementPrice"] = task_data.PreSettlementPrice;
data["AskVolume1"] = task_data.AskVolume1;
data["UpdateTime"] = task_data.UpdateTime;
data["UpdateMillisec"] = task_data.UpdateMillisec;
data["AveragePrice"] = task_data.AveragePrice;
data["BidVolume5"] = task_data.BidVolume5;
data["BidVolume4"] = task_data.BidVolume4;
data["BidVolume3"] = task_data.BidVolume3;
data["BidVolume2"] = task_data.BidVolume2;
data["PreOpenInterest"] = task_data.PreOpenInterest;
data["AskPrice2"] = task_data.AskPrice2;
data["Volume"] = task_data.Volume;
data["AskVolume3"] = task_data.AskVolume3;
data["AskVolume2"] = task_data.AskVolume2;
data["AskVolume5"] = task_data.AskVolume5;
data["AskVolume4"] = task_data.AskVolume4;
data["UpperLimitPrice"] = task_data.UpperLimitPrice;
data["BidVolume1"] = task_data.BidVolume1;
data["InstrumentID"] = task_data.InstrumentID;
data["ClosePrice"] = task_data.ClosePrice;
data["ExchangeID"] = task_data.ExchangeID;
data["TradingDay"] = task_data.TradingDay;
data["PreDelta"] = task_data.PreDelta;
data["OpenInterest"] = task_data.OpenInterest;
data["CurrDelta"] = task_data.CurrDelta;
data["Turnover"] = task_data.Turnover;
data["LastPrice"] = task_data.LastPrice;
data["SettlementPrice"] = task_data.SettlementPrice;
data["ExchangeInstID"] = task_data.ExchangeInstID;
data["LowestPrice"] = task_data.LowestPrice;
data["ActionDay"] = task_data.ActionDay;
//保存测试时间
data["tick_time"] = task.task_time;
data["frequency_time"] = this->t.QuadPart;
this->onRtnDepthMarketData(data);
};
问题出在,最后的这三行中,请问这个错误应该如何消除?
按照知乎帖子“vn.trader的tick-to-trade延时测试”一文,链接为https://zhuanlan.zhihu.com/p/24242972,想测试一下本机的内部耗时,vnpy为1.8.1版本,在visual studio 2013 (boost为boost_1_68_0版本)编译的时候,出现如下错误:
错误 2 error C2039: “task_time”: 不是“Task”的成员
错误 3 error C2039: “t”: 不是“MdApi”的成员
错误 4 error C2228: “.QuadPart”的左边必须有类/结构/联合
5 IntelliSense: class "Task" 没有成员 "task_time"
原文代码的github链接失效了,所以不知道具体还改了哪些地方,我只改了“vn.trader的tick-to-trade延时测试”一文中提到的内容,不知道为什么会出现这样的错误(boost版本的原因?),请指点一下,谢谢