200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 股票量化交易软件:利用指标实时优化智能交易系统

股票量化交易软件:利用指标实时优化智能交易系统

时间:2019-07-31 03:09:22

相关推荐

股票量化交易软件:利用指标实时优化智能交易系统

每次赫兹股票量化在图表上启动智能交易系统时,我们都会面临选择最佳参数以便获得最大盈利能力的问题。 为了找到这些参数,我们会基于历史数据优化交易策略。 然而,如您所知,行情在不断变化。 随着时间的推移,所选参数逐渐失效。

所以,EA 需要重新优化。 这个周期过程持续不断。 每个用户都会自行选择重新优化的时刻。 但是否有可能令该过程自动化? 有哪些可能的解决方案? 也许,您已研究过利用 自定义配置文件 运行终端来对标准策略测试器进行程序化控制的可能性。 我愿意提供一种非常规方法,并将测试器功能分配给一款指标。

1. 思路

当然,指标绝非意指策略测试器。 那么它如何帮助赫兹股票量化优化 EA 呢? 我的思路是在一款指标当中实现 EA 操作的逻辑,并实时跟踪虚拟交易的盈利能力。 在策略测试器中执行优化时,我们会迭代指定参数执行一连串的测试。 类似策略测试器的通关测试,我们将同时启动若干个单一指标的实例,并指派不同的参数值。 当做出决策时,EA 调查所有启动的指标,并从中选择最佳执行参数。

您也许会问,为什么要重新发明轮子。 赫兹股票量化来分析一下这个决策的利弊。 毫无疑问,这种方法的主要优点是在近乎实时的条件下对 EA 进行优化。 第二个优点在于测试是基于您的经纪商的实时逐笔报价。 另一方面,实时测试有一个巨大的缺点,因为您必须要等待收集统计数据。 另一个优点是当行情随时前进时,测试指标只会重新计算当前的逐笔报价而非整个历史记录,而策略测器每次都从历史记录的开头运行。 这种方法可以在适当的时刻提供更快速的优化。 因此,我们几乎可以在每根柱线上进行优化。

这种方法的缺点则包括基于历史数据测试时缺乏逐笔报价。 当然,赫兹股票量化可以利用 CopyTicks 或 CopyTicksRange。 但是下载逐笔报价历史需要时间,且大量数据重新计算也需要计算资源和时间。 我们不要忘记我们用的是指标,在赫兹股票量化中单一品种的所有指标共处一个线程中运行。 因此,此处有另一个局限 — 太多指标可能导致终端减速。

为了最大限度地降低所述缺陷的风险,我们做出以下假设:

初始化测试指标时,历史记录按 М1 OHLC 价格计算。 在计算订单盈利/亏损时,首先检查止损,随后按最高价/最低价(取决于订单类型)检查止盈。

根据第 1 点,订单仅在蜡烛开盘时下单。

要减少测试指标的运行总数,请采用有意义的方法来选择其中使用的参数。 您可以在此处根据指标逻辑添加最小步幅和过滤参数。 例如,在使用 MACD 时,如果快速和慢速均线的参数范围重叠,则测试指标排除某一组参数重叠部分的运行,如慢速均线周期小于或等于快速均线周期的部分,这与 EA 操作逻辑相悖。 您还可以在区间内添加最小差值,初期丢弃大量假信号的选项。

2. 交易策略

为了测试该方法,赫兹股票量化采用基于三个标准指标 WPR、RSI 和 ADX 的简单策略。 当 WPR 向上超过超卖等级时,触发买入信号(等级 -80)。 RSI 不应处于超买区域(高于等级 70)。 由于两个指标都是振荡器,因此在横盘走势中采用它们是合理的。 ADX 指标检测是否存在横盘,等级不应超过 40。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

卖出则是该信号的镜像。 WPR 指标向下超过超买等级 -20,RSI 应超过等级 30 的超卖区域。 ADX 控制横盘的存在,就像买入时一样。

编辑切换为居中

添加图片注释,不超过 140 字(可选)

如前所述,出现信号之后在新蜡烛上执行入场。 离场则是通过固定止损或止盈来执行的。

出于亏损管理,同一时刻场内只保留不多于一笔的持仓。

3. 准备测试器指标

3.1. 虚拟交易类

在定义了交易策略之后,是时候开发一个测试指标了。 首先,赫兹股票量化需要准备在指标中跟踪的虚拟订单。 文章 [1] 已经描述了一个虚拟订单类。 我们可以利用这项工作,并补充一些小模块。 前面描述的类具有 Tick 方法,该方法使用当前的竞卖价和竞买价检查平仓的时刻。 此方法仅适用于在实时状态下工作,不适用于基于历史数据检查。 我们略微改动上述函数,在其中添加价格和点差参数。 执行操作后,该方法返回订单状态。 添加后的结果,该方法将得到以下形式。

bool CDeal::Tick(double price, int spread) { if(d_ClosePrice>0) return true; //--- switch(e_Direct) { case POSITION_TYPE_BUY: if(d_SL_Price>0 && d_SL_Price>=price) { d_ClosePrice=price; i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point); } else { if(d_TP_Price>0 && d_TP_Price<=price) { d_ClosePrice=price; i_Profit=(int)((d_ClosePrice-d_OpenPrice)/d_Point); } } break; case POSITION_TYPE_SELL: price+=spread*d_Point; if(d_SL_Price>0 && d_SL_Price<=price) { d_ClosePrice=price; i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point); } else { if(d_TP_Price>0 && d_TP_Price>=price) { d_ClosePrice=price; i_Profit=(int)((d_OpenPrice-d_ClosePrice)/d_Point); } } break; } return IsClosed(); }

在附件中可找到完整的类代码。

3.2. 指标编程

接下来,赫兹股票量化编写指标本身。 由于我们的测试指标以某种方式扮演 EA 的角色,因此其输入将类似于 EA 参数。 首先,设置测试区间,以及指标参数中的止损和止盈价位。 接着,指定应用指标的参数。 最后,指出统计数据的交易方向和平均周期。 有关每个参数的更多使用方法,会在指标代码中用到的地方详述。

input int HistoryDepth = 500; //历史数据深度(柱线) input int StopLoss = 200; //止损(点数) input int TakeProfit = 600; //止盈(点数) //--- RSI 指标参数 input int RSIPeriod = 28; //RSI 周期 input double RSITradeZone = 30; //超买/超卖区域大小 //--- WPR 指标参数 input int WPRPeriod = 7; // WPR 周期 input double WPRTradeZone = 30; //超买/超卖区域大小 //--- ADX 指标参数 input int ADXPeriod = 11; //ADX 周期 input int ADXLevel = 40; //ADX 横盘等级 //--- input int Direction = -1; //交易方向 "-1"-所有, "0"-买入, "1"-卖出 //--- input int AveragePeriod = 10; //均化周期

为了与 EA 进行计算和数据交换,请创建包含以下数据的九个指标缓冲区:

1. 盈利成交的概率。

double Buffer_Probability[];

2. 测试期间的盈利因子。

double Buffer_ProfitFactor[];

3. 止损和止盈等级。 可以通过创建匹配指标句柄的数组,并在 EA 中指定等级,或者在执行成交时通过其句柄请求指标参数来排除这两个缓冲区。 但是,目前的解决方案对我来说似乎是最简单的解决方案。

double Buffer_TakeProfit[]; double Buffer_StopLoss[];

4. 用于计算测试区间内执行的成交总数及其盈利数量的缓冲区。

double Buffer_ProfitCount[]; double Buffer_DealsCount[];

5. 以下两个缓冲区用于计算先前的数值,并且仅包含当前柱线的类似数据。

double Buffer_ProfitCountCurrent[]; double Buffer_DealsCountCurrent[];

6. 最后但并不仅限于,缓冲区向 EA 发送信号以便执行成交。

double Buffer_TradeSignal[];

除了指定的缓冲区外,还声明一个用于存储开仓成交的数组,一个用于记录最后一比成交时间的变量,用于存储指标句柄的变量,以及从全局变量块中的指标获取信息的数组。

CArrayObj Deals; datetime last_deal; int wpr_handle,rsi_handle,adx_handle; double rsi[],adx[],wpr[];

在 OnInit 函数的开头初始化指标。

int OnInit() { //--- 获取 RSI 指标句柄 rsi_handle=iRSI(Symbol(),PERIOD_CURRENT,RSIPeriod,PRICE_CLOSE); if(rsi_handle==INVALID_HANDLE) { Print("Test Indicator",": Failed to get RSI handle"); Print("Handle = ",rsi_handle," error = ",GetLastError()); return(INIT_FAILED); } //--- 获取 WPR 指标句柄 wpr_handle=iWPR(Symbol(),PERIOD_CURRENT,WPRPeriod); if(wpr_handle==INVALID_HANDLE) { Print("Test Indicator",": Failed to get WPR handle"); Print("Handle = ",wpr_handle," error = ",GetLastError()); return(INIT_FAILED); } //--- 获取 ADX 指标句柄 adx_handle=iADX(Symbol(),PERIOD_CURRENT,ADXPeriod); if(adx_handle==INVALID_HANDLE) { Print("Test Indicator",": Failed to get ADX handle"); Print("Handle = ",adx_handle," error = ",GetLastError()); return(INIT_FAILED); }

接下来,将指标缓冲区与动态数组关联起来。

//--- 指标缓存区映射 SetIndexBuffer(0,Buffer_Probability,INDICATOR_CALCULATIONS); SetIndexBuffer(1,Buffer_DealsCount,INDICATOR_CALCULATIONS); SetIndexBuffer(2,Buffer_TradeSignal,INDICATOR_CALCULATIONS); SetIndexBuffer(3,Buffer_ProfitFactor,INDICATOR_CALCULATIONS); SetIndexBuffer(4,Buffer_ProfitCount,INDICATOR_CALCULATIONS); SetIndexBuffer(5,Buffer_TakeProfit,INDICATOR_CALCULATIONS); SetIndexBuffer(6,Buffer_StopLoss,INDICATOR_CALCULATIONS); SetIndexBuffer(7,Buffer_DealsCountCurrent,INDICATOR_CALCULATIONS); SetIndexBuffer(8,Buffer_ProfitCountCurrent,INDICATOR_CALCULATIONS);

将时间序列属性分配给所有数组。

ArraySetAsSeries(Buffer_Probability,true); ArraySetAsSeries(Buffer_ProfitFactor,true); ArraySetAsSeries(Buffer_TradeSignal,true); ArraySetAsSeries(Buffer_DealsCount,true); ArraySetAsSeries(Buffer_ProfitCount,true); ArraySetAsSeries(Buffer_TakeProfit,true); ArraySetAsSeries(Buffer_StopLoss,true); ArraySetAsSeries(Buffer_DealsCountCurrent,true); ArraySetAsSeries(Buffer_ProfitCountCurrent,true); //--- ArraySetAsSeries(rsi,true); ArraySetAsSeries(wpr,true); ArraySetAsSeries(adx,true);

在函数结尾处,重置成交数组和最后一笔成交的日期,并将名称分配给我们的指标。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。