启动交易模型,并构建 EA
) C' W- g B W7 q7 T# r( R在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
2 p" v& j* R& ]# h( E为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
8 ~5 T7 S9 u5 ^# G( O以下是制定这些规则的代码。
' i8 M$ J" L5 I6 [//--- Indicator ATR(1) with EMA(8) used for the stop level...
- i' U* ]5 F' hint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1); r$ V4 r6 V; S
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);0 @ l6 w) `) @9 t$ F% U- a
//--- Define a variable that indicates that we have a deal.../ b7 X2 T7 G3 q$ e) ?5 I
bool tem_tick = false;
8 a$ Q$ P2 X0 |" p/ H0 c//--- An auxiliary variable for opening a position
6 w& n1 q7 I4 |' |# l3 y/ f/ K#include<Trade/Trade.mqh>: a& g4 M, B3 t3 B: `4 b7 E2 D
#include<Trade/SymbolInfo.mqh>" s7 Z0 j4 v0 g! w; @
CTrade negocios;
" T# s- e( K' D: w) ]- S% P0 |CSymbolInfo info;+ `8 W$ A$ `- i; w) I6 T( p
//--- Define in OnInit() the use of the timer every second
" s& e& H: X, d/ Q//--- and start CTrade( s/ b0 t# F1 `- n0 p- J/ Q
int OnInit()
) S2 B( T; i- z7 }6 w! i{
" b* A0 \' F% O% A3 |7 h//--- Set the fill type to keep a pending order
# f; O$ v' b, q( q$ n3 ?% L( G7 K//--- until it is fully filled
) G- h& f7 M. A# }0 Jnegocios.SetTypeFilling(ORDER_FILLING_RETURN);' T( z' R4 X- ]
//--- Leave the fixed deviation at it is not used on B3 exchange7 R6 O v+ f. N& l1 t+ q
negocios.SetDeviationInPoints(5);6 ?6 I+ Z) K' D* h
//--- Define the symbol in CSymbolInfo...
1 S2 N" D' T% m4 h. Uinfo.Name(_Symbol);& n' J6 O4 A2 l2 X# ]$ V X
//--- Set the timer...
! y: `* C6 j6 d G2 ?8 Q8 OEventSetTimer(1);5 V, ?: w1 M6 w7 q
//--- Set the base of the random number to have equal tests...
{/ a6 s) L& W& p5 P6 @MathSrand(0xDEAD);% `8 h' n% k7 x& z3 k
return(INIT_SUCCEEDED);$ H/ U& b- D" e
}
1 M# H& s0 v9 _' t: j//--- Since we set a timer, we need to destroy it in OnDeInit().5 m* @) w _5 E+ h% f |
void OnDeinit(const int reason)6 l% v e( f1 u5 W6 K3 E
{
8 Q9 Z r I! o) |EventKillTimer();
% |& f' L# D' J}4 ?/ x8 S# }5 V$ w2 E1 ]
//--- The OnTick function only informs us that we have a new deal' E% x- m$ H& J+ F1 K9 M
void OnTick()4 S! g5 q. c/ v4 P. V
{; X5 X4 C- ^6 b0 f+ D# b" o5 n
tem_tick = true;
6 h% q9 b/ D& X8 G3 l, ]}) \% Q% i5 P) A" x
//+------------------------------------------------------------------+
+ d6 f, }; \) h6 m. T//| Expert Advisor main function |; \. ~5 p9 G' F$ o: p) Q
//+------------------------------------------------------------------+
6 Z$ m3 g1 P* n0 i' z+ uvoid OnTimer()" a. C: ]" P- `/ c5 b% J
{4 k: X8 f# p) Z2 h+ O4 f
MqlRates cotacao[];& A3 c M j8 j' {/ e# {
return ;
7 `; A1 T, g/ N2 O" v! H5 `if (negocios_autorizados == false) // are we outside the trading window?- ]& Q J/ a; q& P! p! n" U2 J
return ;
% ^, i9 T( O( n5 S1 |' y r- i3 O% h//--- We are in the trading window, try to open a new position!3 R ^1 p4 c* K, X
int sorteio = MathRand();
9 ~/ [* [0 j7 |3 u/ o; m//--- Entry rule 1.11 l0 h$ H |/ n! _, ]
if(sorteio == 0 || sorteio == 32767)3 [( @/ N( D' {3 b: U, e
return ;
* Y0 p7 @7 o/ N `if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy) @/ L0 z2 Z' J: N2 `
{
+ c1 k' A: f- w, q' Mnegocios.Buy(info.LotsMin(), _Symbol);
1 r9 Y. Q5 {* x' e3 [0 G}
- D, V' S* K Y6 e5 melse // Draw rule 1.3 -- odd number - Sell5 y0 {- f; G0 E8 @' k# a9 W! K
{
8 k3 N7 d+ r$ wnegocios.Sell(info.LotsMin(), _Symbol);
. n+ N6 j+ ?5 M$ x' D$ n& [0 J& f3 j}1 p8 |9 s- `2 R6 H* ^. ~8 G) q
}3 Y( E! }" c9 u1 T0 ^
//--- Check if we have a new candlestick...
5 P! N5 Y% r# j# I- P6 lbool tem_vela_nova(const MqlRates &rate)
0 p4 h/ z/ K% H. Y% n{
5 Z" e, a8 {7 S' |{
! b: E( d6 x+ x7 rret = true;
/ \8 _" l; l: e: b/ qclose_positions = false;
9 U1 _/ g( ~- D% x' C}7 H3 L, x' V' B: ?' `5 v
else
2 w/ z- \9 Y$ T/ k% P4 G{1 }) T: f4 D! f/ ]( h, `
if(mdt.hour == 16). d V0 U6 {- W, y* l
close_positions = (mdt.min >= 30);' T5 x# ]4 w+ U' |
}- d" O& N: Q1 g) m
}
( m+ e l# b' {, z/ B2 \0 f+ X6 x( Ireturn ret; X4 w4 ], d2 p$ ]1 @# q4 y8 o
}
# D0 b5 e3 M: Z0 h! ?' i y//---! s4 F2 z5 e4 m0 T
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])9 n0 N' F0 i9 k6 w- Z
{2 U7 F- _3 a: e6 p% I, ^$ S" i1 p+ c
if(PositionsTotal()) // Is there a position?
6 t- j2 O/ I3 M! m% |5 V; l{
, I1 ^+ X( }' ]' P' ddouble offset[1] = { 0 };. q+ {$ G! W2 @: [7 A2 f9 M# V( v
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 q4 f8 ~/ @* ~1 R! p( i7 C
&& PositionSelect(_Symbol)) // Select the existing position!
* b' P) ^' m2 f) p( K! h+ [{; h9 X ~) _1 R( w' c$ g
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 U6 n8 ]& k7 U+ L
double SL = PositionGetDouble(POSITION_SL);) F. j3 i6 S! S* v( B: x* f9 X
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
- Y8 w1 E* ~6 R. v! |8 ?: t1 qif(tipo == POSITION_TYPE_BUY)6 L/ n. c6 U; E3 z3 ^/ r; m
{" X' K# y6 y8 C
if (cotacoes[1].high > cotacoes[0].high)# Z, p7 W% G D7 y4 R
{
. q' s% v5 @: U. D1 Cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0]; F9 E2 O8 ?# w) Q, `
info.NormalizePrice(sl);* C6 ^# ?/ O! K3 H/ u5 }
if (sl > SL)
+ Z" C _8 F. J0 q) Y+ L. \8 s{
E: W: D! k7 \" k$ d1 Snegocios.PositionModify(_Symbol, sl, TP);
4 c( y3 b5 v2 Z/ ]+ p1 \& a}, V" q0 N% W y* I7 E6 v+ V# g
}, ^$ K( G1 W! X" O# q8 `! v7 D
}! K# t* h0 _$ x2 m
else // tipo == POSITION_TYPE_SELL
* W2 e3 ]# i/ U9 k( c{
7 `0 j( s$ g/ v% R5 hif (cotacoes[1].low < cotacoes[0].low)
2 ^( ?9 L9 K! e4 w5 I{
6 K* [2 M1 V& F. ]$ R! Preturn true;% Y2 ~5 M9 a: `) X
} M; X' [$ s* Z8 X6 v
// there was no position' g8 z- f% C" v0 `
return false;
3 m# T7 I' W& r* n}
* n+ G3 Y( K3 g+ w& O我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。$ v7 C1 P+ @# }/ D+ m; U
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |