我们已研究过烛条分析技术:在第一篇文章中检查当前市场条件下的形态实际情况,并在第二篇文章中尝试拓展这些研究。 使用开发评估标准,我们研究、测试并比较了各种可能的形态组合。 为此目的,我们开发了一个自定义形态分析器应用程序,其中包含大量用于研究形态的设置。 然而,理论和研究只能提供信息和结论。 任务的逻辑延续是在实际条件下运用它们。
所以,本文的目的是创建一个自定义工具,可令用户能够接收和使用前面所讨论形态的整体信息数组。 我们将创建一个可令您在自己的指标、交易面板、智能交易系统中使用的函数库。
在继续创建函数库结构、类和连接之前,我们先来定义将要用到的数据。 也就是说,我们需要分离负责输入数据和提供结果的方法。 通用函数库结构将基于前面文章中开发的可视化解决方案 — 形态分析器。
我们从应用程序输入数据开始,这些数据会在测试形态时影响结果。
图例 1 在“设置”选项卡中输入参数。
区块 1. 此区块包括烛条类型列表,由现有和生成的形态构成。 每种类型都有其设置,您可以通过单击烛条可视化页面右上角的齿轮图标来查看。 烛条类型 1-5 只有一个设置,而锤子有两个。
区块 2. 权重系数。 有三个参数 К1,К2,К3 影响形态效率评估结果。
区块 3. 以点数为单位的趋势阈值。
区块 4. 测试所生成形态时用到的烛条。 在此处,我们需要顺序号或烛条索引。 使用这些数据,我们将能够获得高达三根烛条的任何尺寸、任何形态的信息。
区块 5. 形态中的烛条数量。 此设置仅适用于自定义形态。
然后我们查看“分析”选项卡和其中包含的输入参数。
图例 2 “分析”选项卡中的输入参数。
区块 6. 此区块包含用于形态分析的当前时间帧和数据样本范围的设置。
区块 7. 现有形态的名称。 它还有一个输入无法从应用程序编辑,但在访问形态并获取有关信息时则必需用到它。
我们在此列举可以从形态分析中获得的数据。 这是在类中创建正确的方法结构所必需的。
确定基本点后,我们继续创建函数库。 我们从创建一个包含所需枚举的文件 Enums.mqh 开始。
//+------------------------------------------------------------------+ //| Enums.mqh | //| 版权所有 2018, MetaQuotes 软件公司 | //| https://www.mql5.com/zh/users/alex2356 | //+------------------------------------------------------------------+ //+------------------------------------------------------------------+ //| 烛条类型 | //+------------------------------------------------------------------+ enum TYPE_CANDLESTICK { CAND_NONE, // 未定义 CAND_MARIBOZU, // Marubozu CAND_DOJI, // 十字星 CAND_SPIN_TOP, // 尖顶 CAND_HAMMER, // 锤子 CAND_INVERT_HAMMER, // 倒锤子 CAND_LONG, // 长体 CAND_SHORT // 短体 }; //+------------------------------------------------------------------+ //| 形态类型 | //+------------------------------------------------------------------+ enum TYPE_PATTERN { NONE, HUMMER, INVERT_HUMMER, HANDING_MAN, SHOOTING_STAR, ENGULFING_BULL, ENGULFING_BEAR, HARAMI_BULL, HARAMI_BEAR, HARAMI_CROSS_BULL, HARAMI_CROSS_BEAR, DOJI_STAR_BULL, DOJI_STAR_BEAR, PIERCING_LINE, DARK_CLOUD_COVER }; //+------------------------------------------------------------------+ //| 趋势类型 | //+------------------------------------------------------------------+ enum TYPE_TREND { UPPER, //上行趋势 DOWN, //下行趋势 FLAT //横盘 }; //+------------------------------------------------------------------+
在此,我们将检测用到的简单烛条类型列表,现有形态的类型以及趋势类型 - 数据是识别图表上现有形态所必需的。
之后我们要创建 Pattern.mqh 文件。 将在其中创建 CPattern 类,在其私有部分中,我们将声明上一节中所提参数的变量。 我们还需要 将文件与枚举联系起来。
//+------------------------------------------------------------------+ //| Pattern.mqh | //| 版权所有 2018, MetaQuotes 软件公司 | //| https://www.mql5.com/zh/users/alex2356 | //+------------------------------------------------------------------+ #include "Enums.mqh" //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CPattern { private: //--- 权重 double m_k1; double m_k2; double m_k3; //--- 以点数为单位的趋势阈值 int m_threshold_value; //--- 长体烛条设置系数 double m_long_coef; //--- 短体烛条设置系数 double m_short_coef; //--- 十字星烛条设置系数 double m_doji_coef; //--- Marubozu 烛条设置系数 double m_maribozu_coef; //--- 尖顶烛条设置系数 double m_spin_coef; //--- 锤子烛条设置系数 double m_hummer_coef1; double m_hummer_coef2; //--- 预设形态的采样范围 int m_range_total; //--- 判定趋势的周期 int m_trend_period; //--- 已发现形态 int m_found; //--- 形态发生 double m_coincidence; //--- 上行或下行走势的概率 double m_probability1; double m_probability2; //--- 效率 double m_efficiency1; double m_efficiency2; //--- 简单的烛条形态 struct CANDLE_STRUCTURE { double m_open; double m_high; double m_low; double m_close; // OHLC TYPE_TREND m_trend; // 趋势 bool m_bull; // 涨势烛条 double m_bodysize; // 实体大小 TYPE_CANDLESTICK m_type; // 烛条类型 }; //--- 形态效率评估属性 struct RATING_SET { int m_a_uptrend; int m_b_uptrend; int m_c_uptrend; int m_a_dntrend; int m_b_dntrend; int m_c_dntrend; };
正如上面的代码所示,我们的程序中加入了两个结构。 第一个结构 CANDLE_STRUCTURE 是判断图表上烛条类型所必需的。 请注意,此结构中使用了两种类型的趋势枚举:来自 Enums.mqh 文件的 TYPE_TREND 和 TYPE_CANDLESTICK,这在之前研究过,并为此结构而创建。 第二种结构 RATING_SET 存储形态出现后的价格走势的评估记录。 有关更多详细信息,请参阅第一篇文章。
现在考察该类的公有部分,它描述了自定义和检索输入参数值的方法,这些方法在函数库结构章节中已描述过。
public: CPattern(void); ~CPattern(void); //--- 设置并返回权重系数 void K1(const double k1) { m_k1=k1; } double K1(void) { return(m_k1); } void K2(const double k2) { m_k2=k2; } double K2(void) { return(m_k2); } void K3(const double k3) { m_k3=k3; } double K3(void) { return(m_k3); } //--- 设置并返回趋势阈值 void Threshold(const int threshold) { m_threshold_value=threshold; } int Threshold(void) { return(m_threshold_value); } //--- 设置并返回长体烛条设置系数 void Long_coef(const double long_coef) { m_long_coef=long_coef; } double Long_coef(void) { return(m_long_coef); } //--- 设置并返回短体烛条设置系数 void Short_coef(const double short_coef) { m_short_coef=short_coef; } double Short_coef(void) { return(m_short_coef); } //--- 设置并返回十字星烛条设置系数 void Doji_coef(const double doji_coef) { m_doji_coef=doji_coef; } double Doji_coef(void) { return(m_doji_coef); } //--- 设置并返回 marubozu 烛条设置系数 void Maribozu_coef(const double maribozu_coef) { m_maribozu_coef=maribozu_coef; } double Maribozu_coef(void) { return(m_maribozu_coef); } //--- 设置并返回尖顶烛条设置系数 void Spin_coef(const double spin_coef) { m_spin_coef=spin_coef; } double Spin_coef(void) { return(m_spin_coef); } //--- 设置并返回锤子烛条设置系数 void Hummer_coef1(const double hummer_coef1) { m_hummer_coef1=hummer_coef1; } void Hummer_coef2(const double hummer_coef2) { m_hummer_coef2=hummer_coef2; } double Hummer_coef1(void) { return(m_hummer_coef1); } double Hummer_coef2(void) { return(m_hummer_coef2); } //--- 设置并返回预设参数的采样范围 void Range(const int range_total) { m_range_total=range_total; } int Range(void) { return(m_range_total); } //--- 设置并返回计算趋势所需的烛条数量 void TrendPeriod(const int period) { m_trend_period=period; } int TrendPeriod(void) { return(m_trend_period); }
在类构造函数中,我们将在“设置”选项卡中描述应用程序中指定的默认参数。
//+------------------------------------------------------------------+ //| 构造函数 | //+------------------------------------------------------------------+ CPattern::CPattern(void) : m_k1(1), m_k2(0.5), m_k3(0.25), m_threshold_value(100), m_long_coef(1.3), m_short_coef(0.5), m_doji_coef(0.04), m_maribozu_coef(0.01), m_spin_coef(1), m_hummer_coef1(0.1), m_hummer_coef2(2), m_range_total(8000), m_trend_period(5) { }
CPattern 类公有部分的第二部分提供了处理所声明输入参数以及获取形态属性和特征的方法的描述。
我们依次详细了解。 了解操作算法非常重要,以便在创建指标、交易面板或智能交易系统时能够有效地运用它们。
TYPE_CANDLESTICK CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift);
参数
返回值
TYPE_CANDLESTICK 枚举中选定的烛条类型。
//+------------------------------------------------------------------+ //| 烛条类型 | //+------------------------------------------------------------------+ enum TYPE_CANDLESTICK { CAND_NONE, // 未定义 CAND_MARIBOZU, // Marubozu CAND_DOJI, // 十字星 CAND_SPIN_TOP, // 尖顶 CAND_HAMMER, // 锤子 CAND_INVERT_HAMMER, // 倒锤子 CAND_LONG, // 长体 CAND_SHORT // 短体 };
实现
//+------------------------------------------------------------------+ //| 返回所选烛条的类型 | //+------------------------------------------------------------------+ TYPE_CANDLESTICK CPattern::CandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,const int shift) { CANDLE_STRUCTURE res; if(GetCandleType(symbol,timeframe,res,shift)) return(res.m_type); return(CAND_NONE); } //+------------------------------------------------------------------+ //| 烛条类型识别 | //+------------------------------------------------------------------+ bool CPattern::GetCandleType(const string symbol,const ENUM_TIMEFRAMES timeframe,CANDLE_STRUCTURE &res,const int shift) { MqlRates rt[]; int aver_period=m_trend_period; double aver=0; SymbolSelect(symbol,true); int copied=CopyRates(symbol,timeframe,shift,aver_period+1,rt); //--- 获取前一根烛条的详细信息 if(copied<aver_period) return(false); //--- res.m_open=rt[aver_period].open; res.m_high=rt[aver_period].high; res.m_low=rt[aver_period].low; res.m_close=rt[aver_period].close; //--- 判断趋势方向 for(int i=0;i<aver_period;i++) aver+=rt[i].close; aver/=aver_period; if(aver<res.m_close) res.m_trend=UPPER; if(aver>res.m_close) res.m_trend=DOWN; if(aver==res.m_close) res.m_trend=FLAT; //--- 判断它是涨势还是跌势烛条 res.m_bull=res.m_open<res.m_close; //--- 获得烛条实体的绝对大小 res.m_bodysize=MathAbs(res.m_open-res.m_close); //--- 获取阴影的大小 double shade_low=res.m_close-res.m_low; double shade_high=res.m_high-res.m_open; if(res.m_bull) { shade_low=res.m_open-res.m_low; shade_high=res.m_high-res.m_close; } double HL=res.m_high-res.m_low; //--- 计算之前烛条的平均实体大小 double sum=0; for(int i=1; i<=aver_period; i++) sum=sum+MathAbs(rt[i].open-rt[i].close); sum=sum/aver_period; //--- 判断烛条类型 res.m_type=CAND_NONE; //--- 长体 if(res.m_bodysize>sum*m_long_coef) res.m_type=CAND_LONG; //--- 短体 if(res.m_bodysize<sum*m_short_coef) res.m_type=CAND_SHORT; //--- 十字星 if(res.m_bodysize<HL*m_doji_coef) res.m_type=CAND_DOJI; //--- marubozu if((shade_low<res.m_bodysize*m_maribozu_coef || shade_high<res.m_bodysize*m_maribozu_coef) && res.m_bodysize>0) res.m_type=CAND_MARIBOZU; //--- 锤子 if(shade_low>res.m_bodysize*m_hummer_coef2 && shade_high<res.m_bodysize*m_hummer_coef1) res.m_type=CAND_HAMMER; //--- 倒锤子 if(shade_low<res.m_bodysize*m_hummer_coef1 && shade_high>res.m_bodysize*m_hummer_coef2) res.m_type=CAND_INVERT_HAMMER; //--- 尖顶 if(res.m_type==CAND_SHORT && shade_low>res.m_bodysize*m_spin_coef && shade_high>res.m_bodysize*m_spin_coef) res.m_type=CAND_SPIN_TOP; //--- ArrayFree(rt); return(true); }
烛条识别方法 GetCandleType() 在公有 GetCandleType() 方法里使用。 GetCandleType() 是私有方法。 它的参数包括当前品种、时间帧和烛条编号,以及指向结构的指针。 基于这些参数执行形态计算和识别。
利用所选蜡烛识别形态类型。 它有 5 个重载方法,因为参数可以是 TYPE_PATTERN 枚举中的现有形态,也可以是由一根、两根或三根烛条组成的生成形态。 参数也可以是 TYPE_PATTERN 枚举中的形态数组。
//--- 识别形态类型 bool PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,int shift); bool PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,const int shift); bool PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,const int shift); bool PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,const int shift); //--- 识别到形态集合 bool PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift);
参数
指向 TYPE_PATTERN 列表中现有形态数组的指针。
//+------------------------------------------------------------------+ //| 形态类型 | //+------------------------------------------------------------------+ enum TYPE_PATTERN { NONE, HUMMER, INVERT_HUMMER, HANDING_MAN, SHOOTING_STAR, ENGULFING_BULL, ENGULFING_BEAR, HARAMI_BULL, HARAMI_BEAR, HARAMI_CROSS_BULL, HARAMI_CROSS_BEAR, DOJI_STAR_BULL, DOJI_STAR_BEAR, PIERCING_LINE, DARK_CLOUD_COVER };
返回值
一个布尔值。
实现
由于 PatternType 方法有 5 种类型的实现,我们将使用各种参数分别对其进行分析。 第一种从 TYPE_PATTERN 枚举中搜索现有形态。 如下所示,这是利用私有方法 CheckPattern 完成的。
//+------------------------------------------------------------------+ //| 识别预定义的形态 | //+------------------------------------------------------------------+ bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,const int shift) { if(CheckPattern(symbol,timeframe,shift)==pattern) return(true); return(false); } //+------------------------------------------------------------------+ //| 检查并返回形态类型 | //+------------------------------------------------------------------+ TYPE_PATTERN CPattern::CheckPattern(const string symbol,const ENUM_TIMEFRAMES timeframe,int shift) { CANDLE_STRUCTURE cand1,cand2; TYPE_PATTERN pattern=NONE; ZeroMemory(cand1); ZeroMemory(cand2); GetCandleType(symbol,timeframe,cand2,shift); // 之前的烛条 GetCandleType(symbol,timeframe,cand1,shift-1); // 当前烛条 //--- 倒锤子,涨势模型 if(cand2.m_trend==DOWN && // 检查趋势方向 cand2.m_type==CAND_INVERT_HAMMER) // 检查“倒锤子” pattern=INVERT_HUMMER; //--- 上吊线,跌势 else if(cand2.m_trend==UPPER && // 检查趋势方向 cand2.m_type==CAND_HAMMER) // 检查”锤子“ pattern=HANDING_MAN; //--- 锤子,涨势模型 else if(cand2.m_trend==DOWN && // 检查趋势方向 cand2.m_type==CAND_HAMMER) // 检查”锤子“ pattern=HUMMER; //--- 射击之星,跌势模型 else if(cand1.m_trend==UPPER && cand2.m_trend==UPPER && // 检查趋势方向 cand2.m_type==CAND_INVERT_HAMMER && cand1.m_close<=cand2.m_open) // 检查 "倒锤子" pattern=SHOOTING_STAR; //--- 吞噬,涨势模型 else if(cand1.m_trend==DOWN && cand1.m_bull && cand2.m_trend==DOWN && !cand2.m_bull && // 检查趋势方向和烛条方向 cand1.m_bodysize>cand2.m_bodysize && cand1.m_close>=cand2.m_open && cand1.m_open<cand2.m_close) pattern=ENGULFING_BULL; //--- 吞噬,跌势模型 else if(cand1.m_trend==UPPER && cand1.m_bull && cand2.m_trend==UPPER && !cand2.m_bull && // 检查趋势方向和烛台方向 cand1.m_bodysize<cand2.m_bodysize && cand1.m_close<=cand2.m_open && cand1.m_open>cand2.m_close) pattern=ENGULFING_BEAR; //--- Harami 交叉,涨势 else if(cand2.m_trend==DOWN && !cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 检查“长体”的第一根烛条和十字星烛条 cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // 十字星在第一根烛条实体内 pattern=HARAMI_CROSS_BULL; //--- Harami 交叉,跌势模型 else if(cand2.m_trend==UPPER && cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 检查“长体”烛条和十字星烛条 cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // 十字星在第一根烛条实体内 pattern=HARAMI_CROSS_BEAR; //--- Harami,涨势 else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 检查“长体”的第一根烛条 cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // 第二根蜡烛不是十字星,第一根蜡烛实体大于第二根蜡烛实体 cand1.m_close<cand2.m_open && cand1.m_open>=cand2.m_close) // 第二根烛条实体位于第一根烛条实体内 pattern=HARAMI_BULL; //--- Harami, 跌势 else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 检查“长体”的第一根烛条 cand1.m_type!=CAND_DOJI && cand1.m_bodysize<cand2.m_bodysize && // 第二根蜡烛不是十字星,第一根蜡烛实体大于第二根蜡烛实体 cand1.m_close>cand2.m_open && cand1.m_open<=cand2.m_close) // 第二根烛条实体位于第一根烛条实体内 pattern=HARAMI_BEAR; //--- 十字星,涨势 else if(cand1.m_trend==DOWN && !cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 检查“长体”烛条和第二根十字星 cand1.m_close<=cand2.m_open) // 十字星开盘价低于或等于第一根蜡烛收盘价 pattern=DOJI_STAR_BULL; //--- 十字星,跌势 else if(cand1.m_trend==UPPER && cand2.m_bull && // 检查趋势方向和烛条方向 (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && cand1.m_type==CAND_DOJI && // 检查“长体”烛条和第二根十字星 cand1.m_open>=cand2.m_close) //十字星开盘价高于或等于第一根蜡烛收盘价 pattern=DOJI_STAR_BEAR; //--- 穿孔,涨势模型 else if(cand1.m_trend==DOWN && cand1.m_bull && !cand2.m_bull && // 检查趋势方向和烛条方向 (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 检查“长体”烛条 cand1.m_close>(cand2.m_close+cand2.m_open)/2 && // 第二根蜡烛收盘价位于第一根烛条的中间位置 cand2.m_open>cand1.m_close && cand2.m_close>=cand1.m_open) pattern=PIERCING_LINE; //--- 乌云盖顶,跌势 else if(cand1.m_trend==UPPER && !cand1.m_bull && cand2.m_bull && // 检查趋势方向和烛条方向 (cand1.m_type==CAND_LONG || cand1.m_type==CAND_MARIBOZU) && (cand2.m_type==CAND_LONG || cand2.m_type==CAND_MARIBOZU) && // 检查“长体”烛条 cand1.m_close<(cand2.m_close+cand2.m_open)/2 && // 第二根蜡烛收盘价低于第一根烛条实体的中间位置 cand1.m_close<cand2.m_open && cand2.m_close<=cand1.m_open) pattern=DARK_CLOUD_COVER; return(pattern); } //+------------------------------------------------------------------+
下一种 PatternType 方法与前一种方法的不同之处在于,所传递参数由搜索形态的数组替代了形态类型:
//+------------------------------------------------------------------+ //| 识别形态数组 | //+------------------------------------------------------------------+ bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN &pattern[],int shift) { for(int i=0;i<ArraySize(pattern);i++) { if(CheckPattern(symbol,timeframe,shift)==pattern[i]) return(true); } return(false); }
接下来,我们研究 PatternType 方法的实现,处理由简单烛条类型生成的形态。 这些形态有三种类型:由一个根、两根或三根烛条组成。 我们逐一考察它们:
//+------------------------------------------------------------------+ //| 按照烛条索引识别形态 | //+------------------------------------------------------------------+ bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,int shift) { //--- 验证烛条索引 if(index<0 || index>11) return(false); //--- CANDLE_STRUCTURE cand,cur_cand; RATING_SET ratings; ZeroMemory(cand); IndexToPatternType(cand,index); //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,cur_cand,shift); // 当前烛条 //--- if(cur_cand.m_type==cand.m_type && cur_cand.m_bull==cand.m_bull) return(true); return(false); }
实现搜索一根烛条形态的方法,这与 CandleType() 方法非常相似,尽管传递的参数类型和范围有所不同。 注意以前没有使用过的私有方法 IndextoPatternType():
//--- 将烛条索引转换为其类型 void IndexToPatternType(CANDLE_STRUCTURE &res,int index);
它将简单类型烛条的索引转换为其类型,并将其传递给指定的结构。
以下是两根烛条形态的方法:
//+------------------------------------------------------------------+ //| 按照烛条索引识别形态 | //+------------------------------------------------------------------+ bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int shift) { //--- 验证烛条索引 if(index1<0 || index1>11 || index2<0 || index2>11) return(false); //--- CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand; RATING_SET ratings; ZeroMemory(cand1); ZeroMemory(cand2); IndexToPatternType(cand1,index1); IndexToPatternType(cand2,index2); //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,prev_cand,shift+1); // 之前的烛条 GetCandleType(symbol,timeframe,cur_cand,shift); // 当前烛条 //--- if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull) return(true); return(false); }
代码实现与前一个非常相似。 不过,请注意在选择烛条索引进行分析时应考虑以下特征:由于该形态由两根烛条组成,因此烛条 'index1' 将按 'shift' 偏移,而对于 index2 - 则按 'shift+1'。 同样的特性涉及三根烛条形态的方法实现:
//+------------------------------------------------------------------+ //| 按照烛条索引识别形态 | //+------------------------------------------------------------------+ bool CPattern::PatternType(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,int shift) { CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2; RATING_SET ratings; //--- ZeroMemory(cand1); ZeroMemory(cand2); ZeroMemory(cand3); //--- IndexToPatternType(cand1,index1); IndexToPatternType(cand2,index2); IndexToPatternType(cand3,index3); //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,prev_cand2,shift+2); // 之前的烛条 GetCandleType(symbol,timeframe,prev_cand,shift+1); // 之前的烛条 GetCandleType(symbol,timeframe,cur_cand,shift); // 当前烛条 //--- if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull) return(true); return(false); }
返回指定类型的已发现形态的数量。 对于现有形态 TYPE_PATTERN,它有 3 个方法重载,以及由 1-3 个简单烛条类型组成的生成形态。
//--- 返回指定类型的已发现形态的数量 int Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern); int Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index); int Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2); int Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);
参数
返回值
已发现的指定类型的形态数量。
实现
这种方法的实现非常简单。 私有方法 PatternStat() 负责收集统计信息相关的主要操作。
//+------------------------------------------------------------------+ //| 返回指定类型的已发现形态的数量 | //+------------------------------------------------------------------+ int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern) { PatternStat(symbol,timeframe,pattern); return(m_found); } //+------------------------------------------------------------------+ //| 返回指定类型的已发现形态的数量 | //+------------------------------------------------------------------+ int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1) { PatternStat(symbol,timeframe,index1); return(m_found); } //+------------------------------------------------------------------+ //| 返回指定类型的已发现形态的数量 | //+------------------------------------------------------------------+ int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2) { PatternStat(symbol,timeframe,index1,index2); return(m_found); } //+------------------------------------------------------------------+ //| 返回指定类型的已发现形态的数量 | //+------------------------------------------------------------------+ int CPattern::Found(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3) { PatternStat(symbol,timeframe,index1,index2,index3); return(m_found); }
PatternStat() 方法有两种类型:用于现有形态,和生成形态。 我们来详细研究它们。 第一个用于 TYPE_PATTERN 枚举中的形态:
//+------------------------------------------------------------------+ //| 获取有关给定形态的统计信息 | //+------------------------------------------------------------------+ CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern) { //--- int pattern_counter=0; //--- RATING_SET pattern_coef={0,0,0,0,0,0}; //--- for(int i=m_range_total;i>4;i--) { if(CheckPattern(symbol,timeframe,i)==pattern) { pattern_counter++; if(pattern==HUMMER || pattern==INVERT_HUMMER || pattern==HANDING_MAN) GetCategory(symbol,timeframe,pattern_coef,i-3); else GetCategory(symbol,timeframe,pattern_coef,i-4); } } //--- CoefCalculation(pattern_coef,pattern_counter); }
第二个用于由简单烛条类型的索引组成的生成形态。
//+------------------------------------------------------------------+ //| 获取有关给定形态的统计信息 | //+------------------------------------------------------------------+ void CPattern::PatternStat(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2=0,int index3=0) { CANDLE_STRUCTURE cand1,cand2,cand3,cur_cand,prev_cand,prev_cand2; RATING_SET rating={0,0,0,0,0,0}; int pattern_total=0,pattern_size=1; //--- ZeroMemory(cand1); ZeroMemory(cand2); ZeroMemory(cand3); ZeroMemory(cur_cand); ZeroMemory(prev_cand); ZeroMemory(prev_cand2); //--- if(index2>0) pattern_size=2; if(index3>0) pattern_size=3; //--- if(pattern_size==1) IndexToPatternType(cand1,index1); else if(pattern_size==2) { IndexToPatternType(cand1,index1); IndexToPatternType(cand2,index2); } else if(pattern_size==3) { IndexToPatternType(cand1,index1); IndexToPatternType(cand2,index2); IndexToPatternType(cand3,index3); } //--- for(int i=m_range_total;i>5;i--) { if(pattern_size==1) { //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,cur_cand,i); // 当前烛条 //--- if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull) { pattern_total++; GetCategory(symbol,timeframe,rating,i-3); } } else if(pattern_size==2) { //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,prev_cand,i); // 之前的烛条 GetCandleType(symbol,timeframe,cur_cand,i-1); // 当前烛条 //--- if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull) { pattern_total++; GetCategory(symbol,timeframe,rating,i-4); } } else if(pattern_size==3) { //--- 获取当前的烛条类型 GetCandleType(symbol,timeframe,prev_cand2,i); // 之前的烛条 GetCandleType(symbol,timeframe,prev_cand,i-1); // 之前的烛条 GetCandleType(symbol,timeframe,cur_cand,i-2); // 当前烛条 //--- if(cur_cand.m_type==cand1.m_type && cur_cand.m_bull==cand1.m_bull && prev_cand.m_type==cand2.m_type && prev_cand.m_bull==cand2.m_bull && prev_cand2.m_type==cand3.m_type && prev_cand2.m_bull==cand3.m_bull) { pattern_total++; GetCategory(symbol,timeframe,rating,i-5); } } } //--- CoefCalculation(rating,pattern_total); }
这两个方法的实现均包含一个新方法。 这是私有方法 CoefCalculation():
//--- 计算系数 bool CoefCalculation(RATING_SET &rate,int found);
它处理搜索和测试形态时获得的所有结果。 它的参数包含一个指向 RATING_SET 结构的指针,该结构负责收集有关形态效率测试结果,和已发现形态数量的数据。 所分析形态的所有其他参数和属性在 CoefCalculation() 方法中计算。
//+------------------------------------------------------------------+ //| 计算效率评估系数 | //+------------------------------------------------------------------+ bool CPattern::CoefCalculation(RATING_SET &rate,int found) { int sum1=0,sum2=0; sum1=rate.m_a_uptrend+rate.m_b_uptrend+rate.m_c_uptrend; sum2=rate.m_a_dntrend+rate.m_b_dntrend+rate.m_c_dntrend; //--- m_probability1=(found>0)?NormalizeDouble((double)sum1/found*100,2):0; m_probability2=(found>0)?NormalizeDouble((double)sum2/found*100,2):0; m_efficiency1=(found>0)?NormalizeDouble((m_k1*rate.m_a_uptrend+m_k2*rate.m_b_uptrend+m_k3*rate.m_c_uptrend)/found,3):0; m_efficiency2=(found>0)?NormalizeDouble((m_k1*rate.m_a_dntrend+m_k2*rate.m_b_dntrend+m_k3*rate.m_c_dntrend)/found,3):0; m_found=found; m_coincidence=((double)found/m_range_total*100); return(true); }
返回形态发生的频率。 对于现有形态 TYPE_PATTERN,它有 3 个方法重载,以及由 1-3 个简单烛条类型组成的生成形态。
//--- 返回形态出现的频率 double Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern); double Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index); double Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2); double Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3);
参数
返回值
以百分比表示的形态出现频率。
实现
与 Found() 方法类似。 唯一的区别是它返回 m_coincidence 变量的值。
//+------------------------------------------------------------------+ //| 返回形态出现的频率 | //+------------------------------------------------------------------+ double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern) { PatternStat(symbol,timeframe,pattern); return(m_coincidence); } //+------------------------------------------------------------------+ //| 返回形态出现的频率 | //+------------------------------------------------------------------+ double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1) { PatternStat(symbol,timeframe,index1); return(m_coincidence); } //+------------------------------------------------------------------+ //| 返回形态出现的频率 | //+------------------------------------------------------------------+ double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2) { PatternStat(symbol,timeframe,index1,index2); return(m_coincidence); } //+------------------------------------------------------------------+ //| 返回形态出现的频率 | //+------------------------------------------------------------------+ double CPattern::Coincidence(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3) { PatternStat(symbol,timeframe,index1,index2,index3); return(m_coincidence); }
返回给定形态出现后的走势概率百分比。 对于现有形态 TYPE_PATTERN,它有 3 个方法重载,以及由 1-3 个简单烛条类型组成的生成形态。
//--- 返回给定形态出现后的走势概率 double Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend); double Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend); double Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend); double Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);
参数
//+------------------------------------------------------------------+ //| 趋势类型 | //+------------------------------------------------------------------+ enum TYPE_TREND { UPPER, //上行趋势 DOWN, //下行趋势 FLAT //横盘 }; //+------------------------------------------------------------------+
返回值
给定形态出现后的走势概率百分比。
实现
与 Found() 方法类似。 唯一的区别是它返回 m_probability1 或 m_probability2 变量的值,具体取决于所选的趋势类型。
//+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend) { PatternStat(symbol,timeframe,pattern); if(trend==UPPER) return(m_probability1); if(trend==DOWN) return(m_probability2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1); if(trend==UPPER) return(m_probability1); if(trend==DOWN) return(m_probability2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1,index2); if(trend==UPPER) return(m_probability1); if(trend==DOWN) return(m_probability2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Probability(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1,index2,index3); if(trend==UPPER) return(m_probability1); if(trend==DOWN) return(m_probability2); return(0); }
返回形态效率系数。 对于现有形态 TYPE_PATTERN,它有 3 个方法重载,以及由 1-3 个简单烛条类型组成的生成形态。
//--- 返回形态效率系数 double Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend); double Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index,TYPE_TREND trend); double Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend); double Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend);
参数
//+------------------------------------------------------------------+ //| 趋势类型 | //+------------------------------------------------------------------+ enum TYPE_TREND { UPPER, //上行趋势 DOWN, //下行趋势 FLAT //横盘 }; //+------------------------------------------------------------------+
返回值
形态效率系数。
实现
与 Found() 方法类似。 唯一的区别是它返回 m_efficiency1 或 m_efficiency2 变量的值,具体取决于所选的趋势类型。
//+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,TYPE_PATTERN pattern,TYPE_TREND trend) { PatternStat(symbol,timeframe,pattern); if(trend==UPPER) return(m_efficiency1); if(trend==DOWN) return(m_efficiency2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1); if(trend==UPPER) return(m_efficiency1); if(trend==DOWN) return(m_efficiency2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1,index2); if(trend==UPPER) return(m_efficiency1); if(trend==DOWN) return(m_efficiency2); return(0); } //+------------------------------------------------------------------+ //| 返回给定形态出现后的走势概率 | //+------------------------------------------------------------------+ double CPattern::Efficiency(const string symbol,const ENUM_TIMEFRAMES timeframe,int index1,int index2,int index3,TYPE_TREND trend) { PatternStat(symbol,timeframe,index1,index2,index3); if(trend==UPPER) return(m_efficiency1); if(trend==DOWN) return(m_efficiency2); return(0); }
在考察了处理形态的工具之后,我们实现两个指标和一个智能交易系统来演示函数库的使用示例。
我们从指标开始,该指标在图表上显示 TYPE_CANDLESTICK 枚举中所选类型的烛条。 在 Indicators 文件夹中创建 Pattern 文件夹。 在此文件夹中,创建指标文件 CandleDetector.mq5。 我们关联 Pattern.mqh 函数库,用于处理形态操作并设置未来指标的初始属性:
//+------------------------------------------------------------------+ //| CandleDetector.mq5 | //| 版权所有 2019, MetaQuotes 软件公司 | //| https://www.mql5.com/zh/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "版权所有 2019, MetaQuotes 软件公司" #property link "https://www.mql5.com/zh/users/alex2356" #property version "1.00" #property indicator_chart_window #property indicator_buffers 1 #property indicator_plots 1 #include <Pattern/Pattern.mqh> //+----------------------------------------------+ //| 指标绘图参数 | //+----------------------------------------------+ //---- 将指标绘制为标签 #property indicator_type1 DRAW_ARROW //---- 指标线宽度 #property indicator_width1 1
The next step is to determine key settings which will affect the display of this or that candlestick type.
//+----------------------------------------------+ //| 指标输入参数 | //+----------------------------------------------+ input TYPE_CANDLESTICK CandleType=1; // 烛条类型 input color LabelColor=clrCrimson; input double LongCoef=1.3; input double ShortCoef=0.5; input double DojiCoef=0.04; input double MaribozuCoef=0.01; input double SpinCoef=1; input double HummerCoef1=0.1; input double HummerCoef2=2; input int TrendPeriod=5;
接下来,在初始化中,配置指标外观,并确定输入参数中用于搜索的所有数值。
//+------------------------------------------------------------------+ //| 自定义指标初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //---- 初始化计算开始的数据变量 min_rates_total=TrendPeriod+1; //---- 定义指标数值的显示精度 IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //---- 将动态数组 Signal[] 设置为指标缓冲区 SetIndexBuffer(0,Signal,INDICATOR_DATA); //---- 指标 1 的画图开始偏移 PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total); //---- 按时间顺序设置缓冲区中元素的索引 ArraySetAsSeries(Signal,true); //---- 设置在图表上不可见的指标值 PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); //---- 指标品种 PlotIndexSetInteger(0,PLOT_ARROW,108); //--- PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor); //---- Pat.Long_coef(LongCoef); Pat.Short_coef(ShortCoef); Pat.Doji_coef(DojiCoef); Pat.Maribozu_coef(MaribozuCoef); Pat.Spin_coef(SpinCoef); Pat.Hummer_coef1(HummerCoef1); Pat.Hummer_coef2(HummerCoef2); Pat.TrendPeriod(TrendPeriod); return(INIT_SUCCEEDED); }
注意 CandleType() 方法 — 它用于在图表上搜索选定的烛条类型。
//+------------------------------------------------------------------+ //| 自定义指标迭代函数 | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //---- 检查计算是否有足够的柱线 if(rates_total<min_rates_total) return(0); //---- 声明局部变量 int limit,bar; //---- 按时间序列设置数组中元素的索引 ArraySetAsSeries(low,true); //---- 重新计算周期自 “第一根” 柱线编号开始计算 if(prev_calculated>rates_total || prev_calculated<=0) // 检查指标是否为首次计算 limit=rates_total-min_rates_total; // 计算所有装修按的起始索引 else limit=rates_total-prev_calculated; // 计算新柱线的起始索引 //---- 指标的主要计算循环 for(bar=limit; bar>=0; bar--) { Signal[bar]=0.0; if(Pat.CandleType(Symbol(),PERIOD_CURRENT,bar)==CandleType) Signal[bar]=low[bar]-200*_Point; } return(rates_total); } //+------------------------------------------------------------------+
指标操作示例如图例 3 所示(搜索长体烛条)。
图例 3 CandleDetector 指标操作示例。
第二个指标将从 TYPE_PATTERN 枚举中搜索指定的形态。 实现与前一个非常相似。 此代码的不同之处在于 计算部分里使用的方法 和 一个输入参数。
//+----------------------------------------------+ //| 指标输入参数 | //+----------------------------------------------+ input TYPE_PATTERN PatternType=1; // 形态类型 input color LabelColor=clrCrimson; input double LongCoef=1.3; input double ShortCoef=0.5; input double DojiCoef=0.04; input double MaribozuCoef=0.01; input double SpinCoef=1; input double HummerCoef1=0.1; input double HummerCoef2=2; input int TrendPeriod=5; //--- CPattern Pat; double Signal[]; //---- 为数据计算开始声明整数变量 int min_rates_total; //+------------------------------------------------------------------+ //| 自定义指标初始化函数 | //+------------------------------------------------------------------+ void OnInit() { //---- 初始化计算开始的数据变量 min_rates_total=TrendPeriod+2; //---- 定义指标数值的显示精度 IndicatorSetInteger(INDICATOR_DIGITS,_Digits); //---- 将 SignUp[] 动态数组设置为指标缓冲区 SetIndexBuffer(0,Signal,INDICATOR_DATA); //---- 指标 1 的画图开始偏移 PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,min_rates_total); //---- 按时间顺序设置缓冲区中元素的索引 ArraySetAsSeries(Signal,true); //---- 设置在图表上不可见的指标值 PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,EMPTY_VALUE); //---- 指标品种 PlotIndexSetInteger(0,PLOT_ARROW,108); //--- PlotIndexSetInteger(0,PLOT_LINE_COLOR,LabelColor); //---- Pat.Long_coef(LongCoef); Pat.Short_coef(ShortCoef); Pat.Doji_coef(DojiCoef); Pat.Maribozu_coef(MaribozuCoef); Pat.Spin_coef(SpinCoef); Pat.Hummer_coef1(HummerCoef1); Pat.Hummer_coef2(HummerCoef2); Pat.TrendPeriod(TrendPeriod); } //+------------------------------------------------------------------+ //| 自定义指标迭代函数 | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { //---- 检查计算是否有足够的柱线 if(rates_total<min_rates_total) return(0); //---- 声明局部变量 int limit,bar; //---- 按时间序列设置数组中元素的索引 ArraySetAsSeries(low,true); //---- 重新计算周期自 “第一根” 柱线编号开始计算 if(prev_calculated>rates_total || prev_calculated<=0) // 检查指标首次计算 limit=rates_total-min_rates_total; // 计算所有柱线的起始索引 else limit=rates_total-prev_calculated; // 计算新柱线的起始索引 //---- 指标的主要计算循环 for(bar=limit; bar>0; bar--) { Signal[bar]=0.0; if(Pat.PatternType(_Symbol,_Period,PatternType,bar)) Signal[bar]=low[bar]-200*_Point; } return(rates_total); } //+------------------------------------------------------------------+
PatternDetector 操作结果如图例 4 所示(搜索吞噬 - 涨势形态)。
图例 4 PatternDetector 指标操作示例。
现在我们创建一个智能交易系统,它可以在图表上找到形态并根据所选形态开仓。 每种成交类型都可以使用独立的形态类型。 附加模式允许在现有形态和利用简单烛条类型生成的形态之间进行选择。
我们在 Experts 文件夹中创建 Pattern 文件夹,然后添加 PatternExpert.mq5,其内容是编写的 EA 代码。 在第一阶段,关联 Pattern.mqh 函数库以便处理形态,以及用于交易操作的 Trade.mqh 函数库。 声明类实例并引入 PATTERN_MODE 枚举,该枚举允许在现有形态和生成形态之间进行切换。
//+------------------------------------------------------------------+ //| PatternExpert.mq5 | //| 版权所有 2019, MetaQuotes 软件公司 | //| https://www.mql5.com/zh/users/alex2356 | //+------------------------------------------------------------------+ #property copyright "版权所有 2018, MetaQuotes 软件公司" #property link "https://www.mql5.com/zh/users/alex2356" #property version "1.00" #include <Pattern/Pattern.mqh> #include "Trade.mqh" CTradeBase Trade; CPattern Pat; //+------------------------------------------------------------------+ //| 形态搜索模式 | //+------------------------------------------------------------------+ enum PATTERN_MODE { EXISTING, GENERATED };
现在定义智能交易系统的输入参数。 EA 参数在第一个模块中提供:
//+------------------------------------------------------------------+ //| 智能交易系统输入参数 | //+------------------------------------------------------------------+ input string Inp_EaComment="Pattern Strategy"; // EA 注释 input double Inp_Lot=0.01; // 手数 input MarginMode Inp_MMode=LOT; // 资金管理 //--- EA 参数 input string Inp_Str_label="===EA parameters==="; // 标签 input int Inp_MagicNum=1111; // 魔幻数字 input int Inp_StopLoss=40; // 止损(点数) input int Inp_TakeProfit=30; // 止盈(点数)
第二部分包含设置和交易参数。
//--- 交易参数 input ENUM_TIMEFRAMES Timeframe=PERIOD_CURRENT; // 当前时间帧 input PATTERN_MODE PatternMode=0; // 形态模式 input TYPE_PATTERN BuyPatternType=ENGULFING_BULL; // 买入形态类型 input TYPE_PATTERN SellPatternType=ENGULFING_BEAR; // 卖出形态类型 input uint BuyIndex1=1; // 简单蜡烛1的买入索引 input uint BuyIndex2=0; // 简单蜡烛2的买入索引 input uint BuyIndex3=0; // 简单蜡烛3的买入索引 input uint SellIndex1=1; // 简单蜡烛1的卖出索引 input uint SellIndex2=0; // 简单蜡烛2的卖出索引 input uint SellIndex3=0; // 简单蜡烛3的卖出索引 input double LongCoef=1.3; // 长体蜡烛系数 input double ShortCoef=0.5; // 短体蜡烛系数 input double DojiCoef=0.04; // 十字星蜡烛系数 input double MaribozuCoef=0.01; // Maribozu 蜡烛系数 input double SpinCoef=1; // 尖顶蜡烛系数 input double HummerCoef1=0.1; // 锤子蜡烛系数1 input double HummerCoef2=2; // 锤子蜡烛系数2 input int TrendPeriod=5; // 趋势周期
我们更详细地考察其中一些参数:
其他参数类似于上述考察的指标。 除了检查之外,还在初始化模块中设置趋势周期值,这会影响图表的形态检测。
//+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- 检查与交易服务器的连接 if(!TerminalInfoInteger(TERMINAL_CONNECTED)) { Print(Inp_EaComment,": No Connection!"); return(INIT_FAILED); } //--- 检查自动交易许可 if(!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED)) { Print(Inp_EaComment,": Trade is not allowed!"); return(INIT_FAILED); } //--- Pat.TrendPeriod(TrendPeriod); //--- return(INIT_SUCCEEDED); }
计算部分易于理解。 我们考察 买入和卖出 信号搜索函数。
//+------------------------------------------------------------------+ //| 智能系统即时报价函数 | //+------------------------------------------------------------------+ void OnTick() { if(!Trade.IsOpenedByMagic(Inp_MagicNum)) { //--- 如果有买入信号,则开单 if(BuySignal()) Trade.BuyPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment); //--- 如果有卖出信号,则开单 if(SellSignal()) Trade.SellPositionOpen(Symbol(),Inp_Lot,Inp_StopLoss,Inp_TakeProfit,Inp_MagicNum,Inp_EaComment); } }
这些函数类似,因此我们仅考察其中一个 BuySignal(),它搜索买入信号。
//+------------------------------------------------------------------+ //| 买入条件 | //+------------------------------------------------------------------+ bool BuySignal() { if(PatternMode==0) { if(BuyPatternType==NONE) return(false); if(Pat.PatternType(_Symbol,Timeframe,BuyPatternType,1)) return(true); } else if(PatternMode==1) { if(BuyIndex1>0 && BuyIndex2==0 && BuyIndex3==0) { if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,1)) return(true); } else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3==0) { if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,1)) return(true); } else if(BuyIndex1>0 && BuyIndex2>0 && BuyIndex3>0) { if(Pat.PatternType(_Symbol,Timeframe,BuyIndex1,BuyIndex2,BuyIndex3,1)) return(true); } } return(false); }
该函数包含对当前所选模式、现有形态或生成形态 的检查。 相应地选择输入参数:TYPE_PATTERN 或生成形态的一组索引。
我们以两种模式测试和优化所生成智能交易系统:使用 TYPE_PATTERN 枚举中的现有形态,以及由图例 1 中的区块 4 所示的简单烛条类型组成的生成形态。
将使用以下参数测试智能交易系统:
生成形态模式。
我们确定要测试和优化的参数。
图例 5 在生成形态模式下设置优化参数 。
图例 5 显示了测试和优化条件。 测试结果获得的最佳参数显示在第二个数值列中。 回测结果和图表如下面的图例 6 所示。
图例 6 生成形态模式的最佳参数测试结果。
现有形态模式。
设置测试和优化的参数。
图例 7 在现有形态模式下设置优化参数 。
同样,最佳优化结果的参数显示在第二列中。 现在我们进行单次测试。 结果如下图例 8 所示。
图例 8 现有形态模式下的最佳参数测试结果。
下面附带的存档包含所有描述文件,并在文件夹中正确安置。 若要正确操作,应将 MQL5 文件夹保存到终端的根目录下。 若要查找 MQL5 文件夹所在的根文件夹,请在 MetaTrader 5 中按 Ctrl+Shift+D 或使用关联菜单,如图例 9 所示。
图例 9 如何在 MetaTrader 5 根目录中找到 MQL5 文件夹。
本文中使用的程序
# |
名称 |
类型 |
描述 |
---|---|---|---|
1 |
Pattern.mqh | 函数库 | 用于处理形态的函数库 |
2 | CandleDetector.mq5 | 指标 | 烛条搜索指示器 |
3 | PatternDetector.mq5 | 指标 | 形态搜索指标 |
4 | PatternExpert.mq5 | 智能交易系统 | 利用形态操作的智能交易系统 |
5 | Trade.mqh | 函数库 | 交易函数的类 |
本社区仅针对特定人员开放
查看需注册登录并通过风险意识测评
5秒后跳转登录页面...
移动端课程