概述
1 C$ ^ l1 N# _9 ^我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。7 Y4 X- A& Z) @, n! C% i$ z1 _
赫兹量化交易软件5 { H* p) @% X" h9 C% N ?
自定义指标和 Heiken Ashi 定义
; u# d9 q- k2 q& T4 W; n2 l在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件
) m. O. Z" _! f' O8 g9 j简单的 Heiken Ashi 指标5 [# B5 t( y3 ^6 U6 i0 S X$ e
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件; R) G& d+ V! U' h' \
我们来查看创建此自定义指标需要完成的所有步骤。
7 X( S) f2 M5 N$ r4 \通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:9 G" Q6 w# R' \2 w1 _
(indicator_separate_window) 在单独的窗口中显示指标。
. g6 U) u5 H& G* m) Y(indicator_buffers) 确定指标计算的缓冲区数量。+ U; f, |0 Q1 |* o
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。
) k$ [$ H2 Q. k(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。, Y' B1 o# Q. T
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。; V* [9 n# |; N
(indicator_widthN) 还要确定 N 或图形序列的宽度。' l( c, N$ v+ W1 i. {
(indicator_labelN) 确定图形序列 N 的标签设置。 D# W! u& T& l1 K. y
#property indicator_separate_window
0 j" n9 R: G5 a1 y#property indicator_buffers 5
+ j P4 ]9 D0 a; x2 V#property indicator_plots 1
3 ~ Z0 q4 G# A% Q5 Y1 P; x' C6 B#property indicator_type1 DRAW_COLOR_CANDLES
! H4 h% g: J9 R: ?$ A5 i0 }( a# q#property indicator_color1 clrBlue, clrRed
* M7 X6 S' R1 s9 P#property indicator_width1 21 I: t' ? H- Y! V# {
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
* z6 y' A. I5 n' _% D为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
- H5 ]8 n& ?) |' W2 Kdouble haOpen[];
" n" g9 ^" _+ ^/ }double haHigh[];
9 r4 I$ g1 E b- Zdouble haLow[];8 C5 z6 p8 K" Q/ ~* O1 O% ~
double haClose[];
, C2 R' S' q& C: u2 Ddouble haColor[];
& ~/ A2 d8 v$ H% S, a/ ^% a4 c' W在 OnInit() 中,此函数初始化正在运行的指标。; O% W/ P4 C" p- I3 v; D
int OnInit()
) B: e8 H( K1 o; B# X; _/ R& g9 d2 h调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件
s7 I& r* T. M( K# g5 n+ ]8 r2 r其参数为:! _8 a( N+ ~/ t! H2 e
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
! a' G0 U1 {, ]4 d0 ybuffer[]: 在我们的自定义指标中声明的数组。
4 Y w7 u7 u! qdata_type: 我们需要在指标数组中存储的数据类型。
1 d* }8 n, ~7 k5 aSetIndexBuffer(0,haOpen,INDICATOR_DATA);5 `$ z- Q/ v7 V/ C8 z1 w u
SetIndexBuffer(1,haHigh,INDICATOR_DATA);. T/ P& \' o' w+ h
SetIndexBuffer(2,haLow,INDICATOR_DATA);- v" G! K7 ^; D$ A% c5 c9 l
SetIndexBuffer(3,haClose,INDICATOR_DATA);- {7 y8 U. ^9 O5 s5 v
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
- L3 Z) s/ \: Y2 g9 n* @/ N通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:
+ ^4 l9 P1 I# J6 P/ V) C9 _( O) Rprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
% L; n- R( v" e0 t- Nprop_value: 属性的值,我们将指定(_Digits)。
: E& r1 F: a, ^) @/ U8 }( G# GIndicatorSetInteger(INDICATOR_DIGITS,_Digits);6 k N8 ]* w3 D6 W
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:
. p' \! ?# }8 E6 L: P9 E7 Aprop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
% ^' p& ` o' W5 ]: S; c) gprop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
5 x p1 e9 j/ aIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");3 {" I+ g5 u+ |( i" O
调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
4 L+ o( d" S% _0 q8 W0 Mplot_index: 图形绘图的索引,我们将指定 0。
" h) s2 N2 d9 \# T- @. L- O2 _prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。- p1 Q& P, m( B$ w( q) A
prop_value: 属性值。
3 `, Q' C% F& p. i) v6 APlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);3 F6 \6 k4 Q$ L9 y/ J0 y
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。; b/ C' I3 y' G6 p$ n9 k
return(INIT_SUCCEEDED);
4 Y2 Y: q. ^" |7 M在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件/ Z7 u# g: N* m0 g$ c
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。
3 @% N! o/ ^1 m8 c& Bint OnCalculate(const int rates_total,
5 Z. y4 {/ @+ y L ]' c$ q% Q* _: Jconst int prev_calculated,
$ n! G8 s* z3 Y% ^! U6 Y" M$ ?5 G& lconst datetime &time[],9 {, ^) Y" Y- {
const double &open[],# E. T3 S1 P' V; E2 T
const double &high[],
& B2 `' T" M; O5 P& O9 { lconst double &low[],
, t# N3 R. r! X9 c& _const double &close[],' T) ~' ]0 Y; ?+ Q; E- C a6 f
const long &tick_volume[],% j4 t0 P1 V+ n7 ?: }: m
const long &volume[],
4 |: C5 j0 m' h5 Y: X9 j- @6 k6 Xconst int &spread[])
8 W3 h9 Y! R9 I创建一个整数型 “start” 变量,我们稍后将为其赋值:
- b1 w9 y* |. a+ Pint start;
* ]$ U8 K0 Y( ?3 D: R: G. l/ Q H使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:
K' K% ?5 e/ S d4 X! Hif(prev_calculated==0)
8 N. @3 C" F4 @, m) g. k( u{
5 E" X p; e7 k2 D/ d0 ]haLow[0]=low[0];6 } ]# z: }# N2 r& ], k
haHigh[0]=high[0];8 S! H8 R# H+ E* p
haOpen[0]=open[0];5 }# z- X) p% z9 a9 H; ~; [8 o$ E
haClose[0]=close[0];
7 S1 C) m# e: M4 T( @2 W Ustart=1;' c3 ]& L6 Y1 s9 r7 Q
}/ {" h5 j' J& a7 U* b
else
- R* {5 r7 g4 x: f/ wstart=prev_calculated-1;: w6 K6 j8 o$ z! [% R3 ]
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
4 s0 [ n* c1 p; Y这三个表达式将是:5 \7 U9 [' N& D) v7 |& _0 V8 X! V
i=start: 对应起始位置。
9 c4 b! Q* _! m+ qi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。3 S' p# u% W# D) \+ [4 X* L4 ^
i++: 加 1 作为新的 i。
5 W2 _) _9 i" w$ m# \我们每次在循环过程中需要执行的操作:( s2 K8 r& p) E% ^, Z( T/ g
计算四个双精度变量
) f/ P# g; o3 OhaOpenVal: 对应 Heiken Ashi 开盘价。
6 q6 H/ S, k5 F1 @" Y; q# ChaCloseVal: 对应 Heiken Ashi 收盘价。
$ t2 v% `8 e) f3 W! s ZhaHighVal: 对应 Heiken Ashi 最高价。
) z. V' y/ ?8 n# ]# D- ]; Q: J! rhaLowVal: 对应 Heiken Ashi 最低价。8 e$ E. [( {/ R
在上一步中分配的计算值与以下内容相同
% t1 U& z) C3 \6 F* y9 y$ B- `+ yhaLow=haLowVal
& S) Q; H B$ y0 Q ?/ ?' chaHigh=haHighVal
# S' E; \8 O/ Z2 V; |! @haOpen=haOpenVal: t$ c) S* G+ R! f, B- o# P7 b; i
haClose=haCloseVal1 R: j5 E3 S8 ^( w) Z) I: ~
检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
" _6 O& Q$ ^. ]0 J5 k1 Rfor(int i=start; i<rates_total && !IsStopped(); i++)
}+ u" i4 |8 h' `{8 z* q8 G6 w/ B O$ J: J3 _
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;; x( P; g7 y$ E8 n/ Q
double haCloseVal=(open+high+low+close)/4;
. y( p8 Q7 w2 w- Z! v+ O- Vdouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));; z0 O! }. n" e3 @1 J0 ~
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));
9 j7 d, k! z1 j& g/ y5 ehaLow=haLowVal;: U4 A9 g9 i# w: j& X; Q. R
haHigh=haHighVal;/ b Q6 q! Q/ T& _5 R
haOpen=haOpenVal; c! z1 d K: \1 L3 i0 K; _1 a
haClose=haCloseVal;: N' I6 T1 m# m5 G* ]5 a
//--- set candle color. W( \! T" w7 X1 }" _* ?/ ?. ]0 Y
if(haOpenVal<haCloseVal)
: e5 ^4 V% j( m( f/ JhaColor=0.0;3 r6 i% o2 d' L: M' ]" ]. L! s; q8 ^1 y
else, j G. N: b7 x9 i& s0 ^/ _
haColor=1.0;
; A1 s- f. R4 u% @}% ~0 z* |9 k# P# ?
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。
; [! B2 `; h. o# o/ d0 {4 Wreturn(rates_total);
: e# n0 u3 |) ^8 w b; n然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
' o5 P/ a+ v% p; b//+------------------------------------------------------------------+
8 f( O! Q* W; J# g//| simpleHeikenAshi.mq5 |9 J. `! K" k* y; J8 i, p4 I# q$ i
//| Copyright 2023, MetaQuotes Ltd. |% q9 _* T9 b3 f0 p, j& [" p
//| https://www.mql5.com |, M, }0 G4 p8 g7 v, |$ k4 D. L
//+------------------------------------------------------------------+) H o/ x8 i7 @. [# J
#property copyright "Copyright 2023, MetaQuotes Ltd."
% g( R. B! ^8 D# y N6 ~ K#property link "https://www.mql5.com"! x5 J% u E& X* j9 v
#property version "1.00"
# I% N4 v$ L# E4 x8 I" g' x#property indicator_separate_window0 x& o+ \# T+ F; p! I q! s
#property indicator_buffers 5) `3 j# g8 b I6 C& n0 d
#property indicator_plots 1
& [4 V2 F/ x' g5 u" y4 H$ w2 H#property indicator_type1 DRAW_COLOR_CANDLES6 m# W1 u7 u% u; o- Y! E1 A; P
#property indicator_color1 clrBlue, clrRed
+ O" g% q5 Z' [& U7 F: U$ b- c#property indicator_width1 2& o+ b/ f5 `4 F8 t- ~# a) P
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
1 L/ i# u- W) a$ o' ?/ H4 tdouble haOpen[];
, l9 {6 x) R4 N- T$ Y6 u& A/ Gdouble haHigh[];
; l( O7 }9 O! r6 ~double haLow[];$ I7 I9 N: C, W( g
double haClose[];
7 `& I4 ~% b/ j, N$ M: v, Udouble haColor[];
4 B& i. ~4 C# ?: L g/ Y! ^7 M# Aint OnInit()
: q4 B! p. [5 D$ p/ Y{
! Z" s, ?5 ?6 j2 j/ [SetIndexBuffer(0,haOpen,INDICATOR_DATA);
4 x, P' t6 V1 F" J9 J' }1 c5 z7 pSetIndexBuffer(1,haHigh,INDICATOR_DATA);
5 N Q% D# v6 V! g, g0 Y0 m* {( `SetIndexBuffer(2,haLow,INDICATOR_DATA);
- W: h# h# N' L' A$ s% G, `SetIndexBuffer(3,haClose,INDICATOR_DATA);6 B7 e0 ?$ r5 n* X1 s L7 N" w
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
. }2 i. N9 c" e7 JIndicatorSetInteger(INDICATOR_DIGITS,_Digits); X0 g1 j H% p, |! a2 P
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");& {7 E/ \9 ]6 | ?: b$ `
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
) t& S: Z$ @ c- }7 V y/ lreturn(INIT_SUCCEEDED);
5 @: X! U. n3 Y( w0 s2 V6 w8 z}; ^2 p5 c: W+ W# N1 h$ ?' d
int OnCalculate(const int rates_total,
, G1 R& h* u3 z3 Hconst int prev_calculated,/ \4 Q$ y1 P, k; x2 |1 N
const datetime &time[],, j2 M: {. F5 C1 o- i ]
const double &open[],# a. ]: B. Y, B- D
const double &high[],
, i7 | _: V- V/ N, e) E! sconst double &low[],! E: z4 |/ V' f, ^ E3 g) S
const double &close[],( \! d9 i2 R5 i, Q) d% o
const long &tick_volume[],; Y" \2 j. Z/ W2 e$ l3 E" F1 }: z
const long &volume[], |