启动交易模型,并构建 EA
i) O. y0 o0 ^" V' f* W8 m在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
7 |1 _! | k4 i5 \为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。, s6 W! x" F$ f6 `9 t: A3 X9 t
以下是制定这些规则的代码。8 N3 N# U: r8 {& j( x- p/ |* c
//--- Indicator ATR(1) with EMA(8) used for the stop level...) r2 _9 ]& N0 e3 T, j* c3 n
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);0 ?6 S- R( j, R# P. n9 A
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 l4 U7 e+ X& c9 Y* c9 j3 t//--- Define a variable that indicates that we have a deal...
% S8 j) g. N5 T9 j5 Xbool tem_tick = false;
1 B F: V; j: A7 }4 p//--- An auxiliary variable for opening a position
' ?" [8 z( q$ [1 W0 t% D. d#include<Trade/Trade.mqh>
3 `) T7 e4 c4 j; Y: I#include<Trade/SymbolInfo.mqh>+ Z- V- o2 g. A# `" a6 A* t, R! e
CTrade negocios;
" r% i: {% c# g* \' K) XCSymbolInfo info;) W) K: b( \8 e7 i
//--- Define in OnInit() the use of the timer every second
0 F& o# V: o$ N& H2 c' F& K//--- and start CTrade% }9 x$ z9 O9 T" I0 Y: I" _
int OnInit()
* ?# P+ I2 ~; h{8 } m: i# j! \. J; ~* O( {
//--- Set the fill type to keep a pending order
7 y! ^/ `, K( m) u* H//--- until it is fully filled" f# C3 E" Z2 K9 g
negocios.SetTypeFilling(ORDER_FILLING_RETURN);4 a. j& k$ Y! b
//--- Leave the fixed deviation at it is not used on B3 exchange; e) i2 d% c& g' J
negocios.SetDeviationInPoints(5);# q1 j2 R2 M7 u0 K, U) h
//--- Define the symbol in CSymbolInfo...
# N. `' Y" P& f8 J8 A% ginfo.Name(_Symbol);3 B4 b: W7 x( g8 y& ]. U6 P. i
//--- Set the timer...
- g M0 u0 \8 M" Z7 `2 nEventSetTimer(1);
8 f3 X% _' P. z' B0 G//--- Set the base of the random number to have equal tests...: x0 N3 }0 s) e! I4 \3 |
MathSrand(0xDEAD);
9 w5 a$ X% E; Q/ Creturn(INIT_SUCCEEDED);# L! G7 J* F; V/ Q; Z4 T8 f
}
" Z1 `! K0 _ w0 U//--- Since we set a timer, we need to destroy it in OnDeInit().
% U; d' z4 R2 I1 q3 q, c \, d, xvoid OnDeinit(const int reason)4 o* l! ?8 P$ P0 l
{
! g0 H& X) \% W% \& i! m( u1 @EventKillTimer();
$ m# }6 c2 Q9 V# K6 F$ |}
( N6 n9 r" |! q+ V% S9 Q//--- The OnTick function only informs us that we have a new deal
* J5 d! u- |- I5 o# f8 Nvoid OnTick()* u/ t9 v6 `# `/ \; I
{
* [. h# Y; K' n& B0 ` {tem_tick = true;9 n& \* O: P3 u+ u
}
" Q8 {/ O6 i" z5 l1 U//+------------------------------------------------------------------+
7 \/ J$ U% m# L3 a//| Expert Advisor main function |
! j! u; `( b) `8 N, A% a; k//+------------------------------------------------------------------+% O9 ^! U) R% d) w2 x+ i% A
void OnTimer()
C. o" [& L6 e9 e{
* i: {1 w; D, s$ EMqlRates cotacao[];0 }, v/ P/ x$ ~* O: C0 F
return ;
8 V" l9 h: _/ n: ~" `8 vif (negocios_autorizados == false) // are we outside the trading window?
' Q1 {2 D) A- C+ A8 E. Creturn ;
* b, J& B R+ R8 O2 J- p% C% e T//--- We are in the trading window, try to open a new position!
6 B1 p! z: U4 c5 Q S: Kint sorteio = MathRand();
V' `; ^$ Q- o% v, R7 z//--- Entry rule 1.1! H* C% @; h) Q# F
if(sorteio == 0 || sorteio == 32767)
% \4 `9 j4 b' N3 \, W- o, {# S, areturn ;4 o% X# B/ L# j. j
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy0 e# M L# U4 ^/ s; {! d
{
) Z2 `& j8 o+ r$ |negocios.Buy(info.LotsMin(), _Symbol);
+ B# I n% B: u2 o3 ~1 F( t}
, A. r7 j1 O7 c. P7 ? `7 z% Velse // Draw rule 1.3 -- odd number - Sell- W) @+ Q1 V2 C0 @9 Y, @, p
{
& }) j6 j. H6 e9 q1 fnegocios.Sell(info.LotsMin(), _Symbol);
: h. u' J; i, P0 v. d}
! } X: u4 F. [}
6 s( s! [$ y: f; T. s+ a B+ _//--- Check if we have a new candlestick...
( Z0 c8 s f y9 k9 e. E2 Gbool tem_vela_nova(const MqlRates &rate)
3 a$ N6 _' `, \# b \8 q0 c6 M{: R+ e }) N2 d7 r. t
{1 C8 K: c8 N* }+ a. Q& \3 c$ J6 g
ret = true;
1 k2 q5 S z! V% V7 ?: Jclose_positions = false;6 q1 X4 E/ f0 C4 T
}
: \0 f. Q! P- N* j' Melse
$ A) p/ z" F' |: b& } O4 } ^4 Z{/ }% p: t+ F3 K
if(mdt.hour == 16)
- `! t/ F0 u0 H w1 Y. hclose_positions = (mdt.min >= 30);. Y) X3 p% B2 r7 g* d7 N6 R
}
, m3 h, w9 B$ Y' d: @}8 ]; E7 t5 \' E- D4 g
return ret;7 e$ [/ @0 a6 V( J
}/ ]1 q3 R& ^6 {3 J6 y
//---- g/ k# r% i7 r5 g, N+ |0 ^
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])( j3 \ B. |$ r% ^* R( W3 X
{
+ ?* z5 M- ^* c. j: Wif(PositionsTotal()) // Is there a position?6 O/ Z0 h7 D$ E0 m: {4 Z; n, [2 S
{
5 n5 o2 L5 L0 S" z8 J& Q6 `double offset[1] = { 0 };
0 q, r: _2 d9 qif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
* ]; l! b& L2 ^- a% [&& PositionSelect(_Symbol)) // Select the existing position!7 @: G1 t8 s4 A# Q6 Y: t1 k8 A
{' B" x* L$ K3 Z* N: q: x: s
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
) m. E( D [! I& t+ adouble SL = PositionGetDouble(POSITION_SL);9 S0 s* R2 @: K% ?" ]9 S! ~
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
# ?& T3 i, ]) ~0 g5 Cif(tipo == POSITION_TYPE_BUY)
2 f" n3 z k' Q6 L; j4 V/ o) G{
$ i& c: Z' Z5 c; \6 r/ Q9 _" oif (cotacoes[1].high > cotacoes[0].high)
1 D3 l5 s3 u) V9 G. y{6 x& Z( z/ R, q2 I" Q
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; q, a _; ?7 M i% R
info.NormalizePrice(sl);
$ h0 r. ~ z+ _. p" Z! oif (sl > SL)
* C6 C6 b2 E* n! m+ r{
# V* F* g/ }+ x, w1 N- nnegocios.PositionModify(_Symbol, sl, TP);
$ r6 V7 [& q7 ?}
! R4 `$ E- ~/ G1 g5 R/ [, j: R( ~( d/ h}
! Z7 e7 F! ]/ F! K3 j& G* I- v5 F}
. I# p y2 [1 y: o, |2 ~else // tipo == POSITION_TYPE_SELL
3 O9 ^- C4 R; s. ^. @. a1 Y: Y5 l# @{
& O% `( O6 F; f9 b* Hif (cotacoes[1].low < cotacoes[0].low)
7 o& `: U T$ A5 b{$ G% ^( W; R4 N2 U
return true;* R6 T+ y: ?# ]) _ |" t
}2 z8 X2 `" V: e2 B
// there was no position$ G' o7 s9 J/ x3 `
return false;7 Q8 g- r; G* h g2 G/ N5 N
}
* M$ b- n* Q5 |! A我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- [( e4 J0 d( Y# ]3 H2 K
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |