概述
/ j. f9 F1 I& ]6 E我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
- S( V* ?. M# n赫兹量化交易软件7 I# `: a( t( X+ B; r1 V w
自定义指标和 Heiken Ashi 定义
7 P3 c- D& k( H( P在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件' B2 k# L u4 ?$ {" ^
简单的 Heiken Ashi 指标6 i# o2 H% U6 H5 R% D! X8 S
在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件: S8 z" t$ Q' U, ]2 u K+ K
我们来查看创建此自定义指标需要完成的所有步骤。
, A9 {* K" v" \ o. i通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:
M, ?0 `* w$ S/ p: B. H, x(indicator_separate_window) 在单独的窗口中显示指标。 \9 o( Z8 k8 Z: \$ s# l
(indicator_buffers) 确定指标计算的缓冲区数量。( f- p# A& P E) ~
(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。. n- O& B8 Z D. S! W6 m
(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。9 `" [. c: C4 d! y* e
(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。. I! ]; r. i8 p
(indicator_widthN) 还要确定 N 或图形序列的宽度。4 \: ~8 ~- K0 Q) w- h, L
(indicator_labelN) 确定图形序列 N 的标签设置。2 F- [. U' }) V2 y! c+ v& C
#property indicator_separate_window
3 k: N# X/ p8 q: | ~+ t#property indicator_buffers 5
7 ?* a% ]7 B. i' ~6 X8 N#property indicator_plots 1
% |( V! D+ D8 t" H#property indicator_type1 DRAW_COLOR_CANDLES
! B5 H3 w/ q9 J9 j' y#property indicator_color1 clrBlue, clrRed8 c( z" Z' \, X* J& c; F3 d
#property indicator_width1 2, `: S) F# ?7 w
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"9 P) @4 _7 h8 V- ?8 p9 H
为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。- O/ M' t% _9 @; _3 z) S- m3 i
double haOpen[];
; c: w) A* V% J/ Z" f" P* f: e2 x+ L5 Xdouble haHigh[];* D! Q- {& x1 F9 [
double haLow[];
2 i1 v+ _9 ]' X* }2 y; M( D; rdouble haClose[];: j0 y$ r# I! R7 L2 j
double haColor[];
- m' X5 y/ @' s( o( Y5 n0 ~# N% C, N在 OnInit() 中,此函数初始化正在运行的指标。
: H7 c" u# e4 u8 r2 M& S4 Cint OnInit()- g4 w* ?$ i M. x
调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件, f s7 ~% L. c! { V) o9 {
其参数为:3 r5 v) P. [3 ^- _/ h B: _2 C
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
8 D0 q+ v8 Q$ Ibuffer[]: 在我们的自定义指标中声明的数组。
" H; V8 F- {; t0 k) Ydata_type: 我们需要在指标数组中存储的数据类型。8 k1 q1 Z$ m8 l) f J; Y2 [/ B# Z
SetIndexBuffer(0,haOpen,INDICATOR_DATA);
5 \! ?0 s- l B0 T& z5 N/ n1 ESetIndexBuffer(1,haHigh,INDICATOR_DATA);* N9 N7 P' D, |: b8 ~! K5 v$ r, F
SetIndexBuffer(2,haLow,INDICATOR_DATA);- k% c& r( v4 U/ c
SetIndexBuffer(3,haClose,INDICATOR_DATA);& X+ l0 J& Q# b( O4 N2 [+ `. u
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);( [ ]: _8 i, ?' ^0 ~1 T
通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:7 S& A0 b9 @4 \9 B2 ]' f
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
+ F* \0 @5 e+ `6 [7 x# N7 Bprop_value: 属性的值,我们将指定(_Digits)。
) j4 Y% p( O; Z! |; @IndicatorSetInteger(INDICATOR_DIGITS,_Digits);: [4 A9 T& I* G" H2 w! C
调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:
. a2 S% {) d1 r6 W9 Q3 \- {prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。
" z. g5 t" Y7 K: d0 mprop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。
, Y; X$ L) s* R% r+ U8 x# sIndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
2 {8 d6 I( g& f: i9 N7 ~' @调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
& g9 Z4 q' V4 j' vplot_index: 图形绘图的索引,我们将指定 0。
" R7 b, D; S1 J/ i) K0 ?( q4 wprop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。
! A/ I5 m6 h3 d; N7 f9 Sprop_value: 属性值。3 q* V8 v B4 y) Z. U$ u
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);+ b( X, c# V: c* O
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
+ f3 G, _$ I4 i3 c+ ?, G( r$ freturn(INIT_SUCCEEDED);
+ l; \; z9 Q* N. F! J! w在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件( C* l/ H6 m. c. B. G
基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。
, e |! s9 P: A; _int OnCalculate(const int rates_total,6 ]9 S9 e" Y, U
const int prev_calculated,
3 S& w; t v1 ~/ |' j& B8 hconst datetime &time[],5 R, l3 v5 ]# d5 a
const double &open[],: J: d- h0 v& w5 r1 j. B# p
const double &high[],2 C B& D* ]0 @/ A
const double &low[],
) a9 m, f" }# L- ?* |$ h1 jconst double &close[],
/ @. F4 W1 @5 y. jconst long &tick_volume[],: N8 r% p/ W B5 M/ F% V- @' o
const long &volume[],
# w: i' m& G3 F" F0 t! wconst int &spread[])
8 O8 \" I$ \: w7 {* f4 W创建一个整数型 “start” 变量,我们稍后将为其赋值:' z# w! ~5 O/ {* R; c: x' A
int start;- W% L4 m* w/ I( M, I# h
使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:/ W3 g: g1 T+ S( a+ j: p8 C
if(prev_calculated==0)
, {9 G# ~( G; N- D" W{
& v+ h" U! s2 N0 ehaLow[0]=low[0];
/ t, q0 B P, m, lhaHigh[0]=high[0];
4 _' b. K9 L! q0 p1 KhaOpen[0]=open[0];0 z$ O+ r0 l. h; i& v/ d
haClose[0]=close[0];5 Y$ R5 t& @' r0 J- J# s. j7 L" _
start=1;
! [( M6 G9 [; R0 n0 ]}
. c7 X) ?# M$ K/ a" g, d* R) felse) H+ z% }& c# B( E7 @7 {
start=prev_calculated-1;
! ~" c4 A$ Q6 ^9 I在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。
' J: a j& l; X9 C V这三个表达式将是:
* I* b7 t4 X$ Q% Q* }1 u* fi=start: 对应起始位置。
" `# D8 h! Y0 Bi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
% N, P% E% H: U# pi++: 加 1 作为新的 i。
4 _; z* Y( P2 s& j9 B( F" v我们每次在循环过程中需要执行的操作:9 n& n* f3 L( m) R, \+ Q) Z
计算四个双精度变量
2 ]6 }2 W4 p' `$ \2 h1 |haOpenVal: 对应 Heiken Ashi 开盘价。
: }0 {- i7 Q8 p& \0 a6 j2 k8 Z! zhaCloseVal: 对应 Heiken Ashi 收盘价。; C& k- j% p9 I! f0 w5 M" ~
haHighVal: 对应 Heiken Ashi 最高价。
3 q' ?9 l& d7 p3 JhaLowVal: 对应 Heiken Ashi 最低价。
5 ^6 n" N& E' F. f M在上一步中分配的计算值与以下内容相同
& E2 }( l& [% a; D( zhaLow=haLowVal
' K3 R3 m$ e, r" o4 b% [% vhaHigh=haHighVal4 b) z4 @& D, u2 ^; c! ]7 d& X
haOpen=haOpenVal/ Y( }* u2 d# F* g( P+ g
haClose=haCloseVal
1 D+ Z# @: Z. Z1 b4 o# q检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。
6 S3 C* x- c, j" `for(int i=start; i<rates_total && !IsStopped(); i++)
2 S: O, k6 [$ @5 ^{) u9 M# w9 @* s/ a3 {7 l
double haOpenVal =(haOpen[i-1]+haClose[i-1])/2;- b1 | W3 d' A( }6 w9 J2 p3 r
double haCloseVal=(open+high+low+close)/4;
/ l2 K, i' G: L; g% y' F+ }double haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));1 r5 U7 e5 f. e: ?* h
double haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));0 P9 ~7 D( }$ s
haLow=haLowVal;
( p- t2 ]; H9 [, E( RhaHigh=haHighVal;) `5 b) j2 Z4 Y1 e! H% M5 y8 {
haOpen=haOpenVal;9 [7 M# O& M" t6 w# o- E
haClose=haCloseVal;
: B `! A; ^( o) n//--- set candle color9 K1 Z8 e* _# Z! @
if(haOpenVal<haCloseVal)
; _; T; \2 E! @' ]+ T1 HhaColor=0.0;& |( g* P. H6 h9 J! D
else8 T' K0 R' q+ w
haColor=1.0;# i) L2 E- c6 [- E; O
}; r! ~ s Y& p% C$ M ~) `. x0 P
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。- V9 e4 W$ g) c( f* k1 E
return(rates_total);
5 y) E4 g5 F: i- f e$ {$ Y然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:
! M( G* X- i7 M//+------------------------------------------------------------------+
! t( n3 r& S1 G$ [' O; h& C9 z" i//| simpleHeikenAshi.mq5 |" S$ A3 @! p7 J3 u) \
//| Copyright 2023, MetaQuotes Ltd. |
3 {: `5 P- x. A: A//| https://www.mql5.com |% r+ E# U" r* O
//+------------------------------------------------------------------+0 n, Y: t) |; ]+ q% C9 e2 h
#property copyright "Copyright 2023, MetaQuotes Ltd."
/ w9 D3 ~' ]$ N- J7 i& b#property link "https://www.mql5.com"
$ E7 J" a/ b! v1 @0 }" e# Z#property version "1.00"
% w( M) \0 ~( C7 R#property indicator_separate_window
- H) C2 j4 J3 D1 V- J8 W6 `#property indicator_buffers 5
) x. a$ b9 R, L% F# c#property indicator_plots 17 y# C& ?3 ^! r% O- L. \
#property indicator_type1 DRAW_COLOR_CANDLES& |& [3 `9 T0 x3 O4 b
#property indicator_color1 clrBlue, clrRed) k. q- V% v5 K* L
#property indicator_width1 2
% M6 |9 r4 n; Q5 x#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
& B9 l# d9 d8 }4 i8 V2 Sdouble haOpen[];7 a$ D: {/ w& l G. L
double haHigh[];& N8 @% i5 O+ J/ a, _: f1 V f
double haLow[];
. U7 ` ]( l3 n8 A# ndouble haClose[];& a6 R4 z' T! |# d4 g- x
double haColor[];
9 _- b. n. O4 d; _% dint OnInit(), t7 `7 D2 e J2 j+ N
{
7 v3 p4 @( K3 B: q p& E! eSetIndexBuffer(0,haOpen,INDICATOR_DATA);( a7 h6 J6 y6 G9 S
SetIndexBuffer(1,haHigh,INDICATOR_DATA);
. v, J; `" q; f- \* VSetIndexBuffer(2,haLow,INDICATOR_DATA);
* {% t# d |# Y8 I7 ~ lSetIndexBuffer(3,haClose,INDICATOR_DATA);
* ^% I% l }6 v( qSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);) B! f4 J' n3 I$ [1 v+ X! b
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);2 e4 b' q/ l( G1 h. k k
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
# x2 Y6 x0 V: `8 ~0 l4 H# X5 \PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
( n% V5 W' d, J' Q7 creturn(INIT_SUCCEEDED);2 N( v/ K F. O2 T
}
* d! r0 v9 n$ G$ N* Nint OnCalculate(const int rates_total,1 _& c/ C6 T" x4 A9 }. Y0 _
const int prev_calculated,9 }' h$ Z$ k( I1 [! W
const datetime &time[],2 G2 L; n1 s' O2 ~( e) W; C& [
const double &open[],* A3 ^8 N$ i2 M6 p% G
const double &high[],
5 f2 |2 n, M- d+ Sconst double &low[],- b \2 q" l# i, V* R7 J! U
const double &close[],9 C: z) b1 k5 r0 ~* U6 m0 p% X
const long &tick_volume[],- P0 V$ y3 L: i
const long &volume[], |