启动交易模型,并构建 EA
! |7 ~" K; c2 ]3 O! f" m) |在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) x& Y9 E1 N2 ]# S+ |2 A6 W为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。, [4 E& m% a. p, u: F' x
以下是制定这些规则的代码。2 F7 z/ s% T" y( F
//--- Indicator ATR(1) with EMA(8) used for the stop level...
& U3 U# i& z: Z5 c9 _int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
, w1 @' @& Z$ p! H h! B7 cint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);. ?0 E' \# Y3 y$ r& f
//--- Define a variable that indicates that we have a deal...
v& {8 l. ]* s" F: rbool tem_tick = false;
( E9 M* X6 Z% b1 _* g//--- An auxiliary variable for opening a position- _$ @8 n) s( C' X" S9 D
#include<Trade/Trade.mqh>5 d% L" N; d! m/ C6 A: c
#include<Trade/SymbolInfo.mqh>+ j$ B6 E( K5 o; B# u6 c: e: [
CTrade negocios;
. {6 L% v0 b) ^& U- dCSymbolInfo info;, Y' u) s7 D8 s) J5 I2 O9 P8 a' ^1 q
//--- Define in OnInit() the use of the timer every second7 K; c$ x& w8 ^
//--- and start CTrade
1 y$ Y* m( w* s$ V* Y/ ]- z! C9 q2 s& Vint OnInit()
" u1 l4 O" j4 U1 y5 N6 ]{
3 w) P- A* E1 D+ w//--- Set the fill type to keep a pending order
/ j$ b) C, ]% u//--- until it is fully filled
" B8 E x, T/ V9 h3 d0 [% b6 V `; Anegocios.SetTypeFilling(ORDER_FILLING_RETURN);
: b% k9 d( p& a2 f9 t5 r( ?9 W//--- Leave the fixed deviation at it is not used on B3 exchange0 T$ r/ A% J P! V: [, i
negocios.SetDeviationInPoints(5);( a' b- L( U, }: u+ a4 f ]$ c1 [
//--- Define the symbol in CSymbolInfo...
' r: {% N+ \' {info.Name(_Symbol);
/ E7 U# k/ N- Q- Z8 S//--- Set the timer...
0 e3 O' R" @ ?; OEventSetTimer(1);' @# V& R$ h( s3 S
//--- Set the base of the random number to have equal tests...( J$ y, {# |' B6 ~
MathSrand(0xDEAD);
: z. x. h/ B4 ?' T5 r. V* p# y* greturn(INIT_SUCCEEDED);5 V( {3 h8 r) t8 {( h0 U
}
& L! P. [ P2 k+ o/ M//--- Since we set a timer, we need to destroy it in OnDeInit().
5 U9 Q6 I3 U5 o T! Ovoid OnDeinit(const int reason)% ?/ u- A# V6 ]8 T/ E' V! j, W8 Z
{
4 Z0 o( P% _ rEventKillTimer();
- c. k! @. u- A: J}
. S7 w- {4 C+ ]8 K- Y$ c//--- The OnTick function only informs us that we have a new deal
" A0 I. S D. K. ^% zvoid OnTick()
* }3 u, W5 A8 R2 b3 O{
. m, N+ Y2 V! j4 |tem_tick = true;) w: v1 Z4 }! R8 V" f$ a3 g: e" |
}" e( J7 \& _1 s) @. k1 T
//+------------------------------------------------------------------+
) I3 W- e4 |, k! j# a8 q//| Expert Advisor main function |2 o$ X9 O! }* i* Z3 k, h& W7 q |- ~
//+------------------------------------------------------------------+
/ j* L) @- w& s9 S/ w6 Tvoid OnTimer()
5 p1 j0 Z( U& I{! A+ U; m0 a2 v% T+ V+ b
MqlRates cotacao[];* X9 r' }- p4 f
return ;! J9 X5 A. }/ s" P
if (negocios_autorizados == false) // are we outside the trading window?
% h: l; O- M% [3 ireturn ;; J/ e$ c& @- a) b
//--- We are in the trading window, try to open a new position!
5 }1 g% x5 d4 D8 p5 E/ a( zint sorteio = MathRand();* ~) N. `! o& G/ P
//--- Entry rule 1.1
' u; R# K0 P* }; Z6 Fif(sorteio == 0 || sorteio == 32767): @! M1 e" ^$ l6 ?" }7 R# ?3 F
return ;( g! @, e9 X5 v2 }- f- y/ L
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy/ u/ \4 v+ z0 |3 P
{% Y+ S" g( o' e- q2 n+ W+ n4 h" h4 j1 ^
negocios.Buy(info.LotsMin(), _Symbol);2 F3 q N5 `9 u: J+ R4 y
}9 j4 a* j2 w- V0 u; R# a
else // Draw rule 1.3 -- odd number - Sell$ c0 a: R# K# i" d, s- c
{1 T8 r7 H+ K W W) w8 O
negocios.Sell(info.LotsMin(), _Symbol);
7 h/ y% i4 W3 y, V p9 B. J) h}
) ?8 q: c2 R. \7 Q. ^( J}* u ^2 S3 F6 A- x
//--- Check if we have a new candlestick...
& t$ ~' t8 U4 v% g, ]bool tem_vela_nova(const MqlRates &rate)
$ n( }7 g! w3 }, l- h6 C2 [; S{ X5 `2 n% c' j1 t6 }* _ G/ c
{6 a+ q) E% [3 l, l
ret = true;2 C% `3 ]0 {( D7 [0 k& H5 C
close_positions = false;
' _/ r6 D6 {6 Q3 ~" [}6 ?' F& e2 V* u
else/ Q$ {4 r* l4 h, i' L! ]
{8 z3 r- A% }6 s6 y4 V x* n
if(mdt.hour == 16)
0 n# u! |! o* L7 t: ^, r5 K9 lclose_positions = (mdt.min >= 30);
6 ?2 T) G8 [7 k: S: u7 t}
; Z2 g8 ^7 D4 h* P% h}. G( _: F' |- H
return ret;
) d. ?. N2 P! d7 {' y- Y8 `}
6 b1 o3 J+ o: Q4 |9 M4 c: U9 e% h( ~//---+ t/ K5 B! `# y% d
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
1 r6 Z4 C h/ ~$ K{/ z7 m1 ? B+ h; y
if(PositionsTotal()) // Is there a position?
4 w2 I' |1 H2 [; j! q! g{
7 I- ?. ?, k8 i- R. {- ^double offset[1] = { 0 };
]7 s1 d( N2 z* l2 fif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?3 n9 |: h4 I5 d: K! Z
&& PositionSelect(_Symbol)) // Select the existing position!# g% V0 { _% s! h
{
4 j$ a1 H* F- R% {2 Y; \ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
( q9 Q" N0 g/ m- j# D9 d w7 n: \double SL = PositionGetDouble(POSITION_SL);
; o" j: \1 h! v, `& Rdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
+ O: g9 E& X1 _0 Cif(tipo == POSITION_TYPE_BUY)+ [% ~7 G4 j1 u5 \5 F
{* g* C: z5 X1 [0 z2 l
if (cotacoes[1].high > cotacoes[0].high)7 L+ ]$ M Q. `0 Y9 v
{# ]% ]8 d" Q! f3 T4 a, P; G
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
+ i) I$ P3 y" c# sinfo.NormalizePrice(sl);" ?% A! I8 `$ k& a4 W
if (sl > SL)7 Z8 o( z% ?; `, t# \0 N
{ A8 H! [6 Z- _8 r
negocios.PositionModify(_Symbol, sl, TP);! A2 ]. |' J. K. ?/ L
}
) u& _& s6 g A- z0 f. v}
+ \8 b8 D4 }" F2 a& n+ v( W}1 ~. k2 t% [1 o8 I
else // tipo == POSITION_TYPE_SELL. Q) x6 m9 ?) k! v/ b
{
6 N# X- O% ~( T& I% y2 Tif (cotacoes[1].low < cotacoes[0].low)
* k! J) s+ s1 l, ?$ X{# \- o4 Q* _5 [( j. Y
return true;
N+ j% I( ?( t; V1 U2 b}
& x: |* C6 z! R$ j* @7 x4 s3 p// there was no position- z0 @+ t2 O+ |& q( t* T' R
return false;4 a+ x4 Z3 R7 n
}( R% D8 L& G, I1 v2 _ P
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; K) T- x* P+ e+ ?8 v
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |