启动交易模型,并构建 EA9 v7 s* H8 K8 |* M4 u8 v8 K
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。: [/ B2 ^8 c* G
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
$ C& a9 I2 f. n7 N以下是制定这些规则的代码。
) k$ \& t: y$ M; T. K//--- Indicator ATR(1) with EMA(8) used for the stop level... t3 @' x n: L4 \$ A
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);; Q. m: d" k7 M5 H5 Y% |& g0 Z
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
1 G) Z+ X" I/ ?1 e9 Z/ A; v//--- Define a variable that indicates that we have a deal..., S' B- a# V: v, N: c
bool tem_tick = false;) \' O5 `8 ?6 e# b) ~! z; }$ v9 `6 h9 D
//--- An auxiliary variable for opening a position( I0 ]) B. r: l/ c% j% d. O
#include<Trade/Trade.mqh>( w5 R5 Q, M" K
#include<Trade/SymbolInfo.mqh>1 O; o6 P9 S$ h% U
CTrade negocios;
) @2 `2 J; w% V, } DCSymbolInfo info;
7 I2 P9 N ?* [" K//--- Define in OnInit() the use of the timer every second
6 G; Q9 z$ t: q9 ~//--- and start CTrade
9 K6 U2 ` N0 _7 R) I! [int OnInit()1 _0 F% r g+ w% H8 A$ f! w- W* s
{5 z) U4 w$ A" L* M" x
//--- Set the fill type to keep a pending order
7 N+ \% R n9 ]; }2 _//--- until it is fully filled
3 a$ l) |. Z0 W0 j/ Bnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
$ t( C5 G. b9 x& b5 F//--- Leave the fixed deviation at it is not used on B3 exchange
2 D0 \8 _3 z- y cnegocios.SetDeviationInPoints(5);- }7 u0 O7 k% w1 `& L7 M
//--- Define the symbol in CSymbolInfo...
" K# ^- m/ u9 B7 p! V6 ~info.Name(_Symbol);3 \8 c% d g: J6 D5 ~
//--- Set the timer...
( }* r/ y# N5 m0 lEventSetTimer(1);
x) C) X) J2 g4 g' U# j: t//--- Set the base of the random number to have equal tests...3 K. H9 y% p5 r. ^5 E! D7 X. F
MathSrand(0xDEAD);* A- {; h5 i: H9 y
return(INIT_SUCCEEDED);6 M- C2 S. t0 K- Q
}
# o3 W* U4 t, @//--- Since we set a timer, we need to destroy it in OnDeInit().
0 s7 I0 C6 p9 r" _0 S3 wvoid OnDeinit(const int reason)
/ C7 j+ @# t( U{
. J8 V7 s/ X/ H7 G( Y* x% }3 lEventKillTimer();
- L- _# X" S6 B' l}
9 j& e0 _; j8 P//--- The OnTick function only informs us that we have a new deal
& m# c* Q+ _. W9 C: C: `void OnTick() x' D8 E2 x# h0 |' _ `& t
{
7 ^' Z R5 s) e, r6 `tem_tick = true;
" C$ w/ s( ? K8 H; n. {}9 I7 k3 ]0 P+ H: H5 v1 u: K
//+------------------------------------------------------------------+
- }- N) v5 I1 n: J! W6 P4 e//| Expert Advisor main function |- p. U( O6 r3 \, x2 e
//+------------------------------------------------------------------+. R' @: \' r: s7 a3 Q
void OnTimer()
) t' ^; f/ O- D{% D; I8 w8 @' d8 W
MqlRates cotacao[];
: k* b3 ^; D: W. ?3 jreturn ;9 g- J* i$ |: S6 N. X
if (negocios_autorizados == false) // are we outside the trading window?
- L7 [ z2 \" s" O( B. Preturn ;
/ ]& Q# ]/ X& S: o( `//--- We are in the trading window, try to open a new position!
' b, ?+ E" I/ `7 ?9 ]8 z0 D. Yint sorteio = MathRand();
+ f' d' w* j' i//--- Entry rule 1.16 g, v0 |' B8 N! n: ~% L0 q
if(sorteio == 0 || sorteio == 32767)
. c! o! d+ m% a' ~return ;
4 V3 F8 \0 [% X7 Mif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
0 c1 \1 G' z! }8 |: M+ f{
Y/ J0 m" Y0 U" R6 k% v% L+ Ynegocios.Buy(info.LotsMin(), _Symbol);! n/ f+ k" i" u0 T
}0 o1 W g3 K% r- K5 j
else // Draw rule 1.3 -- odd number - Sell
* D3 S% a! x0 Q4 o3 {) J' j{
4 I9 d4 R- j9 c" J3 |( _& A: Gnegocios.Sell(info.LotsMin(), _Symbol);- I }4 l P+ z; K- A0 d
}
6 H9 ?! T) M$ g; X2 u r}
! [$ A9 F6 V" G+ O: ^- }//--- Check if we have a new candlestick...
/ O2 Q, ]' j P8 P5 [; @bool tem_vela_nova(const MqlRates &rate). E3 n, ~' a; b" r& d+ t
{
% |, q' f3 j' k# H: v{$ d4 ~ z* J5 n
ret = true;! y, i8 K9 k4 Y
close_positions = false;
6 n! G6 Y5 a2 H$ S9 I}% x# g+ Q$ r6 Z: P
else) M# n! b1 Z6 G
{
8 J. o$ Z5 w+ Eif(mdt.hour == 16)* U2 {) T6 a! Q, M; D$ y+ a
close_positions = (mdt.min >= 30);
+ F& ]& ` y2 C1 h4 [, T% [+ z}2 i$ o5 g0 z8 d0 q& @/ e; t1 ^% x. F
}
, g$ U' M0 c+ K7 g+ D0 P: `return ret;$ o$ n. O' ?: c
}2 }, k, r, ^8 B3 Q
//---0 X1 `' {6 w9 e( y; q7 `
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
5 j9 i% i7 h# q5 k3 c5 z: O{5 x% y+ i1 \; v' K0 R# m
if(PositionsTotal()) // Is there a position?' Z; H$ h. K; w0 `( `6 [
{! N6 ^/ B$ Z0 o ^& l b
double offset[1] = { 0 };
; C! {) ?. E: N9 S Nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
; d+ ]# o L/ D&& PositionSelect(_Symbol)) // Select the existing position!
- \ w' ^: @7 e# n# y1 N* W% |{
4 y0 U3 i+ E1 ^, DENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
5 c' ?2 {6 [% Y- A9 rdouble SL = PositionGetDouble(POSITION_SL);+ [& ~5 v5 I8 X& x0 L8 i6 e
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));) i2 O6 E" z8 \' a$ u; w
if(tipo == POSITION_TYPE_BUY)! \5 @" n3 t* m/ f
{
! \* \5 i3 d8 C0 z6 yif (cotacoes[1].high > cotacoes[0].high)6 R0 x2 n1 W% {% Y. s" C; h5 B
{
8 G( ^0 l3 b6 v; Y# T" F9 f0 z: Mdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];8 q' S2 Y; W9 C' {7 K- i: D
info.NormalizePrice(sl);6 [& A0 l* b; k; p$ \: E
if (sl > SL)- m! F# h) Z5 M t: U, ]9 K
{6 r: Y2 o* n9 M4 D# j) S- a
negocios.PositionModify(_Symbol, sl, TP);
* u1 _2 V1 j( U. W# r( r( o}; v t- E+ `5 l {- u& D" [
}9 K$ N1 U" t& J+ m! \) B6 t" a, H" k
}+ I9 [8 P. r8 D- S
else // tipo == POSITION_TYPE_SELL
7 [" i; t+ N* a V{7 t( E/ T' e) H! m
if (cotacoes[1].low < cotacoes[0].low): d0 B7 e. R8 o; u3 L' ~ s$ u
{
9 }6 X+ l- V! L& X1 |return true;
" ?+ y+ ]8 v4 o7 Q( x}
6 F2 @+ ?- {( \$ \+ ?// there was no position
8 [' D5 p. d! K& H$ s% s \return false;
: \1 h, I9 g" k}3 U! e' y; X B2 w
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
$ _5 q' K1 }8 ^/ p6 {9 Y到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |