启动交易模型,并构建 EA& t' B. a+ l: v5 Q7 V0 ]
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
- B+ l0 ?- X9 Y, q' ^为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
! K# x- O/ }3 \2 i以下是制定这些规则的代码。
" }6 i9 q V4 C/ k//--- Indicator ATR(1) with EMA(8) used for the stop level...( T3 ]! L# Y( g+ c I$ r/ e
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);3 u8 L9 {8 ^5 q; \
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' {( ^+ j$ `) M( @//--- Define a variable that indicates that we have a deal...8 A! ?. G l- \7 y8 e; D( P6 Y' I
bool tem_tick = false;1 i* G9 X" Z8 H. b
//--- An auxiliary variable for opening a position) p7 a0 o6 Z! n3 E: V
#include<Trade/Trade.mqh>
8 B! r* m! d: s" i" B#include<Trade/SymbolInfo.mqh>4 r _ U; X d1 l5 x4 Z) Y/ u0 ^
CTrade negocios;
7 y- _: S4 t5 ~! VCSymbolInfo info;
- n" _8 V5 \7 M/ w//--- Define in OnInit() the use of the timer every second5 u5 O) Z. Y1 T2 m
//--- and start CTrade
7 `: I' j$ @. ^3 A6 r R. k$ Eint OnInit()8 n3 b' B- e' j: M
{
" K! A2 m0 Q; I, Y* E//--- Set the fill type to keep a pending order
% a+ q( z! V$ h+ {- H z//--- until it is fully filled: R* T3 r! i% N6 I6 B8 t
negocios.SetTypeFilling(ORDER_FILLING_RETURN);* \! H) w+ U$ D1 T2 q* a
//--- Leave the fixed deviation at it is not used on B3 exchange
7 E& s* F" {" s( {$ }) X- bnegocios.SetDeviationInPoints(5);9 K% @# m- U' W4 I: W9 T7 ?
//--- Define the symbol in CSymbolInfo...
5 Q# m$ k% j d) K3 L4 n4 hinfo.Name(_Symbol);+ _: L7 u9 Z5 p; l+ O
//--- Set the timer...
8 w! K8 ~% U1 a/ R' K3 fEventSetTimer(1);* [! ~* l$ N, R3 ^
//--- Set the base of the random number to have equal tests...3 R& x% _2 e3 E
MathSrand(0xDEAD);7 ], Y* B, S$ F* p. J" B
return(INIT_SUCCEEDED);3 G9 ?, n. a! @0 {
}
9 F* W( U1 @* C8 q; D//--- Since we set a timer, we need to destroy it in OnDeInit().5 k L* w- k$ E& ?5 E
void OnDeinit(const int reason)
/ z1 T; R7 b6 x/ Q& {) S{% x+ n' _6 P" ~! [; Y# y, `
EventKillTimer();
4 y' a; w; ~- u+ @1 `5 e}) F" X5 D# Y# Z
//--- The OnTick function only informs us that we have a new deal
/ `4 |2 F, \ tvoid OnTick()+ I0 [ S- p5 X* v, P
{
, Q4 B9 p8 L1 s- ~$ Q7 Y' p2 Otem_tick = true;5 n/ i2 W( I$ W4 Q, k
}
+ f% ]! W; O9 l4 j: U7 Q//+------------------------------------------------------------------+
9 I: k/ D, Y t$ i% W _! A. t//| Expert Advisor main function |
4 L1 P9 h0 E# x Q8 e: i//+------------------------------------------------------------------+
+ p& x5 J- _' Xvoid OnTimer()
( ]6 ?5 z: S" T, z5 w1 V{/ G" [" K! i% B9 L' _/ h
MqlRates cotacao[];
: d7 y# t5 ~! F. `( k7 _7 a! K$ hreturn ;
+ l, t6 ?4 E5 }1 o) q% k4 m Yif (negocios_autorizados == false) // are we outside the trading window?
! r. P+ \9 g, c9 v) u: M. o V( Jreturn ;
; e. h, H" m" O% v5 K- B% r- i//--- We are in the trading window, try to open a new position!
) |1 Q5 b" _) vint sorteio = MathRand();4 }: d% w d6 d4 F2 k7 I) B2 \. M
//--- Entry rule 1.1
1 s% {* a) r A# u5 j, e/ {3 }if(sorteio == 0 || sorteio == 32767)& l' Z- ]. C* ?0 t1 @8 f+ W/ T& k
return ;
, ?7 R: e5 n2 l' i" D" t+ P# N5 k0 Gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
?( @$ r0 @9 }* `! k{1 j K) u4 R2 y2 s! w* k
negocios.Buy(info.LotsMin(), _Symbol);
/ t ]% e. Q2 D: v6 v, L}
3 J* P3 u/ k6 f8 j4 pelse // Draw rule 1.3 -- odd number - Sell
6 ]. b3 Y, f# Z5 ?: [{! k7 D- e3 S( `' S+ M
negocios.Sell(info.LotsMin(), _Symbol);
1 b' C- B: |3 U" `}: {' y. t3 k; ^0 K
}
& d4 R) o0 X+ {0 \- O9 u6 H; j$ G//--- Check if we have a new candlestick...
% V1 {3 @! ?" Y1 Jbool tem_vela_nova(const MqlRates &rate)
0 d, V/ I7 n9 I( i$ P* ]{
! ?6 L( ]4 N) \4 a" }( j{* @' h$ f0 Y2 y5 J
ret = true;/ r5 ^8 K" `$ \6 b
close_positions = false;
# n9 W: p; C$ P}
8 b/ d+ M4 z/ O* G+ f/ [; Zelse
: L# ^) \$ r% G0 g; L7 l{$ g5 e0 q$ J9 [+ h2 ?! K" F
if(mdt.hour == 16), ?4 U# ]( t! q0 G1 G& f
close_positions = (mdt.min >= 30);
" K* h/ I2 K8 e! v: b}6 A8 M. w( w. F4 s
}; }& ~; l E; K" C# M
return ret;
6 i9 Q( o' x6 Z6 o8 q}% z( _0 f9 ?, ]# n
//---
4 C ~/ S2 |5 F$ B( R ?- G. k- zbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
7 z6 d' j4 O) i" q" K{
- ^. @; m1 r# v3 x9 ^. \if(PositionsTotal()) // Is there a position?) K) V+ V& P5 u% z; N
{5 `$ O% l) F+ L0 D4 x9 S
double offset[1] = { 0 };) K6 a4 t5 [/ d' A
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?5 \# c( H5 `% L o+ h
&& PositionSelect(_Symbol)) // Select the existing position!
# X9 g. e- e- L |{6 O( I1 x8 o/ s5 x5 w. e
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);& E3 p3 K+ g- x+ K! x1 X8 T8 I$ \
double SL = PositionGetDouble(POSITION_SL);
0 w$ R; g* y; q3 ]: ]0 x# udouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));- b D" i7 [9 z
if(tipo == POSITION_TYPE_BUY)# Q0 C* Y- y5 f5 D
{
, v# x8 r8 C: F6 T) J1 lif (cotacoes[1].high > cotacoes[0].high)0 }7 z& k6 V- K0 ], s$ L' K- u4 m
{
6 h) ]6 I8 W( h8 G9 g }% o4 o' ^double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
- A( R. G1 A0 u$ n. `# R! n) }info.NormalizePrice(sl);
, t( V/ s: ?* L9 x3 l: o( o# S, Lif (sl > SL)4 _' A' P4 S5 I" @( G9 Y
{2 g/ {- i i5 R1 c1 }" b
negocios.PositionModify(_Symbol, sl, TP);
7 b" x' i: G% T! E}
) Z* ^9 c9 X" }7 B$ L+ m4 t0 _}
7 F( W, {; ^ p. P: h: j5 I}
2 r: m- R, S+ d# qelse // tipo == POSITION_TYPE_SELL
2 Y4 C# d. X+ x( I$ E8 e9 {5 v{& N M n% [! x7 G
if (cotacoes[1].low < cotacoes[0].low)% p7 W0 q u% y/ q+ J/ ~% v M
{
7 J4 X0 N5 l2 t/ treturn true;
4 f b: M+ M6 \* r( `6 n# W}; y4 a \3 ?) u) z2 |
// there was no position8 k6 i- J6 u N7 b
return false;$ q; o; ^! Y/ z: q* c
}
; `# w8 S1 z" e我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
9 {' W' O' k. m3 E到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |