1. 概述
本文提供了一种走势延续模型的程序化定义。 主要思路是定义两个波浪 — 主浪和修正浪。 对于极值点,我应用分形以及“潜在”分形 — 尚未形成分形的极值点。 接着,我将尝试收集有关波浪走势的统计数据。 数据将加载到 CSV 文件。
2. 模型描述 - 常规特点
文章中所述的走势延续模型由两个波浪组成:主浪和修正浪。 图例 1 是该模型的示意性描述。 AB 是主浪,BC 是校正浪,而 CD 是走势主趋势的延续。
![走势延续模型 走势延续模型](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_1_20181203021952685.png)
图例 1. 走势延续模型
在图表上,这看起来如下:
![AUDJPY H4 上的走势延续模型 AUDJPY H4 上的走势延续模型](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_2_20181203021952997.png)
图例 2. AUDJPY H4 上的走势延续模型
3. 图表上的模型识别原理
模型识别原理如表 1 所示。
表 1. 走势延续模型在趋势背景下的识别原理
# |
下跌趋势的模型识别原理 |
# |
上涨趋势的模型识别原理 |
1 |
极值柱线是其高/低值高于/低于前两根柱线高/低值的那根柱线 |
1 |
极值柱线是其高/低值高于/低于前两根柱线高/低值的那根柱线 |
2 |
修正浪应始终按照顶端极值的存在结束(点 С - 参见 图例 1 和 图例 2) |
2 |
修正浪应始终按照底端极值的存在结束(点 С - 参见 图例 1 和 图例 2) |
3 |
修正浪的持续时间不能太长,应限制在几根柱线。 |
3 |
修正浪的持续时间不能太长,应限制在几根柱线。 |
4 |
修正走势的高点 (点 С - 参见 图例 1 和 图例 2) 应低于主要走势的高点 (点 A - 参见 图例 1 和 图例 2) |
4 |
修正走势的低点 (点 С - 参见 图例 1 和 图例 2) 应高于主要走势的低点 (点 A - 参见 图例 1 和 图例 2) |
5 |
入场点时效性原则 - 只应在入场点形成的确定时刻开仓 |
5 |
入场点时效性原则 - 只应在入场点形成的确定时刻开仓 |
4. 算法构造和编写代码
1. 输入参数,OnInit() 函数和初始变量声明
首先,我们需要包含 CTrade 类,以便简化对交易操作的访问:
#include <Trade\Trade.mqh>
CTrade trade;
Next, define input parameters:
input ENUM_TIMEFRAMES base_tf;
input ENUM_TIMEFRAMES work_tf;
input double SummRisk=100;
input double sar_step=0.1;
input double maximum_step=0.11;
input bool TP_mode=true;
input int M=2;
input bool Breakeven_mode=true;
input double breakeven=1;
在基准周期上,EA 定义入场方向,而操作周期用于定义入场点。
程序根据每笔成交的总风险计算手数。
EA 还可以根据指定的利润与风险比率(М 参数)设置止盈,并根据指定的利润与止损比率(breakeven 参数)将持仓移至盈亏平衡点。
在描述输入参数之后,为 base_tf 和 work_tf 时间帧声明指标句柄和数组变量:
int Fractal_base_tf,Fractal_work_tf;
int Sar_base_tf,Sar_work_tf;
double High_base_tf[],Low_base_tf[];
double Close_base_tf[],Open_base_tf[];
datetime Time_base_tf[];
double Sar_array_base_tf[];
double FractalDown_base_tf[],FractalUp_base_tf[];
double High_work_tf[],Low_work_tf[];
double Close_work_tf[],Open_work_tf[];
datetime Time_work_tf[];
double Sar_array_work_tf[];
double FractalDown_work_tf[],FractalUp_work_tf[];;
EA 应用了两个指标:用于定义极值部分的分形,和用于持仓尾随停止的抛物线。 我还将采用抛物线在 work_tf 操作时间帧内定义一个入场点。
然后在 OnInit() 函数中接收指标句柄,并用初始数据填充数组。
int OnInit()
{
Sar_base_tf=iSAR(Symbol(),base_tf,sar_step,maximum_step);
Sar_work_tf=iSAR(Symbol(),work_tf,sar_step,maximum_step);
Fractal_base_tf=iFractals(Symbol(),base_tf);
Fractal_work_tf=iFractals(Symbol(),work_tf);
ArraySetAsSeries(High_base_tf,true);
ArraySetAsSeries(Low_base_tf,true);
ArraySetAsSeries(Close_base_tf,true);
ArraySetAsSeries(Open_base_tf,true);
ArraySetAsSeries(Time_base_tf,true);;
ArraySetAsSeries(Sar_array_base_tf,true);
ArraySetAsSeries(FractalDown_base_tf,true);
ArraySetAsSeries(FractalUp_base_tf,true);
CopyHigh(Symbol(),base_tf,0,1000,High_base_tf);
CopyLow(Symbol(),base_tf,0,1000,Low_base_tf);
CopyClose(Symbol(),base_tf,0,1000,Close_base_tf);
CopyOpen(Symbol(),base_tf,0,1000,Open_base_tf);
CopyTime(Symbol(),base_tf,0,1000,Time_base_tf);
CopyBuffer(Sar_base_tf,0,TimeCurrent(),1000,Sar_array_base_tf);
CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf);
CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf);
ArraySetAsSeries(High_work_tf,true);
ArraySetAsSeries(Low_work_tf,true);
ArraySetAsSeries(Close_work_tf,true);
ArraySetAsSeries(Open_work_tf,true);
ArraySetAsSeries(Time_work_tf,true);
ArraySetAsSeries(Sar_array_work_tf,true);
ArraySetAsSeries(FractalDown_work_tf,true);
ArraySetAsSeries(FractalUp_work_tf,true);
CopyHigh(Symbol(),work_tf,0,1000,High_work_tf);
CopyLow(Symbol(),work_tf,0,1000,Low_work_tf);
CopyClose(Symbol(),work_tf,0,1000,Close_work_tf);
CopyOpen(Symbol(),work_tf,0,1000,Open_work_tf);
CopyTime(Symbol(),work_tf,0,1000,Time_work_tf);
CopyBuffer(Sar_work_tf,0,TimeCurrent(),1000,Sar_array_work_tf);
CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf);
CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf);
return(INIT_SUCCEEDED);
}
首先,我们收到 指标'句柄,然后在 时间序列 中定义数组的顺序,并用数据填充数组。 我相信 1000 根柱线的数据对于 EA 操作来说已经足够了。
2. 一般参数
在此,我开始运用OnTick() 函数操作。
在“常规参数”部分中,我通常写入市价数据并声明设置仓位的变量。
int Digit=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
double f=1;
if(Digit==5) {f=100000;}
if(Digit==4) {f=10000;}
if(Digit==3) {f=1000;}
if(Digit==2) {f=100;}
if(Digit==1) {f=10;}
double spread=SymbolInfoInteger(Symbol(),SYMBOL_SPREAD)/f;
double bid=SymbolInfoDouble(_Symbol,SYMBOL_BID);
double ask=SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double CostOfPoint=SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE);
double RiskSize_points;
double CostOfPoint_position;
double Lot;
double SLPrice_sell,SLPrice_buy;
int bars_base_tf=Bars(Symbol(),base_tf);
int bars_work_tf=Bars(Symbol(),work_tf);
string P_symbol;
int P_type,P_ticket,P_opentime;
3. 更新数组数据
数组最初在 OnInit() 函数中填充,但数组数据应始终保持相关性。 在每次逐笔报价中填充数组意味着系统负载太重,会大大减慢操作。 因此,建议出现新柱线时再重新填充数组。
为此,使用以下结构:
static datetime LastBar_base_tf=0;
datetime ThisBar_base_tf=(datetime)SeriesInfoInteger(_Symbol,base_tf,SERIES_LASTBAR_DATE);
if(LastBar_base_tf!=ThisBar_base_tf)
{
}
使用这种方法,零号柱线的数据会丢失,因此,我已经为索引 #0 柱线上的数据包含了单独的数组。
我们还应该用分形数据分别更新数组。 每当第 #0 柱线的极值高于或低于前两个极值点时,应重新填充它们。
填充数组的示例在下面提供。
1. 出现新柱线时填充数组
首先,在出现新柱线时填充数组:
ArraySetAsSeries(High_base_tf,true);
ArraySetAsSeries(Low_base_tf,true);
ArraySetAsSeries(Close_base_tf,true);
ArraySetAsSeries(Open_base_tf,true);
ArraySetAsSeries(Time_base_tf,true);
ArraySetAsSeries(Sar_array_base_tf,true);
ArraySetAsSeries(FractalDown_base_tf,true);
ArraySetAsSeries(FractalUp_base_tf,true);
static datetime LastBar_base_tf=0;
datetime ThisBar_base_tf=(datetime)SeriesInfoInteger(_Symbol,base_tf,SERIES_LASTBAR_DATE);
if(LastBar_base_tf!=ThisBar_base_tf)
{
CopyHigh(Symbol(),base_tf,0,1000,High_base_tf);
CopyLow(Symbol(),base_tf,0,1000,Low_base_tf);
CopyClose(Symbol(),base_tf,0,1000,Close_base_tf);
CopyOpen(Symbol(),base_tf,0,1000,Open_base_tf);
CopyTime(Symbol(),base_tf,0,1000,Time_base_tf);
CopyBuffer(Sar_base_tf,0,TimeCurrent(),1000,Sar_array_base_tf);
CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf);
CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf);
LastBar_base_tf=ThisBar_base_tf;
}
ArraySetAsSeries(High_work_tf,true);
ArraySetAsSeries(Low_work_tf,true);
ArraySetAsSeries(Close_work_tf,true);
ArraySetAsSeries(Open_work_tf,true);
ArraySetAsSeries(Time_work_tf,true);
ArraySetAsSeries(Sar_array_work_tf,true);
ArraySetAsSeries(FractalDown_work_tf,true);
ArraySetAsSeries(FractalUp_work_tf,true);
static datetime LastBar_work_tf=0;
datetime ThisBar_work_tf=(datetime)SeriesInfoInteger(_Symbol,work_tf,SERIES_LASTBAR_DATE);
if(LastBar_work_tf!=ThisBar_work_tf)
{
CopyHigh(Symbol(),work_tf,0,1000,High_work_tf);
CopyLow(Symbol(),work_tf,0,1000,Low_work_tf);
CopyClose(Symbol(),work_tf,0,1000,Close_work_tf);
CopyOpen(Symbol(),work_tf,0,1000,Open_work_tf);
CopyTime(Symbol(),work_tf,0,1000,Time_work_tf);
CopyBuffer(Sar_work_tf,0,TimeCurrent(),1000,Sar_array_work_tf);
CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf);
CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf);
LastBar_work_tf=ThisBar_work_tf;
}
2. 使用柱线 #0 的数据填充数组
索引 #1 或更高柱线上的数据现在始终保持相关,而索引 #0 柱线上的数据仍然过时。 我已经为存储零号柱线上的数据包含了单独数组:
double High_base_tf_0[],Low_base_tf_0[];
double Close_base_tf_0[],Open_base_tf_0[];
datetime Time_base_tf_0[];
double Sar_array_base_tf_0[];
ArraySetAsSeries(High_base_tf_0,true);
ArraySetAsSeries(Low_base_tf_0,true);
ArraySetAsSeries(Close_base_tf_0,true);
ArraySetAsSeries(Open_base_tf_0,true);
ArraySetAsSeries(Time_base_tf_0,true);
ArraySetAsSeries(Sar_array_base_tf_0,true);
CopyHigh(Symbol(),base_tf,0,1,High_base_tf_0);
CopyLow(Symbol(),base_tf,0,1,Low_base_tf_0);
CopyClose(Symbol(),base_tf,0,1,Close_base_tf_0);
CopyOpen(Symbol(),base_tf,0,1,Open_base_tf_0);
CopyTime(Symbol(),base_tf,0,1,Time_base_tf_0);
CopyBuffer(Sar_base_tf,0,TimeCurrent(),1,Sar_array_base_tf_0);
double High_work_tf_0[],Low_work_tf_0[];
double Close_work_tf_0[],Open_work_tf_0[];
datetime Time_work_tf_0[];
double Sar_array_work_tf_0[];
ArraySetAsSeries(High_work_tf_0,true);
ArraySetAsSeries(Low_work_tf_0,true);
ArraySetAsSeries(Close_work_tf_0,true);
ArraySetAsSeries(Open_work_tf_0,true);
ArraySetAsSeries(Time_work_tf_0,true);
ArraySetAsSeries(Sar_array_work_tf_0,true);
CopyHigh(Symbol(),work_tf,0,1,High_work_tf_0);
CopyLow(Symbol(),work_tf,0,1,Low_work_tf_0);
CopyClose(Symbol(),work_tf,0,1,Close_work_tf_0);
CopyOpen(Symbol(),work_tf,0,1,Open_work_tf_0);
CopyTime(Symbol(),work_tf,0,1,Time_work_tf_0);
CopyBuffer(Sar_work_tf,0,TimeCurrent(),1,Sar_array_work_tf_0);
3. 更新分形数据
应更新含有分形数据的数组。 每次 #0 柱线的极值都高于或低于前两根时,应重新填充数组:
if(High_base_tf_0[0]>High_base_tf[1] && High_base_tf_0[0]>High_base_tf[2])
{
CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf);
}
if(Low_base_tf_0[0]<Low_base_tf[1] && Low_base_tf_0[0]<Low_base_tf[2])
{
CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf);
}
if(High_work_tf_0[0]>High_work_tf[1] && High_work_tf_0[0]>High_work_tf[2])
{
CopyBuffer(Fractal_work_tf,0,TimeCurrent(),1000,FractalUp_work_tf);
}
if(Low_work_tf_0[0]<Low_work_tf[1] && Low_work_tf_0[0]<Low_work_tf[2])
{
CopyBuffer(Fractal_work_tf,1,TimeCurrent(),1000,FractalDown_work_tf);
}
4. 搜索极值
我们回到走势延续模型。 为此,我们需要回顾 图例 2。
АВ 段是主浪,而 ВС 是修正浪。 根据模型识别原理,修正浪应始终以极值结束,因为这是一个分形。 在图像上,它被标记为 С。 应该从这一点开始搜索极值,直到检测到其余的极值。 然而,在入场的那一刻,形成的(确认的)分形可能已不存在。 所以,当柱线极值高于/低于前两根柱线时,我们需要寻找一种情况 — 这种柱线的高/低将形成点 С。 另外,请记住,在入场之时,修正走势的高/低点(点 С)可以位于零号或索引大于零号的柱线上。
表 2 示意极值定义的顺序。
表 2. 极值定义序列
# |
对于下跌趋势 |
对于上涨趋势 |
1 |
寻找修正走势高位(点 С) |
寻找修正走势低位(点 С) |
2 |
自修正走势的高点寻找下一个顶端极值(点 А) |
自修正走势的低点寻找下一个底端极值(点 А) |
3 |
在点 C 和 A 之间寻找点 В(修正走势低点) |
在点 C 和 A 之间寻找点 В(修正走势高点) |
1. 搜索下跌趋势的极值
int High_Corr_wave_downtrend_base_tf;
int UpperFractal_downtrend_base_tf;
int Low_Corr_wave_downtrend_base_tf;
if(High_base_tf_0[0]>High_base_tf[1] && High_base_tf_0[0]>High_base_tf[2])
{
High_Corr_wave_downtrend_base_tf=0;
}
else
{
for(n=0; n<(bars_base_tf);n )
{
if(High_base_tf[n]>High_base_tf[n 1] && High_base_tf[n]>High_base_tf[n 2])
break;
}
High_Corr_wave_downtrend_base_tf=n;
}
for(n=High_Corr_wave_downtrend_base_tf 1; n<(bars_base_tf);n )
{
if(FractalUp_base_tf[n]!=EMPTY_VALUE)
break;
}
UpperFractal_downtrend_base_tf=n;
int CountToFind_arrmin=UpperFractal_downtrend_base_tf-High_Corr_wave_downtrend_base_tf;
Low_Corr_wave_downtrend_base_tf=ArrayMinimum(Low_base_tf,High_Corr_wave_downtrend_base_tf,CountToFind_arrmin);
2. 搜索上涨趋势的极值
int Low_Corr_wave_uptrend_base_tf;
int LowerFractal_uptrend_base_tf;
int High_Corr_wave_uptrend_base_tf;
if(Low_base_tf_0[0]<Low_base_tf[1] && Low_base_tf_0[0]<Low_base_tf[2])
{
Low_Corr_wave_uptrend_base_tf=0;
}
else
{
for(n=0; n<(bars_base_tf);n )
{
if(Low_base_tf[n]<Low_base_tf[n 1] && Low_base_tf[n]<Low_base_tf[n 2])
break;
}
Low_Corr_wave_uptrend_base_tf=n;
}
for(n=Low_Corr_wave_uptrend_base_tf 1; n<(bars_base_tf);n )
{
if(FractalDown_base_tf[n]!=EMPTY_VALUE)
break;
}
LowerFractal_uptrend_base_tf=n;
int CountToFind_arrmax=LowerFractal_uptrend_base_tf-Low_Corr_wave_uptrend_base_tf;
High_Corr_wave_uptrend_base_tf=ArrayMaximum(High_base_tf,Low_Corr_wave_uptrend_base_tf,CountToFind_arrmax);
3. 将修正浪的高/低值约化到统一变量
因此,我们已发现了极值柱线索引。 但我们还需要参考柱线的价格和时间值。 为了引用修正浪的高点值或低点值,我们必须使用两个不同的数组,因为修正浪的高点或低点可以在零号索引柱线上,也可以在索引大于零号的柱线上。 这对于操作来说很不方便,因此使用 if 运算符 将它们的值带入公共变量会更合理。
double High_Corr_wave_downtrend_base_tf_double,Low_Corr_wave_uptrend_base_tf_double;
datetime High_Corr_wave_downtrend_base_tf_time,Low_Corr_wave_uptrend_base_tf_time;
if(High_Corr_wave_downtrend_base_tf==0)
{
High_Corr_wave_downtrend_base_tf_double=High_base_tf_0[High_Corr_wave_downtrend_base_tf];
High_Corr_wave_downtrend_base_tf_time=Time_base_tf_0[High_Corr_wave_downtrend_base_tf];
}
else
{
High_Corr_wave_downtrend_base_tf_double=High_base_tf[High_Corr_wave_downtrend_base_tf];
High_Corr_wave_downtrend_base_tf_time=Time_base_tf[High_Corr_wave_downtrend_base_tf];
}
if(Low_Corr_wave_uptrend_base_tf==0)
{
Low_Corr_wave_uptrend_base_tf_double=Low_base_tf_0[Low_Corr_wave_uptrend_base_tf];
Low_Corr_wave_uptrend_base_tf_time=Time_base_tf_0[Low_Corr_wave_uptrend_base_tf];
}
else
{
Low_Corr_wave_uptrend_base_tf_double=Low_base_tf[Low_Corr_wave_uptrend_base_tf];
Low_Corr_wave_uptrend_base_tf_time=Time_base_tf[Low_Corr_wave_uptrend_base_tf];
}
因此,修正浪的高/低价格和时间值被写入变量。 无需每次访问不同的数组。
如果我们汇总搜索极值的工作,事实证明可根据模型识别概念发现了点 A,B 和 C(见表 4 和表 5)。
表 4. 下跌趋势的点 А,В 和 С 的值
参数 |
点 A 值 |
点 B 值 |
点 C 值 |
柱线索引 |
UpperFractal_downtrend_base_tf |
Low_Corr_wave_downtrend_base_tf |
High_Corr_wave_downtrend_base_tf |
时间值 |
Time_base_tf[UpperFractal_downtrend_base_tf] |
Time_base_tf[Low_Corr_wave_downtrend_base_tf] |
High_Corr_wave_downtrend_base_tf_time |
价格值 |
High_base_tf[UpperFractal_downtrend_base_tf] |
Low_base_tf[Low_Corr_wave_downtrend_base_tf] |
High_Corr_wave_downtrend_base_tf_double |
表 5. 上涨趋势的点 А,В 和 С 的值
参数 |
点 A 值 |
点 B 值 |
点 C 值 |
柱线索引 |
LowerFractal_uptrend_base_tf |
High_Corr_wave_uptrend_base_tf |
Low_Corr_wave_uptrend_base_tf |
时间值 |
Time_base_tf[LowerFractal_uptrend_base_tf] |
Time_base_tf[High_Corr_wave_uptrend_base_tf] |
Low_Corr_wave_uptrend_base_tf_time |
价格值 |
Low_base_tf[LowerFractal_uptrend_base_tf] |
High_base_tf[High_Corr_wave_uptrend_base_tf] |
Low_Corr_wave_uptrend_base_tf_double |
5. 模型识别条件
在本章节中,我仅说明本文中所描述模型的最基本条件特征。
表 6. 用于识别走势延续模型的最小条件集合
# |
下跌趋势条件 |
上涨趋势条件 |
1 |
修正浪高点(点 C)低于其后极值的高点(点 А) |
校正浪低点(点 C)高于其后的极值低点(点 А) |
2 |
修正浪低点索引(点 В)超过高点索引(点 С) |
修正浪高点索引(点 В)超过低点索引(点 С) |
3 |
修正走势持续时间为 2 到 6 根柱线(从点 В 开始的柱线数) |
修正走势持续时间为 2 到 6 根柱线(从点 В 开始的柱线数) |
用于所描述模型识别条件的代码提供如下。 条件收集在两个逻辑变量中:一个是下跌趋势,另一个是上涨趋势:
bool Model_downtrend_base_tf=(
High_Corr_wave_downtrend_base_tf_double<High_base_tf[UpperFractal_downtrend_base_tf] &&
Low_Corr_wave_downtrend_base_tf>High_Corr_wave_downtrend_base_tf &&
Low_Corr_wave_downtrend_base_tf>=1 && Low_Corr_wave_downtrend_base_tf<=6
);
bool Model_uptrend_base_tf=(
Low_Corr_wave_uptrend_base_tf_double>Low_base_tf[LowerFractal_uptrend_base_tf] &&
High_Corr_wave_uptrend_base_tf>Low_Corr_wave_uptrend_base_tf &&
High_Corr_wave_uptrend_base_tf>=1 && High_Corr_wave_uptrend_base_tf<=6
);
6. 创建控制
EA 应至少执行三次检查。
前两次检查验证入场的时效性。 第三次则确认在一个模型中只开一仓,即它确保没有重复开仓。
参见图例 3. 虚线标记入场点所在的开仓区域 — 位于点 В 和 С 之间。 当价格突破点B 的价位时,不建议稍后入场,因为这会增加风险。 这是程序应该执行的第一次检查。
![走势延续模型 走势延续模型](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_3_20181203021953154.png)
图例 3. AUDJPY H4 上的走势延续模型
在某些情况下,价格可能突破点 В 再回落到开仓区域。 这种情况不能考虑进行交易。 这是程序应该进行的第二次检查。 最后,为了避免多次开仓,我们需要引入限制:1 个模型 — 1 笔持仓。 这是程序应该执行的第三次检查。
1. 在开仓区域形成入场点控制
这一切都很简单:对于卖出模型,竞买价应该超过修正走势低点(点 В)。 对于买入模型,竞买价应该低于修正走势高点(点 В)。
bool First_downtrend_control_bool=(bid>=Low_base_tf[Low_Corr_wave_downtrend_base_tf]);
bool First_uptrend_control_bool=(bid<=High_base_tf[High_Corr_wave_uptrend_base_tf]);
2. 价格回滚到开仓区域的控制
为了实现这种控制,我们应当从当前索引开始直到修正走势的高/低点柱线(点 В),定义具有最低“低”价(对于卖出)的柱线,或具有最高“高”价(对于买入)的柱线。 为实现此目的,若是卖出模型则采用 ArrayMinimum() 函数,而买入模型则为 ArrayMaximum() 函数。
进而,将修正走势的低/高索引(点 В),与得自 ArrayMinimum() 和 ArrayMaximum() 函数的索引进行比较。 如果它们匹配,则修正走势没有突破低/高点,在交易之间可以考虑入场情况。 如果索引不一致,则走势已经提前开始,且开仓也为时已晚。
int Second_downtrend_control_int=ArrayMinimum(Low_base_tf,0,Low_Corr_wave_downtrend_base_tf 1);
if(Low_base_tf_0[0]<Low_base_tf[Second_downtrend_control_int])
{
Second_downtrend_control_int=0;
}
bool Second_downtrend_control_bool=(Second_downtrend_control_int==Low_Corr_wave_downtrend_base_tf);
int Second_uptrend_control_int=ArrayMaximum(High_base_tf,0,High_Corr_wave_uptrend_base_tf 1);
if(High_base_tf_0[0]>High_base_tf[Second_uptrend_control_int])
{
Second_uptrend_control_int=0;
}
bool Second_uptrend_control_bool=(Second_uptrend_control_int==High_Corr_wave_uptrend_base_tf);
3. 在单个模型中消除重复仓位
此控制用于限制持仓的数量。 其背后的思路:一个模型 — 对于一笔持仓。 对持仓进行逐一分析。 如果在当前图表上已有一笔持仓,则从入场点定义最接近该笔持仓的极值柱线 - 根据交易类型则为修正走势的高/低点(从入场点开始的点 С)。
之后,检测到的柱线时间 — 修正走势的高/低点(从入场点开始的点 С)— 与当前修正走势的高/低点的时间(当前点 С)进行比较。 如果它们匹配,则不应开仓,因为没有符合此模型的仓位。
创造卖出控制:
int Bar_sell_base_tf,High_Corr_wave_downtrend_base_tf_sell;
bool Third_downtrend_control_bool=false;
if(PositionsTotal()>0)
{
for(i=0;i<=PositionsTotal();i )
{
if(PositionGetTicket(i))
{
P_symbol=string(PositionGetString(POSITION_SYMBOL));
P_type=int(PositionGetInteger(POSITION_TYPE));
P_opentime=int(PositionGetInteger(POSITION_TIME));
if(P_symbol==Symbol() && P_type==1)
{
Bar_sell_base_tf=iBarShift(Symbol(),base_tf,P_opentime);
if(Bar_sell_base_tf==0)
{
if(High_base_tf_0[Bar_sell_base_tf]>High_base_tf[Bar_sell_base_tf 1] && High_base_tf_0[Bar_sell_base_tf]>High_base_tf[Bar_sell_base_tf 2])
{
High_Corr_wave_downtrend_base_tf_sell=Bar_sell_base_tf;
}
else
{
for(n=Bar_sell_base_tf; n<(bars_base_tf);n )
{
if(High_base_tf[n]>High_base_tf[n 1] && High_base_tf[n]>High_base_tf[n 2])
break;
}
High_Corr_wave_downtrend_base_tf_sell=n;
}
Third_downtrend_control_bool=(
Time_base_tf[High_Corr_wave_downtrend_base_tf_sell]==High_Corr_wave_downtrend_base_tf_time
);
}
if(Bar_sell_base_tf!=0 && Bar_sell_base_tf!=1000)
{
for(n=Bar_sell_base_tf; n<(bars_base_tf);n )
{
if(High_base_tf[n]>High_base_tf[n 1] && High_base_tf[n]>High_base_tf[n 2])
break;
}
High_Corr_wave_downtrend_base_tf_sell=n;
}
Third_downtrend_control_bool=(
Time_base_tf[High_Corr_wave_downtrend_base_tf_sell]==High_Corr_wave_downtrend_base_tf_time
);
}
}
}
}
创造买入控制:
int Bar_buy_base_tf,Low_Corr_wave_uptrend_base_tf_buy;
bool Third_uptrend_control_bool=false;
if(PositionsTotal()>0)
{
for(i=0;i<=PositionsTotal();i )
{
if(PositionGetTicket(i))
{
P_symbol=string(PositionGetString(POSITION_SYMBOL));
P_type=int(PositionGetInteger(POSITION_TYPE));
P_opentime=int(PositionGetInteger(POSITION_TIME));
if(P_symbol==Symbol() && P_type==0)
{
Bar_buy_base_tf=iBarShift(Symbol(),base_tf,P_opentime);
if(Bar_buy_base_tf==0)
{
if(Low_base_tf_0[Bar_buy_base_tf]<Low_base_tf[Bar_buy_base_tf 1] && Low_base_tf_0[Bar_buy_base_tf]<Low_base_tf[Bar_buy_base_tf 2])
{
Low_Corr_wave_uptrend_base_tf_buy=Bar_buy_base_tf;
}
else
{
for(n=Bar_buy_base_tf; n<(bars_base_tf);n )
{
if(Low_base_tf[n]<Low_base_tf[n 1] && Low_base_tf[n]<Low_base_tf[n 2])
break;
}
Low_Corr_wave_uptrend_base_tf_buy=n;
}
Third_uptrend_control_bool=(
Time_base_tf[Low_Corr_wave_uptrend_base_tf_buy]==Low_Corr_wave_uptrend_base_tf_time
);
}
if(Bar_buy_base_tf!=0 && Bar_buy_base_tf!=1000)
{
for(n=Bar_buy_base_tf; n<(bars_base_tf);n )
{
if(Low_base_tf[n]<Low_base_tf[n 1] && Low_base_tf[n]<Low_base_tf[n 2])
break;
}
Low_Corr_wave_uptrend_base_tf_buy=n;
}
Third_uptrend_control_bool=(
Time_base_tf[Low_Corr_wave_uptrend_base_tf_buy]==Low_Corr_wave_uptrend_base_tf_time
);
}
}
}
}
7. 描述入场条件
应在操作周期定义入场点 — work_tf。 这对于及时入场是必要的,并且如果可能的话,能够减少风险的点数。 抛物线指标的读数作为信号:如果当前柱线上的指标值超过当前柱线的高点,而在前一根柱线上,指标值低于同一柱线的低点,则是卖出时间。 对于买入,案例相反。
bool PointSell_work_tf_bool=(
Low_work_tf[1]>Sar_array_work_tf[1] &&
High_work_tf_0[0]<Sar_array_work_tf_0[0]
);
bool PointBuy_work_tf_bool=(
High_work_tf[1]<Sar_array_work_tf[1] &&
Low_work_tf_0[0]>Sar_array_work_tf_0[0]
);
8. 交易条件
在此阶段,我们将所有先前创建的条件和控制组合到一个逻辑变量中。
bool OpenSell=(
Model_downtrend_base_tf==true &&
First_downtrend_control_bool==true &&
Second_downtrend_control_bool==true &&
Third_downtrend_control_bool==false &&
PointSell_work_tf_bool==true
);
bool OpenBuy=(
Model_uptrend_base_tf==true &&
First_uptrend_control_bool==true &&
Second_uptrend_control_bool==true &&
Third_uptrend_control_bool==false &&
PointBuy_work_tf_bool==true
);
9. 处理交易操作
交易操作的运作可分为:
1. 设定仓位
SLPrice_sell=High_Corr_wave_downtrend_base_tf_double spread;
SLPrice_buy=Low_Corr_wave_uptrend_base_tf_double-spread;
if(OpenSell==true)
{
RiskSize_points=(SLPrice_sell-bid)*f;
if(RiskSize_points==0)
{
RiskSize_points=1;
}
CostOfPoint_position=SummRisk/RiskSize_points;
Lot=CostOfPoint_position/CostOfPoint;
trade.PositionOpen(_Symbol,ORDER_TYPE_SELL,NormalizeDouble(Lot,2),bid,NormalizeDouble(SLPrice_sell,5),0,'');
}
if(OpenBuy==true)
{
RiskSize_points=(bid-SLPrice_buy)*f;
if(RiskSize_points==0)
{
RiskSize_points=1;
}
CostOfPoint_position=SummRisk/RiskSize_points;
Lot=CostOfPoint_position/CostOfPoint;
trade.PositionOpen(_Symbol,ORDER_TYPE_BUY,NormalizeDouble(Lot,2),ask,NormalizeDouble(SLPrice_buy,5),0,'');
}
2. 设定止盈
if(TP_mode==true)
{
if(PositionsTotal()>0)
{
for(i=0;i<=PositionsTotal();i )
{
if(PositionGetTicket(i))
{
SL_double=double (PositionGetDouble(POSITION_SL));
OP_double=double (PositionGetDouble(POSITION_PRICE_OPEN));
TP_double=double (PositionGetDouble(POSITION_TP));
P_symbol=string(PositionGetString(POSITION_SYMBOL));
P_type=int(PositionGetInteger(POSITION_TYPE));
P_profit=double (PositionGetDouble(POSITION_PROFIT));
P_ticket=int (PositionGetInteger(POSITION_TICKET));
P_opentime=int(PositionGetInteger(POSITION_TIME));
if(P_symbol==Symbol())
{
if(P_type==0 && TP_double==0)
{
double SL_size_buy=OP_double-SL_double;
double TP_size_buy=SL_size_buy*M;
double TP_price_buy=OP_double TP_size_buy;
trade.PositionModify(PositionGetInteger(POSITION_TICKET),SL_double,NormalizeDouble(TP_price_buy,5));
}
if(P_type==1 && TP_double==0)
{
double SL_size_sell=SL_double-OP_double;
double TP_size_sell=SL_size_sell*M;
double TP_price_sell=OP_double-TP_size_sell;
trade.PositionModify(PositionGetInteger(POSITION_TICKET),SL_double,NormalizeDouble(TP_price_sell,5));
}
}
}
}
}
}
3. 将持仓移至盈亏平衡点
double Size_Summ=breakeven*SummRisk;
if(Breakeven_mode==true && breakeven!=0)
{
if(PositionsTotal()>0)
{
for(i=0;i<=PositionsTotal();i )
{
if(PositionGetTicket(i))
{
SL_double=double (PositionGetDouble(POSITION_SL));
OP_double=double (PositionGetDouble(POSITION_PRICE_OPEN));
TP_double=double (PositionGetDouble(POSITION_TP));
P_symbol=string(PositionGetString(POSITION_SYMBOL));
P_type=int(PositionGetInteger(POSITION_TYPE));
P_profit=double (PositionGetDouble(POSITION_PROFIT));
P_ticket=int (PositionGetInteger(POSITION_TICKET));
P_opentime=int(PositionGetInteger(POSITION_TIME));
if(P_symbol==Symbol())
{
if(P_type==0 && P_profit>=Size_Summ && SL_double<OP_double)
{
trade.PositionModify(PositionGetInteger(POSITION_TICKET),OP_double,TP_double);
}
if(P_type==1 && P_profit>=Size_Summ && SL_double>OP_double)
{
trade.PositionModify(PositionGetInteger(POSITION_TICKET),OP_double,TP_double);
}
}
}
}
}
}
5. 收集统计数据
首先,您需要确定一组统计指标:
- 品种;
- 成交类型;
- 入场时间;
- 开仓价格;
- 止损价位;
- 止损大小;
- 最大盈利价位;
- 最大盈利大小;
- 成交区间。
必要的假设,最大盈利点是在开仓位置之后形成的主要周期的第一个上/下分形的高/低位。
首先,我们需要在策略测试器中测试 EA 操作。 为了测试,我选择了 AUDJPY,区间为 2018.01.01-2018.08.29。 选择 D1 为主要时间帧,而 H6 用与操作时间帧。 每笔成交风险 — $100。 持仓移至盈亏平衡点 1/2, 设置止盈 — 1/3 (风险/盈利)。
![EA 输入 EA 输入](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_4_2018120302195475.png)
图例 4. EA 输入
测试后,将报告保存在 CSV 文件中。 在终端本地文件夹中,创建新的 report.csv 文件。 复制报告数据并写入文件(从“订单”部分)。 我们应该删除与平仓相关的行,如图例 5 所示:
![从报告中删除与平仓相关的行 从报告中删除与平仓相关的行](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_5_20181203021954591.gif)
图例 5. 从报告中删除与平仓相关的行
复制列:
- 开仓时间;
- 品种;
- 类型;
- 价格;
- 止损。
因此,report.csv 文件将如下所示:
![report.csv 文件内容 report.csv 文件内容](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_6_20181203021954966.png)
图例 6. report.csv 文件内容
现在,我们需要创建一个从 report.csv 文件中读取数据的脚本,并创建新的 file_stat.csv 文件以及其它统计信息:
- 止损大小;
- 最大盈利价位;
- 最大盈利大小;
- 成交区间的柱线数。
为了解决这个任务,我借用了 “MQL5 编程基础:文件” 一文中 “使用分隔符读取文件到数组”章节的现成解决方案。 我还添加了数组,并用 file_stat.csv 文件中存储的列数值填充数组。
创建一个新脚本,在 OnStart() 函数下编写读取文件并写入数组的代码:
bool ReadFileToArrayCSV(string FileName,SLine &Lines[])
{
ResetLastError();
int h=FileOpen(FileName,FILE_READ|FILE_ANSI|FILE_CSV,';');
if(h==INVALID_HANDLE)
{
int ErrNum=GetLastError();
printf('File open error %s # %i',FileName,ErrNum);
return(false);
}
int lcnt=0;
int fcnt=0;
while(!FileIsEnding(h))
{
string str=FileReadString(h);
if(lcnt>=ArraySize(Lines))
{
ArrayResize(Lines,ArraySize(Lines) 1024);
}
ArrayResize(Lines[lcnt].field,64);
Lines[lcnt].field[0]=str;
fcnt=1;
while(!FileIsLineEnding(h))
{
str=FileReadString(h);
if(fcnt>=ArraySize(Lines[lcnt].field))
{
ArrayResize(Lines[lcnt].field,ArraySize(Lines[lcnt].field) 64);
}
Lines[lcnt].field[fcnt]=str;
fcnt ;
}
ArrayResize(Lines[lcnt].field,fcnt);
lcnt ;
}
ArrayResize(Lines,lcnt);
FileClose(h);
return(true);
}
接下来,指定输入:
#property script_show_inputs
input ENUM_TIMEFRAMES base_tf;
input double sar_step=0.1;
input double maximum_step=0.11;
int Fractal_base_tf;
double High_base_tf[],Low_base_tf[];
double FractalDown_base_tf[],FractalUp_base_tf[];
struct SLine
{
string field[];
};
在 OnStart() 函数内部,获取 iFractals 指标句柄,声明并填充高/低价格数组。 我们还需要在 for 循环使用 bars_base_tf 变量,并使用 f 变量来存储价格数字容量,具体取决于品种价格中的小数位数。 此变量用于将止损和最大盈利值转换为整数。
Fractal_base_tf=iFractals(Symbol(),base_tf);
ArraySetAsSeries(High_base_tf,true);
ArraySetAsSeries(Low_base_tf,true);
ArraySetAsSeries(FractalDown_base_tf,true);
ArraySetAsSeries(FractalUp_base_tf,true);
CopyHigh(Symbol(),base_tf,0,1000,High_base_tf);
CopyLow(Symbol(),base_tf,0,1000,Low_base_tf);
CopyBuffer(Fractal_base_tf,0,TimeCurrent(),1000,FractalUp_base_tf);
CopyBuffer(Fractal_base_tf,1,TimeCurrent(),1000,FractalDown_base_tf);
int bars_base_tf=Bars(Symbol(),base_tf);
int Digit=(int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS);
double f=1;
if(Digit==5) {f=100000;}
if(Digit==4) {f=10000;}
if(Digit==3) {f=1000;}
if(Digit==2) {f=100;}
if(Digit==1) {f=10;}
接下来,声明数组和变量:
int i,j,n;
datetime opentime[];
string symbol[];
string type[];
string openprice[];
string sl_price[];
int index[];
int down_fractal[];
int up_fractal[];
double sl_size_points[];
string maxprofit_price[];
double maxprofit_size_points[];
int duration[];
bool maxprofit_bool[];
int maxprofit_int[];
在此之后,继续将文件中的数据读取到数组中:
SLine lines[];
int size=0;
if(!ReadFileToArrayCSV('report.csv',lines))
{
Alert('Error, see details in the \'Experts\'' tab);
}
else
{
size=ArraySize(lines);
ArrayResize(opentime,ArraySize(lines));
ArrayResize(symbol,ArraySize(lines));
ArrayResize(type,ArraySize(lines));
ArrayResize(openprice,ArraySize(lines));
ArrayResize(sl_price,ArraySize(lines));
ArrayResize(index,ArraySize(lines));
ArrayResize(down_fractal,ArraySize(lines));
ArrayResize(up_fractal,ArraySize(lines));
ArrayResize(sl_size_points,ArraySize(lines));
ArrayResize(maxprofit_price,ArraySize(lines));
ArrayResize(maxprofit_size_points,ArraySize(lines));
ArrayResize(duration,ArraySize(lines));
ArrayResize(maxprofit_bool,ArraySize(lines));
ArrayResize(maxprofit_int,ArraySize(lines));
for(i=0;i<size;i )
{
for(j=0;j<ArraySize(lines[i].field);j=j 5)
{
opentime[i]=(datetime)(lines[i].field[j]);
}
for(j=1;j<ArraySize(lines[i].field);j=j 4)
{
symbol[i]=(lines[i].field[j]);
}
for(j=2;j<ArraySize(lines[i].field);j=j 3)
{
type[i]=(lines[i].field[j]);
}
for(j=3;j<ArraySize(lines[i].field);j=j 2)
{
openprice[i]=(lines[i].field[j]);
}
for(j=4;j<ArraySize(lines[i].field);j=j 1)
{
sl_price[i]=(lines[i].field[j]);
}
}
}
openrpice[] 和 sl_price[] 数组具有字符串数据类型。 若要在计算中使用它们,请使用 StringToDouble() 函数将它们转换为 double 类型。 但是,在这种情况下会丢失小数。 为避免这种情况,请使用 StringReplace() 函数将逗号替换为小数点:
for(i=0;i<size;i )
{
StringReplace(openprice[i],',','.');
StringReplace(sl_price[i],',','.');
}
然后定义开仓所在柱线的索引:
for(i=0;i<size;i )
{
index[i]=iBarShift(Symbol(),PERIOD_D1,opentime[i]);
}
之后,找到最接近开仓所在的下位和上位分形:
for(i=0;i<size;i )
{
if(type[i]=='sell')
{
for(n=index[i];n>0;n--)
{
if(FractalDown_base_tf[n]!=EMPTY_VALUE)
break;
}
down_fractal[i]=n;
}
}
for(i=0;i<size;i )
{
if(type[i]=='buy')
{
for(n=index[i];n>0;n--)
{
if(FractalUp_base_tf[n]!=EMPTY_VALUE)
break;
}
up_fractal[i]=n;
}
}
接下来,以点数为单位定义止损,并将点数转换为整数:
for(i=0;i<size;i )
{
if(type[i]=='sell')
{
sl_size_points[i]=(StringToDouble(sl_price[i])-StringToDouble(openprice[i]))*f;
}
if(type[i]=='buy')
{
sl_size_points[i]=(StringToDouble(openprice[i])-StringToDouble(sl_price[i]))*f;
}
}
根据先前检测到的分形,您可以确定最大利润价位。 但首先,我们需要确保持仓不会因止损而过早平仓。 查验代码:
for(i=0;i<size;i )
{
if(type[i]=='sell')
{
for(n=index[i];n>down_fractal[i];n--)
{
if(High_base_tf[n]>=StringToDouble(sl_price[i]))
break;
}
maxprofit_int[i]=n;
maxprofit_bool[i]=(n==down_fractal[i]);
}
}
for(i=0;i<size;i )
{
if(type[i]=='buy')
{
for(n=index[i];n>up_fractal[i];n--)
{
if(Low_base_tf[n]<=StringToDouble(sl_price[i]))
break;
}
maxprofit_int[i]=n;
maxprofit_bool[i]=(n==up_fractal[i]);
}
}
现在您可以编写用于确定最大利润价位的代码:
for(i=0;i<size;i )
{
if(type[i]=='sell' && maxprofit_bool[i]==true)
{
maxprofit_price[i]=(string)Low_base_tf[down_fractal[i]];
}
if(type[i]=='sell' && maxprofit_bool[i]==false)
{
maxprofit_price[i]='';
}
if(type[i]=='buy' && maxprofit_bool[i]==true)
{
maxprofit_price[i]=(string)High_base_tf[up_fractal[i]];
}
if(type[i]=='buy' && maxprofit_bool[i]==false)
{
maxprofit_price[i]='';
}
}
然后您可以确定最大利润的大小。 如果控制被激活,止损的利润将为负数值:
for(i=0;i<size;i )
{
if(type[i]=='sell' && maxprofit_bool[i]==true)
{
maxprofit_size_points[i]=(StringToDouble(openprice[i])-Low_base_tf[down_fractal[i]])*f;
}
if(type[i]=='sell' && maxprofit_bool[i]==false)
{
maxprofit_size_points[i]=sl_size_points[i]*-1;
}
if(type[i]=='buy' && maxprofit_bool[i]==true)
{
maxprofit_size_points[i]=(High_base_tf[up_fractal[i]]-StringToDouble(openprice[i]))*f;
}
if(type[i]=='buy' && maxprofit_bool[i]==false)
{
maxprofit_size_points[i]=sl_size_points[i]*-1;
}
}
最后,我们定义开仓所在柱线与最大利润之间的持续时间(以柱线为单位)。 如果由止损激活平仓控制,则持续时间被定义为开仓所在柱线与触发止损柱线之间的差。:
for(i=0;i<size;i )
{
if(type[i]=='sell' && maxprofit_bool[i]==true)
{
duration[i]=index[i]-(int)down_fractal[i];
}
if(type[i]=='sell' && maxprofit_bool[i]==false)
{
duration[i]=index[i]-maxprofit_int[i];
}
if(type[i]=='buy' && maxprofit_bool[i]==true)
{
duration[i]=index[i]-(int)up_fractal[i];
}
if(type[i]=='buy' && maxprofit_bool[i]==false)
{
duration[i]=index[i]-maxprofit_int[i];
}
}
之后,我们将小数点替换回逗号以便正确显示参数:
for(i=0;i<size;i )
{
StringReplace(openprice[i],'.',',');
StringReplace(sl_price[i],'.',',');
StringReplace(maxprofit_price[i],'.',',');
}
现在,剩下的只是将获得的数据写入 file_stat.csv 文件:
int h=FileOpen('file_stat.csv',FILE_READ|FILE_WRITE|FILE_ANSI|FILE_CSV,';');
if(h==INVALID_HANDLE)
{
Alert('Error opening file!');
return;
}
else
{
FileWrite(h,
'Symbol',
'Deal type',
'Open time',
'Open price',
'SL',
'SL size',
'Max profit level',
'Max profit value',
'Duration in bars');
FileSeek(h,0,SEEK_END);
for(i=0;i<size;i )
{
FileWrite(h,
symbol[i],
type[i],
TimeToString(opentime[i]),
openprice[i],
sl_price[i],
NormalizeDouble(sl_size_points[i],2),
maxprofit_price[i],
NormalizeDouble(maxprofit_size_points[i],2),
duration[i]);
}
}
FileClose(h);
Alert('file_stat.csv file created');
检查:在输入中设置基准时间帧周期后(在我的情况下为 D1),启动图表上的脚本。 之后,具有以下参数集合的新 file_stat.csv 文件将显示在终端的本地文件夹中:
![file_stat.csv 文件内容 file_stat.csv 文件内容](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_7_2018120302195560.png)
图例 7. file_stat.csv 文件内容
6. 结束语
在本文中,我们分析了以编程方式确定走势延续模型的方法之一。 该方法的关键思路是在不采用任何指标的情况下搜索修正走势高/低极值。 然后基于发现的极值检测模型的连续点。
我们还讨论了将测试结果写入数组及其后续处理,根据策略测试器中的测试结果收集统计数据的方法。 我相信,有可能开发一套更有效的收集和处理统计数据的方法。 不过,这种方法对我来说似乎最简单和全面。
请记住,本文描述了定义模型的最低要求,最重要的是,EA 提供的最小控制集合。 对于实盘交易,应该扩展控制集合。
以下是走势延续模型识别的示例:
![模型识别 模型识别](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_8_20181203021955185.png)
图例 8. 走势延续模型识别样品
![模型识别 模型识别](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_9_20181203021955294.png)
图例 9. 走势延续模型识别样品
![趋势延续模型识别样品 趋势延续模型识别样品](http://image109.360doc.com/DownloadImg/2018/12/0314/148672567_10_20181203021955419.png)
图例 10. 走势延续模型识别样品
![趋势延续模型识别样品 趋势延续模型识别样品](http://pubimage.360doc.com/wz/default.gif)
图例 11. 走势延续模型识别样品
本文中使用的程序
# |
名称 |
类型 |
说明 |
1 |
Trade.mqh |
类库 |
交易操作类 |
2 |
MQL5_POST_final |
智能交易系统 |
EA 定义走势延续模型 |
3 |
Report_read |
脚本 |
收集统计数据的脚本 |
|