概述
2 W8 t% y5 u4 z+ p$ Z& Z, b; D2 {我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。) i4 v* ]. j6 w; @' N* n* ]
赫兹量化交易软件6 ^' L. f: V3 s' R9 |' Y
自定义指标和 Heiken Ashi 定义
% S9 u: w* s/ w8 ` z! }在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件8 I1 B% Q8 E7 ?2 t8 x
简单的 Heiken Ashi 指标1 @1 E7 n. q3 s0 d& u* X. W
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件
# y; l% Z8 D2 `; |5 n5 M我们来查看创建此自定义指标需要完成的所有步骤。8 H: `; t, K; f; A
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:/ z5 S" Y+ Y( ~. I/ i
(indicator_separate_window) 在单独的窗口中显示指标。
: a1 o8 [1 B. r8 A3 n$ J(indicator_buffers) 确定指标计算的缓冲区数量。* O* m9 L# U. T0 |! U, O7 v
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
2 W- `( A' O% i8 z8 }(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
; y! T8 L- y0 [& b" `5 U/ T(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。- L7 Y; L9 |: ]. J6 q
(indicator_widthN) 还要确定 N 或图形序列的宽度。
* F0 E9 g6 a& \5 x% }8 h# P: c' s(indicator_labelN) 确定图形序列 N 的标签设置。; b& M7 W( z7 M8 C$ F& N
#property indicator_separate_window
% _0 F: S% ?4 {2 Q" [9 H( f( L#property indicator_buffers 5
) D; d3 O; C& c: g3 M' b#property indicator_plots 1" ~+ p6 H- i: H% W/ d6 n& q
#property indicator_type1 DRAW_COLOR_CANDLES
, w. C% G- K |+ `" J#property indicator_color1 clrBlue, clrRed
1 u7 U1 @! ~5 F#property indicator_width1 2
% w% S4 S5 B( A8 S#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"/ ~( J7 h# t0 w
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
. M t0 ~% ?3 Z, idouble haOpen[];5 J2 \9 ?3 b8 r) N5 _; m w, P& x% |
double haHigh[];
# R; t" a+ B7 C! U0 ldouble haLow[];3 G* h& R. ]- {1 E1 F9 a
double haClose[];
" Z- H# M1 F* `* } qdouble haColor[];
& Z# Z0 p/ [1 ?' E h, x4 Y d在 OnInit() 中,此函数初始化正在运行的指标。 ]0 M: c+ u; E+ ]2 i; T5 E6 ^
int OnInit()
) z. F! `1 B9 W# f5 }) a调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
! N# M0 p2 ^- J其参数为:
0 ]1 {0 w. \6 u/ _index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
* h/ h" ^. B. n' Wbuffer[]: 在我们的自定义指标中声明的数组。$ N1 D: ?5 a1 f- S" a
data_type: 我们需要在指标数组中存储的数据类型。3 m/ I0 w$ U6 A
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
$ _- Q3 l8 q6 g+ W+ o* J. ~- i( v. DSetIndexBuffer(1,haHigh,INDICATOR_DATA);5 O5 S: d P# p: ^! q# y1 k& ^+ q
SetIndexBuffer(2,haLow,INDICATOR_DATA);
/ _* W" m. ?0 `* P: pSetIndexBuffer(3,haClose,INDICATOR_DATA);/ P/ C z' j3 s# \
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
, O: d) V n0 f0 b' M1 A6 D7 H通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:$ N) J1 n8 W7 ~' P3 m
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
, F* k, d' _6 R( lprop_value: 属性的值,我们将指定(_Digits)。
, k5 l% a- H" K: | C2 B; VIndicatorSetInteger(INDICATOR_DIGITS,_Digits);* |6 [, e v. W. P5 y
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:( o0 S$ j7 V9 L& e1 F. ~( s8 ~
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
, g7 E1 i' Z7 l. ^7 x& L2 Yprop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
/ w) H1 f9 d, P* TIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
, @' N) i& T; a: r调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
T" `/ y% h f( X. Nplot_index: 图形绘图的索引,我们将指定 0。( ^+ |$ W9 [, s: B6 Z, G3 k1 t
prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
8 ]9 _% r9 C3 L' E5 fprop_value: 属性值。
4 h$ e3 t& o ]PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);. z3 g, T9 Y' K5 L
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
, t$ J; u" N xreturn(INIT_SUCCEEDED);
, E, a- z& ?+ c4 W. P( h8 P1 s; ?在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件/ `* [# ^: W2 @" \7 ~+ E5 u: v
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。6 Q( M& e5 i6 E, k7 M" h% l! W
int OnCalculate(const int rates_total,
, Q. Y% c' p: K- D& Aconst int prev_calculated,
" e+ z- N' w/ i5 @7 yconst datetime &time[],
1 N' C n0 x' O7 M# nconst double &open[],1 E7 a$ _( r! l I( a
const double &high[],
# Z9 h5 m8 t. i: g6 q7 r% C9 W8 econst double &low[],
- v0 P- V/ L# X( Vconst double &close[],
6 R+ T) y& \' | E: y2 E6 aconst long &tick_volume[],
, k' @4 s1 ?- d, Y8 G: V1 `const long &volume[],
' J8 Q# M% X: Xconst int &spread[])
6 I2 s' E& A. Q+ b' T% e创建一个整数型 “start” 变量,我们稍后将为其赋值:
. e; z5 p# e2 U- q% Qint start;
3 K! G9 M' p8 c9 Z, P0 Y3 Q3 z+ `& [ H% j使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:
& R2 Q6 i' K, M1 j, Kif(prev_calculated==0)
8 \ L2 b, p2 O1 i, q{
+ c$ o. q( _& { [2 P$ whaLow[0]=low[0];
# [ |) j6 m5 s* jhaHigh[0]=high[0];
2 ^9 n+ `( x8 s! FhaOpen[0]=open[0];) P; E3 w& E' N* Z
haClose[0]=close[0];
2 n3 w: v! Q' B3 K9 O5 X% _& dstart=1;5 I$ I) {( H" Z& P' A/ \' y9 C2 A
}8 |2 _. V$ B* i2 L
else
( n) x) j9 V) P; a' Astart=prev_calculated-1;; E1 d9 F# v% c! \) k( a% }
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。2 U, q% I2 i7 q- S9 V. F* g" i/ T
这三个表达式将是:
1 Y! U* ^* F) @* P. Hi=start: 对应起始位置。 V0 V6 J F9 |" d+ G
i<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
( t Q% c# Y* Yi++: 加 1 作为新的 i。
O" T. }$ {, I我们每次在循环过程中需要执行的操作:
# L5 B. F5 X( k* D" v( q计算四个双精度变量
, Q' A( g8 C) y" J& n( A) ^7 thaOpenVal: 对应 Heiken Ashi 开盘价。8 ^1 Z" v% L4 |' y
haCloseVal: 对应 Heiken Ashi 收盘价。
: j+ y7 t: d# K& M& dhaHighVal: 对应 Heiken Ashi 最高价。
7 i, ?! h n% FhaLowVal: 对应 Heiken Ashi 最低价。
3 }1 D" ~5 k0 ^& T9 v: d在上一步中分配的计算值与以下内容相同4 t, S9 r7 D% n; {
haLow=haLowVal% Y- I' O/ e" Q9 z, u' t$ a
haHigh=haHighVal
: Z8 m* O% I" v x# jhaOpen=haOpenVal8 y! x9 E& b" a6 N! q% k
haClose=haCloseVal
' ^: Z) n# V0 \: p4 A4 ~3 w检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。% z/ q9 T( n: P
for(int i=start; i<rates_total && !IsStopped(); i++)' s1 f$ Z/ |0 l: A: P, u: b: \# w5 b
{+ Z' t' v5 x" P6 f- Z$ T- x
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
- ~% }3 K1 K2 ?6 h' _, ?double haCloseVal=(open+high+low+close)/4;
/ _: g/ G* s# g8 l6 h7 bdouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));! W3 @/ a; U; _8 T. D# ]; {6 H" G+ x* t
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));3 k0 z5 h# A) b/ p2 b
haLow=haLowVal;
- m* H$ t+ r8 V( [# N. WhaHigh=haHighVal;
! q9 K: X% { P5 |. @( V; EhaOpen=haOpenVal;: ?- W: b5 `% S* Q! Y% F, M" \! v
haClose=haCloseVal;
9 v. A" U% M1 C/ u- [1 I+ X' G: v//--- set candle color
& H. P2 K. T) H4 l7 o, ?! zif(haOpenVal<haCloseVal)
9 P$ C5 |+ S5 H! h4 rhaColor=0.0;% ], W5 V# l0 ]: o
else$ x6 L6 O6 T0 P3 o3 q, s
haColor=1.0;, W. t5 [1 w# X4 h" \; [
}- F4 c8 E- a' I: L0 j v! @
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
, @& E) n0 K3 N ireturn(rates_total);! t7 e7 O* S2 u# z* n
然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
$ F$ G5 h; a- q- X8 ?//+------------------------------------------------------------------+# H5 [- ?2 p- A7 X7 A0 e1 W
//| simpleHeikenAshi.mq5 |
5 ?. A+ x& ~* w//| Copyright 2023, MetaQuotes Ltd. |
% R l5 U4 R% R//| https://www.mql5.com | S. z) k- a5 \' ^' ?
//+------------------------------------------------------------------+
1 T3 Y5 i% B+ ~* z#property copyright "Copyright 2023, MetaQuotes Ltd."
8 @ {1 W( }' r8 o& e1 m#property link "https://www.mql5.com"$ X3 q% J/ n/ ^5 F
#property version "1.00"" h7 a( H3 N4 F3 J$ F' e A. U* z
#property indicator_separate_window' B* |3 ^9 I3 c' u3 d' }1 f7 a
#property indicator_buffers 5
, Z' ]7 F" \9 A" T#property indicator_plots 1
$ t" |) Q/ n# A#property indicator_type1 DRAW_COLOR_CANDLES
0 T8 Q" v) H# m2 f#property indicator_color1 clrBlue, clrRed; V4 i5 F' [, Y3 U
#property indicator_width1 20 O$ J" P8 l* t- O) ~# H( t
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"7 s$ z7 r3 x& t. c
double haOpen[];
; n; v% b* V% n. ^) C0 I: ^double haHigh[];# U9 e" p+ z+ e5 k. Y, ?
double haLow[];4 M7 h3 s9 \: ]9 f) \; s
double haClose[];3 N7 l+ E$ Q1 q
double haColor[];
% h. P& U' I: J' f5 c. P1 Z. w G* zint OnInit()
8 Z- J0 \* j6 ^+ \- y- |{* l' k: _+ w0 r1 P# X
SetIndexBuffer(0,haOpen,INDICATOR_DATA);. c0 x) Z) Y' D6 j7 w
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
* `5 S& q8 p z: W, u2 |4 K6 S \0 E7 `SetIndexBuffer(2,haLow,INDICATOR_DATA);( j F$ r0 ~, _1 W
SetIndexBuffer(3,haClose,INDICATOR_DATA);) n; F+ X1 ]6 W( Q" ] F. t4 S
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
( }& }3 B; H8 V) l. {- k$ P4 rIndicatorSetInteger(INDICATOR_DIGITS,_Digits);: x3 Z# V% q9 B0 V8 q+ G7 z
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");" F3 w H8 S( a; B. L
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);, A9 s" s$ Y/ R, _ x' K5 U( W2 A6 e
return(INIT_SUCCEEDED);% j9 u( [6 T5 X# |8 w. V) x. ]' H
}
- W- N! w H3 G2 {5 J/ _int OnCalculate(const int rates_total,: C+ p: o. M0 U/ L9 z
const int prev_calculated,6 R D) P: p$ M/ r" F( N/ ^
const datetime &time[],
# k; D6 Z8 w7 [6 U- ]; vconst double &open[],% T$ r5 W& T$ O7 q
const double &high[],
5 ]/ Z8 o& h& R0 xconst double &low[],
: O6 _/ T2 P/ U* N* Nconst double &close[],
6 {! F3 I& T: E. U/ jconst long &tick_volume[],- h& }2 x$ m1 j$ @# i7 ^
const long &volume[], |