概述
, q# H" I4 z. x. o我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
2 Z5 a, `. f4 n% y8 Z赫兹量化交易软件) {7 ~! |5 M2 g0 |9 i$ C+ O
自定义指标和 Heiken Ashi 定义
' \9 U5 A& j: p% @在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件
, M) G0 T& C7 W8 T简单的 Heiken Ashi 指标
$ T2 a5 B/ w+ Y! f在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件" z8 W! o2 I- m# R/ F% R1 [$ d
我们来查看创建此自定义指标需要完成的所有步骤。9 G. v$ T3 B* M) {
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:. d8 Q0 N, Q( G+ R: N( c7 i {' p
(indicator_separate_window) 在单独的窗口中显示指标。5 V, n, E3 h' w1 ?; E( r* T$ [
(indicator_buffers) 确定指标计算的缓冲区数量。
+ A5 ^- ~/ }- Z6 D# E# a5 q( Z(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
5 ?8 h* r4 L% L(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
; s2 w- }2 I, S+ d& O6 i( K(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。5 Q- b2 ]; {3 |- c, |# H6 K2 A" N0 ^' C
(indicator_widthN) 还要确定 N 或图形序列的宽度。
2 _* |7 l0 Q- Z/ F, ?(indicator_labelN) 确定图形序列 N 的标签设置。' b- j3 N/ k" Y! n- Z$ q
#property indicator_separate_window
2 D; w0 e. W0 j% G#property indicator_buffers 5
3 y" y6 f6 U7 D2 L5 E) @2 }0 J#property indicator_plots 1
2 e2 A. X/ `1 G! w1 ]! U/ {: F* X3 {3 m#property indicator_type1 DRAW_COLOR_CANDLES0 B! {2 ]: V$ L/ Q# s5 B% T
#property indicator_color1 clrBlue, clrRed' K3 ?# V3 g. M; y, [. {4 |
#property indicator_width1 2
7 U6 [: a, [8 o7 q; \1 V#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"6 n* D' o4 p" f* h4 ?2 F4 |0 Y3 s
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
' c) y- P# q* o6 z$ `$ r0 xdouble haOpen[];
' q4 K) Q/ a% S# Odouble haHigh[];
" I$ z# a1 b3 f& L9 rdouble haLow[];
0 ]7 Z$ O7 o; |9 C9 fdouble haClose[];( n' Z0 t" D; _7 e0 `1 \) m
double haColor[];
# u) x. b+ z2 R在 OnInit() 中,此函数初始化正在运行的指标。
( s! r1 D9 B+ L: sint OnInit()2 f; X' R# k: l7 W9 D
调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
% x \! v6 j! _, T; w8 u4 ~" B其参数为:
4 ]! F0 w$ v2 W h( A$ vindex: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。8 {- h2 F/ P2 F. P6 \2 n0 Z3 @
buffer[]: 在我们的自定义指标中声明的数组。
* {, N3 Z8 D+ L5 idata_type: 我们需要在指标数组中存储的数据类型。$ ^7 Q9 F2 [% ^7 O* M0 x
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
( }! c: t _7 O0 L9 ESetIndexBuffer(1,haHigh,INDICATOR_DATA);; O1 f* W4 {$ |! D/ j" O* z o' ]
SetIndexBuffer(2,haLow,INDICATOR_DATA);6 E. V7 G& @6 Q8 Q
SetIndexBuffer(3,haClose,INDICATOR_DATA);% ?* O. S4 w7 Z
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
: [: C1 W: I$ F- k% M0 z通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
' x8 K% R( S( p5 J1 g+ fprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。: }$ ]9 b* N6 U0 Y, M* D+ I
prop_value: 属性的值,我们将指定(_Digits)。
5 k# j+ [3 i( m/ VIndicatorSetInteger(INDICATOR_DIGITS,_Digits);: ^2 x' ~8 Y1 F+ }/ T/ Q7 q
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:
: A$ U# l& T8 Jprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。5 L8 b B4 d+ ]% e) T- w
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。0 N! F( R' P, f! ^" o$ n* v( T
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
. f `+ }, `6 A% K3 P调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
" k" B' `% Q6 H; W% j) ?- V' e: zplot_index: 图形绘图的索引,我们将指定 0。
( x7 g' h! }+ `# x4 iprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。9 l2 k6 ]& M+ p7 Q
prop_value: 属性值。% E/ ^/ M' R% s) ~3 P
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
' ^# t, N6 R. s% J) I O然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。 B# {2 ]* X0 I' x8 }1 Y
return(INIT_SUCCEEDED);
" U& k0 ~/ f1 E7 @' u3 a在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件2 Z) K0 x6 @6 m
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。% ~5 U. v/ o% n' ~ F1 R% [; \
int OnCalculate(const int rates_total," i3 t" S" h5 s# H$ p
const int prev_calculated,
6 D C( K* ]4 Gconst datetime &time[],' w. \, w, }' L( g" T
const double &open[],! Z; H; f8 z0 |8 e: I7 E, B
const double &high[],
' l" `6 C0 Y# c0 A0 h$ Q1 H8 econst double &low[],, M8 d% ?% t: m! P
const double &close[],% ?. c/ @2 t' ?% ?; }
const long &tick_volume[],1 Z0 J6 _" [6 y5 x- g; A) [$ ]
const long &volume[],8 y6 A; i5 `' I( J
const int &spread[]): _! C3 b9 F( q/ r
创建一个整数型 “start” 变量,我们稍后将为其赋值:! I0 h. R" Y: Q0 h; T6 D
int start;1 C) G# \0 j3 ?+ b1 ]' x }
使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:
! T# O; s) C5 O, q- M2 c4 lif(prev_calculated==0)
1 L* V2 R% S7 B1 K! }{2 s, o. d* i7 P1 X5 U
haLow[0]=low[0];+ x" x$ r5 N/ v3 `9 A2 F4 C
haHigh[0]=high[0];1 v) n9 t7 q E- A' K8 a; L. Z
haOpen[0]=open[0];
3 L' p9 P9 E- b2 u* n8 g [0 xhaClose[0]=close[0];7 ]1 r' _/ T I9 I# W7 X3 o
start=1;$ x( B! V z' [0 v" A
}$ ?: L" ~3 k* F# i' X: b& p9 ?; Y3 d0 {
else2 \0 T: j. x, V$ W) i4 N
start=prev_calculated-1;
* L) _" |& N# ?& n在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
& i s0 g. @8 W这三个表达式将是:
$ m* }3 V' P% {7 h" Zi=start: 对应起始位置。
) L! s- z! j3 m: q7 A* v1 fi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。" v3 \, `9 E9 }
i++: 加 1 作为新的 i。
+ u1 E, b$ ~) c0 O我们每次在循环过程中需要执行的操作:
# i& D) a5 x7 n0 u计算四个双精度变量
; _. ]2 S7 Z, Y1 W n! shaOpenVal: 对应 Heiken Ashi 开盘价。
v2 s8 `+ x6 I. O' ~haCloseVal: 对应 Heiken Ashi 收盘价。! @; S! F$ ?2 n \
haHighVal: 对应 Heiken Ashi 最高价。
' J( @- ?2 P! T5 yhaLowVal: 对应 Heiken Ashi 最低价。7 Z( h |! m/ {0 z" O& i8 z" B$ Q6 Z
在上一步中分配的计算值与以下内容相同/ N8 r: t$ X# y' m
haLow=haLowVal
& I* f9 ^- D# x2 V0 \; xhaHigh=haHighVal
M. r' g3 G" N" ]* _3 X& FhaOpen=haOpenVal( L5 t. w; K) N
haClose=haCloseVal- s) X# s4 }0 V+ w* }5 X
检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
, d+ O* t* o. L$ `& Sfor(int i=start; i<rates_total && !IsStopped(); i++)
3 }! d! ^7 y, `5 ^5 ~9 y{+ v0 m; I; n9 _" l+ R9 ~
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
$ T( ]/ P; ^. p+ K5 }double haCloseVal=(open+high+low+close)/4;0 V" y6 S! v9 a( N
double haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
: h" @' x: D! p$ sdouble haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
: d! P" n- P+ s& T4 S3 E, rhaLow=haLowVal;+ z4 J: v$ G) u3 L
haHigh=haHighVal;& N* y9 v" [3 ~: i
haOpen=haOpenVal;7 d+ J3 a" ?& _
haClose=haCloseVal;$ }' A4 _$ r; ]% v* z
//--- set candle color- Z2 ]3 y4 a+ G+ q1 ~& q! w
if(haOpenVal<haCloseVal)
3 I2 L; \& J4 t, j% [haColor=0.0;
5 W' B! l5 y* g9 n: melse
' }% r* ?6 e4 S/ bhaColor=1.0;$ y( U7 Y& q3 |$ U0 K; P9 h
}0 |. x' K8 `% |6 q. f5 s+ i# f, s
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
& H- L2 A# z- d5 |1 }" Vreturn(rates_total);
3 S8 C' p& U( x9 @3 ]. V! O然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:7 n9 S2 c' a" x
//+------------------------------------------------------------------+3 `/ u% e( X9 \4 h& O. E# F
//| simpleHeikenAshi.mq5 |' Z0 \$ A3 `; y2 T2 q7 t% z
//| Copyright 2023, MetaQuotes Ltd. |
+ F$ p- l: g8 u//| https://www.mql5.com |3 f+ V4 Z2 S, R; L1 r
//+------------------------------------------------------------------+
( n- W! _1 N+ F) N, k+ f) I#property copyright "Copyright 2023, MetaQuotes Ltd."
6 g$ V: `9 E8 k#property link "https://www.mql5.com"
: ]: @4 ]8 D1 c#property version "1.00"2 T! N( }+ B( ~8 P" a: e3 W6 c
#property indicator_separate_window+ e+ ]8 A/ @& O& [
#property indicator_buffers 58 F; K# R8 C1 g; r+ m7 w1 m7 { L
#property indicator_plots 1
# r; ^' E* {+ `1 w% G* J$ n#property indicator_type1 DRAW_COLOR_CANDLES
# ~* }# c5 W4 m# D1 N) H#property indicator_color1 clrBlue, clrRed
+ r7 ?+ p I$ N3 E; d! w#property indicator_width1 2
( c* R6 E* K P& O; h" R1 F#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
. @* P8 `6 g' e$ C4 cdouble haOpen[];" ^; S- L/ L& J" F" t
double haHigh[];
g0 P8 ^8 O$ Q8 v9 Q. ndouble haLow[];
( m1 z) Y0 x( L8 n. {double haClose[];
4 C7 V/ X, M' i& o7 x5 O5 kdouble haColor[];
5 H( m* V7 r. L) @" wint OnInit()
9 O8 D; T" @& |7 ]0 ]% A{, L& q, i) \' a0 j# [2 p8 q
SetIndexBuffer(0,haOpen,INDICATOR_DATA);: |8 j! M3 d% h( W2 j0 R4 f
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
' f4 ~( p/ v7 Z2 x- w) RSetIndexBuffer(2,haLow,INDICATOR_DATA);
1 }0 X) O& F$ H0 z0 eSetIndexBuffer(3,haClose,INDICATOR_DATA);' ~/ G5 g8 T" e8 p f
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
' O- W3 \7 |. ^2 G9 lIndicatorSetInteger(INDICATOR_DIGITS,_Digits);/ V, [1 l0 L, A8 y6 z+ L) J
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");$ v4 a: [2 F! f
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
0 r. L. N6 J3 j7 K$ T+ qreturn(INIT_SUCCEEDED);7 L2 x Z9 B' ?5 h# o
}9 h( y2 N4 w+ L3 g, W
int OnCalculate(const int rates_total,
( S% k( c$ u; z: vconst int prev_calculated,
* a$ |% p3 r9 ^: u) uconst datetime &time[],
/ M- z5 Q7 x( _) q" [7 @const double &open[],6 m- n" A4 W4 [% {
const double &high[],
) c" c8 r7 b( C( C) uconst double &low[],
$ i3 k4 {8 @ b( _9 D! |: yconst double &close[],& G$ i* l. w0 ?7 X! p0 j+ z5 ?
const long &tick_volume[],
# C9 C/ k* o# O/ S1 [% [const long &volume[], |