启动交易模型,并构建 EA
# k8 Y D/ J) q K( V: Y在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) i0 v- ?& E( x) \ x为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
! z: ~ M5 J# z& N以下是制定这些规则的代码。6 B. p; B1 G& x/ I+ r0 T
//--- Indicator ATR(1) with EMA(8) used for the stop level...
% |+ a- n( G o+ O! ^6 R( zint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);1 \# B1 o5 h& S
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);1 y+ F$ h! ~6 ]& F" j2 g; ?
//--- Define a variable that indicates that we have a deal...
1 g( s! p9 \! W3 h1 B5 w3 Mbool tem_tick = false;
- B+ y0 y& ^2 a5 p6 J9 t//--- An auxiliary variable for opening a position' H, _1 W& {1 x. Q7 i/ v
#include<Trade/Trade.mqh>1 {4 T2 x- h% n
#include<Trade/SymbolInfo.mqh>
! e6 ^1 E: ~; r( w _% y6 E5 Q) S: M3 c8 VCTrade negocios;
" ~; O7 A0 l% Z- U+ iCSymbolInfo info;; o4 _+ D5 T* F1 Z% o4 D/ t+ W7 O) G
//--- Define in OnInit() the use of the timer every second
4 r# j5 X8 W6 q9 j7 w* M//--- and start CTrade
$ E8 x# l8 Z6 o6 e: ?int OnInit()
! B8 T3 ]- V( ?% n; E. P/ d{/ P: [' s* `, g2 I9 n* D# Z) o
//--- Set the fill type to keep a pending order0 f% J) i. a4 T0 k' P7 j
//--- until it is fully filled" ?5 v* p A9 Z* f2 O- x
negocios.SetTypeFilling(ORDER_FILLING_RETURN);9 \) F5 J1 e7 o, o
//--- Leave the fixed deviation at it is not used on B3 exchange
. N- i1 T; a# {; inegocios.SetDeviationInPoints(5);! }1 b3 S3 x$ L- b" ~2 y
//--- Define the symbol in CSymbolInfo...' N) Q9 @# ^! Z+ L" f
info.Name(_Symbol);; V& V7 b( a8 z! [) P
//--- Set the timer...5 b, C3 T, n& z( H* N; O; U
EventSetTimer(1);+ T% O" {) V$ b% Q; I
//--- Set the base of the random number to have equal tests...$ ^ L3 h+ Y+ e
MathSrand(0xDEAD);- o9 T5 \. O: a, e( _
return(INIT_SUCCEEDED);+ Y, P J+ W+ }' m" J! ~
}; ]1 v" T# O, U2 a. F
//--- Since we set a timer, we need to destroy it in OnDeInit().9 y* ?/ [/ `1 w( ?
void OnDeinit(const int reason)5 E$ j& \0 p. U! V
{
3 C) D& b2 E8 Q9 i" t4 N, `EventKillTimer();
. G6 `4 L$ l8 C* T& n8 I}
u; {0 K; A' @" t5 m6 G//--- The OnTick function only informs us that we have a new deal w) _# J. F. n0 I
void OnTick()* B% z- o$ e) E0 Z1 i; n2 O
{
$ O: m8 B' z' C& @* @! etem_tick = true;
, D6 u6 Q# h+ E' A/ h& ~}- j2 X: t1 j0 c4 ]; h$ G6 ~! `
//+------------------------------------------------------------------+
$ D9 Y: Z$ K! Z$ I# O& c//| Expert Advisor main function |/ e% j) K" U$ h. H/ U- @$ J/ \: O0 b
//+------------------------------------------------------------------+1 R8 {( M6 Y( X: q) C4 b6 ^
void OnTimer()
6 B. z" R( z) ^: C. l/ R# K{
4 x9 Y# D: \3 F& RMqlRates cotacao[];* d- n, ?3 c6 x' n8 ?
return ;
- S' w6 N# J' z8 m g% wif (negocios_autorizados == false) // are we outside the trading window?
* R0 T* F% O4 e9 j; r& A9 l: wreturn ;8 g3 u, p: M4 r, {. p+ d# r
//--- We are in the trading window, try to open a new position!6 v" d# D( E0 F7 F) y$ |6 `
int sorteio = MathRand();& k. [8 t, w, s$ N
//--- Entry rule 1.1+ E9 a. a- ~/ I& E+ f
if(sorteio == 0 || sorteio == 32767)
4 C2 z, ~. o# o; vreturn ;
1 R) L$ y0 {5 W, n& }& iif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy5 `6 z0 c! v {$ z
{' C1 q1 R) H s, _* [( }6 W
negocios.Buy(info.LotsMin(), _Symbol);+ j* h; _2 i! m
}
& N. h6 F' R1 B, D# o" s8 Pelse // Draw rule 1.3 -- odd number - Sell
. L7 T6 l' X, s, @. x7 D{$ i% {4 ^% w) b( p6 N
negocios.Sell(info.LotsMin(), _Symbol);
8 l) b: g, G# ?9 U1 {}' w8 J3 s. z: i$ l+ l
}) r6 I+ o6 U7 [- M- h1 }$ _6 e8 @+ ~
//--- Check if we have a new candlestick...
) [- e$ e' D2 n+ l9 X& H3 Z' U, Abool tem_vela_nova(const MqlRates &rate)0 X1 H" E. L& J) r% o3 z# f
{. U* o" K J# I. N" T) @* b1 u
{
& |6 S7 A* j& M, f$ ~ret = true;+ o& i7 i7 ~7 h
close_positions = false;, @) _" E; Y0 }$ g
}; B3 x# ~. @2 g" j! `' ~% y0 U! Z/ ]
else0 O0 m+ V( ^& p. ^. A2 f3 S! c
{
% ]& Z* E# Y( z$ S% I6 Mif(mdt.hour == 16)
- ?. ?, c% }, R! W( Wclose_positions = (mdt.min >= 30);+ |! t' v- f. t# y5 N \% p- l
}
, x# c& p7 v) x9 Q: m}
6 h7 h5 G' \8 B1 s" b- }3 C, [/ creturn ret;" ?2 ~: c+ I$ U. C2 G
}
. o6 @! x: D4 @( K, L//---/ U! A/ V; s! m4 W6 y; \
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
5 \6 ]/ f( k1 F0 |* n5 F{
/ l; r( M! M7 uif(PositionsTotal()) // Is there a position?
2 e8 S9 V; f' S5 H. _- E y) u{
# N c- i- e6 y% X9 m2 Ddouble offset[1] = { 0 };, l' ^/ N$ R8 r8 Q
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?' C ]8 R, }& X0 B+ e" v
&& PositionSelect(_Symbol)) // Select the existing position!$ V- s8 h: V! R$ C" {( C
{
* f" i# Y# G K4 `6 MENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);' U; y+ |4 L5 q* o
double SL = PositionGetDouble(POSITION_SL);
0 z7 Q8 ~! p0 Qdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
' A2 F9 M$ _* iif(tipo == POSITION_TYPE_BUY)& s6 u5 Q# L9 ~& T0 w
{" ? b8 a6 r ^ y
if (cotacoes[1].high > cotacoes[0].high)
# [2 \, ^3 n& ^: z{( ]( A) P7 q# I
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];3 w# f# Q3 C/ P3 n% a- f' b
info.NormalizePrice(sl);& v! J/ a5 o- H( E7 _ M* @
if (sl > SL)
: w! @* C: ]7 z$ j* {" m+ d+ T6 n{
1 N* }/ ?. o% _: E* W, d1 a% [negocios.PositionModify(_Symbol, sl, TP);% w: |3 F3 n% I4 a z. w2 A
}
- E# j6 w4 h4 `}1 G4 ]' u" X) J( j$ b
}1 l$ x- e2 J# g+ B2 f
else // tipo == POSITION_TYPE_SELL
' n9 ?8 H# `* W{9 r2 N1 R- v* A+ A5 H
if (cotacoes[1].low < cotacoes[0].low)3 A3 I q$ |) D& m% D1 T2 y; ]1 l
{
9 q0 U2 N5 k* {% v0 f0 Q. X! jreturn true;( s R" a$ R" [9 B: I- D
}
; C# ?/ ~* H0 q! U' L9 v4 h6 p. t; K// there was no position# J# {0 a- u. B, F; q' g2 T
return false;
) E$ | F6 y3 G, ?- J" V3 Y3 I}
7 @- h: v3 q, l! n) d我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
2 l1 u* M; F/ h) i0 N到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |