VeighNa量化社区
你的开源社区量化交易平台
hxxjava's Avatar
Member
离线
419 帖子
声望: 155

黄裳 wrote:

请教一个问题,在盘中实时行情之下,行情每跳一下,相应的一分钟线,以及基于一分钟线合成的五分钟,30分钟,以及小时线会跟着跳动吗??也就是随着每一个tick的到来,会自动更新1分钟线。但五分钟以及以后的周期,是不是也是同步更新的??
或者只是一分钟线完成以后,才更新五分钟线?也就是五分钟线每个bar,只更新五次。每一分钟更新一次??

用户CTA策略使用vnpy系统自带的BarGenerator时,假如你创建K线生成器的方法是:

self.bg1 = BarGenerator(self.on_bar,5,self.on_5min_bar)
self.bg2 = BarGenerator(self.on_bar,30,self.on_30min_bar)

那么对tick数据的处理节奏是:

1、用户策略的on_tick()每个tick都会被执行,on_tick()接受tick推送数据,产生1分钟bar,tick数据的时间的分钟数与1分钟bar的分钟数不相同时结束1分钟bar,然后执行on_bar
2、在交易时段内每1分钟都会执行on_tick(),on_bar()接受1分钟bar,利用这些1分钟bar合成出5分钟bar,然后执行on_5min_bar(),利用这些1分钟bar合成出30分钟bar,然后执行on_30min_bar()
3、在交易时段内每5分钟都会执行on_5min_bar(),on_5min_bar()接受5分钟bar,你的策略就可以利用这些5分钟bar进行交易的入场和离场信号。
4、在交易时段内每30分钟都会执行on_30min_bar(),on_30min_bar()接受30分钟bar,你的策略就可以利用这些30分钟bar进行交易的入场和离场信号。
因此,在不是整5分钟的时候,5分钟bar是不会被更新的;在不是整30分钟的时候,30分钟bar是不会被更新的.

老秦 wrote:

下载利用tick合成k线好像都是等长的,比如1分钟,5分钟等。我想按累积成交金额合成K线,比如tick的累计金额达到一个阈值,就合成一根k线,vnpy能不能实现这个?

请看看:K线种类总结

远山 wrote:

请问下楼主,怎么不让K线、成交量等图形不要顶着视图的上下边框绘制(如K线视图,最高价最低价都是顶着上下边框绘制的)?一来有些指标绘制会超过视图内所有K线的最低最高价,二来也很不美观。对Qt的图形编程完全是门外汉,看了看代码,暂时没找出修改的地方。
另外,少量K线时,每根K线显示得非常大,按缩放键也不起作用。看代码似乎最小缩放比例跟载入的K线数量有关,如果想让少量K线也能缩放到合适观看的尺寸,需要怎么修改?

你说的让K线、成交量等图形不要顶着视图的上下边框绘制,其实特别容易,只要修改下容纳chart_widget的容器就可以了。研究下Qt5的界面设计就OK了。
K线图的操控在pyQtGraph中有标准的方法,如按住鼠标左键左右拖动,滚轮前后波动等等,自己摸索下吧。

只有日K数据可以进行CTA策略回测吗?

  1. 首先vnpy的回测是基于tick数据或者1分钟K线数据的。通常每日使用米筐的数据,根据的你的用户身份,你可能是可以获得某个合约的历史tick数据(通常年费是2-3万多甚至更多)或者1分钟K线数据(通常年费是3千多), vnpy的回测引擎会把这些tick数或者1分钟K线数据合成为你的策略里指标需要的N分钟K数据。
  2. 你的指标应该是基于这个N分钟K线的几个或者成交量计算得到的。由此计算出开仓和平仓信号,同时也确定来开仓和平仓的价格。也就是说开仓和平仓的价格本质上来自于tick数据和1分钟K线数据。
  3. 如果你从其他的渠道只获得来某个合约的日K数据,而不是tick数据或者1分钟K线数据,那么以vnpy目前的回测机制是无法回测的,至少需要自己有针对性地修改。因为没有tick数据或者1分钟K线数据,你的策略的on_tick()是由tick数据推动的,on_bar()函数是有1分钟K线数据推动的,这个两种数据你都没有,策略的on_day_bar()【假设你就是这样命名的】是无法被执行的,因此是无法回测了。
  4. 就算你自己有针对性地修改了回测引擎,也可以on_day_bar()函数了,你的开仓价格和平仓价格因为没有tick数据和1分钟K线数据,只能够使用日K线的开、高、收、低之类的价格而使得测试因为太过粗糙而变得毫无意义。相当于你没有历史行情的细节,怎么能够进行精细的回测呢?可能对于股票之类无杠杆的合约还勉强算的上回测,而对于期货这样的高杠杆的合约,这样的回测几乎没有任何意义!
  5. 对于一根含有较大价格跳空的日K线,单从日K线本身是无法看出来的,跳空区间是无法开仓和平仓的,如果你没有tick数据或1分钟K线数据,想当然地认为你可以在日K线内部的某个价格进行交易,那可能会回测出错得离谱的结果!
  6. 建议vnpy初学者还是先注册个米筐的账户,先试用几个月,然后再购买。别把心思放在可以省钱的免费数据源上,因为麻烦的数据清洗和转换工作,让你的策略开发和调试变成无穷无尽的烦恼。

自己做个策略账户,对每个运行策略的交易进行记录进行保存,然后计算盈亏、保证金和手续费进行统计,就可以了.

学与忍 wrote:

我合并到回测界面,用界面测试时,发现k线图的日期要比回测系统的成交组件和委托组件日期慢一天。打开k线图表时会比较卡。

如果K线的数量比较多的话,首次打开的应该是比较慢的。应该是使用合成的K线来显示,比如你使用15分钟的K线来产生信号,那么就直接使用15分钟的K线来显示。回测使用默认的1分钟K线显示,K线数量就会很多,当然觉得卡啦,即使使用其他软件也会觉得卡的。

看看ArrayManager的update_bar()函数的代码就知道了

    def update_bar(self, bar: BarData) -> None:
        """
        Update new bar data into array manager.
        """
        self.count += 1
        if not self.inited and self.count >= self.size:
            self.inited = True

        self.open_array[:-1] = self.open_array[1:]
        self.high_array[:-1] = self.high_array[1:]
        self.low_array[:-1] = self.low_array[1:]
        self.close_array[:-1] = self.close_array[1:]
        self.volume_array[:-1] = self.volume_array[1:]
        self.open_interest_array[:-1] = self.open_interest_array[1:]

        self.open_array[-1] = bar.open_price
        self.high_array[-1] = bar.high_price
        self.low_array[-1] = bar.low_price
        self.close_array[-1] = bar.close_price
        self.volume_array[-1] = bar.volume
        self.open_interest_array[-1] = bar.open_interest

李贵珍 wrote:

xiaohe wrote:

  1. 要load_bar完成后(初始化完成后),trading状态才会变为true。
  2. 可以去engine.py看一下load_bar函数。默认use_database为false,会先去接口拿数据,没有的话会去rqdata找,最后才会去database。

如果数据库中只有两天的数据,load_bar(10) 会不会出问题?

关于这个问题,可以看看这篇帖子:https://www.vnpy.com/forum/topic/4890-fen-xi-yi-xia-pan-zhong-qi-dong-ctace-lue-dai-lai-de-di-yi-gen-he-cheng-kxian-cuo-wu

kingmo888 wrote:

hxxjava wrote:

kingmo888 wrote:

直接基于portfolio_manager改造吧,这个是多品种的,构造了指数后从这里多品种来做。

谢谢,一直没有关注portfolio_strategy,原来是这样的,不错!

后来经过分析,感觉还是不如cta引擎来的方便。因为要维护理论持仓的时候,真的挺麻烦的。

用米筐的某个主力合约前复权的xx888来跟踪主力合约的做法确实比较合理些,只是xx888无法订阅,在实时行情下需要对指标合约进行合成处理!。

cczhu wrote:

这个只是当前界面运行中的交易可以显示, 关闭后, 再次打开, 历史委托的reference没法显示了吧,因为没法保存啊

建议:
想办法把包含reference的order和trade保存起来,再次启动vnpy的时候把历史order和trade从文件读取,并且恢复到oms的orders,trades字典里就OK了。

