启动交易模型,并构建 EA
) y; q; L0 O! z在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。% t F# j2 Z0 {* J( E
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
! w& @, D3 j5 ]- I+ o以下是制定这些规则的代码。
; Y3 L) n/ L0 q6 w/ r//--- Indicator ATR(1) with EMA(8) used for the stop level...
! h& y# D' J7 D' ~int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
5 U! D, U1 ~2 R4 v- qint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
2 E7 E# Z: s" |% P I) t N2 | o//--- Define a variable that indicates that we have a deal...
8 v! N* l4 E1 r4 ]5 T/ Ebool tem_tick = false;1 \( D+ Q" C1 n7 o0 I
//--- An auxiliary variable for opening a position1 v( x9 q4 n3 Y6 N9 n1 R6 _: i& F
#include<Trade/Trade.mqh>/ \2 _. q, X' e& R; w
#include<Trade/SymbolInfo.mqh>0 \$ }) _8 t* P9 Z) L
CTrade negocios;
+ K( Q. ^1 A: g* b; NCSymbolInfo info;2 B0 _$ }6 e8 L9 d# _$ R7 g
//--- Define in OnInit() the use of the timer every second
! L5 \; Z. C0 ^" O) Y/ l: W4 ^//--- and start CTrade
+ |0 o C8 s, `& i8 [' Y' Rint OnInit()# t- v: c6 f9 O8 @5 h3 F
{
* c: Q! [) z. c# i//--- Set the fill type to keep a pending order, b/ v. b D9 R) k9 E4 y) K
//--- until it is fully filled
% k2 U+ ]+ s* C8 Enegocios.SetTypeFilling(ORDER_FILLING_RETURN);
$ z9 s3 o9 C$ w( _//--- Leave the fixed deviation at it is not used on B3 exchange
! y9 d" r) g% Lnegocios.SetDeviationInPoints(5);& \. w2 q5 n y5 d% b
//--- Define the symbol in CSymbolInfo...) b4 r; [) Z7 @' }
info.Name(_Symbol);
2 d6 e5 Y+ d4 r2 b# U; @2 j1 z2 f//--- Set the timer...% l- U2 v0 h" i q4 l/ z4 }+ P
EventSetTimer(1);
3 a! M0 E$ t B, G6 U//--- Set the base of the random number to have equal tests...
4 j7 i2 N9 z0 t6 e/ P( pMathSrand(0xDEAD);
$ ?/ A" ^9 e$ s6 e, |3 \& @& Jreturn(INIT_SUCCEEDED);
9 V% |' j# w% `) q}( I% t$ E. X* Z& }4 k5 q7 K; \
//--- Since we set a timer, we need to destroy it in OnDeInit().
% W! B& P7 k+ Y0 \void OnDeinit(const int reason)/ R! x+ z# L6 R: p* W
{5 G# e3 K0 V4 j; Q2 [0 T. Y3 I1 P
EventKillTimer();
2 S1 J x4 L0 S8 m* o% |}
4 k% P5 u' N0 r1 |' T8 u% P//--- The OnTick function only informs us that we have a new deal
^& ~: C) o6 H v" V1 C: j0 jvoid OnTick()$ a# r7 K1 C @2 X
{& `/ Q4 O2 a# v% m. V
tem_tick = true;
4 _; S9 Y) p, [}
$ w4 Q3 y h0 i( ~, g4 a//+------------------------------------------------------------------+
7 P3 v1 T2 M0 u6 A//| Expert Advisor main function |
" G2 O8 U- [/ D$ f$ l. f# h//+------------------------------------------------------------------+0 N4 g9 p0 w2 ^3 h* K
void OnTimer(), v: c9 J% `4 k7 x Q& m' v& c
{5 ^. F7 Q% Q4 v
MqlRates cotacao[];
5 x( ?% J5 {" n3 Treturn ;
* T. B w0 p5 p6 F7 l5 fif (negocios_autorizados == false) // are we outside the trading window?
9 S |8 P3 U( W9 B6 Treturn ; b0 [9 ?4 c8 y8 j) A( p1 P
//--- We are in the trading window, try to open a new position!0 t0 |* k# e7 p5 y) D3 ]
int sorteio = MathRand();
S" _& ^$ X+ G" n: p* E' B- ^//--- Entry rule 1.1
& F: v* W9 w! D% ~if(sorteio == 0 || sorteio == 32767)! c y+ A8 I1 j* E7 a [' v
return ;& r7 H' y$ o. @% f; H
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy2 s; }$ [* @9 {1 x" {, a3 |
{: M- A7 Y9 q9 o
negocios.Buy(info.LotsMin(), _Symbol);
& o7 x8 A m* i0 c& ~: x3 K2 A}
, R$ Y/ w+ F4 }' R7 Lelse // Draw rule 1.3 -- odd number - Sell
- E3 r) B/ |: Z8 v g& h) M9 r{& {6 n( `, b+ v
negocios.Sell(info.LotsMin(), _Symbol);
4 Z% u6 \5 X6 Z% `}
7 M O; a6 C( p& [; t; U" k}
( k; }' [5 P+ l1 T//--- Check if we have a new candlestick...8 Y m, t5 [4 a$ s4 N7 n9 S
bool tem_vela_nova(const MqlRates &rate)
: `$ y6 Y/ e* H{4 E0 O% [( h& E2 S1 \ o" Q) x
{
* |0 E" O/ z i" k1 [2 Rret = true;
9 v. _+ J" s5 G8 R* Y7 B! jclose_positions = false;
/ b4 x7 L- t& s; d/ z) n}
/ A C, e5 d7 E9 o( m( P5 Pelse
4 e2 p' |2 C5 j2 g* e{
5 p* m( x- G/ ^/ @if(mdt.hour == 16)0 ]# }9 i8 l) F. T3 v& N5 z7 Q0 N
close_positions = (mdt.min >= 30);, k6 E }0 f& V- N3 K+ l
}
9 y0 V. j% Z' }: ?, a0 y}! D B) }; }" G# P4 a9 d# R5 I2 s. @
return ret;
; O: [7 Z( g$ C& [" D5 W6 n' G$ R}5 W7 K+ ?0 O7 w. h3 W& n x1 W
//---4 \* i8 W& b! j$ t5 ?( w* h8 r- y
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
1 C+ [! h6 ~9 I/ K7 T( V. ^! E* V: }{
& _3 X4 s k. q6 t* D; Q. Qif(PositionsTotal()) // Is there a position? @! w' Z; G2 G# f
{0 f# S4 x- |% P/ w! m! z
double offset[1] = { 0 };7 Y3 M9 q- j ]. f
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" M0 t* e% s: ]) q- Y&& PositionSelect(_Symbol)) // Select the existing position!* I5 G6 @- K: U: ?4 b
{
$ m4 c% b$ A( D* c: fENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE); W7 r/ g+ {4 r' [: A
double SL = PositionGetDouble(POSITION_SL);, u/ V+ e" V" t1 r
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
3 }* {9 _: l3 P/ o7 l3 \if(tipo == POSITION_TYPE_BUY)5 Y9 p( Q5 N) D/ ~) S' ^
{. O9 i1 Z* H7 \
if (cotacoes[1].high > cotacoes[0].high)
% |5 G# @4 x6 N! V{; J9 l' w U, H5 e+ R
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];7 k8 j4 r% x% H- L* O! J
info.NormalizePrice(sl);% u) y. s4 ]. W% F
if (sl > SL)
7 g$ d4 v, I, @' s* x p{
# C, `9 q& z! R' J% {0 @6 Qnegocios.PositionModify(_Symbol, sl, TP);4 z: Q) X( a) J' Q' {0 A
}/ w x0 F5 W- _$ y
}* g1 ]% I9 ] Q. N: ?- x
}) n- d! P( C, ]0 G
else // tipo == POSITION_TYPE_SELL
# [% p) F( T/ D* h) O5 p5 U8 ^{
2 I% C4 D. N0 H! \ f- i0 }; b; Mif (cotacoes[1].low < cotacoes[0].low)
, t( b2 y5 j! `# L4 V7 H. x5 T9 `{0 e$ J2 `: |+ @* J, s0 U1 Y! d
return true;
/ x3 I, s% \, F- v/ e0 k" { n}
! E$ ?$ J" i* B& Z! ~/ b+ d* o2 h// there was no position
; m4 D' c4 J% n; o3 U1 a/ Dreturn false;$ A5 c6 S2 l; j
}
* p7 X, |5 f0 N5 L" v我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 E. v' n) g. V3 w! X; [: J. U
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |