概述
+ m8 |( o4 \2 A& U( |9 R! A# n我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。; v$ G: x( a$ D, n7 p1 }
赫兹量化交易软件1 v, y5 P7 w+ q. ?1 Q/ p7 O
自定义指标和 Heiken Ashi 定义
. @: a$ e$ K$ x7 p. |在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件
3 s, ]7 r. z, |: D简单的 Heiken Ashi 指标
. ~ n r3 x# A3 L5 i: H在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件6 }2 I$ V* m0 I) j/ r+ `# j. I
我们来查看创建此自定义指标需要完成的所有步骤。3 F( H5 _; r2 ]) w! N
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:6 u- H) a' E1 [6 |7 M
(indicator_separate_window) 在单独的窗口中显示指标。& Z7 F: ]- T+ B: X( x- }
(indicator_buffers) 确定指标计算的缓冲区数量。
& v& h# c9 }0 }' f% U(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
1 V; |+ V" L" g8 Z5 N3 r* d6 ]0 b(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。! h6 R8 b0 ]* V' E6 z* y1 D* m X* q( l
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
' o7 V9 E! r4 j9 g1 C1 p6 d(indicator_widthN) 还要确定 N 或图形序列的宽度。
2 |5 i) `9 Y- }. G0 ^% R6 t(indicator_labelN) 确定图形序列 N 的标签设置。: {' o9 p2 k4 j9 h6 ]% B& |
#property indicator_separate_window
. G1 p9 F' I/ A% x#property indicator_buffers 5# `/ k: p4 J; m, z8 N P
#property indicator_plots 1: k b# ?0 \" S) O" S
#property indicator_type1 DRAW_COLOR_CANDLES
3 m2 \+ ]! m$ `( u/ z$ c#property indicator_color1 clrBlue, clrRed0 {7 L7 V4 d# Z- P& w0 d( A1 X
#property indicator_width1 2% J0 W7 Y [2 h
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"; i8 Z- N* b V- _7 `
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
2 U5 G/ o1 p0 E Qdouble haOpen[];4 G: M X" N1 }. J1 m# k; u
double haHigh[];
( {& H$ f" ]8 Sdouble haLow[];
. r9 v3 o3 u6 E3 adouble haClose[];
9 _ B8 V' s9 x. U qdouble haColor[];
+ c+ J0 t1 X$ s, X7 v5 v; u. j在 OnInit() 中,此函数初始化正在运行的指标。/ Z$ H" `6 H3 U M
int OnInit()
3 d6 @5 p, U; r9 i) N0 r调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件2 u0 r% c- M7 R" a+ X
其参数为:' i+ ]$ V d: |2 _+ i
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。9 M$ F3 ~6 Q/ Y* s* C& i- ^
buffer[]: 在我们的自定义指标中声明的数组。3 u& [0 @* a4 v
data_type: 我们需要在指标数组中存储的数据类型。
4 Z7 U. D: e% K* I) F# \SetIndexBuffer(0,haOpen,INDICATOR_DATA);
9 o6 e- m& H2 r6 z3 q7 ]SetIndexBuffer(1,haHigh,INDICATOR_DATA);
: U$ b# ~" G" y7 d) ^5 KSetIndexBuffer(2,haLow,INDICATOR_DATA);8 e% b _/ i$ T- v& B9 j* P
SetIndexBuffer(3,haClose,INDICATOR_DATA);+ Z: r* p. m; b
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);9 o1 I, G4 i% R+ [* M, B
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:1 p% w/ l" e: W( L' O# d
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
, ^" |. l! n3 [; j, y$ n, zprop_value: 属性的值,我们将指定(_Digits)。4 L+ g* k$ o H
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
. l' n+ a8 X# Q5 y: c0 c调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:
8 t6 F1 W- P7 @! d6 y6 a, W' fprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
6 L4 q6 h& L& J% D Z" C" h4 ~+ vprop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
! c$ r$ F9 e$ F- C/ Z0 FIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");, F8 N7 k6 o, P: N; C/ q6 z8 b! J
调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:" U/ ]8 w( x" x' F, C8 r; P0 h5 M
plot_index: 图形绘图的索引,我们将指定 0。- b2 ?/ K7 Q( ^2 \# M2 U8 N5 ]5 U
prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。! l& H. P* z9 V8 g: n
prop_value: 属性值。
, E4 S2 Y) i# ?$ z, N2 _PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);: {; {. i& i4 ]$ d9 e8 o
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。& y% h6 [1 @5 E
return(INIT_SUCCEEDED);
% D% r; J' u Y: Y& C* D在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件1 Q# ~9 d3 u2 p9 Y5 W. m
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。% U p9 W% c6 b3 W0 Y. ~2 s& h
int OnCalculate(const int rates_total,
9 Y- n1 u: i4 `9 O5 Oconst int prev_calculated,
7 L9 U- x4 H: W" \. S1 rconst datetime &time[],
% d; z O- T: s, }" ?1 c4 T. Zconst double &open[],3 {$ }) G% P$ ~3 Z7 ~% _
const double &high[],
& n# v- F% }: R! I8 x0 Tconst double &low[],% b. {; f( b# I! Q1 y+ v9 f5 c
const double &close[],
* U. s+ e+ i/ F$ fconst long &tick_volume[],
* W+ l( d! i' n$ P5 c1 fconst long &volume[],
2 d: X" _9 }, ?const int &spread[]), o4 `' i3 X: S+ l& ?; @
创建一个整数型 “start” 变量,我们稍后将为其赋值:
! k- A& f$ u( T" ]int start;
2 o4 R! z/ B% i( W2 W使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start: J& u2 B4 a3 |
if(prev_calculated==0)
" p1 h" F0 a2 N& Q; t{; u' V6 C6 O6 E, u/ e
haLow[0]=low[0];
! P9 K$ k/ _( ?: s5 s, o( _haHigh[0]=high[0];
9 T+ H) x S4 x, ]) lhaOpen[0]=open[0];
2 ^' \8 `5 q/ VhaClose[0]=close[0];
+ l1 Q5 {- q) V7 G Ostart=1;
/ L6 h! G# S% z7 c$ m}
) W5 F# [' ]* h" @else
: Y" P' J) N1 L7 w0 g1 y0 l Cstart=prev_calculated-1;7 p5 i; q0 ^, T1 d6 m4 a% T8 D7 S
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
- E' V) x5 `- B% C6 g: @" h$ [这三个表达式将是:
9 w' e# I# d2 ii=start: 对应起始位置。
- D j1 {9 g2 E& u. Ci<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。# G* ~3 t8 a8 R& p& u
i++: 加 1 作为新的 i。8 m0 \4 u! B5 b" E- ^% K
我们每次在循环过程中需要执行的操作:2 E- ^4 c% G& E5 N7 N1 X9 h9 Q$ m$ X, Z
计算四个双精度变量7 i6 B6 i$ d g
haOpenVal: 对应 Heiken Ashi 开盘价。0 p3 H: l6 H( X$ i) q% ? K( u
haCloseVal: 对应 Heiken Ashi 收盘价。
! r2 S2 n0 }; x6 ?+ ehaHighVal: 对应 Heiken Ashi 最高价。- ]( ]+ n% m8 [3 b. {
haLowVal: 对应 Heiken Ashi 最低价。' C4 {# s% E% w' ^, G4 ]: @
在上一步中分配的计算值与以下内容相同4 w+ t; y" @7 h* q
haLow=haLowVal p [: L7 L' b9 y$ V4 l" L* M. z
haHigh=haHighVal
4 B2 b# l/ W+ A2 ]) w- E$ p" L$ |haOpen=haOpenVal7 B/ T0 I4 P0 F7 r7 u0 @
haClose=haCloseVal
, e$ g3 V! i8 k2 K% l检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
, Z" s3 p+ R! |+ ?$ t* P0 Hfor(int i=start; i<rates_total && !IsStopped(); i++)4 ]3 r2 L8 Z& i C) R
{7 _. c; r" R' {( b
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
0 x. t, X/ O5 w Kdouble haCloseVal=(open+high+low+close)/4;
* g/ b3 k* H& _0 L8 U/ xdouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));8 Q% C- q* [* A+ D
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
2 ]. E) r0 Z& b' m0 G* F. m$ |haLow=haLowVal;9 P% y G0 R1 B0 V8 E5 S
haHigh=haHighVal;4 X& N& v0 f/ W+ I' M+ `
haOpen=haOpenVal;
* F- P- x9 p0 m5 s- c3 F3 HhaClose=haCloseVal;
: Z' Y3 R) x. f5 k1 q) R& }//--- set candle color1 S4 t! K* m; i# w& i, W4 Q$ A
if(haOpenVal<haCloseVal)/ v% V. b; U; r# F8 ~6 ?) F/ X
haColor=0.0;. p O# _. J5 V7 o
else
6 ~* |$ g c6 P% a$ ~5 ]haColor=1.0;, V+ l$ G8 p# |$ P6 z( L2 u
}/ G; b7 ^) j1 f' J
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
& D- D# u6 M0 Z# X4 r/ O0 j9 k6 yreturn(rates_total);* x; u/ O; L. s! U
然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:' s6 X+ i" b6 e3 d! F
//+------------------------------------------------------------------+6 T% ]/ M7 z0 U! I7 e% {+ b
//| simpleHeikenAshi.mq5 |2 M7 K6 ^ y6 z# w1 N7 N$ F% q
//| Copyright 2023, MetaQuotes Ltd. |( a. t2 C5 q& x6 W# i% S
//| https://www.mql5.com |. Y- |( I" q- ` ?& E8 t3 t- G
//+------------------------------------------------------------------+5 E4 k/ S$ @4 ]% M' @3 O
#property copyright "Copyright 2023, MetaQuotes Ltd."1 k3 Y" P( z+ ~( {2 {4 T
#property link "https://www.mql5.com"7 m$ y8 J5 w+ }
#property version "1.00"& Y b+ ?7 ]6 [3 o" ]2 f: E) U
#property indicator_separate_window
7 `* i+ J7 f4 v: O' O$ Y& S/ C#property indicator_buffers 5
( {5 J: s" J, o& H#property indicator_plots 1
5 \& N1 G6 n9 O1 u& B#property indicator_type1 DRAW_COLOR_CANDLES
! [+ l2 f1 ~7 a/ r#property indicator_color1 clrBlue, clrRed5 R4 W* M7 R) E+ Y- [% G
#property indicator_width1 20 ?" e! B& g, L: O
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close": W g. c' A [. n
double haOpen[];
$ j/ {/ M$ ~) @; K- w W/ _& Wdouble haHigh[];/ P& g3 c0 A, m& T- P
double haLow[]; F4 [$ f: r8 f7 h$ y ^
double haClose[];
9 n/ O) v( \! }( y+ m) Xdouble haColor[];, p8 H5 M& ~5 X- c" F6 j
int OnInit()
' i. [4 s4 W' \% f0 V u{4 |; _2 L* @2 K7 B/ S; Z0 ?# q3 v z
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
# p/ [) \% y! ^9 mSetIndexBuffer(1,haHigh,INDICATOR_DATA);. V4 S5 D( i. L" `$ @: `+ M
SetIndexBuffer(2,haLow,INDICATOR_DATA);; R0 W+ b" q) W. W9 S6 H* f
SetIndexBuffer(3,haClose,INDICATOR_DATA);" o. s: }! h4 N3 `; h4 `) Z
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);" c1 A S2 s6 T Q8 o
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
1 I8 |7 j" P: B1 I7 GIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");( E o/ ]% _0 M: @ Y$ _
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);& p9 K5 I$ W0 ]: T9 v
return(INIT_SUCCEEDED);
3 V: v2 A0 j0 i' t! q* M) O# k}
4 z; r3 D [# i/ F8 q' j2 q4 ^int OnCalculate(const int rates_total,- m4 ~: I5 _; c. a
const int prev_calculated,
6 o- d( d3 J \- ~4 P. ?const datetime &time[],! G: Q: F# u) {, T$ V+ p, _, }
const double &open[],+ d" i" P/ _: K+ B" R
const double &high[],# ~; m5 Z8 M/ C6 A3 ~
const double &low[],& S! v# T# P3 L8 ?
const double &close[],
8 e5 ~/ A" A4 }! ^const long &tick_volume[],! A# `' h( V7 y& |
const long &volume[], |