kingmo888 wrote:

直接基于portfolio_manager改造吧,这个是多品种的,构造了指数后从这里多品种来做。

谢谢,一直没有关注portfolio_strategy,原来是这样的,不错!

kingmo888 wrote:

期权合约数现在是个天量啊。tdapi的回调函数又必须刷新合约,没招。

不过我好奇的是楼主在测试2、3这二者的差异,盲猜这难道就是py和c++的效率差别?

不是,是2楼管理员的回答就是答案。
因为使用SimNow的CTP接口连接的时候,在CTP接口初始化的时候,推送的只有期货合约的信息,不含相关期权合约的信息。如果你连接和实际在期货公司的CTP生成接口的时候,在CTP接口初始化的时候,推送的不光有期货合约的信息,还有相关期权合约的信息。而期权合约的数量特别多,
例如一个PTA2101合约,它的期货合约1条就推送完了,而与PTA2101相关的期权合约多达50个,其中包含25个看涨合约和25个看跌合约,每个都要推送到客户端。
所以初始化过程就由原来SimNow的CTP接口连接的3~5秒,猛增到实际在期货公司的CTP生成接口的17到32秒!
这不是vnpy的问题,另外vnpy的CTP接口库也是用C++写成的。

1 目前的CTA策略只有一个合约

class CtaTemplate(ABC):
    ... ...
    def __init__(
        self,
        cta_engine: Any,
        strategy_name: str,   
        vt_symbol: str,             # 合约代码
        setting: dict,
    ):

用户策略启动后,CTA策略引擎帮助订阅代码为vt_symbol合约的行情,用户策略收到tick推送之后,合成1分钟bar、N分钟bar乃至小时日线的bar。
策略在on_xmin_bar()函数中实现交易信号的计算并且完成交易逻辑。
我们可以知道,策略使用vt_symbol合约的行情指导了对vt_symbol合约的交易。

2 CTA策略的应该包含两个合约参数:指标合约和交易合约

2.1 何为交易合约

交易合约是指CTA策略要交易的合约,目前CTA策略里的合约参数就是交易合约,如果是期货的话,我们一般都选择主力合约来交易。

2.2 何为指标合约

指标合约是指CTA策略用来进行各种指标计算的合约,它可以和要交易的合约相同,也可以不同。可以是交易合约所在品种或者板块的指数,也可以是交易合约所在品种的指数或者主连合约,也可以选择如rqdata中的经过主力合约如rb888,rb999之类的主连合约,这样合约是通过行主力合约间的升水和贴水的方式得到的,没有主连合约那样的在主力合约去换时产生的巨大跳空,更加合理。

2.3 增加指标合约的好处

  1. 我们一般都选择主力合约,因为流动性好,在品种合约中占据主导地位。
  2. 主力合约会变化,到期之后需要即时换约
  3. 主力合约的K线通常较短,通常较短,长的7,8个月,短的2,3个月,不利于指标分析。一个期货合约上线通常不足一年,它成为主力合约的时间更短,它在非主力合约时期和成为主力合约之后的行情节奏有时候会判若两人!
  4. 主连合约的时间通常较长,可以长达数年,便于指标分析,但是不可以交易!
  5. 合约指数的时间通常也较长,可以长达数年而且连续平滑,便于指标分析,也是不可以交易!
  6. 如果增加了指标合约,分型行情的时候,使用指数或者主连合约来分析,交易的时候才有主力合约来交易,就可以实现自动换约,及时跟踪到最新的主力合约,有可以避免新近主力合约K线数量太少的问题,一举两得!

3 如何修改?

要做到这一点,需要修改的类包括:

3.1 修改CtaEngine:

对send_order等需要需要区分对策略的交易合约发送委托单,
策略初始化时需要同时订阅指标合约和交易合约的行情。

3.2 修改CtaTemplate:

加指标合约参数vt_symbol1,
指标计算时时有指标合约的行情数据进行进行
交易时使用交易合约进行交易

3.3 修改CTA的StrategyManager

使得在CTA策略在创建时可以输入指标合约

在CTP接口的交易接口的SPI中,有OnRtnOrder和onRtnTrade两个数据接口:

1 OnRtnOrder推送的数据结构CThostFtdcOrderField

struct CThostFtdcOrderField
{
    ///经纪公司代码
    TThostFtdcBrokerIDType BrokerID;
    ///投资者代码
    TThostFtdcInvestorIDType InvestorID;
    ///合约代码
    TThostFtdcInstrumentIDType InstrumentID;
    ///报单引用
    TThostFtdcOrderRefType OrderRef;
    ///用户代码
    TThostFtdcUserIDType UserID;
    ///报单价格条件
    TThostFtdcOrderPriceTypeType OrderPriceType;
    ///买卖方向
    TThostFtdcDirectionType Direction;
    ///组合开平标志
    TThostFtdcCombOffsetFlagType CombOffsetFlag;
    ///组合投机套保标志
    TThostFtdcCombHedgeFlagType CombHedgeFlag;
    ///价格
    TThostFtdcPriceType LimitPrice;
    ///数量
    TThostFtdcVolumeType VolumeTotalOriginal;
    ///有效期类型
    TThostFtdcTimeConditionType TimeCondition;
    ///GTD日期
    TThostFtdcDateType GTDDate;
    ///成交量类型
    TThostFtdcVolumeConditionType VolumeCondition;
    ///最小成交量
    TThostFtdcVolumeType MinVolume;
    ///触发条件
    TThostFtdcContingentConditionType ContingentCondition;
    ///止损价
    TThostFtdcPriceType StopPrice;
    ///强平原因
    TThostFtdcForceCloseReasonType ForceCloseReason;
    ///自动挂起标志
    TThostFtdcBoolType IsAutoSuspend;
    ///业务单元
    TThostFtdcBusinessUnitType BusinessUnit;
    ///请求编号
    TThostFtdcRequestIDType RequestID;
    ///本地报单编号
    TThostFtdcOrderLocalIDType OrderLocalID;
    ///交易所代码
    TThostFtdcExchangeIDType ExchangeID;
    ///会员代码
    TThostFtdcParticipantIDType ParticipantID;
    ///客户代码
    TThostFtdcClientIDType ClientID;
    ///合约在交易所的代码
    TThostFtdcExchangeInstIDType ExchangeInstID;
    ///交易所交易员代码
    TThostFtdcTraderIDType TraderID;
    ///安装编号
    TThostFtdcInstallIDType InstallID;
    ///报单提交状态
    TThostFtdcOrderSubmitStatusType OrderSubmitStatus;
    ///报单提示序号
    TThostFtdcSequenceNoType NotifySequence;
    ///交易日
    TThostFtdcDateType TradingDay;
    ///结算编号
    TThostFtdcSettlementIDType SettlementID;
    ///报单编号
    TThostFtdcOrderSysIDType OrderSysID;
    ///报单来源
    TThostFtdcOrderSourceType OrderSource;
    ///报单状态
    TThostFtdcOrderStatusType OrderStatus;
    ///报单类型
    TThostFtdcOrderTypeType OrderType;
    ///今成交数量
    TThostFtdcVolumeType VolumeTraded;
    ///剩余数量
    TThostFtdcVolumeType VolumeTotal;
    ///报单日期
    TThostFtdcDateType InsertDate;
    ///委托时间
    TThostFtdcTimeType InsertTime;
    ///激活时间
    TThostFtdcTimeType ActiveTime;
    ///挂起时间
    TThostFtdcTimeType SuspendTime;
    ///最后修改时间
    TThostFtdcTimeType UpdateTime;
    ///撤销时间
    TThostFtdcTimeType CancelTime;
    ///最后修改交易所交易员代码
    TThostFtdcTraderIDType ActiveTraderID;
    ///结算会员编号
    TThostFtdcParticipantIDType ClearingPartID;
    ///序号
    TThostFtdcSequenceNoType SequenceNo;
    ///前置编号
    TThostFtdcFrontIDType FrontID;
    ///会话编号
    TThostFtdcSessionIDType SessionID;
    ///用户端产品信息
    TThostFtdcProductInfoType UserProductInfo;
    ///状态信息
    TThostFtdcErrorMsgType StatusMsg;
    ///用户强评标志
    TThostFtdcBoolType UserForceClose;
    ///操作用户代码
    TThostFtdcUserIDType ActiveUserID;
    ///经纪公司报单编号
    TThostFtdcSequenceNoType BrokerOrderSeq;
    ///相关报单
    TThostFtdcOrderSysIDType RelativeOrderSysID;
    ///郑商所成交数量
    TThostFtdcVolumeType ZCETotalTradedVolume;
    ///互换单标志
    TThostFtdcBoolType IsSwapOrder;
    ///营业部编号
    TThostFtdcBranchIDType BranchID;
    ///投资单元代码
    TThostFtdcInvestUnitIDType InvestUnitID;
    ///资金账号
    TThostFtdcAccountIDType AccountID;
    ///币种代码
    TThostFtdcCurrencyIDType CurrencyID;
    ///IP地址
    TThostFtdcIPAddressType IPAddress;
    ///Mac地址
    TThostFtdcMacAddressType MacAddress;
};

2 OnRtnTrade推送的数据结构CThostFtdcTradeField

struct CThostFtdcTradeField
{
    ///经纪公司代码
    TThostFtdcBrokerIDType BrokerID;
    ///投资者代码
    TThostFtdcInvestorIDType InvestorID;
    ///合约代码
    TThostFtdcInstrumentIDType InstrumentID;
    ///报单引用
    TThostFtdcOrderRefType OrderRef;
    ///用户代码
    TThostFtdcUserIDType UserID;
    ///交易所代码
    TThostFtdcExchangeIDType ExchangeID;
    ///成交编号
    TThostFtdcTradeIDType TradeID;
    ///买卖方向
    TThostFtdcDirectionType Direction;
    ///报单编号
    TThostFtdcOrderSysIDType OrderSysID;
    ///会员代码
    TThostFtdcParticipantIDType ParticipantID;
    ///客户代码
    TThostFtdcClientIDType ClientID;
    ///交易角色
    TThostFtdcTradingRoleType TradingRole;
    ///合约在交易所的代码
    TThostFtdcExchangeInstIDType ExchangeInstID;
    ///开平标志
    TThostFtdcOffsetFlagType OffsetFlag;
    ///投机套保标志
    TThostFtdcHedgeFlagType HedgeFlag;
    ///价格
    TThostFtdcPriceType Price;
    ///数量
    TThostFtdcVolumeType Volume;
    ///成交时期
    TThostFtdcDateType TradeDate;
    ///成交时间
    TThostFtdcTimeType TradeTime;
    ///成交类型
    TThostFtdcTradeTypeType TradeType;
    ///成交价来源
    TThostFtdcPriceSourceType PriceSource;
    ///交易所交易员代码
    TThostFtdcTraderIDType TraderID;
    ///本地报单编号
    TThostFtdcOrderLocalIDType OrderLocalID;
    ///结算会员编号
    TThostFtdcParticipantIDType ClearingPartID;
    ///业务单元
    TThostFtdcBusinessUnitType BusinessUnit;
    ///序号
    TThostFtdcSequenceNoType SequenceNo;
    ///交易日
    TThostFtdcDateType TradingDay;
    ///结算编号
    TThostFtdcSettlementIDType SettlementID;
    ///经纪公司报单编号
    TThostFtdcSequenceNoType BrokerOrderSeq;
    ///成交来源
    TThostFtdcTradeSourceType TradeSource;
    ///投资单元代码
    TThostFtdcInvestUnitIDType InvestUnitID;
};

3 问题现象:

3.1 委托单报单日期错误

CThostFtdcOrderField中的有InsertDate(报单日期)字段和TradingDay(交易日),可是中信建投期货把InsertDate填入交易日,而不是委托单报单之时的日期。

3.2 成交单成交日期错误

CThostFtdcTradeField中的有TradeDate(成交日期)字段和TradingDay(交易日),可是中信建投期货把TradeDate填入交易日,而不是成交单成交之时的日期。

3.3 持仓信息在不同的官方软件显示错误

中信建投期货推荐的软件有数据客户端“金建投”和“快期V2”。
本人使用vnpy进行交易,分别使用金建投和快期V2,登录后看到的持仓信息,同一时间、同一品种、看到的持仓均价和浮动盈亏是不一样的,表现为:
1 金建投软件显示的持仓均价和浮动盈亏是对的
2 快期V2软件显示的持仓均价和浮动盈亏是错误
3 vnpy软件显示的持仓均价和浮动盈亏是错误,而且与快期V2显示结果相同

4 与中信建投技术人员反应问题

调试发现,a2101合约,只要是在21:00之后的夜盘交易的记录,委托单的InsertDate和成交单中的TradeDate,均被加上1日或者3日。
现在经过4天左右与中信建投技术人员的交流,他们拒绝承认自己的委托单的InsertDate和成交单中的TradeDate字段错了。
我把从CTP接收到的OrderData和TradeData数据打印给他们,中信建投技术人员说这是第三方表达,不认可vnpy。并且说InsertDate和TradeDate在夜盘的时候就应该是交易日,应该+1或者+3。
现在问题一直没有得到解决。

5 希望有关类似遭遇的朋友,积极发表看法。

请问是快期v2和vnpy在CTP接口处理错误了吗,还是中信建投搞错了?

已经开盘了就不要从CTP接口获取主力合约的的开盘价,从米筐接口get_price1分钟的就可以啦,夜盘是日内的第一个bar的open_price,白盘9:00的那一个bar的,无需订阅,简单。

你可能是没有连接CTP吧?

正确的步骤:
0、赋值ctp接口的设置:

ctp_setting = {
    "用户名": "xxxxx",
    "密码": "*****",
    "经纪商代码": "jjjjj",
    "交易服务器": "ip:port",
    "行情服务器": "ip:port",
    "产品名称": "name",
    "授权编码": "auth_code",
    "产品信息": ""
}

1、创建EventEngine类型的消息引擎event_engine
2、创建MainEngine类型的主引擎main_engine = MainEngine(event_engine)
3、main_engine.add_gateway(CtpGateway)
4、main_engine.connect(ctp_setting, "CTP")
5、创建ScriptEngine类型script_engine = ScriptEngine(main_engine,event_engine)
6、run(script_engine)

  1. 米筐的账户有tick权限的与没有权限的费用差别一个2~3万另一个是3000,而且即使有tick权限,主力合约也只有上一个交易日的收盘价,因为今天的还没有结束它不会更新这个数据。
  2. 主力合约都给你找到了,你找到主力合约的今日第一个分钟bar的开盘价,这个不就是你要的开盘价吗?

ahren wrote:

借鉴您的方法,直接从rqdata抓取主力合约列表以及相关open,close,high等数据,现在要实现高低开提示,需要获取当日open价格,好像rqdata get_price 是获取历史价格,那么怎么获取所有主力合约当日开盘价呢?比如今天是周六,get_latest_trading_date,在通过get_price对于有夜盘的品种无法获取到周五夜盘开盘价格

rqdata的主力合约列表是根据历史日行情比较后得到的,当日行情没有接受是无法得到的,不存在你所说的取主力合约当日open价格的问题。而且在一个月中一个品种的某个合约一旦成为主力合约,即使其后有段时间交易金额或者持仓量不再是最大,也不一定会不再是主力合约了,它会有一定的连续性。具体的可以见米筐的接口文档。
不同的软件或机构对主力合约的选择和延续规则可能不一样,例如文华的主力合约定义规则和米筐的可能是不一样的。但是大致是差不多的。他们的目的就是找到市场中参与方最多的、流动性最好的交易合约。

ahren wrote:

第一步骤,主要函数实现,放在那个文件夹下?

  1. 第一步骤的主要函数实现可以放在你认为合适的文件夹下,如:vnpy\usertools\myutility.py中
  2. 在你需要调用这些函数的文件的开头这样引入myutility.py的函数:
    from vnpy.usertools.myutility import get_contract_kinds,get_all_dominants
  3. 然后参照步骤二来使用get_contract_kinds(),get_all_dominants()函数,来获取当前市场正在交易的品种和这些品种中的主力合约。我这里是把它们print了一下,你怎么使用就是另外一回事了。
© 2015-2022 微信 18391752892
备案服务号:沪ICP备18006526号

沪公网安备 31011502017034号

【用户协议】
【隐私政策】
【免责条款】