启动交易模型,并构建 EA8 y8 K# E0 z) ]1 D, p4 p
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ e0 E: x# t1 B- Z/ {) ]
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
0 Y8 v2 w4 c8 l4 d以下是制定这些规则的代码。
, i- K/ V" r. c" ^& \/ t9 b! Y9 R: {//--- Indicator ATR(1) with EMA(8) used for the stop level.../ [% `! r8 d6 j7 k, @* |& \5 b
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
) i+ h9 q0 b4 Q4 o7 h' T4 ^int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
$ J0 t5 t& T( P//--- Define a variable that indicates that we have a deal...( ^! N- t$ L3 T9 U( I
bool tem_tick = false;
- N" s5 n O; Q( d# ?' M- e5 I//--- An auxiliary variable for opening a position2 }& ~6 z4 S) ], }# l- J8 u
#include<Trade/Trade.mqh>
8 P* L6 I1 b" x$ S7 }7 N#include<Trade/SymbolInfo.mqh>% x% v6 [* q" l& Y7 K2 K
CTrade negocios;& ]5 ~# o+ j) K4 j
CSymbolInfo info;. D6 g7 A: u, N: d
//--- Define in OnInit() the use of the timer every second
B6 W2 N* A2 X, Y) ` W//--- and start CTrade
' q. u% t' k6 z( a; w1 y8 x& L& ?int OnInit()& c5 D6 i5 |. _8 u
{
( w* t& `2 @$ Y/ H0 E//--- Set the fill type to keep a pending order
4 R6 f) ]9 ?( C2 R//--- until it is fully filled
+ {" X( k- r# c/ l+ K; Tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);7 W: m: O3 Q5 x! q, C6 }4 Y4 L
//--- Leave the fixed deviation at it is not used on B3 exchange
; L( g5 H& ? j0 E4 Dnegocios.SetDeviationInPoints(5);- Y7 y1 u1 J7 H
//--- Define the symbol in CSymbolInfo..." J- f; j4 s' s$ G n, A& i
info.Name(_Symbol); ~! Z' P) U% Y5 r# j6 C* Z
//--- Set the timer...* M) v5 M( U. |# n- h$ b
EventSetTimer(1);
1 x* ]* w0 O% F0 Z9 D+ ^% ?//--- Set the base of the random number to have equal tests...! N4 `0 \2 A( l
MathSrand(0xDEAD);# l' J2 Q5 j! p1 k1 I4 d/ B
return(INIT_SUCCEEDED);
( C9 F5 |. s5 Q2 U}
1 L: T2 P7 R3 B( P- n# w//--- Since we set a timer, we need to destroy it in OnDeInit().( @, ~2 n2 ?( _* S5 A3 K
void OnDeinit(const int reason)/ u) i( ~; f! e) K+ b, ~
{+ Z- ~* A" B! ]- J! P9 f' d! N4 o0 p9 y" H
EventKillTimer();3 O( \ \3 Z0 H# V6 d2 y9 ^) h
}8 e+ ]% f: b" n4 h, G+ w8 K+ z+ m! j" U
//--- The OnTick function only informs us that we have a new deal5 h8 t9 c* B5 H
void OnTick()
5 v5 b& n( I2 l5 N$ w" @{
, B" v \( e4 F; a" y( E, Z) }% ytem_tick = true;
2 _, i2 F/ Q% i" V* G) v}
' l# ^& O) b4 T/ j2 b- m//+------------------------------------------------------------------++ ^& {$ z. G4 l% F4 L
//| Expert Advisor main function |4 G ]) Y+ g9 B' s0 R/ J$ q
//+------------------------------------------------------------------+( o3 ]/ [& p4 K& u
void OnTimer()# k5 {/ ` ] ?" l- H
{
5 J, m9 v% l7 Y. h, YMqlRates cotacao[];( i$ \% g+ u' t$ e3 c6 C4 `/ P
return ;
% V' O7 J5 s3 _7 }6 e5 g8 x& `if (negocios_autorizados == false) // are we outside the trading window?
' @/ A; a& x8 k2 M' n h( M: b0 \return ;
3 @7 _/ w+ d% x) r//--- We are in the trading window, try to open a new position!
" j3 z7 Q' C% K8 y, C, T! G$ _int sorteio = MathRand();
4 Z9 [! [" g5 p9 a7 _3 A//--- Entry rule 1.1+ ~( `0 h. c8 A2 ^' ]6 m* T* K
if(sorteio == 0 || sorteio == 32767)+ W8 @' l3 h; O7 U
return ;
) B+ l! C# {$ P4 b& nif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
+ C0 t. Q' q6 S! P% Q2 p$ s& i$ l{
, f% G1 N! B2 C4 z, nnegocios.Buy(info.LotsMin(), _Symbol);+ { e' B3 }5 h4 T6 j% S! Z
}
6 `" o$ c; a# c; Z" }else // Draw rule 1.3 -- odd number - Sell1 M0 V6 N, B6 y e( L2 P1 a4 v( T
{
5 Y; F# D, a, P# h! pnegocios.Sell(info.LotsMin(), _Symbol);
4 W" `1 Y, p, F! t+ f, D7 m}: D- a2 E y% \: _" G4 i! c7 M
}
0 L; `$ o3 {9 k4 L* p: v {8 N//--- Check if we have a new candlestick...9 ^6 B' D9 O4 U
bool tem_vela_nova(const MqlRates &rate)
- k q1 E- ]; @ O& a% x( Y9 G5 N{
+ g7 Q# w8 N0 [4 S( o- E: N5 B{$ ~! h6 [0 _9 V0 |1 H1 G0 {
ret = true;
; b1 w4 U5 I9 M6 n& aclose_positions = false; X0 ~0 x9 q$ J
}
. i/ v$ G& h, gelse
9 e! ~( W- w+ O$ e, t& U, c) ~{
. X8 C0 R% S$ ]- Q, \4 _if(mdt.hour == 16)
0 u" Y6 N$ q& Z+ S+ u# [close_positions = (mdt.min >= 30);" ~: b" ^: e0 ^. _. w+ d0 K
}: X+ J! T2 k+ C3 }# D }
}. a: `5 ?- p |- Q: a% i
return ret;
; v* D% ~$ Y; l" [1 ]' _. y! Q' M}
* b' R* A) k* B7 C# p//---1 ^0 S3 e; f4 l
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])* s4 g, P ~/ w# M) g6 W3 w
{
) m9 a. i/ h; `2 E1 l/ cif(PositionsTotal()) // Is there a position?
9 t9 Y h J" ?3 m{- D1 C5 G& ], e. {5 ^ Z
double offset[1] = { 0 };9 k) x! y8 ?0 p4 ~' C" b% V/ ~
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
# {8 v6 v4 F: K/ j( q. x6 k5 M&& PositionSelect(_Symbol)) // Select the existing position!
5 a6 k3 F7 R4 B# z# y( P) f2 B{
8 z* O1 C( R$ O7 P0 SENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
3 K8 {! p% x+ Rdouble SL = PositionGetDouble(POSITION_SL);0 @9 @$ ^/ l/ c- s
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));6 m* L( L% p$ p) g3 J1 c, f7 f
if(tipo == POSITION_TYPE_BUY)
4 ?3 Y+ Q. v2 E: k$ Q8 z{3 b2 \6 G9 v+ g o; d
if (cotacoes[1].high > cotacoes[0].high)
5 [8 C, ?2 J( e0 I ?) j{
+ h+ F+ _/ z, W! zdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
5 ~8 n% e) Z+ G* h+ u+ Ninfo.NormalizePrice(sl);
# O6 W/ V* r g4 o6 h/ Y9 Sif (sl > SL)
1 W; I& X7 }4 N$ \$ Z{
& s$ m! u' c* Qnegocios.PositionModify(_Symbol, sl, TP);
0 _- l# U- x. ~4 P}6 O1 j0 m7 d( b2 s0 H
}
! H1 S; e: Q: m2 U) m/ Q; c}
* w K' d. h, |+ l* O3 g$ [else // tipo == POSITION_TYPE_SELL+ i) W$ {7 t' D% h
{' G, Z1 `- M- ?; [/ L" Y$ q0 W0 Y
if (cotacoes[1].low < cotacoes[0].low)
" _# ~9 V; b( }{
8 ^/ ]! ?$ T8 T5 A* B+ `return true;
: a' Q% d4 L' G}' Z i* Z }2 R. n, i
// there was no position( X$ f0 a- l8 L2 H& i9 e' n
return false;
, A% k) l( T: u* d G7 G; R}
1 ~+ T/ O; A+ K我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。( h. D1 w+ L3 S
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |