启动交易模型,并构建 EA* k, \+ i6 \; d: B4 ]
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。& E8 g) [3 O2 p) v6 ~' p
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
& U$ c7 {% t( d以下是制定这些规则的代码。1 R6 D2 a; R" ^% ?
//--- Indicator ATR(1) with EMA(8) used for the stop level.../ S" f: V- ^' w V. W
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
: n- g( p1 d# I7 X0 Eint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
) v6 R: \! n, ]//--- Define a variable that indicates that we have a deal...
! y. v7 \5 h3 _# Tbool tem_tick = false;
* x- G" ]( _$ a& S; w* U4 R//--- An auxiliary variable for opening a position% Z* p' o4 D. w# _$ D8 g
#include<Trade/Trade.mqh>
& w6 i: u& o6 ~1 {# \; ^ A#include<Trade/SymbolInfo.mqh>
) y' a; e! }3 s1 ~1 W0 wCTrade negocios;$ v( U% f |% P7 U: Z) D
CSymbolInfo info;
* L2 N# r; |* r7 ?) e' W3 p//--- Define in OnInit() the use of the timer every second& @$ j' f& N x- M* e
//--- and start CTrade6 |/ h& G/ O+ c0 X. g; V# r
int OnInit()
/ ?5 b9 r W, X2 c9 ]6 M* z{
* n) O, F9 S8 S7 w//--- Set the fill type to keep a pending order" K5 P4 L" _( K: W
//--- until it is fully filled
. P+ i, {, I* t. H& Rnegocios.SetTypeFilling(ORDER_FILLING_RETURN);; o' N7 w; ^( Q
//--- Leave the fixed deviation at it is not used on B3 exchange
+ K, z$ ~5 C4 ]3 I* `! Rnegocios.SetDeviationInPoints(5);
7 e2 ~& L7 Z! v0 W" ]( c//--- Define the symbol in CSymbolInfo...7 ^1 k% t2 M) E0 m' [
info.Name(_Symbol);: N4 d8 |# K, t0 X+ H$ N/ k8 p
//--- Set the timer.../ m) n3 w. B! n4 n9 T: ?
EventSetTimer(1);
4 S! R9 ]* N- _- e//--- Set the base of the random number to have equal tests...
4 r7 @. _& i1 SMathSrand(0xDEAD);
D& z/ e0 M0 M# ~return(INIT_SUCCEEDED);; U% a' J# y2 w8 N- t2 Y$ S
}, s' @' i& _' \3 r5 m
//--- Since we set a timer, we need to destroy it in OnDeInit().7 S' r9 \2 N* M' ^2 g
void OnDeinit(const int reason)/ F$ F: c6 U9 E) b& f- m
{
* w1 w8 Y. t7 ?. S" K% K1 {EventKillTimer();0 y0 y0 f+ F( r" y7 h+ x. ]+ O
}
' b0 B3 ~5 ^. g( B//--- The OnTick function only informs us that we have a new deal
) g& X' M2 E' D% d3 M- q* y) X; xvoid OnTick()
* a# Q3 ^5 L2 R0 G1 d{
5 Q1 B" x3 I1 i& Y: A+ @) W( Gtem_tick = true;. l: P; o( `8 ^3 u& r
}) j! f9 @/ y/ _. _$ O% I1 @) y
//+------------------------------------------------------------------+
+ N7 r8 j6 c* \% N6 w6 O//| Expert Advisor main function |0 ]% J8 |# ?7 f* O* }
//+------------------------------------------------------------------+$ K& `7 S b. w! k
void OnTimer()( p. p d" ~9 b$ X" O! ], r' d; T
{ P5 t& D2 J- ]- P
MqlRates cotacao[];
. E+ J/ t& \5 U- _9 [# Rreturn ; Y' F+ E' [: u
if (negocios_autorizados == false) // are we outside the trading window?
d8 v% z# r9 u! j: Ereturn ;
0 M# G( U: K& @5 c* M//--- We are in the trading window, try to open a new position!
4 d! w7 O, `2 qint sorteio = MathRand();
& H5 `: \; N& Y4 A3 x6 a//--- Entry rule 1.1
% o6 h5 B+ _" w& b$ Jif(sorteio == 0 || sorteio == 32767)4 P3 `: e$ F+ Z, a/ |& g6 l$ | S
return ;
0 a) s4 d* r4 G" r5 n" Xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy9 K& I/ w4 D% l/ H6 P3 X/ _1 P
{
& l$ \4 U" I& m% ~* _, y1 unegocios.Buy(info.LotsMin(), _Symbol);
' z- t4 P5 R9 v, ^4 V5 s} W! Q1 m; ?% G( @, z' H
else // Draw rule 1.3 -- odd number - Sell' }* ^' G2 M: E' }
{! v: m1 t" l! _3 B" Y n5 X2 H
negocios.Sell(info.LotsMin(), _Symbol);, l& I5 {, e' ~4 ?0 G
}
% @1 v) b9 B; Y# u% ?}/ n% B+ r" I3 k3 w& v3 _
//--- Check if we have a new candlestick...1 n: E5 N$ g: F4 V! Y
bool tem_vela_nova(const MqlRates &rate)
( G, x) Q3 M! F2 X6 _* @7 d{
* E6 x6 V$ G& \. m& E* _9 G{+ v3 m: q; \6 R7 X( T! y
ret = true;
- C8 l+ O6 l4 {$ Pclose_positions = false;
; c3 p! V3 }- p6 T6 U; z, a}
3 m2 [& q/ t$ K( w% o4 Melse
( a) J# d% e1 S; j7 _{
1 c1 o5 Z, L4 p) U9 u, Rif(mdt.hour == 16)
7 T) F/ b; ]$ H% hclose_positions = (mdt.min >= 30);
6 X9 b3 l6 g: g4 S3 Z$ M6 D, ?" V}
( w7 ?) z1 Z8 E6 A2 `}
( t8 q$ {" g2 H5 v9 ureturn ret;
* k' z& T. ^5 R) J3 s}. Q; i8 |* [/ Z( j( v6 `" {9 x
//---5 W$ `- |1 i! }2 `5 p8 i
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
$ y& S$ i7 x- ~5 R; k{
, Z+ A8 i% c* ]; j) H% D8 `if(PositionsTotal()) // Is there a position?
5 k' n) u& L% U [& F{0 h5 E: B' {/ r8 e; }
double offset[1] = { 0 };
# D* g* Q V' O+ R" Q/ G( f2 fif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?, `9 N# g2 d; c
&& PositionSelect(_Symbol)) // Select the existing position!' F' w/ I" ]' h: G! y0 j
{
. g+ }; O6 P. J0 Q. M2 t6 E8 ?2 _ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);& R6 M, z4 h2 d* V! P1 B% {
double SL = PositionGetDouble(POSITION_SL);8 x- x; {9 z7 J) X4 n
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
6 j4 a) Z/ Q1 b, Fif(tipo == POSITION_TYPE_BUY)/ M" i2 O! F- T+ L. l5 ~3 D
{' ~* W- A! E( N" c
if (cotacoes[1].high > cotacoes[0].high)
3 f' B! [, S4 g; h: i) t$ C{
) Q1 [+ A+ L9 }8 H. z2 cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];% }3 i2 Z% c9 M6 j# r! T
info.NormalizePrice(sl);' q2 F; e6 `$ Q
if (sl > SL)
5 y& a" @2 \( {, }% }8 ?9 @{1 z6 ~& x& ~# p/ s$ @2 S: x: @
negocios.PositionModify(_Symbol, sl, TP);
h, I8 R' f0 F1 |}$ P) S. y3 `* o
}
4 S+ {( L3 y( d& Z4 Q8 Y1 I} h& ^2 F% F% o" ^( l P; M7 ^
else // tipo == POSITION_TYPE_SELL0 Q/ s3 E1 J; }% X
{
- w. _" F; l+ ~if (cotacoes[1].low < cotacoes[0].low)9 e9 y; A# P9 M- @
{3 X2 Z0 i2 C/ z3 `1 o- w" Y- m4 [
return true;" o! [; M2 }2 d3 E" T; ^/ n
}
2 c' ?' ]. i) {// there was no position
! k7 m# E8 t' e0 y; `. Yreturn false;
; c5 e, W1 f1 o# p8 g: B}+ p0 D1 _- @. L" b- x
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
4 T s8 l, ~; l5 e3 V到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |