在本文中,我们将从简单到复杂遍历所有阶段,并检查两种类型的交易系统:
- 同一图表上的所有指标(当然,在一个时间时间帧内);
- 与“三重选择”系统相结合。
本文中的 EA 仅适用于净持结算帐户。
关键要点
为了掌握交易系统背后的理念,有必要了解每个 Elder-Ray 元素:价格,EMA,每根柱线上的多头/空头力度指标的高点和低点,以及多头和空头的强度。
- 价格 — 关于资产价值的现行协约。 预期价格上涨的同时买入,在预期价格下跌的情况下卖出。 一笔成交仅在出现急切的买家和卖家时才能进行。
- EMA — 指数均线。 它反映出某一区间内资产价值的平均值。 例如,D1 上的 EMA(13) 是过去 13 天的资产平均价值。 为什么使用指数均线比简单移动平均线更好? A. Elder 在其书中第 4.2 节(“移动平均线”)中回答了这个问题。 简言之,与简单平均值相比,EMA 对趋势变化更敏感。
- 多头力度最大 显示给定柱线图上的最大多头力度。 当价格上涨时,多头赚取利润,因此直到价格达到最高价位前一直做多。 多头力度最大值是多头希望价格走向更高,但没有后续资金做多的时刻。
- 空头力度最小 显示给定柱线上的最大空头强度。 当价格下跌时,空头获利,因此,在价格达到最低价格之前做空。 空头力度最小是空头希望价格进一步下调,但已无力做到这一点的时刻。
- 多头力度 展示多头将价格提升到高于资产平均价值的能力。 通常,多头强度高于零。 如果它低于零,那么这意味着多头陷入恐慌,并即将失去动力。
- 空头力度 反映出空头将价格拉低到资产平均价值以下的能力。 通常,空头强度低于零。 如果它高于零,则意味着多头太强,且空头即将失去动力。
选项 1:单一图表上的所有指标
我们将在 D1 时间帧内探索期货和股票。 所有三个指标(多头力度,空头力度和 EMA)都放在一张图表上。 所有指标的均化周期为 13。
买入规则
- 趋势上升(根据 EMA);
- 空头力度 低于零但走高;
- BuyStop 挂单位于最近两天的最大值之上,而保护性止损位于最后的最小值以下。
CAT, Daily 买入信号
卖出规则
- 趋势走低(根据 EMA);
- 空头力度高于零但走低;
- SellStop 挂单位于最近两天的最小值之下,而保护性止损位于最后的最大值以上。
CAT, Daily 卖出信号
交易规则
观察图例 1 和图例 2,我们可以看到在“单一图表上的所有指标”选项中,买入和卖出规则是在稳定趋势回滚时触发的。 这样的利好时刻极少,特别是由于分析的时间帧为 D1。 所以,在选项“单一图表上的所有指标”中,我们需要分析大量金融产品以便在交易账户上提升交易频率。
D1 图表也有相当大的优势:分析 EMA 斜率,以及多头力度和空头力度指标每天只能执行一次 — 当新柱线出现时。 这正是 EA 的工作方式:针对每个指定的品种在 D1 上等待新柱线,然后查找可能的入场信号。 股票量化软件_赫兹股票量化软件
由于期货和股票仅在净持结算模式下交易,因此此时不能反向开仓(对冲),但我们可以增加同向持仓量。 EA 可以仅针对当前品种进行交易,或是针对存储在文本文件中的若干品种进行交易。 尽管当前品种的一切都很清晰,但选择多品种可能会出现以下问题:
- 我们需要指定一个市场内的大约一百个品种(例如,仅限证券);
- 我们需要指定来自不同市场的多个品种(例如,期货和证券)。
如何从一个市场中选择所有品种? 假设,"CAT" 品种位于 "Stock Markets\USA\NYSE/NASDAQ(SnP100)\CAT"股票量化软件_赫兹股票量化软件
假设此品种适合我们,我们希望从“\NYSE/NASDAQ(SnP100)\”分支中选择所有其它金融产品。 在这种情况下,我们可以执行以下操作:
- 打开该品种图表;
- 启动脚本(我们将其命名为 Symbols on the specified path.mq5)它将接收品种路径(在上例中,对于“CAT”品种,它是“Stock Markets\USA\NYSE/NASDAQ(SnP100)“),并将所获路径中的所有品种保存到文本文件中。 文本文件将保存到公用数据文件夹;
- 它只是在 EA 设置中设定文本文件名。
如果我们需要来自多个市场的品种,则在每个市场上运行脚本(品种列表保存到它的唯一文件中),并手工将两个文本文件合并。
股票量化软件_赫兹股票量化软件
组装 EA。 选项1:单一图表上的所有指标
Symbols on the specified path.mq5 — 获取含品种的文本文件的脚本。
注意: 仅当 "Everything is fine. There are no errors" 文字出现在智能系统栏时才保证脚本工作正常,并且所获含品种的文件可用于 EA 操作!
为了精简文件操作的代码,运用了 CFileTxt 类, 文本文件的操作通过 m_file_txt 执行 — CFileTxt 类对象。 脚本的操作分七步 执行:
//+------------------------------------------------------------------+ //| Symbols on the specified path.mq5 | //| 版权所有 © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "版权所有 © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.002" #property script_show_inputs //--- #include <Files\FileTxt.mqh> CFileTxt m_file_txt; // 文本文件对象 //--- 输入参数 input string InpFileName="Enter a unique name.txt"; // 文件名 //+------------------------------------------------------------------+ //| 脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { //--- 第一步 string current_path=""; if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path)) { Print("ERROR: SYMBOL_PATH"); return; } //--- 第二步 string sep_="\\"; // 分隔符 ushort u_sep_; // 分隔符的代码 string result_[]; // 保存字符串的数组 //--- 获取分隔符代码 u_sep_=StringGetCharacter(sep_,0); //--- 将字符串拆分为子字符串 int k_=StringSplit(current_path,u_sep_,result_); //--- 第三步 //--- 现在输出所有获得的字符串 if(k_>0) { current_path=""; for(int i=0;i<k_-1;i++) current_path=current_path+result_[i]+sep_; } //--- 第四步 string symbols_array[]; int symbols_total=SymbolsTotal(false); for(int i=0;i<symbols_total;i++) { string symbol_name=SymbolName(i,false); string symbol_path=""; if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path)) continue; if(StringFind(symbol_path,current_path,0)==-1) continue; int size=ArraySize(symbols_array); ArrayResize(symbols_array,size+1,10); symbols_array[size]=symbol_name]; } //--- 第五步 int size=ArraySize(symbols_array); if(size==0) { PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size); return; } PrintFormat("On path \"%s\" %d symbols",current_path,size); //--- 第六步 if(m_file_txt.Open(InpFileName,FILE_WRITE|FILE_COMMON)==INVALID_HANDLE) { PrintFormat("ERROR: \"%s\" file in the Data Folder Common folder is not created",InpFileName); return; } //--- 第七步 for(int i=0;i<size;i++) m_file_txt.WriteString(symbols_array[i]+"\r\n"); m_file_txt.Close(); Print("Everything is fine. There are no errors"); //--- } //+------------------------------------------------------------------+
脚本操作算法:
- 第一步: SYMBOL_PATH (品种树中的路径) 定义当前品种;
- 第二步: 以“\”分隔符将所获路径拆分为子串;
- 第三步: 舍弃最后一个子字符串并重新组合当前路径,因为最后字串包含品种名称;
- 第四步: 循环遍历所有可用品种; 如果品种树中的路径与当前品种相匹配,选择品名并将其添加至检测到品种数组中;
- 第五步: 检查检测到品种数组的大小;
- 第六步: 创建文件;
- 第七步: 将我们检测到的品种数组写入文件并关闭。
Elder-Ray 1 — 根据选项 1 进行交易的 EA (或若干个 EA),版本号为 1.xxx : 单一图表上的所有指标。
如何设置开仓量 — 最小手数可能不同
我们来进行一个简单的实验:检查期货和证券的最小手数:遍历与当前品种位于同一路径的所有品种(类似于 Symbols on the specified path.脚本), 但不必将品种保存到文件内部,而是显示最小手数的统计数据。
股票量化软件_赫兹股票量化软件— 用于显示品种组最小手数统计信息的脚本。 脚本以二维数组形式传递品种组和累积统计数据(minimal volume to close a deal 和 counter):
//--- 第四步 /* symbols_array[][2]: [*][minimal volume to close a deal] [*][counter] */
完整的脚本代码:
//+------------------------------------------------------------------+ //| Gets minimal volume.mq5 | //| 版权所有 © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "版权所有 © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.000" //+------------------------------------------------------------------+ //| 脚本程序开始函数 | //+------------------------------------------------------------------+ void OnStart() { //--- 第一步 string current_path=""; if(!SymbolInfoString(Symbol(),SYMBOL_PATH,current_path)) { Print("ERROR: SYMBOL_PATH"); return; } //--- 第二步 string sep_="\\"; // 分隔符 ushort u_sep_; // 分隔符的代码 string result_[]; // 保存字符串的数组 //--- 获取分隔符代码 u_sep_=StringGetCharacter(sep_,0); //--- 将字符串拆分为子字符串 int k_=StringSplit(current_path,u_sep_,result_); //--- 第三步 //--- 现在输出所有获得的字符串 if(k_>0) { current_path=""; for(int i=0;i<k_-1;i++) current_path=current_path+result_[i]+sep_; } //--- 第四步 /* symbols_array[][2]: [*][minimal volume to close a deal] [*][counter] */ double symbols_array[][2]; int symbols_total=SymbolsTotal(false); for(int i=0;i<symbols_total;i++) { string symbol_name=SymbolName(i,false); string symbol_path=""; if(!SymbolInfoString(symbol_name,SYMBOL_PATH,symbol_path)) continue; if(StringFind(symbol_path,current_path,0)==-1) continue; double min_volume=0.0; if(!SymbolInfoDouble(symbol_name,SYMBOL_VOLUME_MIN,min_volume)) continue; int size=ArrayRange(symbols_array,0); bool found=false; for(int j=0;j<size;j++) { if(symbols_array[j][0]==min_volume) { symbols_array[j][1]=symbols_array[j][1]+1; found=true; continue; } } if(!found) { ArrayResize(symbols_array,size+1,10); symbols_array[size][0]=min_volume; symbols_array[size][1]=1.0; } } //--- 第五步 int size=ArrayRange(symbols_array,0); if(size==0) { PrintFormat("ERROR: On path \"%s\" %d symbols",current_path,size); return; } //--- 第六步 for(int i=0;i<size;i++) PrintFormat("Minimal volume %.2f occurs %.1f times",symbols_array[i][0],symbols_array[i][1]); Print("Everything is fine. There are no errors"); //--- } //+------------------------------------------------------------------+
脚本操作算法:
- 第一步: SYMBOL_PATH (品种树中的路径) 定义当前品种;
- 第二步: 以“\”分隔符将所获路径拆分为子串;
- 第三步: 舍弃最后一个子字符串并重新组合当前路径,因为最后字串包含品种名称;
- 第四步: 循环遍历所有可用品种; 如果品种树中的路径与当前品种相匹配,选择品名的最小交易量并在品种数组中执行搜索。 如果此类值已存在,则计数器增加。 如果无此类值,则添加到数组,并将计数器设置为“1.0”;
- 第五步: 检查检测到品种数组的大小;
- 第六步: 显示统计。股票量化软件_赫兹股票量化软件
证券的启动结果:
Gets minimal volume (CAT,D1) Minimal volume 1.00 occurs 100.0 times
以及期货:
Gets minimal volume (RTSRIU8,D1) Minimal volume 1.00 occurs 77.0 times
- 在这两个市场上,手数大小是一样的 — 1.0。
因此,我们不要将系统过度复杂化,并设置最小手数为“1.0”。
可视化应用指标
当您在测试器中启动可视化测试时,您可以看到 EA 所应用的指标。 但若是在终端图表上启动 EA 时,不会显示指标。 在该交易系统中,我希望在图表上看到这些指标,以便对 EA 的工作进行可视化控制。 它看起来应该是这样的:
如您所见,此处我使用了所有指标的自定义颜色和线宽设置(当然,这是手工完成的)。 若要在终端图表上自动应用指标可视化,我们需要稍微重写移动平均线,多头力度和空头力度指标。 我已经在 自定义移动平均值输入颜色 代码中实现了类似的功能 — 指标颜色已包含在输入中:当从 EA 创建指标时,此输入参数可用。 现在,我们只需要开发三个类似的指标。
您可以从代码库中下载这些指标股票量化软件_赫兹股票量化软件。 将下载的指标放在根目录中 [数据文件夹]\MQL5\Indicators\。
Elder-Ray 1.001.mq5 — 应用指标可视化 您可以设置颜色和宽度。 它既可以在策略测试器中使用,也可在图表上启动 EA 时使用:
这是如何实现的?
股票量化软件_赫兹股票量化软件
指标的外观得以管理,周期可在输入中设定,而对于指标操作, 声明存储指标句柄的三个变量 (handle_iCustom_MA, handle_iCustom_Bulls and handle_iCustom_Bears)。
//+------------------------------------------------------------------+ //| Elder-Ray 1.mq5 | //| 版权所有 © 2018, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "版权所有 © 2018, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.000" //--- //--- enum ENUM_INPUT_SYMBOLS { INPUT_SYMBOLS_CURRENT=0, // 当前品种 INPUT_SYMBOLS_FILE=1, // 文本文件 }; //--- 输入参数 input ENUM_INPUT_SYMBOLS InpInputSymbol = INPUT_SYMBOLS_FILE; // 操作品种 ... input uint InpNumberMinLots = 1; // 最小手数 //--- 自定义移动平均线输入 input int Inp_MA_ma_period = 13; // MA: 均化周期 input int Inp_MA_ma_shift = 0; // MA: 水平位移 input ENUM_MA_METHOD Inp_MA_ma_method = MODE_EMA; // MA: 平滑类型 input ENUM_APPLIED_PRICE Inp_MA_applied_price = PRICE_CLOSE; // MA: 价格类型 input color Inp_MA_Color = clrChartreuse; // MA: 颜色 input int Inp_MA_Width = 2; // MA: 宽度 //--- 自定义多头力度输入 input int Inp_Bulls_ma_period = 13; // 多头力度: 均化周期 input color Inp_Bulls_Color = clrBlue; // 多头力度: 颜色 input int Inp_Bulls_Width = 2; // 多头力度: 宽度 //--- 自定义空头力度输入 input int Inp_Bears_ma_period = 13; // 空头力度: 均化周期 input color Inp_Bears_Color = clrRed; // 空头力度: 颜色 input int Inp_Bears_Width = 2; // 空头力度: 宽度 int handle_iCustom_MA; // 用于存储 iCustom 指标句柄的变量 int handle_iCustom_Bulls; // 用于存储 iCustom 指标句柄的变量 int handle_iCustom_Bears; // 用于存储 iCustom 指标句柄的变量 //+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit()
在 OnInit() 中,我们创建自定义指标的句柄(iCustom 已应用),并将创建的指标添加到图表中(ChartIndicatorAdd 已应用)。股票量化软件_赫兹股票量化软件
//+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- 创建指标 iCustom 的句柄 handle_iCustom_MA=iCustom(Symbol(),Period(),"Custom Moving Average Inputs", Inp_MA_ma_period, Inp_MA_ma_shift, Inp_MA_ma_method, Inp_MA_Color, Inp_MA_Width, Inp_MA_applied_price); //--- 如果未创建句柄 if(handle_iCustom_MA==INVALID_HANDLE) { //--- 告之失败并输出错误代码 PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Moving Average Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- 指标提前停止 return(INIT_FAILED); } //--- 创建指标 iCustom 的句柄 handle_iCustom_Bulls=iCustom(Symbol(),Period(),"Custom Bulls Power Inputs", Inp_Bulls_ma_period, Inp_Bulls_Color, Inp_Bulls_Width); //--- 如果未创建句柄 if(handle_iCustom_Bulls==INVALID_HANDLE) { //--- 告之失败并输出错误代码 PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bulls Power Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- 指标提前停止 return(INIT_FAILED); } //--- 创建指标 iCustom 的句柄 handle_iCustom_Bears=iCustom(Symbol(),Period(),"Custom Bears Power Inputs", Inp_Bears_ma_period, Inp_Bears_Color, Inp_Bears_Width); //--- 如果未创建句柄 if(handle_iCustom_Bears==INVALID_HANDLE) { //--- 告之失败并输出错误代码 PrintFormat("Failed to create handle of the iCustom indicator (\"Custom Bears Power Inputs\") for the symbol %s/%s, error code %d", Symbol(), EnumToString(Period()), GetLastError()); //--- 指标提前停止 return(INIT_FAILED); } ChartIndicatorAdd(0,0,handle_iCustom_MA); int windows_total=(int)ChartGetInteger(0,CHART_WINDOWS_TOTAL); ChartIndicatorAdd(0,windows_total,handle_iCustom_Bulls); ChartIndicatorAdd(0,windows_total+1,handle_iCustom_Bears); //--- return(INIT_SUCCEEDED); }