启动交易模型,并构建 EA" m) d0 c+ n" ]2 L+ X
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。7 P6 J3 R) E9 ?$ u( ?
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。% P: @5 q M6 Q1 M" Y. I8 k" z
以下是制定这些规则的代码。$ P" ?% ^5 L$ w7 o* T f/ O
//--- Indicator ATR(1) with EMA(8) used for the stop level...) u- o _. m* L$ t. ?
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
! u/ |/ _& B: {" p, G0 d% b; ?( e& E4 jint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);/ v- e7 X4 d$ J- w; ^4 R" B) Q
//--- Define a variable that indicates that we have a deal...
4 f+ F. m: v3 `( D0 ^5 f( qbool tem_tick = false;
, d4 R# y- Z3 z5 s//--- An auxiliary variable for opening a position
0 Z' M$ S. L" k6 N% M( i#include<Trade/Trade.mqh>2 k3 u, y7 L: ]. q7 Q4 r, U5 e
#include<Trade/SymbolInfo.mqh># h* q! h7 I8 v' E5 ]
CTrade negocios;
" G7 k8 x; M8 J8 Q! D7 HCSymbolInfo info;( y0 c, }6 r2 [+ u7 b
//--- Define in OnInit() the use of the timer every second, |8 `6 ^$ }( ?8 P# v
//--- and start CTrade. C2 H6 o3 }; I! D; U2 ?' | f
int OnInit()$ s% [$ y& Q( \/ ^4 z6 H, u( [* w
{, |# e, V7 I8 n. g
//--- Set the fill type to keep a pending order
2 W, r- X4 _9 g m% U4 i+ ^//--- until it is fully filled$ e. L( f/ _& n, x* M
negocios.SetTypeFilling(ORDER_FILLING_RETURN);4 g, V6 p u: ?5 T& v6 q- t
//--- Leave the fixed deviation at it is not used on B3 exchange
- j# m/ v5 z3 _4 P7 X+ m9 m9 Knegocios.SetDeviationInPoints(5);
( j. L( N/ v: s. t9 @6 A//--- Define the symbol in CSymbolInfo...
" Y1 ~3 ?4 u& B4 S; S; |$ |info.Name(_Symbol);
/ j! R$ f1 A2 o* d, Q/ y1 a//--- Set the timer...
3 A7 f7 c. @6 C2 o; A+ AEventSetTimer(1);
6 ?4 P- w) U0 H7 G( [//--- Set the base of the random number to have equal tests...
. x, b- K, L* i m7 _2 s: `MathSrand(0xDEAD);
. E0 L2 r! f' x! {4 N4 Wreturn(INIT_SUCCEEDED);. _5 i X6 g, P" m+ _$ e
}$ Y7 V' g, Z% e9 H2 B1 T/ D
//--- Since we set a timer, we need to destroy it in OnDeInit().' f1 c7 A& z" U# p# h- ?) v: P
void OnDeinit(const int reason)( }0 G% O9 S2 G2 h- r) ], T/ q0 k
{
& F9 x# {1 s! [$ c k( `# ]EventKillTimer();
# }4 I& i1 Y7 {; D" s; P}) Z' t v" f4 Z$ F2 j9 X
//--- The OnTick function only informs us that we have a new deal8 x A1 L/ d7 Q4 G. Q! t* B9 O
void OnTick()
4 L; L4 |, ]$ h# [! t{( v& |; u& Y( l. {% I1 g
tem_tick = true;" G/ b: R8 }. V. d! @0 d
}
) D) U/ T3 h) t, H5 q4 h9 \//+------------------------------------------------------------------+* {% \4 V5 A" a+ X$ Q& ~) `" m
//| Expert Advisor main function |
! \' [! ]( V) g//+------------------------------------------------------------------+
0 W: v: t" R6 ?" a5 nvoid OnTimer()* m; {; G: |) O& X1 N' j! c
{) J: _3 ? p% A4 O
MqlRates cotacao[];
/ T8 ` c( O4 x- K3 x2 E. Q# Ureturn ;4 D# Z1 X T/ q! ?1 C& `7 x
if (negocios_autorizados == false) // are we outside the trading window?
, n; A0 r3 J0 v& x6 o3 d* ^+ Ereturn ;
/ v- T; L# L9 n3 k2 _! K//--- We are in the trading window, try to open a new position!( X P. F3 M2 B3 n
int sorteio = MathRand();
$ M/ [+ i9 h W/ L//--- Entry rule 1.1& u; S( n7 Y6 S1 H
if(sorteio == 0 || sorteio == 32767)
+ D+ P. y0 W, J* q: Q. j/ A3 c( `return ;
. D. ?2 G! w) M6 _3 gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy3 {& d4 j, j3 x4 m+ e) N' Y
{
% H* w5 X. ~) w" \negocios.Buy(info.LotsMin(), _Symbol);& t7 O: V) M, c6 s
}, u8 D: J5 s4 M1 c3 l. v W
else // Draw rule 1.3 -- odd number - Sell: g% g. F9 L4 U
{
( s8 U' h: Q2 `* vnegocios.Sell(info.LotsMin(), _Symbol);
u% k' c' h* ^- K8 G0 H}
9 l* j3 z$ R% }}& h! N# ^& }0 B5 V: ]
//--- Check if we have a new candlestick...
9 D/ H& Q# c( w s s5 h& j# {' Dbool tem_vela_nova(const MqlRates &rate)4 F2 Q6 o- p9 U& v
{7 L0 I2 ]% I5 B+ w9 {! T& \
{
2 p; A, q0 C5 E- Kret = true;
! C% ^/ G% Z0 s% ~close_positions = false;5 ]7 { {" T: y: F
}
! ]2 {8 ?: @4 n) l% J3 k+ z7 ?else$ k+ r) z1 |4 y1 @: n- N2 C' f
{
q6 i+ @, D r, t# lif(mdt.hour == 16)+ ~ N$ D5 `* e) e, V8 B
close_positions = (mdt.min >= 30);# L1 H2 W- {8 {$ w! N5 ?% o
}
1 E" d' s3 I1 i5 p( L+ P* O/ X- k}
# k+ u) _/ _9 X g9 K7 _, Creturn ret;7 t5 y3 s% W- ]8 W
}
6 Y4 G6 J+ j1 o3 w4 q6 w4 j//---
$ y6 W$ m c. u0 }3 D7 S2 qbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
. a& t5 w+ N) z% S B{% l" ^# `4 J# f1 \
if(PositionsTotal()) // Is there a position?' \ b5 c% [1 s0 U' p+ ~
{% C& l) _& o3 t1 r" [2 }4 M
double offset[1] = { 0 };) h& Q# f" l- [
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?/ c1 c. L* }" p8 A& ?# a2 Q
&& PositionSelect(_Symbol)) // Select the existing position!
2 p7 f5 [! Q2 t+ N w9 T8 p{% K, k. x. ?/ A7 ^/ i- O1 ~9 U
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE); F5 Y6 ~8 p) a6 O# _
double SL = PositionGetDouble(POSITION_SL);
& \9 h* Z( R3 K" N/ K4 Edouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
" h- C1 j h" P0 X+ F, A) ~if(tipo == POSITION_TYPE_BUY)
: a" I5 s1 \' e( r2 R{
. e6 ^0 [- V! O4 V1 B, m2 bif (cotacoes[1].high > cotacoes[0].high)
( q% I+ D) ]' z5 F' T. x, p{
) B" J5 G( h- q6 M& B" sdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];. w7 n, x9 x O
info.NormalizePrice(sl);/ ~4 b3 h8 g2 F ?" ^ X
if (sl > SL)) b6 {: r' Z$ @9 }& o
{/ M0 V. f# w# }$ p2 l, z- u @
negocios.PositionModify(_Symbol, sl, TP);5 f+ g0 ? e- p
}
4 h7 G: o3 p/ P6 r3 L}9 \- r& Z0 n& N
}7 }# V& J& x( v6 Q B9 g2 O
else // tipo == POSITION_TYPE_SELL4 ?+ U& j" L! @$ n- \6 ~
{1 j z/ A5 D; }# w+ ~
if (cotacoes[1].low < cotacoes[0].low)
: t6 | ~- g/ S: W4 r{! X. D/ M% ]( Y2 N
return true;6 W. P3 `& J1 R' T. J, l$ ]
}
' g( Q/ `6 Y2 J5 V, T// there was no position
, t s) c! G1 r) Kreturn false;. Z1 V z; H) N* t/ d! ] v
}( `, ?( K, D. P2 E, W
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
6 P1 x9 U2 |" k到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |