启动交易模型,并构建 EA
. i4 I( ^. A0 R在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
$ e: E* c7 O4 P& r% r3 h5 e为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
; q' p, Q& F% E' b& Q% U以下是制定这些规则的代码。7 L' r7 D/ a, B; F
//--- Indicator ATR(1) with EMA(8) used for the stop level...
4 u( b: R# \( F( R3 E) q( Aint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
+ N4 ?0 Q6 n/ j4 u Y0 Z5 Y+ Rint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);. _) r( ^0 B& A- B" @" E$ L" ^
//--- Define a variable that indicates that we have a deal...
/ w4 Z" {" e' ?9 {. I8 O' a2 ~bool tem_tick = false;
; f+ o k$ q& L' N//--- An auxiliary variable for opening a position$ U0 s2 ]7 Q9 @1 H
#include<Trade/Trade.mqh>
! O3 q& t4 P! j7 a2 B#include<Trade/SymbolInfo.mqh>
5 ~1 G. y/ b* R% \9 ^3 ?$ ?CTrade negocios;
7 y- Q, R |- H" JCSymbolInfo info;
+ h/ x4 I( F/ i1 m4 c9 K//--- Define in OnInit() the use of the timer every second2 A$ K" E2 W' B7 s9 }3 P. _9 A
//--- and start CTrade% k2 E, z) F1 n. E5 k. X
int OnInit()4 |5 E' S6 [0 ?+ p G
{% A' ], H8 p/ h5 Z" k
//--- Set the fill type to keep a pending order; E5 p) W! m( ?0 A- K- b" v1 ~
//--- until it is fully filled
5 L$ l6 N5 v" Y$ Wnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
# D* ^0 z- k9 `& n I( H2 ]//--- Leave the fixed deviation at it is not used on B3 exchange
; J( U1 O8 V' r* l8 N6 Cnegocios.SetDeviationInPoints(5);
, Y P1 G& t0 D9 Y) V6 O4 M: o//--- Define the symbol in CSymbolInfo...' P- f f% v) o) h" t
info.Name(_Symbol);$ p5 Z7 y$ I# d [
//--- Set the timer...
* e. }' B7 I8 z) S! GEventSetTimer(1);+ Z% ^2 _. c( v2 t( P+ Z2 V
//--- Set the base of the random number to have equal tests...
: `5 W- f0 F/ a& s( _ NMathSrand(0xDEAD);$ Y: b% V; k9 o4 C5 s! x1 z" n
return(INIT_SUCCEEDED);
# U5 `6 }' l2 q! F' F: |}3 m1 A. _9 O% f0 k( B M4 z
//--- Since we set a timer, we need to destroy it in OnDeInit().
' N5 ^' ]* N! T, ?9 g; P ]void OnDeinit(const int reason)+ B6 r- j: ?: `0 V d/ p9 ~# N- A
{
3 |* x9 ~4 t3 p! ^* @EventKillTimer();
) `, Q4 U3 I& i9 ~6 k( z: _- }}2 f, C2 `/ A) S. Z6 G3 O
//--- The OnTick function only informs us that we have a new deal
" h7 ~* x# |9 Q" e \% S4 kvoid OnTick()
2 X( D8 a$ Y! [" j; O: p! {" A{8 U8 J; }% j( H! f4 i3 R
tem_tick = true;( Y4 i( x) g0 ]0 d- M' f
}( J' F: `5 g9 T' m' n
//+------------------------------------------------------------------+
; p$ R6 B; ]) o' k6 @% r( P8 `+ C//| Expert Advisor main function |
' U( J I- O* k: v; M4 [2 t* k2 n//+------------------------------------------------------------------+
6 {1 B& F) L8 Z: ^void OnTimer()
3 c4 F" u4 m0 z7 }{
4 H+ b( Z8 j4 j- QMqlRates cotacao[];! k, Q1 y }9 y+ y2 g
return ;
5 x/ l& X- \. K! t5 \$ K* B) xif (negocios_autorizados == false) // are we outside the trading window?
. b3 o: a/ ^; s% O" f5 y6 greturn ;
% H5 t7 ]& k8 }# {' @: ~& E//--- We are in the trading window, try to open a new position!% r4 X. a5 {+ M
int sorteio = MathRand();" D! G' \: c# t; l! ~+ E! L: H n
//--- Entry rule 1.1
, c/ r) u ^$ O: O8 G8 bif(sorteio == 0 || sorteio == 32767)
+ e7 Z4 A: ~, N5 N4 Ureturn ;
7 z8 [/ p3 ? @: [: O& x- cif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
. r& w ^; Z! j; s5 V{
5 B5 t. |6 ^/ l/ [' B8 f$ }negocios.Buy(info.LotsMin(), _Symbol);
3 W& g$ V$ c) \* \& b}, {% a) y4 u4 O' H/ u' o
else // Draw rule 1.3 -- odd number - Sell/ [: K, h3 r( Y( q, V
{2 y* D8 u5 d7 [
negocios.Sell(info.LotsMin(), _Symbol);0 D0 X/ }; K7 {$ U9 f3 c
}9 J% e+ p. u1 ]/ c- F
} ]8 `6 G( |5 t9 U+ z* j2 ^
//--- Check if we have a new candlestick...$ u4 ?4 O* A5 T7 R( U
bool tem_vela_nova(const MqlRates &rate)) b% j' n5 S# m; f
{' Q5 b% F- \- z& ?+ c
{
6 ~4 y z6 M+ r2 M5 t& aret = true;
' i1 w# m. b& n- d# d) t- j2 q: Bclose_positions = false;; E( M& D- m' _! G- K
}
. V, C$ q. w ?else
' p: t7 n* P- b) J) F; ]. @6 \{5 L& ?, f$ ]! q9 c9 ~2 t/ ?
if(mdt.hour == 16)' R( c/ c2 ]5 F3 J9 m6 c
close_positions = (mdt.min >= 30);
6 a( S+ s; V6 Q) {! m7 [) u, R9 R}8 f5 k. b$ d4 i: Z: J8 _
}, K4 ^; I6 U& |
return ret;
6 d% K7 ~0 a# C+ B, }( C2 T}
0 U o' J) f3 ]% m( I C//---& } h, ~) W7 K% D
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
- W" B3 L! {/ ~{
, T: c" h3 f! _6 Bif(PositionsTotal()) // Is there a position?
' _( e, _' D+ F{6 Q; S* Q) L; l
double offset[1] = { 0 };2 E9 x/ j( v; P& J
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
: v( r4 D9 w( z9 M& V$ O9 G- j. m2 M&& PositionSelect(_Symbol)) // Select the existing position!, v4 U4 F8 q3 e+ q# B2 N) t: I
{
8 {: p, e9 @, J7 Q. iENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
# B! u" X4 ~, edouble SL = PositionGetDouble(POSITION_SL);$ ]4 t% c+ F5 j
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
& W" w& `3 p5 G/ l" [if(tipo == POSITION_TYPE_BUY)1 m! m7 d& j/ `0 j9 B
{
! _2 p" Y- P1 {& g3 i/ Iif (cotacoes[1].high > cotacoes[0].high)
4 K9 q; f1 M1 D8 g F6 K{
3 z! W4 _/ O x$ I6 O; @double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
3 N% J, f, |- D4 _1 H3 hinfo.NormalizePrice(sl);
$ u+ h9 @6 E5 W0 e, ?if (sl > SL)# l* o+ |& \' G
{, ?/ J, w' v! s% P
negocios.PositionModify(_Symbol, sl, TP);: b* V- H5 t3 u0 x
}6 \6 E, W. l/ Y1 ?; x" B
}% `2 I, S' s( G; V. I( ?6 n
}
4 j6 X0 L" j) G1 \6 j7 {else // tipo == POSITION_TYPE_SELL
+ P! |: a: Y6 n* Q; } ^% E. V: p* F{
?# ~6 Z$ T6 w7 z7 Q( P5 dif (cotacoes[1].low < cotacoes[0].low)
) m5 y' ~+ ]. O9 |; e{) s" h6 z8 g6 L0 P) r$ I) k7 F
return true;
2 a) p! q, I9 c}
1 z/ \' f) J( W! i K3 K& `// there was no position
f1 m8 S. Z' X; N+ S0 Wreturn false;
7 ~ j c* ~+ W+ K1 y( Z}
9 b4 O' A5 n6 M! ^' w我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
2 q! D9 d. L! w+ N' ~到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |