启动交易模型,并构建 EA- k& M+ G. @6 [ B
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。" g) h. J9 H" s7 b
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* f. J/ [& E" b. \' q
以下是制定这些规则的代码。" f+ [, `: F8 l$ W0 ?& h& f9 z
//--- Indicator ATR(1) with EMA(8) used for the stop level..." k# }3 b# V$ R9 `& l4 W+ Q
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);% N4 a8 W1 C0 T4 G2 a
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);, a; k+ @( F$ T7 [5 L* ?1 G4 [
//--- Define a variable that indicates that we have a deal...% f, b4 g7 l2 r- | v
bool tem_tick = false;8 X9 u( h' z" Z9 ]
//--- An auxiliary variable for opening a position
& H1 w- m3 Z6 P* y9 s#include<Trade/Trade.mqh>
( @+ B$ ?4 Q! X" O0 K% g) p- ^" l' n#include<Trade/SymbolInfo.mqh>
$ E( V& r3 G( L+ y- \3 r9 CCTrade negocios;4 V1 n8 J2 Y: Y' D. N& }+ D
CSymbolInfo info;
; R$ C1 F4 b/ {$ r! z//--- Define in OnInit() the use of the timer every second
2 ~9 I8 t- c$ A+ x1 v5 |6 _# a1 \, O//--- and start CTrade
. ]1 T: Q- f8 ~7 Uint OnInit()7 d `- ~1 O' C" d8 Q K$ E
{
3 A; a2 I" I3 f. @//--- Set the fill type to keep a pending order
* ?9 r. \& @( I! M' g//--- until it is fully filled
2 }. }2 x0 E0 V" znegocios.SetTypeFilling(ORDER_FILLING_RETURN);
4 X7 y( k, m/ L; j4 \2 i//--- Leave the fixed deviation at it is not used on B3 exchange2 n1 L2 k! ~$ D! s$ N9 d4 J- W
negocios.SetDeviationInPoints(5);( K5 g4 z9 h/ P& P) H
//--- Define the symbol in CSymbolInfo...
: z( y# V, f9 u7 j+ @6 @7 x3 winfo.Name(_Symbol);
$ j& y7 X$ O: l2 S# ^: J//--- Set the timer...9 Y9 t. V4 Q' C# m
EventSetTimer(1);
6 T* [/ K- q* j* A//--- Set the base of the random number to have equal tests...$ _2 M% b- W" o5 M4 c0 o9 A1 @
MathSrand(0xDEAD);; N j+ {9 J$ b% R
return(INIT_SUCCEEDED);' n- {. T! n. L
}! O; i* N" W9 `# x( A3 R v
//--- Since we set a timer, we need to destroy it in OnDeInit().1 Z. V' W1 ^: h( `; J" s# ]
void OnDeinit(const int reason)8 r, J% H( J5 Q8 }
{7 @2 \* E6 C5 B! S& s
EventKillTimer();
( ~4 r( j3 M% u1 R}6 s1 W( g2 `8 ?# ~" V. s z
//--- The OnTick function only informs us that we have a new deal: R1 y1 s: j, k6 z9 p7 c. {8 }* ]
void OnTick()
! o; m5 {/ `- V4 V- ?, X{
3 m, L; K+ }/ w0 dtem_tick = true;
: N8 h4 J1 U* v7 X3 J}1 w1 E6 r% n: x: I" [
//+------------------------------------------------------------------+. Q9 T% \, g" ^
//| Expert Advisor main function |* q, @$ }0 T V ^* j7 ?! t8 k
//+------------------------------------------------------------------+
; Z8 y- h. U& G8 c- nvoid OnTimer()
G: q2 p) z6 [9 i r5 e{& D/ R% `4 l- g- @
MqlRates cotacao[];0 d" E L6 g3 H& @2 C1 E2 y* F
return ;
, Z2 Y) Z. l5 F' q3 j- J1 nif (negocios_autorizados == false) // are we outside the trading window?0 u. E0 p7 V% T$ w+ P
return ;! ]7 w7 V, o, L' f# u
//--- We are in the trading window, try to open a new position!; Q: [9 y* r& d( Y
int sorteio = MathRand();
8 M6 I- j1 ^( z) w' f; p& t//--- Entry rule 1.1
4 q: x7 I# p* L- n, c( q1 ^if(sorteio == 0 || sorteio == 32767)) y- K8 T Y5 g; w& ?6 z
return ;1 z4 {- m$ T9 O
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy$ c; j, e& p: p; e, ~% q; ~$ X& B+ v
{, }0 z9 h, A* ?( X
negocios.Buy(info.LotsMin(), _Symbol);: l/ ]3 p- a/ U% E; Y: S
}
' I1 _; @( e1 X6 O( }$ w+ X$ Celse // Draw rule 1.3 -- odd number - Sell
0 `$ p. a! t8 E9 t{- d) ]! q; p# Y. A. E7 y$ d! K
negocios.Sell(info.LotsMin(), _Symbol);. i$ J; s' }4 N9 J. ~
}
! {# }; b& m/ j6 l- {} V7 y8 v& A1 C ~
//--- Check if we have a new candlestick.... h$ i# W- M7 X' L1 Q
bool tem_vela_nova(const MqlRates &rate)/ N8 k+ V2 P5 e) k9 E- z
{9 y/ f0 \9 Q8 O1 D" P, l5 R$ q) L/ l
{. A5 M+ A6 L8 D# d' n; X1 ~
ret = true;$ O( j; L6 T o- N4 X. g) x" K6 C% v
close_positions = false;7 ^2 G; A! z1 B+ e4 R5 A5 J. q
}8 R2 \+ J+ W* H
else
. L0 {5 }' Y! r, `, C, [5 I& w- u{$ [ N& e& [/ l( v# w- ?- Z% d
if(mdt.hour == 16)# ]8 e8 Q% } x8 N- ~+ E$ d
close_positions = (mdt.min >= 30);+ L+ B$ ?, [; c7 R W2 l8 Q$ {& Q: `* u
}
# N8 P( A& b! Q2 \" `}
3 x$ j, ?8 y/ d9 h* i* Breturn ret;- \0 Z0 \/ a0 ^, t: H9 Y. v9 n$ @
}
) L) o! ~/ P" F% p0 q//---, G k# j1 i5 r- @6 l
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
# R+ i# K! C$ S+ u; t{
( D" m% |+ I/ u, D) Bif(PositionsTotal()) // Is there a position?
, @! ?( Z/ _ A0 E{
# X9 |$ l' h- R3 Y8 @double offset[1] = { 0 };' A, ] F) w% b' j" z7 m/ V
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
4 I$ }5 N9 Z7 O3 k4 D& i1 @( t&& PositionSelect(_Symbol)) // Select the existing position!
: M. h& K0 i. T' _: J7 f) v{
4 N4 Q, w( a/ b0 @: g3 o5 m# HENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
' t0 H. X- t2 Fdouble SL = PositionGetDouble(POSITION_SL);
- Q8 m/ {# U) b0 d, U1 \double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
. Q4 v5 w, ~6 s) b6 w5 [' s- fif(tipo == POSITION_TYPE_BUY)
+ A. a* z( Q- c/ A% _) { p{
" X q% ]# Z2 r' J9 iif (cotacoes[1].high > cotacoes[0].high). d {9 P: A. X! r* ^4 |) M3 u( U
{4 ~2 f; O1 V- l3 Z5 K! e! H
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
) }8 j5 I, Z8 F# _7 Minfo.NormalizePrice(sl);: l5 s' t9 v* p1 G/ Y2 ^
if (sl > SL)
0 }+ v* w3 a U5 @( B{7 H( a# `% o6 V2 V! B: B
negocios.PositionModify(_Symbol, sl, TP);; W/ U3 o3 m# k7 {
}! s7 X1 }: u) v7 ^$ P) O/ O
}8 Q" G W0 ~: E* j* L1 L, r& V1 ~2 y
}6 G. E1 H+ B4 B1 @0 v7 _& N
else // tipo == POSITION_TYPE_SELL
0 b! q8 o( e+ q: a{ x* p. S0 q# y( O
if (cotacoes[1].low < cotacoes[0].low)
4 {3 {! @; E5 k" W2 B{
v# q- x" E% W& Dreturn true;
% A9 r2 L4 @/ x' v& ~* G}
: \9 T) l2 Z/ x0 {$ D7 z// there was no position% j1 c( u! y, m* @2 P* q( ~
return false;
: v( M7 y* J" L- F8 j& ]; x}1 i8 _2 d l% u- _; a1 [8 P
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
7 N+ x- X8 V( n/ z9 j) ]! j到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |