启动交易模型,并构建 EA# S' K- ^7 m! l B* \1 D
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。8 J- ]! s4 f+ X5 M
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* H; i6 Z+ _! j/ `4 h
以下是制定这些规则的代码。2 P# k' |! d( n) o/ t
//--- Indicator ATR(1) with EMA(8) used for the stop level...
& p: i3 l! q" E7 O! \int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);6 y$ w g; j) s0 G0 h+ f
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);. k$ C6 F; d9 a& t+ n5 _4 X. e
//--- Define a variable that indicates that we have a deal...+ l; Z. F9 B$ P9 x9 G( c' E
bool tem_tick = false;
# W$ S2 u7 V5 [7 h# w//--- An auxiliary variable for opening a position9 ?5 H3 w1 J, p+ `6 a& K
#include<Trade/Trade.mqh>
" K5 Z( T6 s8 h* Q8 ?#include<Trade/SymbolInfo.mqh>/ Z" H/ u6 Y1 J3 S2 T4 ]8 D5 d; G
CTrade negocios;7 s; {; a! l) K' Z0 p0 n
CSymbolInfo info;
: V1 n9 F8 x' J9 h- L, C//--- Define in OnInit() the use of the timer every second
% [# I" ~2 F0 P6 C4 @& {- Y//--- and start CTrade
$ B; H* n. _# x7 S+ P5 @! dint OnInit()( ^- D, n P/ e7 Y, a+ C: u( a
{
+ y0 `7 S6 |, G6 n% G t//--- Set the fill type to keep a pending order
9 v5 W% T! {, a+ Y9 H//--- until it is fully filled$ ]8 Z( }1 h9 V: y$ q& o% v* K
negocios.SetTypeFilling(ORDER_FILLING_RETURN);) C% H$ J( S0 j: s! P
//--- Leave the fixed deviation at it is not used on B3 exchange
# V: D2 O0 K) o. G! l' X; fnegocios.SetDeviationInPoints(5);# @9 m0 E9 v9 H( U4 d
//--- Define the symbol in CSymbolInfo...
4 e- d5 X% z2 Tinfo.Name(_Symbol);
" e( }, Y- W; I" W! |# ^( E% ~//--- Set the timer...0 P0 D ?$ D; y& C
EventSetTimer(1);; ^6 D9 T( p+ a4 v( d
//--- Set the base of the random number to have equal tests...
# W3 J$ D0 Z: nMathSrand(0xDEAD);' f% ]# r) z8 \1 z2 W
return(INIT_SUCCEEDED);
! ?6 e v4 o7 Z N8 `- d5 k2 X: J}% P5 j& [" m) `& H5 ~. j7 I2 C- d, p
//--- Since we set a timer, we need to destroy it in OnDeInit().
/ N8 K5 l0 t/ Y. rvoid OnDeinit(const int reason)
- l4 p2 H" A% R4 w3 ~{
# H9 O) l6 I$ O% CEventKillTimer();5 v6 b* n) `" L( V$ @8 C
}9 e% C% o X' M5 B# b/ y0 _; M7 M
//--- The OnTick function only informs us that we have a new deal% ]( p3 a5 P( X: i4 h: U
void OnTick()
, b% A( A' d" i$ }" q6 r* I{5 C# a6 e* P! R* U* ^
tem_tick = true;! q# `/ G1 l9 n. r/ v4 t2 _
}. _+ Y6 G4 _1 v: F
//+------------------------------------------------------------------+
/ V' o2 x# w# A8 o: d6 X8 I//| Expert Advisor main function |: Y7 p0 O6 _% p7 y% y$ Z! j
//+------------------------------------------------------------------+& F- Z* e8 v/ ~( f3 O& w) J
void OnTimer()
6 x$ v0 K3 k! H; a{
7 H. a/ p! Z) J3 MMqlRates cotacao[];, b' H6 S1 u0 b8 q( e3 \7 \
return ;2 U' e- v4 d+ C& J/ X0 C
if (negocios_autorizados == false) // are we outside the trading window?: U$ U( C# n% |8 ~3 ~
return ;; K, \# O4 s# q& s$ M- [
//--- We are in the trading window, try to open a new position!( I* s8 A: R4 X/ [* |5 Y
int sorteio = MathRand();1 j6 \% p9 t' v; _2 U' H5 C! N
//--- Entry rule 1.17 C, C: O' F. h% m' Z
if(sorteio == 0 || sorteio == 32767). N6 A C. r% E, ^
return ;0 o, K; Q$ }- v/ b8 S& x X
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy' |) Z, V3 H& g0 R* ?
{
3 c, {; J/ N T: ynegocios.Buy(info.LotsMin(), _Symbol);
$ j0 k% t* Y- L1 P" u1 d}
2 P$ b+ ]1 D+ g( B% selse // Draw rule 1.3 -- odd number - Sell
' \7 j( K+ M7 c& N c/ }{: t- Y: }, S1 w. L0 ^6 B. @
negocios.Sell(info.LotsMin(), _Symbol);! I6 {# A( N- f1 P3 S! a
}
0 v7 y; e. P: ?) c% A& ^' C}
# G0 X" Y# f! z& S+ E- k$ L//--- Check if we have a new candlestick...
# P" P( ]4 b& G2 A+ x+ gbool tem_vela_nova(const MqlRates &rate)
5 M- V. B$ C. y+ n! c. R{
, V- y$ a7 c; Q{( Z1 i3 p8 ~2 r8 `( Y
ret = true; ~5 R. @) @5 f8 O }
close_positions = false;
" c% k* I+ j# B, B8 }}1 K+ G& k4 c! x/ Y7 c. ]
else4 M* W+ U2 @9 l+ u6 T( @: O& k
{( W# L R1 q6 `" s
if(mdt.hour == 16)5 J; N; T# x0 L1 R& o8 F" ^, x$ F
close_positions = (mdt.min >= 30);4 z8 K# z9 W3 b
}
6 ^% \" i# V% J. U# q}; c. w1 E0 |; ^3 k
return ret;
! h4 g- Y6 }* S+ S: s- @& S8 P: W}" j8 G: I/ }4 t
//---
' Z6 O9 K \9 o$ ^) \# x6 nbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
, {% d+ C* m, ~! p+ l{
+ Z) e3 E3 x/ }5 j' _; u ]if(PositionsTotal()) // Is there a position?
+ |8 \, x: ^5 z. H& V{
( ?$ p- l* i3 S1 Ddouble offset[1] = { 0 };
0 u! G$ N: x3 Q+ H- ?1 gif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?8 L; d! W/ C% D5 ]0 ^" A9 \
&& PositionSelect(_Symbol)) // Select the existing position!: H0 } c( G; q+ a
{
t# }( x# ?) d, ?7 Y+ ^) s3 b* QENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);* \- x1 X5 {# w2 S% P
double SL = PositionGetDouble(POSITION_SL);8 u( \, l4 ?, ^( J$ ~
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
# G) u) H5 E1 D Jif(tipo == POSITION_TYPE_BUY)9 C! h$ i, [8 B- z. Q
{
5 {% r' J+ y- Hif (cotacoes[1].high > cotacoes[0].high)
, q( `* k1 ]* n2 A7 p5 z, _8 N{
' a, ^( I. |- W: K7 I6 g7 cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
' O$ x5 ~% b2 M3 S0 \9 tinfo.NormalizePrice(sl);
8 z1 r2 M# y' H; P5 L8 \1 r# H7 uif (sl > SL). k* u: p' D- v9 }. f" O
{
! T; h) C: b0 |; \7 `negocios.PositionModify(_Symbol, sl, TP);) C- Y8 \" j e s# m
}
1 ]. S2 N* r$ J: B}0 q5 ]% i2 E1 i5 [$ S3 Q1 f$ p
}
9 d, E; e5 [2 E, E+ [& aelse // tipo == POSITION_TYPE_SELL' J% |8 X$ B1 j. ?+ \
{
( Q/ [+ {8 U0 v6 iif (cotacoes[1].low < cotacoes[0].low)- w$ Y# m# ^- @" k( t9 `( e: [; z4 ]
{
4 W2 f# s; p* l. ireturn true;
( r. t; M9 `7 }3 r8 h& d6 j. k}
: [/ d/ T+ l1 S. j3 W. T* ?// there was no position& W. s* t8 F6 Z8 j6 ~
return false;, v$ V: w( [2 k1 m% q' }! T8 t
}
' R" E6 j8 M( ?1 B我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 b1 n6 x( Z) {8 J
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |