概述
# F7 k. [4 y3 G- @# t) v1 s我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
% j+ {+ Z% e2 y/ F赫兹量化交易软件# i6 g; C& \" n! t, E
自定义指标和 Heiken Ashi 定义
' z9 [; C# C1 E在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件/ R* g- g& I. s3 x: q
简单的 Heiken Ashi 指标1 W1 M8 U& X X9 g% Z
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件) A) L, y0 q% H& }5 [ Y: B
我们来查看创建此自定义指标需要完成的所有步骤。( k( I- e; M' t- s
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:
. C. a- C; D0 J [' b+ z/ d$ _(indicator_separate_window) 在单独的窗口中显示指标。: t8 e/ y, R2 t, ?9 |& B; t* ]8 L
(indicator_buffers) 确定指标计算的缓冲区数量。) v; E! [3 M) V$ c; {+ Z
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
' A2 j( ?: m' u% O, L4 a(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
" b" ~! m: w: W6 ](indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
3 Y4 M, m1 E, L$ w(indicator_widthN) 还要确定 N 或图形序列的宽度。
2 G( }' ^9 `6 N* z(indicator_labelN) 确定图形序列 N 的标签设置。
/ q- L2 G. I! {1 B. ?#property indicator_separate_window: S, ~* N! |2 |1 K. p8 N
#property indicator_buffers 5
# g- h1 j9 H3 m& k5 i% _0 ^0 ^#property indicator_plots 1 t* Z4 g: `. n3 a$ V
#property indicator_type1 DRAW_COLOR_CANDLES3 T' `# }& r& ~2 ~2 o g2 e
#property indicator_color1 clrBlue, clrRed
, s/ M# A% Q @1 {- ]+ r#property indicator_width1 2
4 A' n( j9 D+ M9 o. S2 j#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close") d6 w* O/ X/ L+ p6 m* J
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。+ P" D- @; ^! }. v. y
double haOpen[];0 J$ }+ V" P& n- M+ c
double haHigh[];
9 a2 S. U7 o5 b. U# @* m0 M' S2 a9 M( xdouble haLow[];% X H o4 M! q2 u2 m
double haClose[];: s% ]! Q; g& d# i" W0 \" K
double haColor[];
- c1 u. w6 H6 V g. Z' j3 {在 OnInit() 中,此函数初始化正在运行的指标。
0 o# I% I9 }" @- H9 y! Z: Y$ p: aint OnInit()
, Q. J6 v. }" c调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
; g6 ~. g0 u. D( q% k其参数为:" C2 O, {- P/ P* o4 [& v
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。/ G4 p. v- y6 Q4 V
buffer[]: 在我们的自定义指标中声明的数组。1 N5 v; Z- j. O5 w/ l+ x
data_type: 我们需要在指标数组中存储的数据类型。
% D4 ]2 Z5 D' U4 U9 P* tSetIndexBuffer(0,haOpen,INDICATOR_DATA);4 e \6 D) R" |4 B: t/ S
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
$ i' x5 v3 @0 F& C! n8 `SetIndexBuffer(2,haLow,INDICATOR_DATA);
2 Q( |3 n+ w- ]& P% ?SetIndexBuffer(3,haClose,INDICATOR_DATA);
`% W" `3 E& oSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);+ p+ w% U$ L+ q0 o
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:4 C5 S z4 ^: m
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
4 [; R! f' Z, L7 {# [prop_value: 属性的值,我们将指定(_Digits)。
6 a: u. O3 T. N, W1 E' X' tIndicatorSetInteger(INDICATOR_DIGITS,_Digits);* k( c% m+ H5 Q' \6 m8 k
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:! X) w: Q$ }5 G
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
0 g W) E( {& H' ~prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。) E* Q' W% U+ Y+ m& `
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
' f& `0 R8 }/ b6 F$ Y调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
b! y# q, o. |" h& @( Oplot_index: 图形绘图的索引,我们将指定 0。
- N7 g# T0 l3 `; h% Y9 t" uprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
8 l2 E, N$ f" m; o/ {2 ?" Aprop_value: 属性值。( @8 N9 r" c. L! i, \$ r% Q3 M
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
# {- t( Z6 ~9 i/ X然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
5 Y, o+ n% r) C2 F) q: N s6 [: kreturn(INIT_SUCCEEDED);9 P! y9 ?7 `9 f1 N! r l* b3 ~. k& H. y
在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件' X* ]. ]& F% j; c5 F# _
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。2 K, r# N2 _/ n# u0 ~. o
int OnCalculate(const int rates_total,- y; _5 M. a# m: G2 y
const int prev_calculated,) x, B9 h) b C7 p$ h: H$ n
const datetime &time[],- G/ A r$ C( \& [4 i
const double &open[],
0 c" z$ O- i) _: i" u4 A, Bconst double &high[],, m+ I4 c4 [/ h# l* |( i
const double &low[],
9 n) g. p+ L4 g: d2 B2 i% {2 Fconst double &close[],- _. n9 z! }5 U. P, O5 _& Z) v# z
const long &tick_volume[],
; `2 _3 e0 B$ e/ o* i) @const long &volume[],, E' C' n# ]: o( i9 s
const int &spread[]) q7 u) p7 N/ i. B% N e
创建一个整数型 “start” 变量,我们稍后将为其赋值:, o/ T/ Y. ^: m1 i! B% C3 B
int start;
# r9 Y: a/ m" \; s1 b' j- }使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:9 @! O `% f8 `. j2 m
if(prev_calculated==0); y! m" {9 }0 p' c) v# \1 o) t$ W* I
{
0 B. |9 a7 Q/ O8 I$ d. dhaLow[0]=low[0];5 f5 p5 N0 y G% Z3 q+ V
haHigh[0]=high[0];
, ]' z* T9 t! u( WhaOpen[0]=open[0];
4 P* ]0 R' a+ l( b5 D$ U7 x/ _- dhaClose[0]=close[0];
- I7 g6 @3 K' ~5 G* _! ~start=1;/ i6 E2 _$ b6 E' n
}. q2 e! d' g% J; Z. y T7 V3 {: N
else
9 Z" m( p1 t! p5 t) n6 J3 H' Vstart=prev_calculated-1;
+ ?6 @& o& u+ X3 P. g; x9 P在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。$ S; v- l* q- l; V' ?
这三个表达式将是:" }3 r# Z% S% c ]4 A! _4 Y- ?
i=start: 对应起始位置。) T5 ^) B% |6 t' j# B/ k
i<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。8 }( Y+ Q0 k# |% r" Z
i++: 加 1 作为新的 i。( A# C% T+ ^5 A/ r: I! n
我们每次在循环过程中需要执行的操作:
/ K( a9 p3 ~; {& h: ^计算四个双精度变量
3 r! B- O% u/ Y y: e* |haOpenVal: 对应 Heiken Ashi 开盘价。 p- A7 r5 E; w3 h
haCloseVal: 对应 Heiken Ashi 收盘价。) B! v4 A* c3 y+ l
haHighVal: 对应 Heiken Ashi 最高价。* R! @" s" J) p/ p
haLowVal: 对应 Heiken Ashi 最低价。" a+ i3 f* z2 o3 L/ A& O
在上一步中分配的计算值与以下内容相同 v1 ]) [; L# I
haLow=haLowVal0 l5 R C6 ?% f2 j5 L
haHigh=haHighVal3 }/ U8 o. ?$ x9 p7 @0 h4 y
haOpen=haOpenVal
6 I# R0 [/ M- `8 Z5 e" {haClose=haCloseVal: q/ H3 I9 ~2 e5 E+ \. g" [
检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
) u0 p- `4 O- ` Qfor(int i=start; i<rates_total && !IsStopped(); i++)4 S+ u; w9 u$ K" V+ Y8 U# C: Y
{+ G$ g+ @% v% a# E% U
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
) `) v% [0 V( q. I7 A& s! o' ndouble haCloseVal=(open+high+low+close)/4;; ?3 a, I# c0 t( W# P
double haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
; `$ C5 K. M' Y+ ?double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));- U2 a0 |' {* G
haLow=haLowVal;
3 V1 @9 P; Y4 x- w7 f4 t& MhaHigh=haHighVal;
a: E6 r/ g ~( M& c6 D; FhaOpen=haOpenVal;
; M* K- r- C4 h! n# r0 yhaClose=haCloseVal;2 z* p+ [. H+ m
//--- set candle color
; Y% t- X3 a- `# X: Vif(haOpenVal<haCloseVal), U6 Y2 s' `! W) |7 `# f
haColor=0.0;
+ T# p3 E2 i* ~5 ~ b& J. kelse
8 ^3 H' P- V P% o' E" c+ khaColor=1.0;" E: X/ f7 S; |# }
}$ E- {' c7 i2 j
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
/ k8 k" s0 k+ J; Z% d. i; i( X: ireturn(rates_total);
! `1 t V7 }- E* o然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
( @6 u; U5 t) j, M) A5 m0 w//+------------------------------------------------------------------+
0 n2 w; S4 i1 M//| simpleHeikenAshi.mq5 |
$ z, U: X5 ?6 |4 {- v! H4 O$ F//| Copyright 2023, MetaQuotes Ltd. |$ M+ x1 W \2 j" H O% Z
//| https://www.mql5.com |- g5 G8 _. f* Y* ?9 D; x
//+------------------------------------------------------------------+
" k: |: a/ J( W& u9 r s#property copyright "Copyright 2023, MetaQuotes Ltd."; q3 }2 I0 T' K5 _. ~. U3 A
#property link "https://www.mql5.com"
5 w7 U0 b9 S# I/ h. F* e6 A#property version "1.00"
9 I3 d8 N7 v$ \2 b: M#property indicator_separate_window
@ O- ]4 j1 h) d#property indicator_buffers 5
; _* `" C- t9 A0 @- i2 [8 U8 t#property indicator_plots 1
. M$ _6 P% b7 \- p( R#property indicator_type1 DRAW_COLOR_CANDLES- X/ Y6 E5 R, E3 `
#property indicator_color1 clrBlue, clrRed
: E8 c; J8 Z9 C#property indicator_width1 2; r6 c5 u; h/ U6 m$ J* k
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
$ e. ]9 l3 p% \ \5 Edouble haOpen[];8 E, ^9 }8 f8 L
double haHigh[];! M. q% Y U8 M) c `9 {
double haLow[];5 \2 m7 X8 a1 K. S
double haClose[];
6 d( d: Z; l- X& j' ?double haColor[];1 d6 U& ^1 b6 c' h/ ^7 M {( v
int OnInit()
b3 ?- H$ n& |: A2 n, O! v8 D{" ?" X& B' m2 j2 w' A- V
SetIndexBuffer(0,haOpen,INDICATOR_DATA);8 x; j6 ]7 Z; @7 U* a6 k1 X& i8 D
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
9 X$ W! H' f' N# v& QSetIndexBuffer(2,haLow,INDICATOR_DATA);
! n5 Y! u; q: S. {SetIndexBuffer(3,haClose,INDICATOR_DATA);
, {7 H) R# A" |( B; o! K% ?6 ASetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
* g. F9 k: I) ~( J% N* G( i, MIndicatorSetInteger(INDICATOR_DIGITS,_Digits);2 x, {( {5 e3 `' T
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");. m5 j- H3 l8 m/ V3 [1 c! w
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);. U0 p( Z: ~% C7 o+ I! C5 ~
return(INIT_SUCCEEDED);
/ a5 g% D! K8 T( u; n8 M}
7 ~* G. n7 o5 K: B/ W) u. mint OnCalculate(const int rates_total,
- Q3 ?* l6 c0 ?0 d8 M: aconst int prev_calculated,5 s" O1 |& I8 d! H, X
const datetime &time[],
/ L& C: E3 B! U f* `& f0 P$ B) \' Econst double &open[],
/ S) m8 a8 w0 dconst double &high[],/ i- v6 X9 n0 G6 e
const double &low[],; K% S5 C9 O2 M5 o- b) h
const double &close[],, e, G2 ?& C5 R l6 S0 P+ m' }; g
const long &tick_volume[],
9 q. T7 Z. \* R* v9 J3 P! S. j+ Econst long &volume[], |