概述5 V* c& y1 r0 }0 H) \# X: k3 g4 V) A% }
我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
3 t- T- O9 Q. }1 M% b: X) @& d赫兹量化交易软件9 _! {0 U4 C# q% r6 n) _1 p) T, _
自定义指标和 Heiken Ashi 定义* e0 K6 c$ h c2 s7 b; a4 E; ^
在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件
5 {7 g) L9 k; O: K* x( S& T: j- e- @简单的 Heiken Ashi 指标1 `; x$ }# \' t* R
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件2 ?0 O+ ]' ]& A# `% T* \( K
我们来查看创建此自定义指标需要完成的所有步骤。
5 b3 L+ L4 D& j2 W4 L/ N6 a通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:1 c9 z# s( ]& J- Z# [
(indicator_separate_window) 在单独的窗口中显示指标。
L* e& ~9 L* @+ Y3 X0 |9 C(indicator_buffers) 确定指标计算的缓冲区数量。+ H5 ?, x5 A9 ?" A
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。& Y# w) O R+ t6 E( f2 }
(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。3 }; ^+ X/ B7 {7 E8 l
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
; O6 _) R" v$ D! L; n7 H3 K" U(indicator_widthN) 还要确定 N 或图形序列的宽度。4 ~$ K- d! P* ]! B
(indicator_labelN) 确定图形序列 N 的标签设置。
; J9 B) z% E8 |$ B& T! K$ n#property indicator_separate_window
) r2 z+ Y7 I. @ y( Y$ r" {#property indicator_buffers 5
1 F$ a' e7 @6 |4 W#property indicator_plots 1
; C* A w6 M; z1 P- _! S' L' R#property indicator_type1 DRAW_COLOR_CANDLES
: |0 e5 a) ?9 k6 u#property indicator_color1 clrBlue, clrRed
7 Y/ p. ?" N; g x/ r#property indicator_width1 2
$ m% X2 `4 [( f6 v n2 W# ]#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
' y0 y. B5 @% q7 A* f( I为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。! C* W' O6 S5 Q8 M8 W- l* Q, I
double haOpen[];
6 s1 |* Z3 X& ~) b, i5 Odouble haHigh[];
! F6 l+ d! y7 g7 M' J4 a8 Jdouble haLow[];
4 o! ^/ L# v9 g0 Qdouble haClose[];7 b) e" Q4 `3 r; W( U
double haColor[];
# i' r' m, R ~4 [( a在 OnInit() 中,此函数初始化正在运行的指标。4 h& E+ `2 u3 s, v$ a# I
int OnInit()
% R" o; h# C* M, _调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件' `# u% |/ Z8 v {
其参数为:) G3 b3 u; x' L
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
/ O" @6 E4 b! X+ zbuffer[]: 在我们的自定义指标中声明的数组。" s6 A* O1 }" } B' A0 t* |, A
data_type: 我们需要在指标数组中存储的数据类型。1 n+ r4 N1 V# F/ L0 U9 m+ S
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
. @/ K) {8 M& Y' B) t: R# \SetIndexBuffer(1,haHigh,INDICATOR_DATA);
# J" e9 u) D8 }( D/ O5 M% b* }SetIndexBuffer(2,haLow,INDICATOR_DATA);# F* ~' ]. l% v. f; J# E1 |
SetIndexBuffer(3,haClose,INDICATOR_DATA);. f! Q$ b R! i2 U s
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);+ d8 Q& f3 w. i' M- B1 }
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
- E% N& ~; h# X- W5 }# Sprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。- Z( ^$ j$ @' U+ P6 L
prop_value: 属性的值,我们将指定(_Digits)。" o7 G: ?2 }$ _! ^3 K4 T
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
0 `. P4 C5 @: y调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:# v$ L. K8 c% ^- G! _9 r6 V9 ]
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。* N1 V# s" [+ `1 q3 u) x
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
1 ~. n8 i* U& i9 DIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
7 [: m J* G+ b6 b. o调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
3 p! j( y+ w2 x( ~8 B+ l# ]. Yplot_index: 图形绘图的索引,我们将指定 0。) ~- ^ z, r2 p
prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。$ @5 y4 A/ \+ ^' d% ]- _, E
prop_value: 属性值。
; A" e9 e3 | x/ H6 Q, VPlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);% a: B' j+ h; k, w. p$ Y ?) l
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。7 L$ [8 f# D: Y! D( @% F! Q
return(INIT_SUCCEEDED);3 V( C4 _, Y7 L
在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件
- w# s# g4 Q% z* G基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。# M. D: l x0 m2 w$ _ B; e/ h
int OnCalculate(const int rates_total,% c# W1 ~" Q1 K1 S) s/ z% p; C
const int prev_calculated,, A1 c: E5 k9 S, S7 c. R
const datetime &time[],
+ L! ^1 z4 P- J$ q( i2 T" sconst double &open[],
$ a% B, G$ X+ Q9 bconst double &high[],
! }9 y. B# \# P- X8 u7 a- I. ~# s: X+ aconst double &low[],3 @7 o. T6 d8 P& g* ?! k
const double &close[],
$ _5 x: q" F- d4 p. pconst long &tick_volume[],
: [* ?1 L9 P- [) K8 hconst long &volume[],
2 h3 n# ~/ E% F) d# K. aconst int &spread[])* v$ F; p9 v" h0 h1 M3 _
创建一个整数型 “start” 变量,我们稍后将为其赋值:+ S, }: |/ f3 F
int start;
7 ^/ x4 Y3 e, A4 G; ^8 \5 z使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:& Y1 F5 E; e7 G1 q: ?2 \5 A
if(prev_calculated==0)
; {5 |0 {+ C! t' |% r{! v0 @$ s+ P4 o3 i
haLow[0]=low[0];: u3 R! m( |# n0 S# m$ `' t
haHigh[0]=high[0];
- ~& h+ n% c/ s" g, O+ dhaOpen[0]=open[0];1 z. @9 T1 A, `0 X
haClose[0]=close[0];
' L+ t6 p/ ?/ Lstart=1;: R& T S" J5 j
}9 h! k% X9 L' A$ K( ^
else
) D# {( V6 d. q$ {$ zstart=prev_calculated-1;9 A' V# {: }$ Y8 f# ~
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
: ]4 R+ I8 a8 n$ c0 r) r这三个表达式将是:
" N, X, M- R) I/ G/ ti=start: 对应起始位置。
! O3 w( T4 [# ~- ti<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
4 ]8 c7 \ J0 X9 R Y! li++: 加 1 作为新的 i。
1 B) v1 h" v* Y7 P9 [7 N3 F4 C我们每次在循环过程中需要执行的操作:- h& d9 n# J( \9 ?
计算四个双精度变量
2 w$ ^, D' H1 X2 W8 hhaOpenVal: 对应 Heiken Ashi 开盘价。
- z/ N g1 m0 L6 d' hhaCloseVal: 对应 Heiken Ashi 收盘价。
2 j8 d* g P% M+ X7 c' bhaHighVal: 对应 Heiken Ashi 最高价。2 D8 m$ V' C% \' l
haLowVal: 对应 Heiken Ashi 最低价。
/ l* Y0 ^4 l2 }* H$ m在上一步中分配的计算值与以下内容相同
/ ~6 n5 [# I: s z3 w8 O3 o' thaLow=haLowVal' i( C ]. {0 j
haHigh=haHighVal
: s; k$ M8 _3 D' u* EhaOpen=haOpenVal
1 U3 o {) h4 chaClose=haCloseVal
0 j1 z1 Z" e% D, [& v检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。# R' [ i3 a: B8 @) D" N7 G
for(int i=start; i<rates_total && !IsStopped(); i++)5 I+ Y9 a$ T- n, ]% g' Y
{
- x |7 K5 g! U* B0 a2 _double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
; M# y) k- i1 W' Y) n, |3 g8 Cdouble haCloseVal=(open+high+low+close)/4;) h" h3 j0 J' Y5 s% t; c5 m
double haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));0 e6 ~" [& T( |" @" J
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
; m; P1 r/ E! R$ xhaLow=haLowVal;
& C& [( Q/ f6 h5 z9 Q' H; S; B, EhaHigh=haHighVal;
8 _& J) B$ o+ t; m7 }; ShaOpen=haOpenVal;
4 q; { F$ K, Q' ~haClose=haCloseVal;
( }4 J2 V2 F7 D! Y4 S( v2 n, g9 N! m//--- set candle color
$ R$ c, P+ o, _0 a ?0 u$ Xif(haOpenVal<haCloseVal); I3 t3 t( }# d! p
haColor=0.0;
, Z/ T+ [( u! x$ v2 Z9 i& I- |7 Welse
" t9 A" |$ m5 V/ R. Q# d- _haColor=1.0;6 @: l# `4 n4 H( ]& d: W' d+ f
}
4 T" r# } U4 m5 G终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
, D$ ]# m8 X* k. E9 f& yreturn(rates_total);5 u0 n+ _) s3 e8 m6 g8 C
然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:& K1 G, f* j) e4 }* X
//+------------------------------------------------------------------+' ^$ k8 a$ ^. b* O
//| simpleHeikenAshi.mq5 |1 S- a( N7 ?+ L/ ?! z
//| Copyright 2023, MetaQuotes Ltd. |
: V7 a5 u4 r; t2 l//| https://www.mql5.com |
: B r) B w) Z3 g. E( ?. c9 g//+------------------------------------------------------------------+
. ~3 `/ h* z2 o# w# r#property copyright "Copyright 2023, MetaQuotes Ltd."! n' K8 i) ?4 m/ Z/ t- a5 c
#property link "https://www.mql5.com"
3 J) w+ Q& Q0 [" A: o#property version "1.00"
+ X" N" f$ H! V e/ t2 Q#property indicator_separate_window
! O/ r5 {- d) X( E/ C5 \. p Z#property indicator_buffers 5
$ [3 J4 e8 e! e3 F6 ^2 I4 F#property indicator_plots 1
7 Y1 J* i4 J) \# \4 N5 A) k" f#property indicator_type1 DRAW_COLOR_CANDLES& m. o! R+ O n
#property indicator_color1 clrBlue, clrRed0 C5 z. _( j7 I8 _
#property indicator_width1 28 @' r% H, X& `
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"7 l: H/ d# Z# I9 h! O( i0 J
double haOpen[];+ n' P+ T: N4 R2 J; F3 F. R
double haHigh[];
+ @0 N& T9 a: H7 h4 C# } ^double haLow[];
+ M9 \* C/ U) K/ e' Jdouble haClose[];& @4 R# g( g* k7 w
double haColor[];
. O4 [4 C* P4 d# r$ V+ Sint OnInit()" S1 J5 J2 A# y$ c2 O/ x' A
{" u( x* O' B( [ p
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
/ m2 b2 D5 `( M( h/ {3 F$ sSetIndexBuffer(1,haHigh,INDICATOR_DATA);. ~# ?/ Y( a6 t- _$ g' T' l' B
SetIndexBuffer(2,haLow,INDICATOR_DATA);9 X) ~# w0 n2 Y, r8 I
SetIndexBuffer(3,haClose,INDICATOR_DATA);
% E' `4 _3 @9 q2 @. m# `, R, sSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
4 t( L9 |. n$ o+ _% Y; Y/ T6 ]IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
1 ^# p9 o1 G% a% L' i3 X6 kIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");- y. _/ {7 y% u
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);& ^" O; V V& Q0 u0 r
return(INIT_SUCCEEDED);3 S' T8 v" A! ?5 K. V' P
}
& ~- {. S" t) X& g& J! `4 gint OnCalculate(const int rates_total,
9 w+ q; t0 w+ P$ \, _const int prev_calculated,4 d, C& Q* G# N8 b* ?7 H* f
const datetime &time[],, N) \& X. @ q3 i& \5 _
const double &open[],: M( d q1 V$ `' V/ w+ V/ c
const double &high[],: A2 {& [4 d) m
const double &low[],5 }/ n2 }! ~& }% Q9 v4 O" g2 ]& Q
const double &close[], P2 D' y% O: _2 T& Q# y
const long &tick_volume[],
2 j Q3 ^9 \2 r8 N0 l) fconst long &volume[], |