概述
; y3 i8 @, u/ g5 l我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。3 h9 G: {* y3 f
赫兹量化交易软件
. i8 s% [ n ^6 k; L. A自定义指标和 Heiken Ashi 定义
% V1 {" o4 t9 m0 A在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件; |: w9 a3 I/ l4 o# n: G2 f
简单的 Heiken Ashi 指标
$ Q" |) d" K, [在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件
9 M* I4 y4 m/ y1 [" @9 v% F+ W6 _我们来查看创建此自定义指标需要完成的所有步骤。0 G: w6 n7 u ^) q0 f1 w
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:6 Q0 k+ g% O5 g: M0 G5 Z( K
(indicator_separate_window) 在单独的窗口中显示指标。
0 D F, B9 X) a4 N(indicator_buffers) 确定指标计算的缓冲区数量。$ X: ] J6 \# T1 h* x# Y
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
0 F- {8 Q7 T% h6 V1 T1 u( x* C(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。. h5 a( W3 Z4 c
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。% B; {1 i4 Y) t
(indicator_widthN) 还要确定 N 或图形序列的宽度。
- D& L9 j4 A+ L" K; k: P. D(indicator_labelN) 确定图形序列 N 的标签设置。" O9 }5 a- y r# F! E( c
#property indicator_separate_window3 G a2 d# M9 y! l: t2 M
#property indicator_buffers 5; w/ Y2 Z W7 y8 J8 q1 J4 i
#property indicator_plots 1& C2 |* U8 t" \! ]
#property indicator_type1 DRAW_COLOR_CANDLES0 c9 c- W* B1 A8 ~4 u: W
#property indicator_color1 clrBlue, clrRed, x! `7 X) U1 F7 z1 e
#property indicator_width1 2; C7 _* \% j& J# c6 Y* o: I
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close") j1 F2 K# b! e( w1 x
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。! f6 Z- }: r; H- c$ I; u
double haOpen[];
& l$ N+ V8 C( Y; t. B8 ]% l5 m: Zdouble haHigh[];5 F+ K5 F6 r4 d9 j9 Y- j/ I, _
double haLow[];' B+ i/ s6 Q, p( e/ C' E" w" t
double haClose[];
8 P% _/ l8 v$ v# @: m1 p9 }double haColor[];
: P/ z9 I x) T在 OnInit() 中,此函数初始化正在运行的指标。
2 o6 s0 ^) P6 Bint OnInit()3 @$ W. y# w' E& w; v
调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件& U, C) v5 @# P8 B1 M/ g1 o
其参数为:, ^, K1 ~, {/ I4 V4 H e! ?
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。, Z' L7 ?" x' `6 K L
buffer[]: 在我们的自定义指标中声明的数组。; {+ m% j' R/ e2 c" B! Q* x
data_type: 我们需要在指标数组中存储的数据类型。
1 s* k* j" e; D/ b; S& {SetIndexBuffer(0,haOpen,INDICATOR_DATA);: E) h$ g/ \" p* _% T
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
; s; b- n, `; U5 iSetIndexBuffer(2,haLow,INDICATOR_DATA);
1 y# O. ?8 C1 m! c' G; n- Z) oSetIndexBuffer(3,haClose,INDICATOR_DATA);
, H& v, S7 Z/ `4 Z" W7 T }; xSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);8 ~( D$ L4 o1 {: S B" L
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
" }& j5 ~$ z8 ?! ^7 [* Hprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
) @" f/ @0 S! u) s1 j6 p Q7 a) jprop_value: 属性的值,我们将指定(_Digits)。8 W. \+ [8 W# h% z2 }+ y5 d
IndicatorSetInteger(INDICATOR_DIGITS,_Digits); X; d. P6 ?+ O. H, b, ?, R, j
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:+ _1 S% i7 Z- N4 \- J
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。 \7 ~2 b; j7 x$ \* R7 t) J0 d
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
2 Q8 n1 d! j$ z' l5 A# V+ EIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");; |- K. ?2 U2 g0 I W9 ]
调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:0 N0 ]' c% ~% n) R E1 k- b
plot_index: 图形绘图的索引,我们将指定 0。
: R. t' c4 O z: d. Y4 }, k2 tprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
. e# x. I& i2 v4 `7 O- mprop_value: 属性值。% _& M+ H) g/ O" A
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);3 Y$ D9 X: J- X6 z, `
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
5 h8 y6 U- i" w% D1 ?1 l! Y3 xreturn(INIT_SUCCEEDED);/ N0 g- r0 [# ^# N" ~6 d- M* v0 s
在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件
: D5 L d$ D6 s基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。( y5 U" @* b9 X0 \9 i6 n3 l
int OnCalculate(const int rates_total,
, @2 V! v! j# I# t9 Yconst int prev_calculated,8 c! g# _& s5 r% v
const datetime &time[],3 A- U3 O1 x( e1 d: u- v, p
const double &open[],4 d. B2 c' e: d N
const double &high[],8 ]9 z: u9 s7 C4 u" ^. c# u
const double &low[], V# k8 d/ ^/ K( |
const double &close[],8 Z! D1 v } ^+ o
const long &tick_volume[],+ m! z5 x: h' K$ Y5 b& B
const long &volume[],
" [& o4 |( r8 }8 z' Aconst int &spread[])
( k) J( D W }" [创建一个整数型 “start” 变量,我们稍后将为其赋值:4 z& g; x9 r# l0 O5 [
int start;# ^5 n* ~6 W+ C7 {" B
使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:) X- G7 T6 U1 ^% [
if(prev_calculated==0)9 _6 e. M" F% q
{, R, O1 r1 ~/ a. n! T# s+ W
haLow[0]=low[0];" O; G" j3 W7 S4 B
haHigh[0]=high[0];" ~0 a- b, q# k* l o1 i$ O
haOpen[0]=open[0];3 }2 T% ]. ^7 V/ T5 J7 L" d4 `
haClose[0]=close[0];+ U& A( j% i" m5 ]; N
start=1;8 J* Z0 [; h2 @" N' [& q$ F3 s4 v
}
( g0 n2 b8 u4 I' \' `7 j: g( K' Delse& w0 A) i" {/ `8 k: k) F
start=prev_calculated-1;
1 q$ ~5 }3 k0 t) @- Q在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
3 i" Q" p& X. P6 I- Q这三个表达式将是:" K# o: I9 B' A9 K- n2 k5 E
i=start: 对应起始位置。
7 V5 `5 {7 t0 Z( \i<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
7 q, [+ s; P3 v. Pi++: 加 1 作为新的 i。 v' X- H3 D* \# E* d/ t
我们每次在循环过程中需要执行的操作:
( Y1 g [* s& G0 S计算四个双精度变量6 f$ T D/ j4 h3 p4 U6 ^4 j0 d
haOpenVal: 对应 Heiken Ashi 开盘价。0 b) @+ g- E. p6 a
haCloseVal: 对应 Heiken Ashi 收盘价。
- l9 U' Y E4 G3 d2 EhaHighVal: 对应 Heiken Ashi 最高价。5 |+ D q3 o2 |. G3 h% X
haLowVal: 对应 Heiken Ashi 最低价。8 {$ i- d7 ]1 k* L
在上一步中分配的计算值与以下内容相同% u3 K$ H; Q7 |8 F
haLow=haLowVal6 a* I" |$ L" e
haHigh=haHighVal H1 U8 V5 D8 e" z" F
haOpen=haOpenVal v- O' W9 Z4 `/ b3 J" C
haClose=haCloseVal
$ _- f; @+ X0 Z* |' d8 K检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。) p' F1 N& D# |+ k
for(int i=start; i<rates_total && !IsStopped(); i++)
4 U! J$ M* K, i8 c! g0 H2 f$ @{& b" |4 a+ s6 \
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
, e) `8 l8 @ u7 \# F. F; ydouble haCloseVal=(open+high+low+close)/4;
' j+ d0 W8 Z4 B* N) @+ Wdouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
5 P+ K G1 g R" m2 Tdouble haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));( p' c# E$ w+ B' d5 t2 c
haLow=haLowVal;# {. ^4 r% q/ g8 r+ V- X+ y
haHigh=haHighVal;
' i7 }6 t5 q. q! Z! U/ @8 | E) bhaOpen=haOpenVal;
* A0 t/ S% ^2 B- ]0 fhaClose=haCloseVal;, Q; {: n9 n; B5 v4 T8 h9 G
//--- set candle color+ r/ F4 O0 k' A1 B% }. T( U
if(haOpenVal<haCloseVal)
( e. \! {0 K+ ` N ghaColor=0.0;- w# M3 P: K2 K) }; W3 ~) g
else% D E T0 o- z9 ~- b
haColor=1.0; ~, F1 Q% D# w& \8 k0 ^ q
}
1 Y. ]# D* ]% u9 `; v+ Q终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。! d/ l7 a& H' A# I. ` E! v+ L: g5 A
return(rates_total);
- K0 L% I: P' E7 Q w/ h9 ]2 O然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
3 J( C: T# l: H0 @8 C. Y+ a//+------------------------------------------------------------------+
' i3 E; T6 ]: N//| simpleHeikenAshi.mq5 |. _! S1 k! V" Q" r+ U& [( i
//| Copyright 2023, MetaQuotes Ltd. |& D' n' [2 ?7 \
//| https://www.mql5.com |
: o' E7 s& `* j6 u c* z& k//+------------------------------------------------------------------+
0 i# P4 L' l1 R5 q {0 Q0 s#property copyright "Copyright 2023, MetaQuotes Ltd."
4 O- R* q% c" Z( O! p) e#property link "https://www.mql5.com"' W2 F6 k. R- [- K3 s1 v: y
#property version "1.00"
4 f' y t- U$ v; s. v j1 B; V#property indicator_separate_window, l, ~* u# X8 q. `$ W7 o
#property indicator_buffers 5
+ f3 V: f. C9 Z8 A0 Q#property indicator_plots 1
5 D8 {$ n$ x( c, K/ q; v#property indicator_type1 DRAW_COLOR_CANDLES( \/ Y4 w, d' {: r: x
#property indicator_color1 clrBlue, clrRed+ d$ ^1 D6 M, Q6 h) F" j& R" i9 S4 ?
#property indicator_width1 2( g: b( n! Q! F* J
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"' g/ E! K' B! x9 \
double haOpen[];
+ j; ^) i9 B$ h' M% \double haHigh[];
5 V) R* Q: O9 g: q; S1 t3 T" ldouble haLow[];
r" Z/ Z+ Q5 k; L4 ?double haClose[];
2 o* C. ~0 i2 X4 E! g9 E- ddouble haColor[];( N( l- k( G, ]) h* y0 I [
int OnInit()
' D/ d a/ |! V* M q; A4 P E0 A" J{
: Y3 y L9 N& aSetIndexBuffer(0,haOpen,INDICATOR_DATA);
Y2 ]" Y0 w3 TSetIndexBuffer(1,haHigh,INDICATOR_DATA);
& M: ?0 u4 b$ }* p3 }SetIndexBuffer(2,haLow,INDICATOR_DATA); J; z9 v8 ?% u' y2 c+ p' B! B
SetIndexBuffer(3,haClose,INDICATOR_DATA);; V, L* c8 d/ W& C
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
X' M% |/ _& Y: Y7 vIndicatorSetInteger(INDICATOR_DIGITS,_Digits);( V5 V( R: K7 \! H; A" f
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");/ D$ c* j8 `7 V/ G; F7 f
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);0 t; Y7 O4 e& ^" @
return(INIT_SUCCEEDED);2 b% P, N5 W9 N, z; r! C
}2 B4 |! p. L3 t) t0 z
int OnCalculate(const int rates_total,
; Y- H$ `! L8 }, ]" fconst int prev_calculated,7 }5 E/ d. d e- N, }% V
const datetime &time[],/ o- y% ~" }; S0 f. F6 S5 g
const double &open[],
8 ~1 Z7 g6 H! M0 J0 O2 r- g% _% u+ ~const double &high[],
+ U. \# R$ u: ^ I7 Z b }const double &low[],9 B5 g; U& ^4 C W
const double &close[],
& @! B# `3 Y( |9 ^7 Aconst long &tick_volume[],
% E0 k; c) h; t Fconst long &volume[], |