启动交易模型,并构建 EA# a0 i( T2 q5 k
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。9 ?3 {! h8 {/ P7 t$ {. M
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 [3 t, Z* P4 H8 {以下是制定这些规则的代码。
* \4 ?8 w& C' A1 O% X//--- Indicator ATR(1) with EMA(8) used for the stop level...
; V: w& |1 U; i! c x% b; ~int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
; }. F6 Q& ]* {" Dint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' H* Y6 g ]$ o5 g//--- Define a variable that indicates that we have a deal...
, }; y9 [) y* E& ]bool tem_tick = false;
# K( F2 z& ]4 V- U, |1 x7 ~' l//--- An auxiliary variable for opening a position
* z1 L# ^# C9 X" d#include<Trade/Trade.mqh>7 W5 e9 N y8 C, ^7 D6 J* J/ x' o
#include<Trade/SymbolInfo.mqh> c; z n" h, s) T
CTrade negocios;3 r( E4 a$ [& E: ^$ Y7 u
CSymbolInfo info;
% w8 N& C9 f; e7 K' B. |//--- Define in OnInit() the use of the timer every second
" f$ x2 t; ?* n. J# k9 d! g" H, }3 x7 h//--- and start CTrade
; s! c! s3 z' x% n/ [3 E, i, k) ?int OnInit()
$ N3 v6 y' Y0 Q- @2 l, U A{& v0 L& I. L; U: l# I5 m6 R' v
//--- Set the fill type to keep a pending order
7 c2 }6 u3 C, X0 t+ M8 W//--- until it is fully filled
% Y7 ~8 z2 I! c' A0 c- onegocios.SetTypeFilling(ORDER_FILLING_RETURN);
+ q8 Q/ Q* _( y. @/ ^2 i6 Z% I//--- Leave the fixed deviation at it is not used on B3 exchange
! ]/ r( i0 J0 ?! Mnegocios.SetDeviationInPoints(5);
8 x& y2 i, U* h9 T9 C2 N# k; D//--- Define the symbol in CSymbolInfo...1 b5 S. w( p- F+ m7 \
info.Name(_Symbol);; \& h [( ~+ L' v3 i
//--- Set the timer...
: w+ l2 x# C# y0 V; Q0 H$ l1 OEventSetTimer(1);
; ] d& u2 q' ?7 c/ g) \: {6 Q//--- Set the base of the random number to have equal tests...
) D- q" `2 P( {) d# q' ?7 VMathSrand(0xDEAD);
! D0 v9 G/ ~$ wreturn(INIT_SUCCEEDED);0 U( t- g' S1 W; G1 C4 H4 E
}
7 E/ i8 y7 W- j6 P3 ?9 P& V% y" f//--- Since we set a timer, we need to destroy it in OnDeInit().' n' p$ O! p0 ^# Y1 @$ Z
void OnDeinit(const int reason)
) P7 }4 M2 R$ U$ K/ h{8 p) q5 ?; y& f( S
EventKillTimer();: d, T* T! [* m; _: b
}# J& f) c! x! U( M2 i- ~
//--- The OnTick function only informs us that we have a new deal
- y1 u, o5 }* d' O' Kvoid OnTick()
3 ?9 ~) Y9 J; E{
2 Y, L' m$ O7 R4 t7 R- I' Btem_tick = true;
i7 g/ r+ ?( ^# F! H2 b7 Z! Z3 o}/ [) V- T! M! y+ l0 ~
//+------------------------------------------------------------------+
$ F4 e5 a7 ]% \9 v9 D//| Expert Advisor main function |5 ^4 Y( b/ P9 e) K7 K5 k
//+------------------------------------------------------------------+5 k2 |1 Q# X! \0 F& D q" J: f
void OnTimer()2 d8 L' K; _ m; D1 b4 W
{5 ]6 D3 d/ Z- c6 b- M
MqlRates cotacao[];: I" A& Q9 K/ z8 I! f
return ;8 w: a9 f2 ~0 Z P4 A
if (negocios_autorizados == false) // are we outside the trading window?' J, ^ S+ @: Y ~6 g/ o) f) _4 H7 K+ ~' J
return ;7 t0 i" S3 f2 q8 y
//--- We are in the trading window, try to open a new position!& b& L% q. v/ N+ E
int sorteio = MathRand();
+ N: Y5 E( K. |. {//--- Entry rule 1.1
; {: y; m# r6 W2 ^5 Hif(sorteio == 0 || sorteio == 32767)- m# S8 Y1 \4 T* e0 F4 }: d z' \/ `
return ;
' H- ^1 f- r/ h" N! x+ f+ mif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy1 o) t; d2 Y8 A9 `3 ?
{) P( T2 a; C' }' C
negocios.Buy(info.LotsMin(), _Symbol);/ x: v2 x6 C; }0 E: a' {
}
6 `6 y# t* ^0 @else // Draw rule 1.3 -- odd number - Sell
4 Y z- ?# @$ `4 P{
: Z/ K9 Y- R" T% M0 l) d, |negocios.Sell(info.LotsMin(), _Symbol);
/ F2 D, i% a$ M% t* r$ ~6 T}6 q2 b4 l ~ N$ ~: f5 l) O
}# d5 v, \0 k% `
//--- Check if we have a new candlestick...
$ Y+ b& p. e0 b( D! l7 a, N9 vbool tem_vela_nova(const MqlRates &rate)
% r4 }4 _5 Q& }8 V* p{" n+ i8 `. x+ b
{
1 v f; }$ x& ?# _" y4 Lret = true;
* ?* P# k- W4 y8 Zclose_positions = false;
I: y; V* h% y}
9 Q; b# {; a0 O" Welse
. r7 P/ n5 T4 r0 U{; C$ _% a5 ^# u4 h5 v9 K; y( ^+ k
if(mdt.hour == 16)2 }' l# h3 r( g; _& J5 l$ |" m
close_positions = (mdt.min >= 30);' ^+ E1 ^, o3 U
}/ K6 a9 _9 V6 e; V* K4 A$ c
}6 U1 y0 a3 o. l: M0 D; b. [* {6 M
return ret;
* _/ C( m4 x+ a}
0 M4 c7 l3 T) \0 m" ^9 o//---* S+ E5 I, L9 K, ]: Q
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
% w! s i- h, z7 `0 _2 S{
- d) O6 g( v+ O6 @1 J8 `if(PositionsTotal()) // Is there a position?
5 o$ m" C! y+ d" N r0 h# [+ m4 Q{4 X) `/ o( {' A [
double offset[1] = { 0 };8 Y- {* Q- Q) ^8 k6 M. O
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
. T3 i* k7 `. j: ^&& PositionSelect(_Symbol)) // Select the existing position!
m4 c+ J7 a- n% U/ V{: \6 N( d M: g, u) J# I
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
+ t( V5 r, M2 P8 [, O. i; Gdouble SL = PositionGetDouble(POSITION_SL);% r7 x; }& V' e% }+ e; _$ D s
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));. W4 j, |8 p" c; X
if(tipo == POSITION_TYPE_BUY): q' d( {% S) I8 q4 Y% Y0 S
{
1 v* o$ W9 M+ K2 Pif (cotacoes[1].high > cotacoes[0].high)- r1 _' d' i1 ^4 ~5 A4 `6 |7 d' W
{
0 @; a. f2 ~+ cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
& ~$ c5 k3 g& b3 M3 A0 r7 yinfo.NormalizePrice(sl);
0 C6 v/ l% x! c" uif (sl > SL)& l' I" f" i8 x& c, R2 d( T9 ` X/ C
{
' f$ j% w. H' z$ H8 hnegocios.PositionModify(_Symbol, sl, TP);
, k R0 F) X/ {1 h}8 ?" X" K, i L9 G, _# g# w. C
}
: b0 j/ |: X' x}) A# [4 h' C; R6 n( N7 o' a. Y" s' w
else // tipo == POSITION_TYPE_SELL
" }; X5 U2 a+ R{% w- O! F# e3 a: r8 p* S% Q/ E
if (cotacoes[1].low < cotacoes[0].low)
: D4 p) f( w M6 {- d+ h+ A{. p$ M; v8 j4 G) z5 I; r# s E
return true;! I: y0 O. S( a- I) |0 ^5 j5 J7 p
}! f3 q' ]# u( \! Z8 s
// there was no position1 Y; l1 N" d5 o5 C( K y* _% C4 Y
return false;( n. Q2 x/ h7 R0 r% ^
}
" P; \& D. f* I, E! [! T我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
c; W$ r; _# i' A到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |