启动交易模型,并构建 EA
# q( _, m1 u7 V: f4 X: C在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。 \: f1 V8 e+ U& m. h/ c9 c+ v& f+ T
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
# ~" A& h" | R2 x9 P以下是制定这些规则的代码。
/ r. W! u) N1 H0 u' S9 ]! K//--- Indicator ATR(1) with EMA(8) used for the stop level...
, H* f. a& E& T" zint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
8 y6 r% d# `# G# y! Wint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 ?' H/ s) k% H5 `3 f//--- Define a variable that indicates that we have a deal...
. J/ h, l5 J7 e" hbool tem_tick = false;7 R, `8 h' g9 I3 M
//--- An auxiliary variable for opening a position' J2 c- r6 W; R( {; h1 ^" O
#include<Trade/Trade.mqh>6 [. N- G# b: o* X, ?
#include<Trade/SymbolInfo.mqh>8 x9 M4 |7 s" n3 ~! n( M
CTrade negocios;
1 k* s9 L" W$ c0 o( e, A; qCSymbolInfo info;& h, b& Z% d9 Y4 t) W
//--- Define in OnInit() the use of the timer every second2 K* }/ u+ M0 M8 L6 Q5 E
//--- and start CTrade
- r9 w1 @6 v7 ~ _* S' x: xint OnInit()9 k$ d* O" S- K* d
{
% z& {* Z2 q2 O; S; ~* h//--- Set the fill type to keep a pending order
4 K H$ u+ ]! C& h4 u; ]//--- until it is fully filled
8 @0 G" M# ^# G& v- rnegocios.SetTypeFilling(ORDER_FILLING_RETURN);2 M2 u+ I1 y- Y( o4 u% F" j
//--- Leave the fixed deviation at it is not used on B3 exchange
! } o# Y& H* P4 znegocios.SetDeviationInPoints(5);, ^) L" D: [( z
//--- Define the symbol in CSymbolInfo...1 l0 {3 z# b! g& H. d
info.Name(_Symbol);
S0 z- m2 x! g7 }4 c//--- Set the timer...( u9 z0 \4 U( J; E' d' l: c2 ]
EventSetTimer(1);6 ^, D/ ]! N* C
//--- Set the base of the random number to have equal tests...* a) W7 B; @# |- ^9 G9 q4 |
MathSrand(0xDEAD);& n# u/ O) N# p+ i ^ J k8 L1 i
return(INIT_SUCCEEDED);# {1 M/ H% s) J N/ H1 _
}
; I) d' B7 g- T( S( F//--- Since we set a timer, we need to destroy it in OnDeInit()." \9 f2 i& V" O" R$ X% k! L9 t
void OnDeinit(const int reason)1 {; W0 G( V+ W+ U0 u
{# C( h0 g. [: ^$ t: U
EventKillTimer();
3 M2 a% ~, P- b6 s}
; b; r' B- g1 e1 g+ g8 C1 Q! u' [//--- The OnTick function only informs us that we have a new deal
7 z# H2 V) h6 R d! @, p( }void OnTick()0 ]5 o. M" ~ B
{' L4 l. K7 q3 g! p& x
tem_tick = true;- U [ O, Q2 {2 l; `
}
+ r3 e& F. g* {4 h' V//+------------------------------------------------------------------+
* {/ e" i: y/ }; m8 q//| Expert Advisor main function |
; o+ y& O' c3 p$ J//+------------------------------------------------------------------+: x8 y3 V& R3 C" v
void OnTimer()" o: j8 r$ q4 X! R7 M2 ~$ ^
{4 y7 n: X3 e7 S4 i: K1 L
MqlRates cotacao[];
9 t6 s+ ^0 ~- b' y7 x( ireturn ;! y9 u2 i; v) v4 ~' T* a" {, m
if (negocios_autorizados == false) // are we outside the trading window?5 K1 E7 [7 A) J9 U& ]3 a, a
return ;
/ P$ ?. e+ B+ s, |+ u9 l& v/ I//--- We are in the trading window, try to open a new position! g' F& N5 e- N
int sorteio = MathRand();
8 `8 e8 f- h5 J& W//--- Entry rule 1.1 v: V# s5 I/ o" e3 V
if(sorteio == 0 || sorteio == 32767)
# w( `5 F/ u$ A, oreturn ;
8 C3 S2 S9 l2 B0 c8 k* kif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
/ t1 V9 N$ I- l{
: V, l$ `0 `+ j0 nnegocios.Buy(info.LotsMin(), _Symbol);* j2 z4 B- i2 v1 W: s7 c, T
}
6 f8 ?+ ~2 ?" O3 F3 ^& belse // Draw rule 1.3 -- odd number - Sell
. m5 S: j- p+ i% n/ l, n& d{: }% i& ~5 `! {5 G- R( }; d# u
negocios.Sell(info.LotsMin(), _Symbol);
# s" t4 Q4 Y. L; i6 G8 A0 Z}3 C4 m4 t, }1 I! F% O
}
F% V# V5 P; k7 e* S1 \8 ~( z//--- Check if we have a new candlestick.../ [5 B+ D: f4 n. Q9 ^
bool tem_vela_nova(const MqlRates &rate)
- [7 @! Q& z2 ~" F8 X{8 ? D6 n5 o, M5 k/ J9 w9 ^4 c9 M
{+ l, E$ W0 q+ u6 b- e
ret = true;" n5 N0 u7 r' a! n' G
close_positions = false;
& M! K: u. `' J1 F( ]}
1 r) B' b+ y- o2 Qelse
, V% j! |( I3 {7 S{
6 ]/ w8 H: O; N+ _- n# }5 sif(mdt.hour == 16)7 V) x: ?$ k* H m* q: {; O
close_positions = (mdt.min >= 30);& o# X* @4 N) x
}1 U2 S! k8 l) l- }% a
}% S W! W, b. \) R. ^) N( u
return ret;
) {4 \# |# N, N P}! Q$ {1 Q y: y# M7 W
//---
4 I5 ?. r6 c/ J; Y+ j& Kbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
; h l* k! M2 r% }{" c& G' Z5 y/ f7 G `/ ^
if(PositionsTotal()) // Is there a position?
, r& y7 p5 d3 P. `{% @7 w' ~+ \% X% s
double offset[1] = { 0 };
z- e* b. m) z/ n7 d- @7 e9 `# Vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?/ b8 l% f6 J( s. M' ?
&& PositionSelect(_Symbol)) // Select the existing position!0 ]& l/ N% ] e) z4 `# \4 S
{
, T% i' p4 B2 H. Q8 nENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);' X" ?8 y* [$ u3 l; u
double SL = PositionGetDouble(POSITION_SL);
$ y2 P& U$ g- d5 W' _7 R3 P+ d Qdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));; S' Z9 O q+ a* a# c, r
if(tipo == POSITION_TYPE_BUY)5 j( r: g3 s2 D8 Q
{
2 Q J; z) L% U4 ]3 rif (cotacoes[1].high > cotacoes[0].high)
2 ~9 V B+ Q9 ^9 Z{
3 O% p7 {( H" I( u1 edouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 U2 r) ^0 |8 B' w5 tinfo.NormalizePrice(sl);! C% Z! v+ y/ F4 E! t3 x
if (sl > SL)! W6 |2 z: Y* u4 X3 S
{% I- p& x# ?4 X( c+ a
negocios.PositionModify(_Symbol, sl, TP);. P2 p# N* |2 H8 j( v
}
& H f Y1 V$ v8 A$ X}
+ q( Z2 C$ R' |$ P2 Y, `2 Y}- w0 }* w( j0 z
else // tipo == POSITION_TYPE_SELL" G8 d8 m* X+ W& S* S9 Y1 c. A
{
) x1 _9 ?# I3 g7 e9 Gif (cotacoes[1].low < cotacoes[0].low)6 t+ J: u ]$ J3 X/ H4 @
{
$ s9 e1 X' R( \" T1 d9 t+ Vreturn true;3 Z1 o! z9 X; u7 l" K
}
q# v% G' v6 R// there was no position
* Q! M! a( f* q- k/ Freturn false;) b5 g" Y0 d' v5 h/ ]( Q
} H3 p+ k: i! K4 M
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。9 v3 h$ E. b0 w
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |