启动交易模型,并构建 EA
& i. H2 ]' S7 J- u5 Q在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
/ v- V1 _5 G3 C4 \; N+ C" H为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
0 T' M P; a3 }9 R& [以下是制定这些规则的代码。
* q. r: U" g* G" x: M//--- Indicator ATR(1) with EMA(8) used for the stop level...& T) x3 D7 F" H. M8 ^, k
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);4 B) F2 Y$ V' t& B% H9 M5 G
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' V& I' W5 [4 f7 h//--- Define a variable that indicates that we have a deal...
9 F7 a$ g& W* {. u. J4 O2 o9 L1 ~bool tem_tick = false;
: E! Y( z, |; B0 Y. Y, ]% [! p//--- An auxiliary variable for opening a position& D- }1 g4 v7 b6 J
#include<Trade/Trade.mqh>; ^9 a# B! x( W; A* ~9 A2 w6 `& ~
#include<Trade/SymbolInfo.mqh>
3 e' R% s6 m7 G/ ^5 D; c( C& hCTrade negocios;' D, B6 f$ Z" S$ X3 A8 ~% D8 d/ g
CSymbolInfo info;
1 t! ~, ~5 c6 Q+ k0 t; n" f: c3 s//--- Define in OnInit() the use of the timer every second. U# o0 v" U( Z* @; v* Z: r
//--- and start CTrade* c8 B; _0 f) D) T
int OnInit()9 i+ A1 x2 Q* u- g* ~* k2 y+ Z
{
$ O1 V) Z9 b* M- `//--- Set the fill type to keep a pending order& U( [. h7 b! [
//--- until it is fully filled
" ]+ o( Q: W0 u; E3 Jnegocios.SetTypeFilling(ORDER_FILLING_RETURN); h$ m* z0 n1 X& [8 L" t
//--- Leave the fixed deviation at it is not used on B3 exchange
+ G: { i+ ?9 |+ t8 f2 v$ ?( j, rnegocios.SetDeviationInPoints(5);" `- S, @9 F9 ]+ G
//--- Define the symbol in CSymbolInfo...4 p* B% p, E( o4 \, \
info.Name(_Symbol);7 K, x3 R7 ^- {( n$ r/ `1 E
//--- Set the timer...8 W! b! k& L9 n6 x. s% \: f0 S
EventSetTimer(1);
) [- m: H( ]0 Q//--- Set the base of the random number to have equal tests...
' Y- k8 e7 t/ Q9 |5 kMathSrand(0xDEAD);2 a3 T; T/ l. \5 q1 ~. }
return(INIT_SUCCEEDED);
: }* R! v e3 E$ e8 a; w}
+ o9 {5 G9 y B; [) s8 c/ g//--- Since we set a timer, we need to destroy it in OnDeInit().
: {+ d5 i, c8 G, X) S6 L, Pvoid OnDeinit(const int reason)
8 Q. [+ \7 F f0 S( [' q: R+ G{
1 \2 W1 B; } F+ E4 C1 |EventKillTimer();
8 |6 n- Q( X* ^8 U' S}
9 Q9 l i/ A. ~; t3 i//--- The OnTick function only informs us that we have a new deal
6 R5 M4 q, U% _void OnTick()
% R T: @' p4 c% C# p, c0 F* Q' R{- S% p8 f9 \2 n* B7 ]( t! B
tem_tick = true;& k9 e( x$ Z' |
}
. A0 f2 p% |; d5 `//+------------------------------------------------------------------+
9 G4 J# B: ^1 m- N//| Expert Advisor main function |7 Z! O5 K, d' w, H) V$ p
//+------------------------------------------------------------------+
/ H& y: S: i* q8 K+ {void OnTimer()6 }; b" ^) g, _( B2 z$ G) }
{* K2 u% a- c- X! z
MqlRates cotacao[];5 A/ S) C$ C+ n" d
return ;
* q; F2 Y% T) Y+ z2 Sif (negocios_autorizados == false) // are we outside the trading window?
) x$ M7 S7 h' ^3 l# {: s3 ? m" Yreturn ;
/ C$ ]; H) W% k0 T+ z4 k//--- We are in the trading window, try to open a new position!7 P. B$ c# {+ r2 L
int sorteio = MathRand(); u+ ^: E* _4 t, R1 E0 O/ [
//--- Entry rule 1.1
& ~( N! J! R) n0 Q: lif(sorteio == 0 || sorteio == 32767)( v5 ]7 u. b! H1 i% R) x2 t
return ;
4 h# F3 ^: q5 E; i2 o0 _. I( ^if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
3 e$ n7 E. B- c! i! c( e8 |{
- c$ R' M5 ^) \0 W; m* ynegocios.Buy(info.LotsMin(), _Symbol);7 I# k' _' R" L9 ]: M: b p5 |" T
}4 y' d% R, m# o% [) l# Y- F
else // Draw rule 1.3 -- odd number - Sell
( g+ i; Q* K5 W Z7 s{
, d+ ?* _9 x- W5 anegocios.Sell(info.LotsMin(), _Symbol);* s8 p5 K9 E) r/ z7 y
}
8 V0 W0 E0 O$ p( k! ?' q}
" C6 t7 n! S$ \/ L+ L/ q/ H//--- Check if we have a new candlestick...
# w3 B a/ T: `' @1 obool tem_vela_nova(const MqlRates &rate)7 [# Q% W3 y9 C5 W) c
{
6 \* A! C! b) \+ V) w{
/ M9 c' y! B3 P& P* H, i9 I3 Mret = true;, {' J r" z; u# x" y8 n" r/ R
close_positions = false;8 A: l. q' P( q3 k0 K5 I( I' U
}
& Q: K& Q; a8 b0 ?2 qelse
0 _, K; n N* a* `/ l n{" B+ v( j5 q6 |0 {
if(mdt.hour == 16): w: ^. s. e/ i) o* _& i
close_positions = (mdt.min >= 30);! }- j5 h4 [. i! A( G0 K4 @1 X p
}0 I% U3 V% M( x+ J
}& }3 a) h, f# z+ m. o$ h. _9 H3 l% E
return ret;& m. Q2 W! e% @# t" S6 q8 k
}) |& d& O# R+ K4 W: o/ `+ z
//---
6 Q& o8 G$ a; V5 z2 p/ L" ?bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
. F0 f! O8 ?0 b' l{
& k% C, A, o# U: E1 J2 iif(PositionsTotal()) // Is there a position?
; W5 Q8 t9 q4 i{5 Q6 ]4 w' x: K
double offset[1] = { 0 };% n1 ~/ u. z/ r W& |
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
@0 M3 i) T8 f C6 [: N&& PositionSelect(_Symbol)) // Select the existing position!
8 B. i# k r- V" W{
. c1 d4 Z" L0 r* F5 H* p" Z9 NENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
% }1 Z& x `/ ^! M( k m- n: kdouble SL = PositionGetDouble(POSITION_SL);
* @$ z1 c, [* g5 O7 |5 Idouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));% \9 m7 E; ]7 R$ l7 D9 I$ \
if(tipo == POSITION_TYPE_BUY)! M4 E. k: p, _* V/ |
{) F3 O1 {9 {3 F) i7 B1 n
if (cotacoes[1].high > cotacoes[0].high)& \, j, o5 w+ J, G; H: ^
{' ~. V l4 ^4 P2 ?
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 A, H2 ^/ r: zinfo.NormalizePrice(sl);( I$ d1 j) ?( S4 B* L; B4 j
if (sl > SL)
9 g. B* T k8 K6 f( x" R' h# Y{
" Q* u, f% r/ inegocios.PositionModify(_Symbol, sl, TP);2 R% ?! b5 \" s- z5 X1 ~
}
# v) ?# \. d+ a: o}( X, f( p+ _# z, c
}
# I" N3 t1 X/ x! Q* h: y& D* |else // tipo == POSITION_TYPE_SELL
, ?5 q; ^+ }9 q. f! A* B{
) Y' ]! h4 O8 D0 _# b2 n2 Lif (cotacoes[1].low < cotacoes[0].low)
, D/ ]1 Y" S, @# K( ?6 K; J{
3 M( L. X+ R- J" m* j5 k& A- Jreturn true;
1 C" M) ~& h4 Q7 J- n+ \6 }}
: r M! q7 {! v# v& O9 X6 L2 z% @// there was no position _# _6 i2 y9 h9 m$ y9 K
return false;
) i, H, `4 W# k4 x4 ^) Q( E}
( w C/ ^* D5 X! i我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。8 [6 N% V* y0 p4 `3 F8 N
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |