概述
; J0 [8 k7 v- I0 x我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
4 ]1 B$ d/ A+ f( C! D' T1 u/ A7 H赫兹量化交易软件
. E; ]3 a, c) Y! n3 g8 C) u* L自定义指标和 Heiken Ashi 定义
o4 Y! @8 p/ h8 h, h/ [在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件2 u( [/ C: Z$ `, x9 D% A0 l
简单的 Heiken Ashi 指标, D! i$ V# |$ s
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件: s$ ]$ C$ q) J8 `6 m3 M
我们来查看创建此自定义指标需要完成的所有步骤。2 N) |' ?- ]) U4 \+ V1 T6 ~7 S
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:( ?% s, g7 e/ p# e
(indicator_separate_window) 在单独的窗口中显示指标。
7 i1 k/ J6 X' d) g9 W" C( \: x(indicator_buffers) 确定指标计算的缓冲区数量。* Y- h' G* Y3 s' c R6 A% C
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
, Y; b" r d2 E9 b- ?(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。 r) N' d: X. O! R2 \ @
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
" k( i" `3 R' U( `9 x$ j(indicator_widthN) 还要确定 N 或图形序列的宽度。# {7 D/ G% r, I: j/ B5 y- X
(indicator_labelN) 确定图形序列 N 的标签设置。
8 V+ ~7 U2 p5 h3 ?5 X W#property indicator_separate_window
9 f1 _* `7 j* d- Q5 ] w9 _" K#property indicator_buffers 5# T2 x- w# u- C9 ?7 c: `- g
#property indicator_plots 18 x5 F1 w4 [) n# \
#property indicator_type1 DRAW_COLOR_CANDLES$ O( t( \% E/ o- R' }8 ~
#property indicator_color1 clrBlue, clrRed! u- N& H4 L" b, |; y) c, ~
#property indicator_width1 2
+ |( L/ ^. b5 j: _7 J4 h2 p#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"2 v. y1 g( @; |( F+ _) v8 ?+ l
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。4 c+ r. h6 j k" `$ [+ F
double haOpen[];
$ H+ A' o" O& Y4 @! hdouble haHigh[];
- H/ o% H( I2 C' Mdouble haLow[];$ D& E3 s4 [( \* F. G
double haClose[];, Q, u: t( D. Y' s% o
double haColor[];
$ V" C" P2 s: n, V在 OnInit() 中,此函数初始化正在运行的指标。5 l6 e$ X6 | N
int OnInit()0 M L$ U6 x8 `! {4 T% d
调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
& N% J7 v5 q6 f& h其参数为:6 k& B3 E2 v. J) D* w% [. L- S
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
7 s! w; {* B/ W5 |0 M6 ?buffer[]: 在我们的自定义指标中声明的数组。
: ], A( b0 S6 P. z6 v* bdata_type: 我们需要在指标数组中存储的数据类型。" F7 T- F7 |3 Q2 z9 R* `
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
) g: v; k3 k% ~( v& iSetIndexBuffer(1,haHigh,INDICATOR_DATA);
: v/ p+ _' R/ [- @( T& \$ mSetIndexBuffer(2,haLow,INDICATOR_DATA);
. X/ S7 o6 U/ O8 z1 v3 cSetIndexBuffer(3,haClose,INDICATOR_DATA);4 l! v4 e$ ~& ]& q
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);4 ~2 v6 c- t4 H: @. G
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:9 {9 D% r8 ]6 z0 `: k! ?4 h
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。1 j: x n8 X. ?8 |' b
prop_value: 属性的值,我们将指定(_Digits)。$ ~! ~. \( y6 |- m: w1 R
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);2 a* }* B+ Q( U; ]# }8 o' v
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:% e4 f) R' w& h8 U8 \( m
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
4 Z s9 {! W9 z7 A* i. q pprop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。: [/ \7 H3 _6 Z: T2 D$ T y
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
+ J4 [$ ~# P" k调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:/ d7 b0 O! u! c6 S& S
plot_index: 图形绘图的索引,我们将指定 0。
; y1 U* H$ T; ^( t( I M' Zprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
: a- |& l' L- O Iprop_value: 属性值。
2 i$ ]+ V1 [, ?1 ?PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
: f3 V- X( K) v然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
6 h" N( B4 {4 w5 r9 z4 |! Xreturn(INIT_SUCCEEDED);
$ u9 f( E U4 ?( L2 ?在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件3 e% N$ Y7 ?. G* D
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。
- l2 j# _* V! Z- n9 p( E' aint OnCalculate(const int rates_total,
8 Q! x% C& c: o% L& Y: H* v; Jconst int prev_calculated,: }; `6 c7 z \9 b& m
const datetime &time[],
" y5 w! p; G" K0 f9 x! ]. Sconst double &open[],
/ w, v) E" \) ^const double &high[],
3 ?9 u& E5 x9 K% c1 lconst double &low[],
0 W8 E" M! m0 f" q* B) v9 ?9 f' J+ J1 l$ pconst double &close[],
$ ]' B% F$ a& [& H: A9 uconst long &tick_volume[],) k& S! T' e1 Y8 W
const long &volume[],2 }7 f$ ?0 [: m8 j" \
const int &spread[])$ z# k1 W# v) M8 y( A+ h2 i% \
创建一个整数型 “start” 变量,我们稍后将为其赋值:
& j- w; m' D* U7 p `) f! x+ B, A: F2 Rint start;
& r/ b, X9 B! B9 F, k) g使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:0 w( Z* A* ^4 g3 |. {+ f
if(prev_calculated==0)( y1 Y8 A4 P$ D4 [
{3 v7 P) F0 q+ I% i4 |+ I2 L T7 ?
haLow[0]=low[0];" y5 e& _; D( M( h8 i) T6 V4 u
haHigh[0]=high[0];
3 [8 m* r% i& `( _! Q1 K) G% {2 d) UhaOpen[0]=open[0];
% r& C4 _: {+ L" a' z$ |haClose[0]=close[0];. m7 L0 ]) \& {$ W) t1 X' L
start=1;
& G- b* j* O* K8 x' L* |}7 J7 t/ }" w. f' K
else- B5 b( f' |& R7 `& _3 z
start=prev_calculated-1;- T6 O* n, Y- ?9 |2 R, S
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
: L k) t3 j* C+ y3 b这三个表达式将是:( l; N( p5 c& @1 i
i=start: 对应起始位置。
3 B% F7 M$ k! O3 Hi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
6 @) }4 U& N2 v) U \i++: 加 1 作为新的 i。
( ]$ j2 ?5 L' y) K我们每次在循环过程中需要执行的操作:
- q+ H3 F/ H; H! m: v计算四个双精度变量4 Y8 G9 Z$ _3 q: }4 l6 [/ s) s
haOpenVal: 对应 Heiken Ashi 开盘价。
# \9 }% C) S9 j! ]) w! {haCloseVal: 对应 Heiken Ashi 收盘价。
- X! v0 I/ d) K3 S8 d$ LhaHighVal: 对应 Heiken Ashi 最高价。
) p2 q7 s3 ~, U5 U& ChaLowVal: 对应 Heiken Ashi 最低价。5 k3 w, d8 x% P) O6 u
在上一步中分配的计算值与以下内容相同( o+ R3 D' Z9 H
haLow=haLowVal' i9 t& a, W& y5 `' p& B
haHigh=haHighVal
- d. U, @1 e0 n" Z; Q$ ]9 _haOpen=haOpenVal' `/ t9 x5 [8 d( F1 J
haClose=haCloseVal
5 N: e0 w ^: D检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。& ^% q1 b4 Z0 T/ W. A* M. D/ o
for(int i=start; i<rates_total && !IsStopped(); i++)! Q% B# ]( h: A. x+ i( l
{
1 h( e8 b: k. e9 Jdouble haOpenVal =(haOpen[i-1]+haClose[i-1])/2;# \' z, l* K; I
double haCloseVal=(open+high+low+close)/4;: X- i( e/ O0 q3 Z' X& o& ?
double haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));* t3 ]; K. \3 ~: N, k& F* X9 f
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
& y" o/ L& P# Y9 l ^, y8 |haLow=haLowVal;1 m: `4 Q% u1 w* A1 t! n8 v
haHigh=haHighVal;, L4 E: V c" J$ Z, A. T; S s2 p
haOpen=haOpenVal;, X( b1 E, J' X5 V
haClose=haCloseVal;7 }+ f1 x0 I* l# Y4 f1 w5 Y* u
//--- set candle color
* s! D0 m9 ]/ [" |' k [# W* Hif(haOpenVal<haCloseVal): ^. z# R7 \# {+ k6 x7 G
haColor=0.0;
* R: { r# X8 W. b4 x' Y3 T+ \" X( Felse
3 d( B H+ r. D6 Z% @haColor=1.0;# o; `6 ^5 e- y! h& b& x( `
}
1 z; g1 p! _( o) f" x8 d, s终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。( O2 k, i4 p* C& ]9 a% v: Y
return(rates_total);
2 a& H2 }# B! o I3 X然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
* E$ D$ t! L/ \) F//+------------------------------------------------------------------+
% A. F( L1 X) U4 B7 q//| simpleHeikenAshi.mq5 |
8 w5 u/ x% P# ^! j+ z% B//| Copyright 2023, MetaQuotes Ltd. |
0 G0 e+ R& v8 @, o! k+ t! ^//| https://www.mql5.com |
3 s" ]% H( u8 x2 F//+------------------------------------------------------------------+
7 W% b8 e/ f, |% [( I) \; J#property copyright "Copyright 2023, MetaQuotes Ltd."& f1 `4 T8 P# I% K% m
#property link "https://www.mql5.com"
( ?3 @. G n& t* ~) C#property version "1.00", s1 @% ~! w% }1 n
#property indicator_separate_window
( [5 f+ m7 H: X* ]' p0 b#property indicator_buffers 5
, p H6 A4 c' `* y2 P& f#property indicator_plots 17 d, i8 D3 a& X+ F" X; i$ a& Z A
#property indicator_type1 DRAW_COLOR_CANDLES
- y5 ~5 F n$ N3 b$ D- g7 Q; O#property indicator_color1 clrBlue, clrRed
1 z. L( o; O; Z, n$ N% g' N' R#property indicator_width1 2. @% _2 N7 [3 [1 K
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
+ [/ N- Z, m% |% g/ ^" @4 N; i8 ddouble haOpen[];2 I9 K x/ s8 A, V
double haHigh[];$ ?8 l' o) n8 O
double haLow[];
" j O# ]* h& P1 K0 u" R% F( Q3 g' Sdouble haClose[];
) O) [9 D0 L. g( c1 y6 U- e, @double haColor[];
4 o" g @+ u. \8 }' m8 N9 eint OnInit()$ w- w. |% z2 N. P1 I' R2 x& O
{; V6 e* m- b6 q ?. j
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
" ~& n1 R& N/ {+ ySetIndexBuffer(1,haHigh,INDICATOR_DATA);
9 B8 s" P* q1 ` s0 U9 oSetIndexBuffer(2,haLow,INDICATOR_DATA);5 E, j: y; m1 v- }
SetIndexBuffer(3,haClose,INDICATOR_DATA);
3 I: s3 s; U% LSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);+ T. u F$ A6 | W* g( W7 j$ b5 G
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
6 U" H, K$ }2 d" uIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
8 ?; `' S% F L" fPlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
# M1 n, P% V% n% y. n* b+ e6 Breturn(INIT_SUCCEEDED);
: i* C' P6 T; E7 A9 v" w) [}
5 c, R, i) L/ }" m4 jint OnCalculate(const int rates_total,2 `0 ]' z4 M/ Y% w# r1 G
const int prev_calculated,
, W9 s/ z- @2 Q0 h7 z- pconst datetime &time[],% p/ P2 Q, Q9 \+ y
const double &open[],
3 x0 ]! r! i, r5 Bconst double &high[],
, ?' G9 t* f) h0 X0 D8 z5 ?const double &low[],
7 F' _% ]; t9 t$ xconst double &close[],
' G1 }( ^5 E" L* {8 J' }; ~" F& Pconst long &tick_volume[],: A. a' k e; C. u
const long &volume[], |