在本文中, 我们将研究构造支撑和阻力线。货币品种的技术分析是在金融市场内进行交易的重要组成部分。自动构造这些线将简化金融分析师和交易员的工作, 并加速技术分析。此外, 此处描述的指标可用于开发智能交易系统。
搜索所有波峰和波底
利用价格图表的局部波峰和波底绘制支撑和阻力线。为了判别这些极点值, 我们将应用众所周知的之字折线 (ZigZag) 指标。我们可以在其输入中设置支撑和阻力线的必要属性。
这些线的比例可以使用之字折线指标的参数进行更改, 且您可以在不同的时间帧应用相同的参数。这令我们能够获得构筑支撑和阻力位所需的极点值。赫兹股票量化软件
下面的图片显示极点值随时间帧的变化而改变。第一张图像显示包含 30 分钟周期的图表. 第二张图像显示的是四个小时。赫兹股票量化软件
选择合适的极点值来构造价位
我们仅构造位于当前价格附近的支撑/阻力线, 意即它们在技术分析期限内与我们的当前状况相关。此外, 为了令这些线的斜率与价格贴合, 我们在下降趋势 (对于阻力线) 期间选取的极点值高于或等于前一个极点值, 或在上升趋势中选取与前一个相同或较低的极点值。在第一幅图像中, 这些可能是 1-2-3-4-5-7, 而在第二幅中 — 1-2-3-6-7-8。
现在我们已定义了极点值的选择标准, 我们来研究如何在代码中实现它们。为了澄清要点, 我们在此仅显示其中一部分。
//+------------------------------------------------------------------+ struct trade_points // 定义极点值的结构 { double price; // 价格 int pos; // 位置, 柱线的索引 bool hpoint; // 为真, 则是波峰 bool lpoint; // 为真, 则是波底 };
在 OnInit() 函数中创建之字折线指标的句柄:
int OnInit() { ZZ_handle=iCustom(_Symbol,_Period,"ZigZag",ExtDepth,ExtDeviation,ExtBackstep); return(INIT_SUCCEEDED); }
进而, 我们通过对所有之字折线指标极点值逐个进行排序, 将数据输入矩阵:赫兹股票量化软件
double max=close[1]; double min=close[1]; int z=0; for(shift=0;shift<rates_total && !IsStopped();shift++) { CopyBuffer(ZZ_handle,0,shift,1,ZigzagBuffer); if(ZigzagBuffer[0]>0) { if(ZigzagBuffer[0]>=max && ZigzagBuffer[0]==high[shift]) { ArrayResize(mass,z+1); max=ZigzagBuffer[0]; mass[z].price=ZigzagBuffer[0]; mass[z].pos=shift; mass[z].hpoint=true; mass[z].lpoint=false; z++; } if(ZigzagBuffer[0]<=min && ZigzagBuffer[0]==low[shift]) { ArrayResize(mass,z+1); min=ZigzagBuffer[0]; mass[z].price=ZigzagBuffer[0]; mass[z].pos=shift; mass[z].lpoint=true; mass[z].hpoint=false; z++; } } }
定义构造趋势线的标准
现在, 在形成具有极点值的数组后, 我们可以构造必要的支撑/阻力线。下面的图像解释了构造这些线的主要标准。
从第一点开始, 我们可以通过以下任何一点来构造趋势线。但并非所有这些趋势线都可以被视为支撑/阻力线。此外, 它们可能随着时间的推移失去其相关性, 从而变得无以致用。由于我们希望清理图表上不必要的图形对象, 我们执行排序来舍弃多余趋势线。
我们假设该趋势线的起点是 A, 第二个极点值是 B, 最后一根柱线附近的点是 C。
可能会有多个标准, 且它们的组合在不同情况下会不断变化。我们只研究最基本的。将来, 所有人都可以根据自己的判断来改进这一指标。赫兹股票量化软件 以下是主要标准:
- АB/BС 距离比率
- 价格穿越 AB 段的次数
- 价格穿越 BC 段的次数
- 从 С 到当前价格的距离
- 趋势线的最小和最大长度
- 趋势线的斜率
- 价格位于阻力线之上或之下
我们来更详尽地研究上述标准, 以更好地理解输入配置。
- 为了保持可接受的比例, 您可以使用菲波纳奇比率并将最小允许比率设置为 0.25 或 0.382。根据这一标准, 长度比率应对应于条件 АB/АС>=02.25 (0.382) 且 BС/АС>=02.25 (0.382)。出于便利起见, 可以在输入中设置该参数的值。赫兹股票量化软件
- 所有存在的趋势线也应按照价格穿过 AB 线的次数进行彻底排序。如何进行这种验证也有很多选项。我们可以只参考收盘价突破这条线的柱线, 或者我们可以参考最高/最低价突破的柱线。第二个标准要验证的是穿过这条线段的柱线数。这些参数也作为输入。赫兹股票量化软件
- 我们可以通过突破次数, 其性质和相对于 BC 段的当前价格位置来评估这条线的重要性。当开发 EA 时, 上述所有标准均可用于形成趋势线以及交易策略。在此指标中, 我们只会显示尚未穿越此段的趋势线。赫兹股票量化软件
- 根据趋势线当前的相关性, 可以过滤从当前价格到首条趋势线的距离。例如, 我们可能只绘制其距离不超过 50-100 点的趋势线。
- 在我们的案例中, 趋势线的最小长度由之字折线指标的输入决定, 但是如果需要也可以监控该参数。指标将检查 AB 和 BC 段的最小长度。
- 由于支撑线更为重要, 因为它们用于开仓, 因此该指标所构造的上升趋势斜率为零或正数, 下跌趋势线斜率为零或负数。赫兹股票量化软件
- 我们可以用两种方式使用这些趋势线。第一个是只参考不折返的趋势线并顺势交易。第二个是只在反向突破趋势线时开单。两种类型的趋势线都很重要, 因此两者都要反映在指标中。
以下是形成下跌趋势阻力线的一部分代码。
// 判断这些趋势线是否符合我们的标准并填写下跌趋势矩阵。 for(j=z-1; j>=0; j--) { if(mass[j].hpoint) for(i=j-1; i>=0; i--) { if(mass[i].hpoint) if(i<j) { a=mass[j].pos; b=mass[i].pos; double ratio=double((a-b)*100/a); // 定义 AB 段与 AC 总长度的比率 if(ratio>fibo && ratio<(100-fibo)) // 定义是否符合标准 1, АB/BС 段的比例 if(b>Min_dist &&(a-b)>Min_dist) // 定义是否满足标准 5, АB 和 BС 段的最小长度 { ax=mass[j].price; bx=mass[i].price; coef=(ax-bx)/(a-b); price=close[1]; deviation=(ax+coef*bx)-price; cross_bc=0; cross_ab=0; if(MathAbs(deviation)<tolerance*_Point) // 定义是否满足条件4 (点 С 到前一根柱线收盘价的距离) { // 从 a 点到 b 点的交叉次数 for(int n=a; n>b; n--) if((close[n]-(ax+coef*(b-n)))>0) cross_ab++; // 从 b 点到端点的交叉次数 for(int n=b-1; n>=0; n--) if(close[n]>(bx+coef*(b-n)) && close[n+1]<(bx+coef*(b-n+1))) cross_bc++; if(cross_bc<=Intersection_bc && cross_bc<=Intersection_ab)// 定义是否满足条件 2 和 3 { // 填写下降趋势矩阵 ArrayResize(DownTrend,y+1); DownTrend[y].a=a; DownTrend[y].b=b; DownTrend[y].ax=ax; DownTrend[y].bx=bx; DownTrend[y].dst=MathAbs(deviation); DownTrend[y].coef=coef; y++; } } } } } } // 使用获得的矩阵显示图表上的下跌趋势线 for(j=0; j<ArraySize(DownTrend); j++) { a=DownTrend[j].a; b=DownTrend[j].b; ax=DownTrend[j].ax; bx=DownTrend[j].bx; coef=DownTrend[j].coef; if(a>0 && b>0 && MathAbs(a-b)>0) { if(a>0 && b>0 && MathAbs(a-b)>0) { //--- 创建趋势线 TrendCreate(0,"DownTrend "+string(j),0,time[a],ax,time[b],bx,DColor,DStyle,DWidth,DBack,DSelection,DRayLeft,DRayRight,DHidden,DZOrder); ChartRedraw(); } }
指标结构的示例:
在交易中使用支撑/阻力线
应用支撑/阻力位的主要交易原则是在上升趋势期间(并在下跌趋势期间卖出)或平坦时段在支撑线附近买入。一些图形模型 (形态) 也会用到。赫兹股票量化软件
这种交易策略令您能够从趋势变化中受益, 即使金融产品处于横盘状态, 或价格形成一种形态。趋势有助于确定交易方向。例如, 如果当前的趋势是向下, 但随后走向横盘, 那么最好在阻力线附近卖出, 而非在支撑位买入。出现下跌趋势意味着卖出交易比买入成功机会更大。如果趋势向上且后面呈三角形, 那么最好在这个三角形的支撑线附近买入。赫兹股票量化软件
在接近支撑/阻力位时顺势交易可能会带来利润, 但价格往往会突破这些价位。所以, 我们需要等待确认此金融产品在该特定价位的重要性。在依据趋势线买入或卖出之前, 您需要等待, 直至价格稳定在其附近。或者, 您可以等待价格从该价位反弹, 并在此后开始交易。赫兹股票量化软件
当自支撑线进行买入交易时, 在价格突破整理区域的高点之后, 等待价格在其附近稳定后再买入是合理的。这可确保该价位能够真实影响价格, 且价格开始自该价位向必要方向 (向上) 移动。这正是我们进行买入交易所需要的。自阻力线进行卖出交易时也会发生类似的情况: 您需要等待阻力区附近的盘整, 并在价格跌破该区域的低点时开仓。赫兹股票量化软件
在开始交易时, 一定要预测它的平仓条件。当从支撑线进行买入交易时, 建议在价格达到强阻力线之前将之平仓。当进行卖出交易时也会发生类似的情况。您也可以在次要支撑/阻力位平仓。当自支撑线买入时, 您需要在上升趋势通道的阻力位卖出。如果价格突破该价位, 您也可以尝试获得更大的利润。例如, 从三角形支撑位 (通常上涨趋势) 买入时, 您可以持仓等待, 直到价格突破三角形并继续向上移动。之后, 您可以在下一条阻力线上离场。赫兹股票量化软件
基于指标的 EA
以下是拥有以下功能的 EA:
- 止损和止盈
- 最大买入/卖出订单数量
- 尾随停止
- 盈亏平衡
- 通过指标信号将反向交易平仓
- 四种高时帧滤波器 (MACD, RSI, WPR, MA) 可供选择
EA 直接与指标生成的趋势线配合工作。因此, 它需要在同一个图表上启动指标才能实时工作。指标设定已在指标本身中配置。EA 也有指标设置, 但它们仅用于测试目的。为了测试 EA, 初始化 EA 时定义的指标句柄已经在代码中创建。赫兹股票量化软件
有三种 EA 操作模式:
- from level — 在趋势线的潜在价格回滚方向上进行交易。如果柱线的高位或低位与该价位交叉, 而收盘价未突破当前趋势线, 且下一根柱线收盘时也未能破位, 则开单交易。EA 检查价格接触后是否突破该趋势线。赫兹股票量化软件
- level breakdown — 在趋势线的潜在突破方向上交易。如果柱线的高位或低位突破该价位, 而收盘价并未突破当前趋势线, 且下一根蜡烛的收盘价突破该趋势线, 则开单交易。
- all — 使用上述两种模式。
以下代码是信号形成时买入和卖出的函数:
//+------------------------------------------------------------------+ int signal() { int res=0; int macd=0; int rsi=0; int wpr=0; int ma=0; if(Use_macd==true)macd=macdS(); if(Use_rsi==true)rsi=rsiS(); if(Use_wpr==true)wpr=wprS(); if(Use_ma==true)ma=maS(); CopyOpen(NULL,0,1,3,O); CopyHigh(NULL,0,1,3,H); CopyLow(NULL,0,1,3,L); CopyClose(NULL,0,1,3,C); Signals=0; for(int i=0;i<ObjectsTotal(0,0,OBJ_TREND);i++) { string sName=ObjectName(0,i,0,OBJ_TREND); if(StringFind(sName,"UpTrend")==0 || StringFind(sName,"DownTrend")==0) { ax=ObjectGetDouble(0,sName,OBJPROP_PRICE,0); bx=ObjectGetDouble(0,sName,OBJPROP_PRICE,1); p1=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,0); p2=(int)ObjectGetInteger(0,sName,OBJPROP_TIME,1); a=iBarShift(p1); b=iBarShift(p2); kkk=(bx-ax)/(a-b); lvl=bx+kkk*b; plvl=bx+kkk*(b-1); if(mode==0 || mode==2) { if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]>lvl)Signals=1; if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]<lvl)Signals=2; } if(mode==1 || mode==2) { if(StringFind(sName,"UpTrend")==0 && L[1]<=plvl && C[1]>plvl && C[0]<lvl)Signals=2; if(StringFind(sName,"DownTrend")==0 && H[1]>=plvl && C[1]<plvl && C[0]>lvl)Signals=1; } } } if(Signals==1 &&(macd==1 || Use_macd==false) && (rsi==1 || Use_rsi==false) && (wpr==1 || Use_wpr==false) && (ma==1 || Use_ma==false))res=1; if(Signals==2 &&(macd==2 || Use_macd==false) && (rsi==2 || Use_rsi==false) && (wpr==2 || Use_wpr==false) && (ma==2 || Use_ma==false))res=2; return(res); } //+------------------------------------------------------------------+
测试表明, 与突破交易相比, 回滚交易的盈利能力较低。
使用以下输入参数测试三种模式的测试图如下所示:
input string s="-------------------------------------------"; // 主设置 input int Magic=12345; input double LotSize=0.1; input int Slippage=30; //滑点, 点数 input int StopLoss=0; //止损, 点数 input int TakeProfit=0; //止盈, 点数 input int TrailingStart=0; //为谁开始, 点数 input int TrailingStop= 0; //尾随停止, 点数 input int TrailingStep= 0; //尾随步长, 点数 input int SL_prof=0; //开始 BE, 点数 input int SL_lev=0; //BE 价位, 点数 input int Buy_max=1; //最大买单数量 input int Sell_max=1; //最大卖单数量 input bool Sig_close=true; //逆势交易平仓 input tip mode=0; input string s0="-------------------------------------------"; // 指标设置 input int _ExtDepth=12; input int _ExtDeviation=5; input int _ExtBackstep=3; input int _Min_dist=0; // 最小距离 input int _fibo=30; // 菲波纳奇比率 input int _tolerance=200; // 冗余 input int _Intersection_ab=1; // 从 a 点到 b 点允许的交汇点数量 input int _Intersection_bc=1; // 从 b 点到 c 点允许的交汇点数量 input string s1="-------------------------------------------"; // MACD 设置 input ENUM_TIMEFRAMES macd_tf=PERIOD_CURRENT; // 周期 input int fast_ema_period=12; // 快速均线周期 input int slow_ema_period=26; // 慢速均线周期 input int signal_period=9; // 差值的均化周期 input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; // 价格类型 input string s2="-------------------------------------------"; // RSI 设置 input ENUM_TIMEFRAMES rsi_tf=PERIOD_CURRENT; // 周期 input int rsi_period=14; // 周期 input ENUM_APPLIED_PRICE rsi_applied_price=PRICE_CLOSE; // 价格类型 input double rsi_max_s=100; // 卖出的最大价格 input double rsi_min_s=70; // 卖出的最小价格 input double rsi_max_b=30; // 买入的最大价格 input double rsi_min_b=0; // 买入的最小价格 input string s3="-------------------------------------------"; // WPR 设置 input ENUM_TIMEFRAMES wpr_tf=PERIOD_CURRENT; // 周期 input int calc_period=14; // 周期 input double wpr_max_s=0; // 卖出的最大价格 input double wpr_min_s=-20; // 卖出的最小价格 input double wpr_max_b=-80; // 买入的最大价格 input double wpr_min_b=-100; // 买入的最小价格 input string s4="-------------------------------------------"; // MA 设置 input ENUM_TIMEFRAMES ma_tf=PERIOD_CURRENT; // 周期 input int ma_period=10; // MA 周期 input int ma_shift=0; // 平移 input ENUM_MA_METHOD ma_method=MODE_SMA; // 平滑类型 input ENUM_APPLIED_PRICE ma_applied_price=PRICE_CLOSE; // 价格类型 input bool Use_macd=true; // 使用 MACD 作为滤波器 input bool Use_rsi=false; // 使用 RSI 作为滤波器 input bool Use_wpr=false; // 使用 WPR 作为滤波器 input bool Use_ma=false; // 使用 MA 作为滤波器 input int sbar=1; // 信号柱线 0-当前, 1-已收盘
在测试过程中, 在其中一个方向上只会开一笔 0.1 手的交易。如果信号相反, 当前交易被平仓, 之后反向开单。应用 MACD 作为过滤器, 意味着在指标值小于零时进行买入交易, 而指标值在大于零时进行卖出交易。测试针对 2015-2017 年 EURUSD H1 进行。