启动交易模型,并构建 EA( a& e4 k: W0 j% X( [
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
8 e g& }8 A' b: ]* p( ~5 H为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) [8 x1 ?9 G. f) H2 [1 U5 \以下是制定这些规则的代码。6 X. Z1 x% ]* h% c
//--- Indicator ATR(1) with EMA(8) used for the stop level...3 E! z: U" H# k- D3 `
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);& Q4 l' D2 F3 A) G2 {( h' G7 S
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
- Z4 Z3 u ^& l# t8 U$ e: X3 M( A//--- Define a variable that indicates that we have a deal...) n0 u/ J6 R/ w8 l$ |# @$ j
bool tem_tick = false;
1 m9 w& z; d5 j//--- An auxiliary variable for opening a position
$ C% \% |/ c; Q6 V L0 f#include<Trade/Trade.mqh>
1 I, z7 G3 Z3 A7 ]9 E#include<Trade/SymbolInfo.mqh>& z* S. F) a/ `. \
CTrade negocios;
: v0 L$ P$ n+ ECSymbolInfo info;& m* ]: _* `: _8 Q
//--- Define in OnInit() the use of the timer every second- b9 l: @/ m5 p
//--- and start CTrade
5 A9 ^( d2 i4 \; u) F3 Dint OnInit()
9 y9 c1 }- A* v9 h{+ t. J& c: J# E& y, ?+ u6 R
//--- Set the fill type to keep a pending order/ d1 N/ s. p: v2 u4 e# i
//--- until it is fully filled2 ?* O+ G9 V- H( I
negocios.SetTypeFilling(ORDER_FILLING_RETURN);$ L# h. ^4 [" t3 m; d9 m: P% r
//--- Leave the fixed deviation at it is not used on B3 exchange
" c; @4 j0 a+ O% wnegocios.SetDeviationInPoints(5);
9 a7 m; T1 }8 T+ ? E3 Q//--- Define the symbol in CSymbolInfo...6 K5 A6 I& d# Z7 Y
info.Name(_Symbol);
& v% n" q2 s6 x& c//--- Set the timer...
! D: Z& x4 x% k* O7 o, NEventSetTimer(1);- }/ ~+ V/ }5 m, t3 t9 ]: j
//--- Set the base of the random number to have equal tests..." d. d, }( ? l2 v$ D
MathSrand(0xDEAD);0 h$ F4 |# p4 M! z
return(INIT_SUCCEEDED);& D% m( C; O$ f6 u' d* s
}( o0 g% p# U# C; I8 N* p6 `
//--- Since we set a timer, we need to destroy it in OnDeInit().
" Y) w" C1 F$ C& n7 m" l, q1 dvoid OnDeinit(const int reason)* R% j/ n3 x+ I3 P, L% f: x! b4 t) B
{
8 g1 K' Z# f/ J. }7 k$ X$ \EventKillTimer();
# p7 E1 c' ~, `5 T, ?: H}
4 m0 s) P+ v* _; U" b7 N+ x# J2 P+ f T//--- The OnTick function only informs us that we have a new deal
; Q! a& F. Y& p7 Yvoid OnTick()
# ~% i/ z6 y) ^& _6 P0 h{ c+ U: K8 q S6 P
tem_tick = true;
$ d/ h' `1 F1 z' v; h$ V* c}9 o' F1 d' A( l6 _
//+------------------------------------------------------------------+" y1 r1 q, I! r
//| Expert Advisor main function |
4 S( R- s& D% ^8 w7 f; ]//+------------------------------------------------------------------+
* c0 F% F2 n x) V+ p& yvoid OnTimer()" _9 v5 g5 ]' f
{
6 Q4 I' y8 ` I+ V5 zMqlRates cotacao[];
6 U; v" H e4 ?! y {. N. u) Kreturn ;& L4 B; q) o6 ]; V0 s9 q v
if (negocios_autorizados == false) // are we outside the trading window?2 _* J! d x! \# B( V
return ;
1 X; W/ n( a4 a' B3 o//--- We are in the trading window, try to open a new position!
* A" G6 N3 Q4 M0 R+ l# mint sorteio = MathRand();
3 d. P! M4 P0 s0 B//--- Entry rule 1.1
% u5 M4 C/ j/ `if(sorteio == 0 || sorteio == 32767)
% W: q( \9 A. b. P. L( Y/ G4 @) ureturn ;0 k. Z& X7 G) o
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
& m" e* h: F5 m; ^( a/ p& |{5 j6 i. e7 h! ~( x8 v% O
negocios.Buy(info.LotsMin(), _Symbol);
2 V( A7 V' A5 I7 {# m+ g}
* |* Z! K, k) f; relse // Draw rule 1.3 -- odd number - Sell$ m$ p, k; M1 N, t) S
{& V! O/ y4 m( t! ~& ~( e: r% W% Q2 I* ]3 l
negocios.Sell(info.LotsMin(), _Symbol);
" K# p4 A3 E m. m6 U}
& `2 f! @$ S2 ~; q4 \}
3 h- z8 _& j) A7 j. _7 t//--- Check if we have a new candlestick...2 H: J, T; \. O! [/ l
bool tem_vela_nova(const MqlRates &rate)
9 |& o3 Q# Y8 W" Y4 a6 ]{
8 X6 ~2 R% g! ^9 g) I# m{
$ P3 O3 K8 Q9 [( Dret = true;
. ^" o/ p7 n- j0 Kclose_positions = false;
) e! g) a! j, F" s9 n' |}
5 O! H8 S7 y _. { }else% q7 Y, f+ o b0 P
{0 U- q5 V: ^2 l. f7 R0 M; D
if(mdt.hour == 16)7 e* D9 }1 G! h: o( ^ |
close_positions = (mdt.min >= 30);
4 x2 [4 @* G6 o2 `}: S8 U' a6 I+ J* j
}8 x" e K& _7 E' H: b+ S! H2 Y
return ret;
9 Y6 l4 Y) h4 G: p9 s}$ `# |2 u; U9 \0 w% c/ o. A1 h
//---
8 l4 V$ {7 u8 z2 z) Xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
) w% i/ b, y5 _+ S, l' D{
4 J6 I( [9 z" Y& {0 E& gif(PositionsTotal()) // Is there a position?$ K% L& L5 H9 Q9 ^- `9 v) X7 S
{' d f3 y1 v$ b# `' f
double offset[1] = { 0 };
( a& ^1 b$ B4 }8 p9 ?if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?: x2 `- D# k9 _# T8 @
&& PositionSelect(_Symbol)) // Select the existing position!
# O8 @) {, j$ ?: T: F- V0 T{: r; J* u4 H3 H P" ^
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);& \% H2 U! ^, E* }
double SL = PositionGetDouble(POSITION_SL);" h. Q9 U- D. A o# r4 `! M: g
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
$ [' [" d Z/ V" ~: v Y: Wif(tipo == POSITION_TYPE_BUY); x& u% U: m3 y' z5 O
{/ C# p9 `! t/ g. U) d
if (cotacoes[1].high > cotacoes[0].high)
/ |. r- L" _1 A) X7 ]4 q{0 g7 [2 A* A& p0 e! j! }
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0]; \. V/ B! F; i6 _
info.NormalizePrice(sl);4 }7 u( r, x8 t4 J" Y0 c
if (sl > SL)
0 [/ w4 V: Y v4 w{2 |1 k6 h4 t4 B( Z# P
negocios.PositionModify(_Symbol, sl, TP);; Q* q, M7 \! |2 A% G8 J
}
3 g. b( ?3 \9 n! \& Z( G- w) h}
% l0 F8 y) H: X}+ Y; a: G- K7 n' g, }2 C" I2 Q
else // tipo == POSITION_TYPE_SELL
/ T j( u2 J! N1 t1 K" ~* H{
9 I. A/ U9 ]6 B2 |if (cotacoes[1].low < cotacoes[0].low)
# V& Y" _' X0 Z{
3 G8 w6 r1 M, D- C+ d3 ?return true;7 ?) k6 h% w: g4 @, |6 k) x* @
}
" `, @# Y" X; J) F Z// there was no position
" j6 c. u _ H" G6 z9 J" F9 p5 Zreturn false;
@4 d5 @$ _" p. y/ ]1 H}3 v E# h3 ?4 K, j* C5 ~8 M
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。: |5 ]; f0 t C7 v
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |