启动交易模型,并构建 EA
1 h1 G$ T' h' r/ t+ j& k# I/ P在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) L6 \1 K8 ~, f1 v& A# A为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。2 q; ^% j$ _8 s* `) ^
以下是制定这些规则的代码。
" a* i& Q. c& `# s: t% _% {/ b j! e: G//--- Indicator ATR(1) with EMA(8) used for the stop level...+ [' s3 m7 s! v
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 i5 C+ y- I1 y% H; H
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
! Y$ D, ~+ T4 \8 G% J//--- Define a variable that indicates that we have a deal...2 Z' ]) N \8 \
bool tem_tick = false;
" C% p& n: v$ u0 r" A//--- An auxiliary variable for opening a position% Q5 c9 y8 L- A" c$ a0 t/ q5 C
#include<Trade/Trade.mqh>
4 N+ k4 l. ?, s, n0 J" V7 V, J#include<Trade/SymbolInfo.mqh>8 D& s2 q/ k+ m& t# e2 T( k8 _& z
CTrade negocios;! |7 d; n( ^6 {4 u$ ^3 S
CSymbolInfo info;
) A8 c9 _; S# s- g//--- Define in OnInit() the use of the timer every second+ W3 H1 x$ X' D, o' o
//--- and start CTrade
9 x' W z8 |1 P. Vint OnInit()
) E" c# C# p: @8 D& S" k{
; l V# U; W7 f* |! {; T2 J! r//--- Set the fill type to keep a pending order1 f7 A$ M& p/ l4 `; L3 z' b
//--- until it is fully filled5 q) K' g7 }. w" i6 I' }: ?
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
- Z) v" j7 t5 _$ N' m# h8 v//--- Leave the fixed deviation at it is not used on B3 exchange
) L! O6 D. y4 znegocios.SetDeviationInPoints(5);; ^) r" m$ [. h6 d
//--- Define the symbol in CSymbolInfo...2 _4 p c$ s, @2 X* ^3 ]( a
info.Name(_Symbol);
( Z8 G+ `; e1 z8 q; W: m, x# u3 w: q5 Z//--- Set the timer...
/ ]" {$ C, I$ D' f; n; U4 kEventSetTimer(1);: q9 D, {9 O( N/ [( f0 \3 m
//--- Set the base of the random number to have equal tests.../ x+ x3 h- z9 B9 F) U$ ^
MathSrand(0xDEAD);4 P( u, x! [' Z5 ?( ~+ X$ v
return(INIT_SUCCEEDED);
% m$ x# t' G X" L1 M4 K}
& A- _3 p3 c# p/ U//--- Since we set a timer, we need to destroy it in OnDeInit().
; V+ \0 E( l; X3 Vvoid OnDeinit(const int reason)
! \& j6 s* M, I- W, W1 `+ d, d{
5 e L: W; _' L4 W1 e# O; QEventKillTimer();9 G3 F' A J( D, o$ M
}
5 g' U9 [$ ~0 g$ l//--- The OnTick function only informs us that we have a new deal
% X/ x. y. |: |& S; Xvoid OnTick()
. J; u+ L/ Q# ]$ h{3 N3 n: Q7 V7 j3 C3 }+ e
tem_tick = true;- ?+ \$ F& H- R/ t0 u8 f4 P" F' h
}( R% |* i% t- ?' i/ R8 K" ?& X
//+------------------------------------------------------------------+
' a$ t5 h T/ u, t1 w2 }, z//| Expert Advisor main function |6 x1 [5 ~+ e! A: t8 ~9 E$ g& l' S
//+------------------------------------------------------------------++ `7 B( S& I! I% `0 N3 r
void OnTimer()
2 x: B. o! Z1 k* u B8 s{+ ^- J# k7 @2 j7 C1 ^( c
MqlRates cotacao[];5 D- b% U: w; A$ c" _- b9 W
return ;9 Y* i1 p5 A0 A, o5 w# |
if (negocios_autorizados == false) // are we outside the trading window? G+ H. P/ X+ }; a. O, W
return ;
# \ X/ t( W4 J) R/ y//--- We are in the trading window, try to open a new position!% K+ _, G, j$ z& T/ ]! q
int sorteio = MathRand();
: w, Q( Q- @( g7 v; b//--- Entry rule 1.1& s6 X" C! i- w& u+ r) J g
if(sorteio == 0 || sorteio == 32767)
3 d/ ?& h- Y4 t" x0 f% n9 Creturn ;6 m# X5 O8 U7 q1 ^3 O4 I) P
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
% e# f2 E+ h$ y- e{
9 `: C- `! V; P6 f! i6 Q$ q5 `negocios.Buy(info.LotsMin(), _Symbol);: i! ]# S! r) k
}
- B6 J; w: I6 lelse // Draw rule 1.3 -- odd number - Sell
3 Q' h; {+ K/ b9 N{
) U% ^7 |& H2 U4 s& H w8 {5 Rnegocios.Sell(info.LotsMin(), _Symbol);) ]0 H3 ]% `8 w, |, K9 \4 y
}* z* N" z* ?/ Q3 R
}. R& m4 J# i% g
//--- Check if we have a new candlestick...
. b$ a1 K/ F% ^" x* j3 ~bool tem_vela_nova(const MqlRates &rate)+ {+ l" g1 I& T: w# x
{5 j5 R% E2 i( N. p5 h
{
$ n3 j+ X, m6 R) M. p- L8 h0 uret = true;
' ?6 H% M& `# V$ }/ aclose_positions = false;
# ?$ X, L* P7 b) h0 n}5 c4 e2 x L' f$ h! ]! j2 c
else$ q0 w" I1 |' n4 V
{/ u! R4 @/ c: z
if(mdt.hour == 16)
h0 z; m5 U( }! G: G0 T* zclose_positions = (mdt.min >= 30);
+ E! i* e5 M2 w6 x0 E' V$ T}5 C1 U, X# }3 u/ ?. _5 A
}
% k. r- a4 J1 wreturn ret;% ]" v9 H7 J& n
}
6 y# ^( E: n& p2 c& Q/ N( K# G1 G//---
1 }5 g9 e& u6 ^! @# l' x! Gbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ {, f! ?# n& Q' u' h/ l9 C- K2 z
{5 r$ p6 ?. Q6 h2 y3 B4 H7 H
if(PositionsTotal()) // Is there a position?
- Z/ ^9 Y: D- _, }7 y5 r# V5 ]{
( P4 N1 @5 @" B( F6 I* A5 O. D& Mdouble offset[1] = { 0 };% K" ^! w5 S4 Q1 h
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?& z, L/ |% T7 U* l
&& PositionSelect(_Symbol)) // Select the existing position!% D4 R, J2 W: G) |
{
( p9 m8 V1 w4 q& _ z, QENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
, }1 @: F# ?- M6 hdouble SL = PositionGetDouble(POSITION_SL);
: L9 p& x+ `& k- w3 n' pdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
3 M5 W# v* ?! B! x: S* X" z4 Yif(tipo == POSITION_TYPE_BUY)
) G0 N9 F9 ^0 c$ t9 a{
5 t: K, I& Z$ ?if (cotacoes[1].high > cotacoes[0].high)
7 j! c4 y& `4 B& ^5 A4 a7 a{
) _7 A6 i* H3 X! d1 Z+ l6 X! Odouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 K2 Q+ x9 k- T' r) Q* E
info.NormalizePrice(sl);
( e* s% N% `: Y0 Bif (sl > SL)
9 Y( G5 `; `% \{
; t" I- P5 X3 y4 Q; ~negocios.PositionModify(_Symbol, sl, TP);; e% i% {. Y6 R% |3 }( W& ~
}
; K9 v/ {& R# E/ F- F' m. a}' B2 ]# \" s0 Q9 G5 I/ I+ D8 c2 S
}7 R: J/ i. B4 t
else // tipo == POSITION_TYPE_SELL9 z( Y; k' U, u1 N# u
{6 n2 p! ^4 F% ]' c3 o
if (cotacoes[1].low < cotacoes[0].low)4 O5 j9 l: X9 f' P. E/ J* ?
{
# T; j9 x+ Y8 Y, z6 y3 o: k/ ]* M) ^return true;
9 @: r+ G5 _1 t: b. R$ _}! o- U7 N) {1 S* J9 W. D% A/ J( J
// there was no position8 |' C* M6 o- s
return false;
o9 O* x9 j: ^+ L& k8 T}( U3 J& m; Q6 @% U) q9 I, A6 ]
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
, j3 I* r# Q2 ?/ ?到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |