概述
' H" Q& ^/ x4 y. U8 z" A# k我们都需要读取图表,任何可以帮助完成此任务的工具都会受到欢迎。 在有助于读取图表的工具之中,指标计算可基于价格、交易量、其它技术指标、或它们的组合,而在交易世界中存在众多新奇的思路。 我们在交易终端中内置了很多现成的指标,如果我们需要添加一些功能以便能适应我们的交易风格,我们会发现这有一些挑战,因为也许无法更改它,除此之外,我们也许无法在交易终端中的内置指标里找到期望的指标。
2 b4 F1 x+ J1 f$ R& _0 m赫兹量化交易软件
* z) G( O1 a4 G9 J- \% r$ i自定义指标和 Heiken Ashi 定义* M; s/ ^) K# r! E9 {
在这一部分中,我们将更详细地学习自定义指标和 Heiken Ashi 指标。 正如我在上一章节的概述中提到的,自定义指标是用户利用 MQL5 编程语言创建的技术分析工具。 它可以在 MetaTrader 5 中用来分析和明晰市场走势,并有助于做出明智的投资决策。 有许多实用的内置技术指标,但有时我们需要根据一些额外和特定的数学、统计或技术概念来分析和理解市场的行为,而这些概念在内置指标中不存在,或者没有指标可以完成任务。 那么,在这种情况下,我们必须自己创建指标 — 这是 MetaTrader 5 平台的功能之一,因为它可以帮助我们创建自己的分析或交易工具,从而满足我们的特定偏好和目标。赫兹量化交易软件3 O, l7 [/ R" C" y* v; ]
简单的 Heiken Ashi 指标
# I5 o! Z9 v* l) V. c5 g% Y在这一部分中,我们将创建一个用在 MetaTrader 5 上的简单 Heiken Ashi 指标。 该指标应持续检查价格(开盘价、最高价、最低价和收盘价),并执行数学计算,以从而成 haOpen、haHigh、haLow 和 haClose 等数值。 根据计算结果,指标应依据数值在图表上绘制不同颜色的烛条:如果烛条方向看涨,则为蓝色,如果为看跌,则为红色。 烛条应作为子窗口显示在传统图表下方的单独窗口之中。赫兹量化交易软件
2 |2 f" z) ^, I6 j2 K我们来查看创建此自定义指标需要完成的所有步骤。4 D# \1 d$ e5 y. e9 ?4 y4 i% M9 K2 `
通过 #property 和标识符值指定附加参数来确定指标设置,如下所示:
( @0 t' t, Y) H; }, Q# [) }+ e(indicator_separate_window) 在单独的窗口中显示指标。% D. x2 E4 D* g$ P2 @, b% ^" R& `
(indicator_buffers) 确定指标计算的缓冲区数量。
( F* O4 C9 }5 F4 z8 i$ C8 T(indicator_plots) 确定指标中图形序列的数量。 图形系列是在创建自定义指标时可用的绘图样式。# |. R6 u0 Y" } b2 R9 ~
(indicator_typeN) 要根据 (ENUM_DRAW_TYPE) 的值确定图形绘图的类型,N 是我们在最后一个参数中确定的图形序列的数量,它从 1 开始。
! V! a, T* e6 t, B(indicator_colorN) 确定 N 的颜色,N 也是我们之前确定的图形序列的数量,它从 1 开始。
# q) N. u6 e; P(indicator_widthN) 还要确定 N 或图形序列的宽度。7 n; |, J9 M. s- p
(indicator_labelN) 确定图形序列 N 的标签设置。
. e0 u( ^+ V: `9 x/ _6 ]. V#property indicator_separate_window! [9 {6 @* s1 N
#property indicator_buffers 5
& @% x+ A2 K7 o5 F0 o! _( l#property indicator_plots 1
- K1 t1 e. r# k#property indicator_type1 DRAW_COLOR_CANDLES
7 p8 Y+ Y# Q8 V0 `' L#property indicator_color1 clrBlue, clrRed! U% P3 ^$ ?/ V4 U
#property indicator_width1 2
+ }4 E* L6 c7 {% T: ]3 t! H#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"
7 e2 D$ o8 D5 `4 o为指标的五个缓冲区(haOpen、haHigh、haLow、haClose、haColor)创建五个数组,均为双精度类型。
d( \) ]* T8 Q" Wdouble haOpen[];
9 R2 v; R& U# j9 P; Idouble haHigh[];; | ]6 q$ G& S
double haLow[];
# P9 q" B. m1 a! L& @0 v$ gdouble haClose[];
. i' k$ B4 Q' U# X. M+ Fdouble haColor[];. G9 u8 ~7 M! E
在 OnInit() 中,此函数初始化正在运行的指标。
7 _- D1 f( B7 O" M! r! gint OnInit()
}3 w0 `5 T. g( i, s调用(SetIndexBuffer)函数为双精度类型的一维动态数组的指标缓冲区进行排序。赫兹量化交易软件: n; p# D9 S5 G/ K# ?( y) u& U" ~2 c) U
其参数为:6 _4 m8 M7 Y' n, }; h6 J
index: 指标缓冲区从 0 开始的编号,此数字必须小于在参数 (indicator_buffers) 中确定的声明值。
) ^# c! |, @. `& l' sbuffer[]: 在我们的自定义指标中声明的数组。
& K6 z, B8 n f8 _+ P& \6 C8 Hdata_type: 我们需要在指标数组中存储的数据类型。
- a$ S8 C3 W. R6 n; e4 c8 lSetIndexBuffer(0,haOpen,INDICATOR_DATA);
5 v5 E9 h/ h) o/ {( l5 uSetIndexBuffer(1,haHigh,INDICATOR_DATA);
* ?% d5 c, u x' L/ C% qSetIndexBuffer(2,haLow,INDICATOR_DATA);
8 T/ ~: Z# D7 G' kSetIndexBuffer(3,haClose,INDICATOR_DATA);( N: f" ? m: b& y9 |
SetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
+ j& A0 i; v; K$ R通过调用(IndicatorSetInteger)函数和调用变体,设置相应指标属性的值,其中我们指定了属性标识符。 其参数为:% H1 \7 b$ @, a( H
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_INTEGER)之一的属性的标识符,我们将指定(INDICATOR_DIGITS)。
4 p' @3 Y- @) p! |. uprop_value: 属性的值,我们将指定(_Digits)。5 V& e2 k9 h/ H* P$ o5 r! K" P% W1 [
IndicatorSetInteger(INDICATOR_DIGITS,_Digits);
A5 {7 m& L4 C4 H调用变体设置相应字符串类型属性的值,我们还在其中指定属性标识符。 其参数为:. D" N3 X7 j2 R
prop_id: 可以是(ENUM_CUSTOMIND_PROPERTY_STRING)之一的属性标识符,我们将指定 (INDICATOR_SHORTNAME)为指标设置短名称。- {" I* q' {! ^$ Y
prop_value: 属性的值,我们将指定(“Simple Heiken Ashi”)。7 y2 |1 C8 F9 D0 ` |1 S
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");
4 \; O; w7 |. l+ h# @) ?2 N/ Z& p调用(PlotIndexSetDouble)函数设置相应指标的对应双精度类型属性值。 其参数为:
# ]* D+ O0 u eplot_index: 图形绘图的索引,我们将指定 0。5 K% q# A) ^0 g E: O" N; g
prop_id:(ENUM_PLOT_PROPERTY_DOUBLE)值之一,对于无绘图,它是(PLOT_EMPTY_VALUE)。 r2 K8 Z" d( G3 G9 P
prop_value: 属性值。
, @4 V3 G. P. U$ a6 g; `" I/ @PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);. F$ y( s1 B" Y! C; Y
然后返回(INIT_SUCCEEDED)作为 OnInit() 函数的一部分,终止它,并返回初始化成功。
" {% F$ s7 k- u3 c. greturn(INIT_SUCCEEDED);3 I& V" G% l" @! T; Y; d# T5 |* V/ |2 n
在指标中调用的 OnCalculate 函数内部,赫兹量化交易软件
! P1 `" M' j' O6 o+ K基于当前时间帧的时间序列进行计算,其处理的价格数据随着计算类型而变化。
" K+ a' ?# O$ Bint OnCalculate(const int rates_total,) L- e! q7 X8 S/ k% h1 v6 b# ~- p
const int prev_calculated,
5 Z, W8 c8 V: n; V5 @! i L8 [& w) econst datetime &time[],6 n6 d5 Z J9 u6 K
const double &open[],) A0 P0 X$ N" a) ?' i
const double &high[],
5 h7 H J, X' U5 N+ I% {! o8 S; Uconst double &low[],0 w; ?4 _( I, Q0 I/ ?2 `7 p
const double &close[],
+ P; K( x+ v' j% {& Kconst long &tick_volume[],
9 p( P' V* `& R# G3 f mconst long &volume[], I$ w4 T7 [3 m6 F1 ?: x: [
const int &spread[])" U# p5 D: ]/ F6 R# } a) T
创建一个整数型 “start” 变量,我们稍后将为其赋值:# J3 `" B! p# q! n# N( N
int start;
1 ^$ m6 `2 l1 ?4 C5 g3 F& T2 d( O使用 'if' 语句返回索引值(最低价、最高价、开盘价和收盘价),如果 prev_calculated 等于 0,则 start 值 = 1;或把返回的值(prev_calculated-1)分配给 start:, U: a8 d: W2 o) ? V U2 s% n
if(prev_calculated==0)# r( p y4 Q1 d) z
{
+ j- Q6 n! Y8 M% H/ }9 rhaLow[0]=low[0];
3 k$ p: X7 O# [- t# w. n! LhaHigh[0]=high[0];) l1 [2 @2 S3 Z. V5 l4 T" a
haOpen[0]=open[0];6 ^6 ^5 Q( V+ L/ ~& y
haClose[0]=close[0];' f# B. A7 P: T& {% f4 F- Z
start=1;' I6 p+ S$ R5 ?1 `, ]
}
2 @, T7 t6 h. I; e) P5 `else+ ]+ \6 U9 r3 M, t
start=prev_calculated-1;3 K) d* f; S& R" N% n
在主循环的 “for” 主体里进行计算,“for” 运算符由三个表达式和可执行运算符组成。* k" I" i" e& D6 R$ d
这三个表达式将是:
6 _8 t& f( D' U7 y& wi=start: 对应起始位置。
( y& @) i$ I( ^# d" bi<rates_total && !IsStopped(): 完成循环的条件。 IsStopped() 检查指标的强制关闭。
! G4 m. Z' K+ x$ u4 M3 Ki++: 加 1 作为新的 i。
4 v C0 N3 L6 U我们每次在循环过程中需要执行的操作:
$ _* W' I D3 x2 K2 x: ~计算四个双精度变量
2 {8 m* w) z: U$ B5 ]! w% phaOpenVal: 对应 Heiken Ashi 开盘价。
! b( |9 n/ G: u1 I- ~haCloseVal: 对应 Heiken Ashi 收盘价。# L2 B8 V6 G6 M% p: U4 P
haHighVal: 对应 Heiken Ashi 最高价。4 S; d# z& k& n) g6 t+ u! [- u
haLowVal: 对应 Heiken Ashi 最低价。
# }# d, g1 c1 l4 W7 _/ X3 S3 b在上一步中分配的计算值与以下内容相同( [. D( U" Z+ e% P0 o1 G- T
haLow=haLowVal8 f( }3 g: I. P+ n- p
haHigh=haHighVal
+ |! L7 E& T; r3 `* H( }haOpen=haOpenVal
8 D9 u k$ m( p, I1 NhaClose=haCloseVal& T: v( T( u# c) m) e! Q
检查 Heiken Ashi 的开盘价是否低于收盘价,我们需要指标绘制蓝色蜡烛;如若不是,我们需要把它绘制为红色烛条。6 _! r2 ?7 f* C
for(int i=start; i<rates_total && !IsStopped(); i++)( R: f* M+ @' |* \7 d
{
# |4 T s o# ydouble haOpenVal =(haOpen[i-1]+haClose[i-1])/2;
8 H; Q, }- X2 y( { gdouble haCloseVal=(open+high+low+close)/4;
; Q' v2 J1 e5 r/ vdouble haHighVal =MathMax(high,MathMax(haOpenVal,haCloseVal));
( W5 n9 T2 b# Xdouble haLowVal =MathMin(low,MathMin(haOpenVal,haCloseVal));- }( j9 @1 C% O; T
haLow=haLowVal;8 x s8 Y% U' z$ ?
haHigh=haHighVal;
2 ?- i: T) x# \; t) K; UhaOpen=haOpenVal;; ?4 H9 p7 J3 T2 C* @4 @/ `/ p2 p0 Q
haClose=haCloseVal; b8 i q9 u8 Y+ O; t2 h
//--- set candle color2 B$ @2 J: T: R! ]. D9 s
if(haOpenVal<haCloseVal): N1 j% O- R- `3 G
haColor=0.0;" u7 Y$ n) Q4 d: A) @' m
else
( M" S3 e- N2 P, Q2 l# @haColor=1.0;
! U5 t, R9 S7 m+ Z' M}4 |' l3 y2 n% m( o6 O, Z
终止函数,并返回(rates_total)作为下一次调用的 prev_calculated。, h. r. _4 \# a) j
return(rates_total);# F7 s/ K( g" q9 L) R/ Q. ~) L
然后我们编译代码,并确保没有错误。 以下是一个模块中的完整代码:1 P# ^: ]5 M+ q) v; s/ E
//+------------------------------------------------------------------+
) T' V$ ^( e' o9 Q//| simpleHeikenAshi.mq5 |3 H& N" f# b T, A5 C- O8 k
//| Copyright 2023, MetaQuotes Ltd. |
, q6 Y9 d" F, p6 U: J//| https://www.mql5.com |" U. o9 T. g, M; m
//+------------------------------------------------------------------+
1 P. o$ d( ~; E6 E* c+ ^#property copyright "Copyright 2023, MetaQuotes Ltd."
) h8 V9 l9 E+ k+ R% N3 q#property link "https://www.mql5.com"
$ {9 ?6 r9 B3 a. a( x% H4 L+ s#property version "1.00"
6 q0 e; i0 |6 }" w#property indicator_separate_window) I. q& L3 v. u; X" P* Q
#property indicator_buffers 5; O1 H$ |8 k. F, d: k; Y+ r3 s
#property indicator_plots 1
% v. Q9 v; {9 F: Q1 e#property indicator_type1 DRAW_COLOR_CANDLES# `' V5 U# N4 T. P0 E# M* k4 r
#property indicator_color1 clrBlue, clrRed0 s; K( h7 {8 N9 t
#property indicator_width1 2* r I2 Q W' i/ m: {' t& R- U
#property indicator_label1 "Heiken Ashi Open;Heiken Ashi High;Heiken Ashi Low;Heiken Ashi Close"$ e1 I1 _! a$ s' N
double haOpen[];
2 H2 \6 z; A i+ R) a+ v( S/ xdouble haHigh[];
* U. f- H- m; J2 I& o( j* ddouble haLow[];7 o- y- L% {. l: A4 r% i
double haClose[];
$ s6 _3 w8 f! I! Z$ udouble haColor[];8 ~* x( [, R9 t5 _' D3 F3 J
int OnInit()
7 k- O6 o) b0 G% m, _3 Z{
& {: {: V5 @ R+ d" _8 Y& G! USetIndexBuffer(0,haOpen,INDICATOR_DATA);
/ z9 M7 @' |- FSetIndexBuffer(1,haHigh,INDICATOR_DATA);
! ]. c; T3 F' I' l; uSetIndexBuffer(2,haLow,INDICATOR_DATA);" E/ w' `' B* ^1 P
SetIndexBuffer(3,haClose,INDICATOR_DATA);
& ]' E& t! U2 Z' u( {% I. J3 O: ~, JSetIndexBuffer(4,haColor,INDICATOR_COLOR_INDEX);
% j! A4 k; o9 e7 gIndicatorSetInteger(INDICATOR_DIGITS,_Digits);3 S. Y7 r8 _' O9 I6 P
IndicatorSetString(INDICATOR_SHORTNAME,"Simple Heiken Ashi");5 f! f. U1 b5 t0 r/ _/ s) ]. N
PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);* r; k1 Q" e3 O. _- X
return(INIT_SUCCEEDED);
$ l' K# ?6 T, O ]}
+ u# Q, Q& ?; f/ `int OnCalculate(const int rates_total,7 W9 N) n j, |+ B/ d& B0 R
const int prev_calculated,
) V* |* ]* b! P# g$ |" Lconst datetime &time[],
; a4 i S# x, G; pconst double &open[],1 Y4 H; J- P& \$ c" P
const double &high[],- Y4 I5 ]: b! T
const double &low[],
/ _' B7 {6 f6 y9 q7 J2 z% J/ @2 jconst double &close[],; V; Y4 E% B/ D) u0 F0 t
const long &tick_volume[],
9 z* c' B: H+ ~4 m$ t+ u# ?6 Z; jconst long &volume[], |