概述% G$ K+ K8 G" k; f+ O4 J7 v" e
我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。* } O v+ c+ W1 c& @
赫兹量化交易软件5 V6 B4 }7 z3 I$ `) C. a
自定义指标和 Heiken Ashi 定义
4 P$ v! u1 |3 a在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件# ]" n1 V9 F2 D- o l
简单的 Heiken Ashi 指标, C6 T& d5 Z) }& Y
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件# \& T H1 n. m7 J
我们来查看创建此自定义指标需要完成的所有步骤。2 M7 ~" H* _% }% P
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示: W+ F, f1 x6 t! ~
(indicator_separate_window) 在单独的窗口中显示指标。+ R) q9 T% t' r) g2 u1 a
(indicator_buffers) 确定指标计算的缓冲区数量。
$ w8 Z2 |% P7 `3 D. P(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。! }# S$ K4 W# F' H3 `' t& L
(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
/ v: N- P; A: I5 Z$ @; g. j(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
' K( a" n% _7 u) y' W' H3 g& n(indicator_widthN) 还要确定 N 或图形序列的宽度。
: ?7 k- R* \9 A2 H, \/ s) [(indicator_labelN) 确定图形序列 N 的标签设置。
; M! D8 p: C3 G8 A& p4 W3 R#property indicator_separate_window
* E# {0 m& B: f3 a/ C' K3 r#property indicator_buffers 5
' R9 w& C1 B3 i& {0 x I#property indicator_plots 19 \7 f- F' H2 Z0 I
#property indicator_type1 DRAW_COLOR_CANDLES7 P) b6 o% U5 p; K
#property indicator_color1 clrBlue, clrRed
' o4 z& c5 P1 m$ X4 O#property indicator_width1 23 ?2 o" f5 k k7 R3 p% z {# Y# V4 d7 d
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"% b' K$ b9 B4 N" x* K- m9 e% a
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
: `0 m v8 j7 ^) x4 u& \" Udouble haOpen[];# @* t! ?% }6 r4 P) l
double haHigh[];
5 i/ q: t* g N7 T' r9 Q3 s6 R, Idouble haLow[];. B( N# y9 i! C" }0 {5 z+ E
double haClose[];
. L1 Y. w; {7 V; W2 }' [double haColor[];
% \- E1 A- Q d, ?在 OnInit() 中,此函数初始化正在运行的指标。' _" Z" h0 s5 E) U) U
int OnInit()
/ f0 F! K1 m0 P. T; _) |4 f$ m3 e. C5 W调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
4 ^ q) m& l, n' m其参数为:
+ t2 b+ p+ }% q, d* sindex: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。8 T( n$ T7 ~# l5 F
buffer[]: 在我们的自定义指标中声明的数组。
0 @8 s4 V6 D( j: P7 ^0 R; Gdata_type: 我们需要在指标数组中存储的数据类型。. {2 ~ V; M/ w% O& |% |
SetIndexBuffer(0,haOpen,INDICATOR_DATA);2 g& U/ H. @8 u3 Q3 s7 H
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
; |* s- M5 s9 P# R. S2 ESetIndexBuffer(2,haLow,INDICATOR_DATA);5 ]3 \( v6 a2 b5 G# _
SetIndexBuffer(3,haClose,INDICATOR_DATA);5 Y3 d& W# \; N. p& u/ O8 }; R
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
% l2 k6 e. J# m: p% Z! `通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
3 I4 [4 G0 _3 X5 }prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。- v/ D5 [2 t# ~# {+ {
prop_value: 属性的值,我们将指定(_Digits)。
& P# @* b. B4 x7 NIndicatorSetInteger(INDICATOR_DIGITS,_Digits);
# @2 K+ a0 A5 _* p9 u调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为: |6 D; a8 @1 \9 J2 R
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。6 O/ S6 a" M- a
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
; O% b! I( r* S, ?2 wIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");0 s! f7 T* w* R6 F* `* M
调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
; k* ]5 t+ p" U3 C+ W1 w/ Nplot_index: 图形绘图的索引,我们将指定 0。
# M, M) c2 W8 v* Y- c: u- eprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
! y$ n4 H- u, v# }prop_value: 属性值。
7 u$ C! M1 t: ?! ]5 dPlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);% J4 P8 w4 ~( K0 {
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。( W7 K5 H, r$ T+ K, r9 v/ l
return(INIT_SUCCEEDED);
2 z; n; F* X J9 R3 C2 q在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件
) e( F6 t/ D' @4 J u2 h基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。% C$ w- w5 O9 Y) R& p4 K. |
int OnCalculate(const int rates_total,
( d# @ P; W8 sconst int prev_calculated,9 ^7 C& k& V4 @( c; A2 s0 G& o$ c
const datetime &time[],
9 q/ q0 h0 ~- X4 ]- P! O+ @const double &open[],2 m5 G. \, }- j9 S: {! \# _
const double &high[],6 r8 k/ ]+ s, A P, n6 X4 S
const double &low[],' `: y7 @/ g2 f/ K* l$ ^
const double &close[],
* m5 x& Y! K( t% m9 rconst long &tick_volume[],: v7 i; ?$ q2 h6 q; z$ _
const long &volume[],5 W. \+ i" D; S; T3 b4 X
const int &spread[])
8 h) d# E9 r7 W& W% R+ R8 s创建一个整数型 “start” 变量,我们稍后将为其赋值:( m) ~% q& @6 N4 ^( ~
int start;& Y7 b/ p* B' V
使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:
1 w) @1 E H% ^2 {( I. ^4 h4 wif(prev_calculated==0)- u5 O# Y- G% M# ?* o/ Y
{% N( x0 q. u# e" e
haLow[0]=low[0];% r" m9 H1 C# B* o1 q" x; u& @& F. g
haHigh[0]=high[0];* b1 D/ c& l. k2 i8 r/ C
haOpen[0]=open[0];
s1 U- ^% T6 f0 S& q6 {haClose[0]=close[0];
- h& q* o* }6 }! g" m" F9 M! p7 Istart=1;0 t2 I. o* G! n( E- a# E' Z4 U4 E
}
( c3 C: ^6 l( _0 |, l% y2 g* Helse
3 ~' ]% }2 u Lstart=prev_calculated-1;
% A# {" X0 Z& l# d. \+ ~( e在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。7 \" P0 B/ O- c+ Q6 C2 O0 ?6 g
这三个表达式将是:
0 P1 o) k- c- b/ e0 Vi=start: 对应起始位置。
/ |, i1 V( Z3 k' ii<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。( k% `& m+ o1 m! | h9 V
i++: 加 1 作为新的 i。
7 g/ V5 M9 e2 x我们每次在循环过程中需要执行的操作:+ D6 J0 l9 P0 W2 B
计算四个双精度变量
" W# v( V, W( \- j4 X7 S: ihaOpenVal: 对应 Heiken Ashi 开盘价。
. V" j0 ^! j$ \0 F4 ~$ L1 ohaCloseVal: 对应 Heiken Ashi 收盘价。$ K! C8 Y$ p( ^6 a$ Y; Z
haHighVal: 对应 Heiken Ashi 最高价。
4 S, `+ i1 p* A5 g- z) t8 \% V1 F: j3 yhaLowVal: 对应 Heiken Ashi 最低价。
6 N( ], \+ W" L! M$ J* J. g/ `7 w在上一步中分配的计算值与以下内容相同
+ J9 ]# \5 r! u& }8 ^- fhaLow=haLowVal' [- F! `( A; O* g& ]+ x+ E
haHigh=haHighVal, b8 b+ _2 W2 U! E; P n' |
haOpen=haOpenVal. I. H% ^% t( V+ p: g
haClose=haCloseVal
% S6 [! o9 \" Y/ t检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
1 q: C8 g5 X8 x5 w: vfor(int i=start; i<rates_total && !IsStopped(); i++)# Z; e; L: Z2 y' H
{
! X6 v0 S' f- q4 a5 R- kdouble haOpenVal =(haOpen[i-1]+haClose[i-1])/2;: R5 ]" W& z0 y
double haCloseVal=(open+high+low+close)/4;
W# K# }6 t# i: Udouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
. |2 ^% e* D2 qdouble haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
9 [4 L1 n: q% O6 }- shaLow=haLowVal;6 }$ \1 o, P! a( X3 M. R( i
haHigh=haHighVal;
( ?1 `& d1 D: k$ f; ?haOpen=haOpenVal;
2 d" K4 l- f/ b( _. HhaClose=haCloseVal;
/ ~2 E Y% g+ T" X, l$ C* y' |//--- set candle color! v7 E, {! G3 {; K* c
if(haOpenVal<haCloseVal)
5 Q) H/ L0 Z; C! N9 _2 `haColor=0.0;0 i8 X: a( G; O: v0 e
else- {8 c6 [/ y; C5 x9 p7 O
haColor=1.0;! {1 C: H3 Z" H: W: P; [$ K
}3 B2 v1 C5 E! d' O8 ~8 k5 v b- P
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
$ b2 S3 v! |( `7 Ireturn(rates_total);, [/ b7 T8 }- \# S
然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:! H4 W+ X/ k4 f. [# C% m$ ?9 U
//+------------------------------------------------------------------+& P! v+ d5 n" i W3 L9 {4 f2 v; U
//| simpleHeikenAshi.mq5 |- o1 G! J5 H/ F) ]% t
//| Copyright 2023, MetaQuotes Ltd. |8 r$ r+ b$ O- p0 ]2 e+ y- I% ^
//| https://www.mql5.com |
3 m+ u' G2 {# s& U# K4 I: _+ a//+------------------------------------------------------------------+
6 \4 b6 `* V8 \7 v* Y, J#property copyright "Copyright 2023, MetaQuotes Ltd."5 h. ?: A$ {/ I# F
#property link "https://www.mql5.com"2 R2 M! M7 S2 J4 ~( }) w
#property version "1.00"
5 t! \/ t# R, W#property indicator_separate_window9 M2 a- Y& P: V; |2 I
#property indicator_buffers 5
9 } G2 X2 }- m0 i* c% D#property indicator_plots 1
7 n+ S* `4 q6 L/ F#property indicator_type1 DRAW_COLOR_CANDLES
& j5 ?! J f) U3 Y1 ?' G#property indicator_color1 clrBlue, clrRed% }' u& m6 b% w8 ]2 i
#property indicator_width1 2
1 H% |1 O: A/ v7 y: _1 _2 h" N#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
* A" @7 m: ]) u9 j. S. adouble haOpen[];
7 @" }3 A- A3 a* D0 U* F2 M) m T( d8 Vdouble haHigh[];
& m+ h. D! G0 Z5 Z0 O: y. e4 mdouble haLow[];
4 C; F& e1 h7 f l3 p+ Pdouble haClose[];
% D/ }) {* |5 p: v) Pdouble haColor[]; z8 f' @7 D$ o3 ^, M
int OnInit(): q1 v% \$ x- B
{
7 x! { o, Q4 ]# g/ s* lSetIndexBuffer(0,haOpen,INDICATOR_DATA);4 u$ e$ h# |8 }8 b8 ]
SetIndexBuffer(1,haHigh,INDICATOR_DATA);0 d" c* o' b% @6 e, N# n
SetIndexBuffer(2,haLow,INDICATOR_DATA);
# f( H# O6 |; O. jSetIndexBuffer(3,haClose,INDICATOR_DATA);
1 \$ q" E% ]/ ASetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);: H8 N0 j; {: Q* }2 c
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);! ], v# p! q% B3 L# K: s8 \5 h
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");7 g5 }# B3 Y9 L% a- F
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
" p9 f& {2 p" Y. ~ o7 Creturn(INIT_SUCCEEDED);8 a% d$ ~* X" h1 H6 O' V5 \
} D( X: a& S4 B- n
int OnCalculate(const int rates_total,3 ?% [4 B& Y; C z
const int prev_calculated,9 _* h. k) H! ]2 M6 Z' E
const datetime &time[],
2 @- U1 M% C( W% `! y* Qconst double &open[],
& r4 e6 ^) ~' wconst double &high[],
& `' B: d) {& E. p z7 X1 f) M& Oconst double &low[],
. T0 R7 }1 k5 n) ]# uconst double &close[],7 m7 k& q0 n+ M5 b G% p
const long &tick_volume[],3 {+ ?( Z% T7 `+ b: r; l: x
const long &volume[], |