启动交易模型,并构建 EA; c* i Z$ M; ~( Q3 _) ~* T0 y" ~
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
- u# ] r- T& P' K) b& X8 U为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 X% R. C# b, x- \, g
以下是制定这些规则的代码。0 V& {+ f% h [) Q( n
//--- Indicator ATR(1) with EMA(8) used for the stop level...
: ^( P: u& A* D3 Rint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
2 W J. f) [& ? Y2 Uint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);+ ]5 |% i( F- ?" L
//--- Define a variable that indicates that we have a deal...
8 ]* x* X: R0 ?# U# Kbool tem_tick = false;
5 [5 O2 n' p- r" f//--- An auxiliary variable for opening a position9 j( l z& F) T0 _$ q3 y
#include<Trade/Trade.mqh>
j7 ?5 w/ u1 f( X#include<Trade/SymbolInfo.mqh>
2 U* M: }7 `' W2 P# N4 h1 oCTrade negocios;
$ R4 O. m/ g. `7 e9 o% c# F7 F9 yCSymbolInfo info;
) `6 h* c- p4 O Z) a* d/ F# _//--- Define in OnInit() the use of the timer every second
0 c2 z. ]0 D3 y) C4 M' B+ z//--- and start CTrade0 [3 }7 H1 }( P* t0 Q3 p
int OnInit()
, o( ^, j. e$ B/ `- X: I{, |9 |7 e! f5 B5 c6 M
//--- Set the fill type to keep a pending order
' A$ v* v0 P3 G+ S//--- until it is fully filled! \! x- S6 ^3 x5 M* K
negocios.SetTypeFilling(ORDER_FILLING_RETURN);2 h2 Z; H6 `( A( J0 N
//--- Leave the fixed deviation at it is not used on B3 exchange
6 Y, O! b6 i: Q( rnegocios.SetDeviationInPoints(5);6 H+ m5 W# x2 D+ f* O
//--- Define the symbol in CSymbolInfo.../ _+ L2 V5 C- J( {! M
info.Name(_Symbol);! f4 a! W7 P n: ]9 F
//--- Set the timer...9 t4 [ i; |, L% b1 ]# S
EventSetTimer(1);: m( P( i* }$ ]! z! ?
//--- Set the base of the random number to have equal tests...& m9 A8 T9 c0 N& ^3 C
MathSrand(0xDEAD);
. F' j% L# Q! ]1 w+ F9 A. L. K! Ereturn(INIT_SUCCEEDED);
( [4 J% {' d7 `+ |}9 ^) z& o5 W q k8 W( F
//--- Since we set a timer, we need to destroy it in OnDeInit().- Y2 T; X' M% r
void OnDeinit(const int reason)
1 d) Y" B$ V' K! F{8 W* C! H% U: _9 P6 A4 S/ P
EventKillTimer();
5 {: J% T, g& }; o" m}
& g, m& ~- ?$ v//--- The OnTick function only informs us that we have a new deal
( K, f5 J6 f2 {( Zvoid OnTick()
! g: m$ g/ T8 v1 F5 w9 [* z: z( g{
5 s0 p8 W7 J" T3 f0 \tem_tick = true;
Y5 H) M; ^$ Z% q5 E u} c, k4 }3 e5 ]
//+------------------------------------------------------------------+& ?6 h; q; d" G3 N Z$ {4 R/ o: m& L
//| Expert Advisor main function |
# q$ y, A! ^, @6 `2 G//+------------------------------------------------------------------+& m3 }# }" `8 v+ Z, M" v
void OnTimer()
: {$ j1 h9 I. ?! C. h% `8 _ K{
1 j1 z9 t* ^% R. j4 K9 bMqlRates cotacao[]; I: d. B5 O9 r, u* z; n9 M
return ;
% M# i4 t& \/ x- w1 s7 _7 oif (negocios_autorizados == false) // are we outside the trading window?5 S5 \2 W( @+ N. b! y6 P
return ;
R) u* V) A* L& o//--- We are in the trading window, try to open a new position! z% q9 G/ P: Y
int sorteio = MathRand();
& W o0 S {, M//--- Entry rule 1.1
2 N5 L7 M+ a8 h; Z0 ]% }# Pif(sorteio == 0 || sorteio == 32767)
/ X/ T4 Q& q ?* greturn ;
/ y1 a, n+ I/ f2 dif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy! Z& A: K8 i7 h5 ~% M* Z2 p* G
{. A& A1 g6 n0 s
negocios.Buy(info.LotsMin(), _Symbol);" b6 o2 c; h0 F0 y: I- }
}& f9 J1 s% I: n
else // Draw rule 1.3 -- odd number - Sell9 P) N( I$ ]0 v6 H
{
. N% @; h, b5 Qnegocios.Sell(info.LotsMin(), _Symbol);
! f+ ?. k h2 y K, u} {" Y7 w$ o" G
}3 I% k/ y7 ?) ]4 E+ _" C: A
//--- Check if we have a new candlestick...
5 O1 r8 C/ V% |; X0 `0 Ubool tem_vela_nova(const MqlRates &rate)
) ~. y" M( n3 `" \4 ?) j( T ~# G% W{
" ]. ?2 B; R7 i) z6 o2 F7 z{3 C' N' N( ~$ \* ]) L7 S
ret = true;
; d" k6 w9 P U) N. C, a- }close_positions = false;
) ^ u* o9 ?5 y. v5 [$ X2 [: a4 v6 a} i/ V% J$ Q$ t% n9 \
else
5 s) i7 B" H3 s6 R{
! w" ~ o7 h+ ^$ Pif(mdt.hour == 16)$ [9 Q; P8 R0 }- V3 S' x
close_positions = (mdt.min >= 30);* F0 `( s+ h/ K$ q
}
1 H P4 q- @( V7 W8 p% o0 D}
. L- r2 A- P; T4 {9 v: K; F1 Ureturn ret;# U$ c- H ^% S; W7 Q
}. i$ a. [, R4 C F$ Q4 }
//---5 s" t Z& V( r
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
8 d {5 _! t: g# z4 m5 q{
& B* n+ {7 Q, q& D( u7 B$ B, qif(PositionsTotal()) // Is there a position?
?. P: X/ ^" L* m* i( v{5 a7 R9 \5 |: i$ h* U7 r
double offset[1] = { 0 };' _+ m% d& c' N( N$ o
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
2 I; m8 M* j; U/ ? |&& PositionSelect(_Symbol)) // Select the existing position!. E% A X. _/ Z( d) z# n
{/ X& q& Y6 l. E: X/ J
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);' a! ?; B) y: J4 A2 |# H3 M
double SL = PositionGetDouble(POSITION_SL);
4 P( D9 F6 J) Y B2 D& c! Qdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
! E# D$ S" @. { l9 S' {) R4 cif(tipo == POSITION_TYPE_BUY)
: z, y& W0 R* f# `; R" [1 H' }5 E{
& {. `7 w) j" r n- d) ]/ oif (cotacoes[1].high > cotacoes[0].high)- V: U7 ]" ^; Z, W, u
{; _: n* U9 p2 P, a) k0 A
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- d# ^+ ` V6 {( K7 o3 Y
info.NormalizePrice(sl);, [0 ~ l a8 u" E
if (sl > SL)
: ?& x& G6 O3 ~) L! t6 P2 }{
& R% e( W8 W0 T3 X# U0 |7 knegocios.PositionModify(_Symbol, sl, TP);
, q; F, i& I; n* T2 f. i) @}# w/ m$ U3 o% a0 T$ t
}
+ i$ i! a- G" ~- L$ T1 D, |}9 I3 g* @! I" a+ L/ M
else // tipo == POSITION_TYPE_SELL
+ i- b) L3 A& k( w- O/ ]4 J{- a' m7 C% Z7 h3 Z3 l
if (cotacoes[1].low < cotacoes[0].low)
" a. s3 K* h; f* r; _{8 b; _1 G# p" X. f
return true;
5 y5 z G/ d& Q2 ^, A: G8 E}
3 i3 z9 }) _& r" f* i) b( q) {// there was no position2 v# z# h7 g; C) U+ E, Y
return false;/ L5 Z. p5 l9 d! p9 `5 k
}
1 g9 S6 ~+ c5 X$ [ ~+ G* x我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
' S8 G+ `" U* N到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |