启动交易模型,并构建 EA) j. J" }9 P1 C7 O6 F- r$ K
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。; Q( M& r" [# }% G9 j$ k. h8 n
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。7 J1 p* r, h y" ?" x; j, B- R. p2 ?
以下是制定这些规则的代码。
7 q+ a2 k9 F# | ?: x3 w' K( R7 K//--- Indicator ATR(1) with EMA(8) used for the stop level...
' h9 G+ ~' j$ ?# W/ t9 l( O( Hint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
) Z1 B/ \8 q# d4 [3 u5 E0 Yint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
8 ~4 J+ j$ A, y9 s! _5 l//--- Define a variable that indicates that we have a deal...6 O% K7 T& l+ f& t: ]6 F
bool tem_tick = false;
9 M0 u* y" Q1 t+ ^4 J9 q0 E; U//--- An auxiliary variable for opening a position
% C1 g( V8 m& T) c/ |: g0 G3 B* P0 u#include<Trade/Trade.mqh>
- m8 }( Z+ ]8 l% U& s% W1 }#include<Trade/SymbolInfo.mqh>
: ^- h0 N7 ^6 v3 _. H. e' gCTrade negocios;
, _0 |, Q% B) e$ KCSymbolInfo info;+ |* d8 t! l% M* ~
//--- Define in OnInit() the use of the timer every second
2 R) f8 [, T# n) c. K9 E( h//--- and start CTrade& |2 z% H, m$ x- E
int OnInit()
! P2 @2 a- j" v$ c- H& T, Y5 S{
( i1 R: R2 x- y# i [' s" B//--- Set the fill type to keep a pending order
& o2 g1 P3 g T! C8 t//--- until it is fully filled
1 {: q8 f1 M. }5 Bnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
0 B" W9 D% @, W4 [( M4 J* T//--- Leave the fixed deviation at it is not used on B3 exchange
& p' j# }( q" u I( g `' Z. \1 enegocios.SetDeviationInPoints(5);% V9 w8 A' u5 v. s. h0 w
//--- Define the symbol in CSymbolInfo...
3 u' B6 f; E, V, D; |1 i* oinfo.Name(_Symbol);6 s6 d6 w/ R& l( S
//--- Set the timer...2 a5 A1 K7 e2 E# I& t6 u
EventSetTimer(1);( J4 b+ s( J0 ~
//--- Set the base of the random number to have equal tests..." G' @! b" g- w) Y H2 z1 O5 e
MathSrand(0xDEAD);
4 a8 E4 W* v. ] qreturn(INIT_SUCCEEDED);' J7 K* P9 A+ R# w; w% ?
}
4 D. j, ?! p+ m//--- Since we set a timer, we need to destroy it in OnDeInit().: M7 m( {& ? m2 }/ r
void OnDeinit(const int reason)
M/ f D8 o( P6 P$ ~% S{0 }2 Q: v* |7 O, W0 x8 T$ t
EventKillTimer();: i( m7 t2 G- f; ~
}2 @8 y! a a/ r3 I
//--- The OnTick function only informs us that we have a new deal
' o0 Q. O9 c. Gvoid OnTick(); T, M& J& c2 A" _
{4 L* Z2 G4 ~% Q% ^9 E! S
tem_tick = true;
' d/ n& h' [# o/ \7 K( M}" q8 A) o p6 q3 U
//+------------------------------------------------------------------+
# W8 _, U$ T; H# T; t//| Expert Advisor main function |
1 w! P6 d# s l' | o, T! M) P//+------------------------------------------------------------------+8 B# @7 [& Z1 {' t4 A: @
void OnTimer()
$ V" `' Q" ]# T G7 n{% O3 s8 c" Q5 g
MqlRates cotacao[];
# w# a6 E9 f, g% M) ereturn ;. G5 k+ |# f- P' R
if (negocios_autorizados == false) // are we outside the trading window?
: g# j9 A+ r; A1 |7 i+ ^return ;
: n; x" {9 l$ R* ?1 Y. V//--- We are in the trading window, try to open a new position!
: n9 x4 t- j$ p6 N- b7 Kint sorteio = MathRand();: ~" }/ Y9 W/ p1 O* v$ @
//--- Entry rule 1.1# e1 {/ a# T' l3 q7 T
if(sorteio == 0 || sorteio == 32767)
4 ~- ^* ?3 S, z7 \8 G' K6 X/ Z, sreturn ;
9 m, l5 x/ \4 |6 jif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy9 L2 X' Y- \1 F+ n; T
{
8 V6 T+ N1 N b. `negocios.Buy(info.LotsMin(), _Symbol);
: P" i6 m' L! |1 m- }}) W: N1 I! B0 S! I: E; w; v
else // Draw rule 1.3 -- odd number - Sell
4 i3 N. V- e2 w3 R{
; }% [9 f; U) g b+ \- Lnegocios.Sell(info.LotsMin(), _Symbol);! X5 I* D( p! {+ j4 o
}; S8 X& D& h3 x0 m" R8 s
}
! G7 C) G. f% L! ]//--- Check if we have a new candlestick...
& P2 I5 ?% g8 h0 wbool tem_vela_nova(const MqlRates &rate)+ Z2 u, k% \0 J- ~: L" v
{3 C# Q" n/ x, E4 W) x5 m
{8 d: V+ `. U8 e) B+ L
ret = true;
* b- y$ Q; m+ K1 K9 c( gclose_positions = false;" _! ^) K+ O2 T
}0 j. e& y5 t. C
else" |: j w8 o. `$ Z& j
{7 j, H; J( Y1 w. J) @
if(mdt.hour == 16)
|+ t2 ]' O6 }& \5 F0 Wclose_positions = (mdt.min >= 30);
s+ i0 M6 c f' ?+ A}$ Z* J, Q. ]) w2 G& T c8 }; C
}
" X: C3 q+ m! Y2 I8 N- V+ M& ureturn ret;% l, U2 \9 M) |
}
* R8 u) ~0 ` T3 w5 ~//---3 P/ ~" j ^" Z* O/ F
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
x% A! Z8 @+ u( ^9 p, x9 x5 G{
" t% ?& \2 s5 W1 |3 @) Nif(PositionsTotal()) // Is there a position?2 X/ B( `: c$ n" q8 c
{
! R' z& z8 x' }, `: j8 Ydouble offset[1] = { 0 };( t) Q2 T0 u2 Z# B( b* W0 D
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?! w' L! R3 o2 _, f" Q
&& PositionSelect(_Symbol)) // Select the existing position!0 f1 g" _" Q; r* z
{$ ^0 B- C s2 G6 Z3 N1 A: j1 F
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 Q& r/ {$ Q1 l1 X# K" D* v
double SL = PositionGetDouble(POSITION_SL);
' C# A( P4 i( G; }double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
r) X% ?+ C5 p) k4 tif(tipo == POSITION_TYPE_BUY)
8 ?! n0 c" b0 F$ q{" a7 i5 K/ E. U5 y/ q7 U
if (cotacoes[1].high > cotacoes[0].high)
' I+ P3 H8 Q4 s% _; F W{! ~* g- d: D6 d; Z/ l, d
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];4 p# _: Y6 C; ~8 W7 d0 ~0 f
info.NormalizePrice(sl);" H0 r: K3 \! }
if (sl > SL)
% Y" Y& s0 @/ ~{
/ Z' Y3 {; h N+ L) ?% q fnegocios.PositionModify(_Symbol, sl, TP);
9 \1 k3 x! K4 D: T) n) B}
( L% B+ b$ ~2 o: R+ A}
0 A b& n l# D& x: I. `' f; T}8 I+ c$ c8 z/ W0 V8 n8 x8 n# Z
else // tipo == POSITION_TYPE_SELL
! n( m8 b# s; O{3 y4 @2 r. R1 L; V
if (cotacoes[1].low < cotacoes[0].low)1 q0 J8 D; B2 ]* }) {7 h8 R. N
{8 D2 H' Z6 T4 A2 O
return true;
0 a/ Q* f5 G; T4 r0 B}1 v: k+ R7 X7 n3 Z; U
// there was no position
4 Y* \' U$ L3 z C: preturn false;/ C+ C; v. u. M/ z. {; F! C6 _
}$ _- V7 M* `& w) F9 j8 x$ o
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。1 c- q t7 x( \/ \, ]' _5 P2 N
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |