概述
) A4 M5 L6 W9 V/ n0 l我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
- ^2 R& M9 @" x+ `/ h赫兹量化交易软件+ S9 g$ t4 W' L; M9 f
自定义指标和 Heiken Ashi 定义) p) C$ v- m) P, S
在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件
8 |9 Q# N: x) a ~% Y/ b简单的 Heiken Ashi 指标
# {1 q% q- B2 m3 T4 T* n+ \! U& d在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件' O7 d9 p6 U- X+ S3 z) ]" m; h% e
我们来查看创建此自定义指标需要完成的所有步骤。
X0 W- Y- k+ ?2 I: ^通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:& \7 J3 }1 l' u* P+ w/ S
(indicator_separate_window) 在单独的窗口中显示指标。
; x" E4 E, D. {' \$ r0 `2 |- f(indicator_buffers) 确定指标计算的缓冲区数量。
4 H/ Q! }; @% O+ ]* n(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
+ s4 h( \$ Y2 n! \(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
- R% C. e* V8 E' J d: |! |(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
8 x" r) Z/ X1 X/ q6 N; W( K: i(indicator_widthN) 还要确定 N 或图形序列的宽度。
& S6 ?# s S+ w, v3 a(indicator_labelN) 确定图形序列 N 的标签设置。
+ A- g$ x/ v( Y1 x( A" m# M#property indicator_separate_window
0 I# {1 f, ^/ F/ t#property indicator_buffers 5
: O' Y* L. [$ {# Y' x+ }1 y' B7 ]#property indicator_plots 1
; S9 Q; E0 o' r8 [. }$ s#property indicator_type1 DRAW_COLOR_CANDLES, a: e6 n3 M% s7 _, R7 o8 T7 u q* \
#property indicator_color1 clrBlue, clrRed
) q# t, A9 {( F* L [#property indicator_width1 2; X* `) k6 m# _! P$ P# M
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
9 @& A0 b- _+ l- d. o, E( V为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。+ ?2 a3 E6 B1 H# F: W
double haOpen[];; d+ D& H# R9 l- e
double haHigh[];# Q) Z! ?; o0 _* {& R* c
double haLow[];( ?, v; c& u2 K. v3 W" N
double haClose[];
8 B8 V- d6 q! X1 Q7 T' o& P0 G" J! Udouble haColor[];1 n5 G7 i/ {# O& Z; V
在 OnInit() 中,此函数初始化正在运行的指标。- V4 m0 g8 ^, ]" L+ [
int OnInit()
1 J+ q" M j% J调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件# p. V: ^( {% L
其参数为:" o! W% q8 C1 p5 ^$ Y a
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。# C8 ~' z i5 v2 A8 \- l
buffer[]: 在我们的自定义指标中声明的数组。0 c2 U/ ~. p# v& p8 [$ a
data_type: 我们需要在指标数组中存储的数据类型。* B- U: [6 J# J+ G
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
7 h+ R E- ]2 _! W" qSetIndexBuffer(1,haHigh,INDICATOR_DATA);
: u! R: ~+ Y2 dSetIndexBuffer(2,haLow,INDICATOR_DATA);1 o% ^0 L) ~5 l2 l& @( ~" E
SetIndexBuffer(3,haClose,INDICATOR_DATA);) p" c$ o2 p: m4 Y1 ? |- c4 L5 v
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);. P. g a+ f/ N/ [5 Z* B' I# G
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
0 t2 f, K# M' ?; _1 pprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
& a# Q& {5 z2 T6 jprop_value: 属性的值,我们将指定(_Digits)。" H9 d% W: l- y5 Y0 q. \
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);& v+ ~, N4 {) c8 V; `. b
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:$ `* Y2 d7 y3 T$ Y
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。. j+ t, R! v8 C
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
# j9 d# U) X( I) y0 p& V; |IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
1 H* N- d5 x0 O2 k) T$ v; C调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
5 Z7 o J8 n. D. P& C0 fplot_index: 图形绘图的索引,我们将指定 0。1 l$ d" g9 R2 w/ K% F" l3 }
prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
% X R. w; O* n6 }) J6 Eprop_value: 属性值。
% g( r' I# L9 g( c( F" l& s `PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);- O) g0 O4 B, J5 a6 |! l
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
& Q/ A4 q. }; E& u! Creturn(INIT_SUCCEEDED);
8 F8 D: i- M7 Q; v/ |在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件1 }; p4 A2 D7 w& ^7 J( t
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。
" a" E2 k! T) @; H" m: A) O" @int OnCalculate(const int rates_total,9 i; v2 U& m4 z8 R5 z( L7 V
const int prev_calculated,
2 `! Y# q" N0 y! ~const datetime &time[],1 K. c" ? s$ d5 c& m! _# G- R
const double &open[],2 b. Y; G% x" |' f$ F+ B
const double &high[],
6 n0 Q8 }4 S$ I) Y* K- aconst double &low[],! m3 _, n& G! v+ k& n. Y2 G
const double &close[],
. f: H; ^# I0 x- V# y0 F, yconst long &tick_volume[],
; Q1 Y" U. u* |4 g) W2 r/ Z/ k: X) sconst long &volume[],; M3 v( u9 S8 |( ]8 x& X1 R
const int &spread[])% V, _) P5 x1 J
创建一个整数型 “start” 变量,我们稍后将为其赋值:
" Q% B5 ~1 p2 s/ z. e6 D/ D5 Cint start;# i# A9 e' v1 [) H
使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:- i0 [) N6 q# L3 S+ |/ w& y. V4 s
if(prev_calculated==0)
, P: K6 n* b8 r+ Z" J{8 M1 |8 t1 s- q* e) N! @' Y
haLow[0]=low[0];5 S- ]) p) S2 {' \" i) _
haHigh[0]=high[0];% L. _0 f( V! `- _9 c) J* x
haOpen[0]=open[0];
% e9 e0 H" B! |haClose[0]=close[0];
: Y0 }- N8 q- B* l# x0 Istart=1;
+ ?" Z- P+ c* X# }- M}
+ z A0 f2 y3 {3 H9 ^. N4 jelse
1 ~/ N5 p/ Z5 I5 K6 Ustart=prev_calculated-1;* D7 _0 c* N# q+ d- M. P$ B
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。 }1 w2 O+ L+ }; D! P4 o6 H3 L
这三个表达式将是:
7 d2 C; h2 B1 {( {- n! qi=start: 对应起始位置。
( L. w# Q T4 Y" r o7 g' N% u9 Gi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。# F1 N' Z8 h: [6 ?' l
i++: 加 1 作为新的 i。$ \) U4 t1 {+ Y: \9 K
我们每次在循环过程中需要执行的操作:3 d( e6 i* r% X" h4 `1 f v
计算四个双精度变量* J/ E" @& C+ f8 @6 F
haOpenVal: 对应 Heiken Ashi 开盘价。
6 L, i) F. c J% d7 M2 J' Z DhaCloseVal: 对应 Heiken Ashi 收盘价。
7 x5 L, C+ Z! R' S6 uhaHighVal: 对应 Heiken Ashi 最高价。
0 J9 a0 d, o* H0 [6 yhaLowVal: 对应 Heiken Ashi 最低价。
+ u$ I; [; F8 r7 \ o9 x7 @在上一步中分配的计算值与以下内容相同0 e* B$ S! X# L) o; e/ J& _! {
haLow=haLowVal! \7 h& m( ~; l0 R K0 \
haHigh=haHighVal# w0 a$ P; A) \2 C
haOpen=haOpenVal6 \! z( y: y7 K# i+ _
haClose=haCloseVal
' V: ~* H- f0 b7 H检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
0 p }% n! \* n& G0 h+ _. ~for(int i=start; i<rates_total && !IsStopped(); i++)! X! x l8 S# x8 x! E' S& S
{7 G; U* k) Z e
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
6 {/ t- H9 v. q0 e# tdouble haCloseVal=(open+high+low+close)/4;
+ D7 t7 A% I% edouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
: R; s4 a9 r6 b3 adouble haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));0 h' V0 T7 |$ t# _# l
haLow=haLowVal;
" t1 f. n5 Y/ mhaHigh=haHighVal;
1 D3 }+ u) h! B8 NhaOpen=haOpenVal;" ~! N& K1 m1 q4 l( _/ b7 p% m9 i8 @
haClose=haCloseVal;* B$ U D$ [6 M. ]- U: @
//--- set candle color
" n& g2 b) z4 L2 iif(haOpenVal<haCloseVal)8 w& M ^' t P' |' t
haColor=0.0;0 m$ ]/ Q0 c2 [! y- x5 I
else
/ Q# b& e$ {" s+ Z9 z+ `" ohaColor=1.0;
4 R+ o" e( K/ J0 x4 y}
; ?) R( z5 q4 k终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
( }% m$ C. {* O4 Z8 K5 F m5 X' `: `return(rates_total);
% l" _- A7 a, b% h然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:, ?( [4 c, G/ A$ R3 `
//+------------------------------------------------------------------+
) Q6 b' i* l3 b; s! q) z" ^//| simpleHeikenAshi.mq5 |* J# V- ^3 m+ ?& ?# [
//| Copyright 2023, MetaQuotes Ltd. |' c& G$ P/ b6 t- J3 m
//| https://www.mql5.com |
d$ _* j) y$ L8 T0 f//+------------------------------------------------------------------+' s+ y" D# D0 j& \8 d
#property copyright "Copyright 2023, MetaQuotes Ltd."6 y. u t, S( e Y2 i( _" L k: W! }6 C
#property link "https://www.mql5.com"& ?3 u+ ]& d* D) }8 f
#property version "1.00"5 z0 W( N3 H8 |8 q8 ?8 k: i
#property indicator_separate_window1 S: Q6 e1 ^% U/ C% R; r5 i' F/ K( D
#property indicator_buffers 5
4 _: E+ F: g. a$ \8 |#property indicator_plots 1
- E! g0 F! W' a! A. O#property indicator_type1 DRAW_COLOR_CANDLES
( C/ J; R/ v7 [* y#property indicator_color1 clrBlue, clrRed+ h4 F$ x- P9 r6 e. t% \4 Z3 R$ q
#property indicator_width1 2' h9 q. {: c0 V0 U
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
1 m2 o, W! d& I9 z- e( i0 {! r6 _double haOpen[];
9 Q8 Y8 U' C% T6 T5 R$ U7 J' X4 wdouble haHigh[];
% o3 b+ _5 r" C6 J) h: V* t; Z7 Hdouble haLow[]; R) k7 q i0 M5 g% x ^. {
double haClose[];
" z0 H; ?% \* Z% R+ o1 d+ g* Ddouble haColor[];& ^3 v x# j$ r
int OnInit(), U$ C& {- l6 z, `4 V) g5 v. W
{
/ n5 } z) c6 [( HSetIndexBuffer(0,haOpen,INDICATOR_DATA);
" T3 J' p% A, u& o# ^8 jSetIndexBuffer(1,haHigh,INDICATOR_DATA);
* s8 L2 Y1 i0 X' ]( GSetIndexBuffer(2,haLow,INDICATOR_DATA);
( c6 A: |3 A0 B0 CSetIndexBuffer(3,haClose,INDICATOR_DATA);1 Q4 ~/ C# [& v ~& T% _
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
* H0 W. J8 D$ P6 M% |3 {IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
]* _+ l8 I y% Y8 V S7 ZIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
* s, R# C' O( |5 x0 x& t! W3 RPlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);( |! I& `- \! D& Z( Z$ J* F
return(INIT_SUCCEEDED);" \+ J* O- m# Q; x
}& D$ p/ g0 E" y5 E) y
int OnCalculate(const int rates_total,5 g- b6 M: b; V! L2 m; h4 D( t9 P
const int prev_calculated,9 H: [2 x& p2 m! y( P
const datetime &time[],# }& ]2 V: ~# v9 [" v) D
const double &open[],
( i' j" M' y+ ]" C% @" m. fconst double &high[],0 H; Q# `, f3 X, `* R
const double &low[],
2 C2 a- h2 g4 G2 j+ D. zconst double &close[],
% R8 \$ y3 b) x5 @ A' U9 Fconst long &tick_volume[],2 l7 s. L* ~- L! _1 X
const long &volume[], |