启动交易模型,并构建 EA
9 {9 A: u$ I- A在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。; A4 x1 y. h; ~* S4 @, k' I+ A
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。' p' ]* e( _- |
以下是制定这些规则的代码。
O. l; [- e# G5 n1 c: @0 r6 e//--- Indicator ATR(1) with EMA(8) used for the stop level...
8 O+ W, y' {& N$ C/ Cint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);, K7 g; G% o& @6 C% U ?
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);0 |( G5 e& C, ^8 L' |" O
//--- Define a variable that indicates that we have a deal...
0 F# n. |+ G& U4 o9 ybool tem_tick = false;% \7 |/ e4 F" H2 D: k' h# g
//--- An auxiliary variable for opening a position6 B/ K5 |: @7 x4 T3 a9 A
#include<Trade/Trade.mqh> b d. N0 k" h
#include<Trade/SymbolInfo.mqh>
i- J, K" K# Q: `2 X- p) XCTrade negocios;
- a" Z! ?6 M, M, P7 @! bCSymbolInfo info;
: x9 O3 @4 m7 y0 b: j+ _- q//--- Define in OnInit() the use of the timer every second; @1 }/ I" _+ X! Z, O V: O; N Z* L
//--- and start CTrade
7 H x s" @/ C+ ]) Y! W4 u2 m. Vint OnInit(), d5 t% m1 l2 ]) z
{- k! {8 O7 l( @$ H" { w: H6 u. f4 @
//--- Set the fill type to keep a pending order
* }: d- `/ b+ m//--- until it is fully filled
4 v0 P) z8 p# L2 k" ^negocios.SetTypeFilling(ORDER_FILLING_RETURN);) f9 j. b% x3 |
//--- Leave the fixed deviation at it is not used on B3 exchange: V5 |0 y1 L; u7 b
negocios.SetDeviationInPoints(5);& W4 d! E% B3 y! m$ I0 {4 O7 q
//--- Define the symbol in CSymbolInfo...& _5 e g% j2 F4 f5 M `" @
info.Name(_Symbol);) I2 N! T# [5 p2 L
//--- Set the timer...2 r1 N5 F) P( e$ t6 r2 T9 L
EventSetTimer(1);
; C5 i; c' Q, z" G! K, d2 G//--- Set the base of the random number to have equal tests...
& T$ P2 x3 O4 D& {0 G0 A- ?MathSrand(0xDEAD);9 G. C, {% f, X3 x( a, o' b5 J
return(INIT_SUCCEEDED);
$ r: N% B* _! k: V a3 q6 k' L& Q1 j}
~6 }6 A6 Z, M7 K- i//--- Since we set a timer, we need to destroy it in OnDeInit().! b8 o) t7 N3 \# v
void OnDeinit(const int reason)
! e+ N* D n2 l1 U{2 d" i6 e, O" N! }
EventKillTimer();
+ s }# f K+ O}; C7 A4 c- `; _$ w0 v& l% a
//--- The OnTick function only informs us that we have a new deal+ Q3 w1 r& O& {3 E; h5 _
void OnTick()
4 J* j# f" v: F A0 I7 t4 Q& ^& W{2 [% G: @6 _6 }! d. }$ ]
tem_tick = true;+ n' t9 b& y" x
}
/ I0 D2 M$ W2 I7 K& s//+------------------------------------------------------------------+
. g% E: _, k" a z' |6 s, G! B+ `//| Expert Advisor main function |
8 O% A/ T0 s# B$ M//+------------------------------------------------------------------+
2 B/ a' E) E" K- p7 T: s9 Ovoid OnTimer()" H! O- }5 z/ X8 E" L9 L
{9 m1 q/ n! W& Q! N i2 D* O
MqlRates cotacao[];
& j4 B+ A& D1 ?' H2 e$ sreturn ;
+ r# l. h. ^2 k: Q! iif (negocios_autorizados == false) // are we outside the trading window?
& P& E8 ?# Q, a9 I6 Oreturn ;
/ l4 e0 i0 u5 Y7 \; e9 }//--- We are in the trading window, try to open a new position!- u `+ Q: i% y3 s
int sorteio = MathRand();
+ L: e7 d- F$ ~) c& Y" t//--- Entry rule 1.1
, t. j; a; S0 L; Gif(sorteio == 0 || sorteio == 32767)
' v9 N5 @1 b# A5 y3 Preturn ;
# V5 [8 j9 t/ t. s! _if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy. }/ Y' J% i# ?0 ^
{5 z( C* o) e2 ~: I9 O4 C; o* b4 B
negocios.Buy(info.LotsMin(), _Symbol);
e9 }. z: {$ C* h- t9 T0 J}
( g7 O4 I7 K; `, u& Nelse // Draw rule 1.3 -- odd number - Sell
6 G" c U# h2 P8 ^4 M5 i$ S b g{
# ]; j( ^& ]6 `negocios.Sell(info.LotsMin(), _Symbol);
- L. u. r. C7 @( c; e}0 X! N! I5 V+ P [8 c
}2 e& i# M* C2 n3 D7 w& N2 u- f
//--- Check if we have a new candlestick...
u4 v8 n1 y j) N% h# rbool tem_vela_nova(const MqlRates &rate)5 t, w- V: }( q0 X8 Y( O
{9 w* P* p) m- f7 W8 z
{- s1 h4 o; K0 K
ret = true;& H5 ~/ E" i5 V x
close_positions = false;
) d6 g: T' r8 ^' A( {8 P, T}! V0 Z+ `6 a* z
else
& i5 P! _; a( I5 v{
. T0 _9 V; U& y* s" G+ ?7 Fif(mdt.hour == 16)
# G" H( z$ @! _! P" H! c+ F# l5 ~$ A* Vclose_positions = (mdt.min >= 30);& E! `/ G: Y: f
}
0 S& `9 a; E# H8 ]}, i4 [' b9 J7 [% o R
return ret;7 r& g9 K) Z, j! d
}* W( z+ j8 }% G/ [, @: [& x
//---1 J% u) B; V: u, ]) M
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
2 t+ @" e5 p9 H+ X( @' u$ F{
; n4 M1 Q0 B# M( Hif(PositionsTotal()) // Is there a position?2 `0 e( n5 u' k z6 U2 V! S
{* Q7 M- @& G) E8 Y& `8 H6 A4 l
double offset[1] = { 0 };1 o& n& y* }: ^: P: D4 |5 R
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 H$ o# s: R8 _" ]
&& PositionSelect(_Symbol)) // Select the existing position!$ N h9 f8 ~% P+ |4 Y' E
{, E% O8 k; w* }
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);+ b3 Z* k% x0 {* s$ V4 u
double SL = PositionGetDouble(POSITION_SL);
- N5 j( G: ~4 ?- ^6 ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
: T9 }" @: L0 J/ aif(tipo == POSITION_TYPE_BUY)6 u7 j; e# Z& j/ P2 Q! P
{
2 w. X4 v3 Q' B$ Z4 h5 m* ~4 Zif (cotacoes[1].high > cotacoes[0].high)
( [, f) N6 E2 M4 p: c# [{1 G% \9 D$ S$ D- [
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];( k- H% i5 L7 a9 E
info.NormalizePrice(sl);7 u" p& ^ t* c7 s5 B$ ?
if (sl > SL)
; ^7 p, w8 E3 H; F1 \$ h3 e, `% U{
+ e; ?8 h9 i& C" Lnegocios.PositionModify(_Symbol, sl, TP);$ b. F. P- U9 [$ l: g8 q# \& b
}- h+ U$ s. L2 Q6 j
}
2 w6 V7 o/ e' T4 B, B; v; X% ]: ^}
, f9 a1 L; i* U3 J9 Telse // tipo == POSITION_TYPE_SELL" d* q/ b* a+ n; l5 w
{
& f. Y4 o% v4 u& D3 D( Uif (cotacoes[1].low < cotacoes[0].low)7 @. `$ C) }9 W% L' g
{
5 ^; P4 e! @; w' \return true;- W5 b+ T* c4 c0 T. o$ @9 f$ Y' g
}
. V v- V8 B* ?) S// there was no position$ V# \' B, ^1 O9 c( W' A& I; u3 q
return false;7 |" W# ]0 R8 A! M6 S
}
/ i i6 V0 l) S- |1 e2 a我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。" ^5 d8 _/ s* X1 Y- _( q
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |