启动交易模型,并构建 EA; s) X/ O8 M. M9 X, ]1 L) t
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
0 \) _; H! B4 L& l y' ~0 u8 p为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
( b r; z9 q/ e$ X以下是制定这些规则的代码。
. o5 p- r! f/ G& s//--- Indicator ATR(1) with EMA(8) used for the stop level...* C8 c2 A" K! w( L# \) G( s
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
2 l* i0 W% P! z& u9 Mint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);6 c9 o3 x' {9 K9 j3 }( [
//--- Define a variable that indicates that we have a deal...
' r$ }( D. X5 ~bool tem_tick = false;& y- [4 [* O! j5 E" g4 v% n
//--- An auxiliary variable for opening a position
. O# X& S8 _! M: E. ^4 r#include<Trade/Trade.mqh># C$ G* f- y* h' L8 w
#include<Trade/SymbolInfo.mqh>* Q; c# \) s) ^% u6 V$ b' Q
CTrade negocios;
0 i) B0 D: k8 j4 A- i: Y) j; u, K( p. JCSymbolInfo info;& C& x/ u# ~: q" q; {( w$ ~
//--- Define in OnInit() the use of the timer every second. b# p8 B6 g- Z
//--- and start CTrade
8 T V' |# J) X& S/ iint OnInit()" ` ~2 c, a3 T& W# l2 c* ]
{
0 t7 Y5 b D7 D//--- Set the fill type to keep a pending order
* e( w+ Z6 B0 c: G//--- until it is fully filled) l1 Y0 p% w' f5 V' c
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
1 t2 f; H1 H. v//--- Leave the fixed deviation at it is not used on B3 exchange
) x3 R" z* @7 u) } ^. Knegocios.SetDeviationInPoints(5);7 t' |1 U- @! k
//--- Define the symbol in CSymbolInfo...0 F; i$ U; T2 z$ W2 V
info.Name(_Symbol);) N1 r& y4 A9 w+ Y2 c
//--- Set the timer...0 T6 n; Q* ]; Q$ K7 b3 I
EventSetTimer(1);# B R8 f0 q2 F- g. e) L
//--- Set the base of the random number to have equal tests...
2 i1 d2 i b# d9 z) XMathSrand(0xDEAD);6 `$ ]% W R' \3 ~+ l6 Y' Q
return(INIT_SUCCEEDED); L5 L9 s1 _8 b2 C- r' j$ j& ?# A- V
}$ E6 p0 O; k r
//--- Since we set a timer, we need to destroy it in OnDeInit().
6 Y. X& j7 c6 O2 y8 G( g P2 xvoid OnDeinit(const int reason)
& W7 G! w" c: }. e{
) @5 [* {; U7 s( sEventKillTimer();
4 D6 o( e4 {; u' ?: j$ m" h}
; V. P. _- I* R0 q0 k, ]& _/ F; k//--- The OnTick function only informs us that we have a new deal
3 j2 `( |. |% r0 H6 u3 wvoid OnTick()
" G) H& [ n- R{
. c9 D& h* t/ j, E6 d0 k9 Otem_tick = true;
) `$ @6 x8 u( H6 y ~}4 Y3 h) u( b% F9 D) B+ b% S- f% t
//+------------------------------------------------------------------+% W) X2 T9 \2 j0 [7 a% a- _
//| Expert Advisor main function |2 b7 k K" J6 M6 i
//+------------------------------------------------------------------+8 |1 B$ `! N7 U* p6 V; I# K
void OnTimer()
. F0 ~5 A- A3 v1 w% k2 R{
! Q" g1 B: N' W& nMqlRates cotacao[];
6 Y" k4 K- b) _return ;
' z" @# i+ U) {0 q& w% vif (negocios_autorizados == false) // are we outside the trading window?
6 E+ w E7 u4 a' C. J% Jreturn ;$ Q1 _4 | E4 z$ G0 G7 n
//--- We are in the trading window, try to open a new position!
; G2 x$ o3 L0 P+ M/ iint sorteio = MathRand();
. K' ]$ d1 e3 L2 O! r( |( P//--- Entry rule 1.1
N; ^% }' P) s: y0 J! @& tif(sorteio == 0 || sorteio == 32767)% K; j4 j) y8 z5 B
return ;
, g9 t; c0 N' x7 r9 x/ eif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
8 \% m9 T* O% l' m0 }' I2 E{7 I- O$ O9 r' n
negocios.Buy(info.LotsMin(), _Symbol);
. J, G( R. m: {4 z}
( @$ I7 q0 a4 w G5 [. `else // Draw rule 1.3 -- odd number - Sell, g' f* ^! o) r/ L( h
{: c5 A/ m4 o, Z, S
negocios.Sell(info.LotsMin(), _Symbol);
1 k# p8 _* X' N7 K. ~ `}; w4 N2 y N0 Y; W, I9 x5 g. B
}
. s0 d) H' A( u; h0 `: ?$ F//--- Check if we have a new candlestick...! p) y2 O7 s/ r
bool tem_vela_nova(const MqlRates &rate)2 \) a2 Z1 ]6 }. {+ t
{
5 i" r+ X& V" x# x{
. s' z, p4 v) n' W# {7 oret = true;
! e2 {$ m2 K" V8 lclose_positions = false;' V3 `. R7 y1 S$ ?; a& k& A Q% L
}
! P: _5 [" d: o8 T$ ~4 @- Gelse! H; u, q: q; b& }3 F0 ~3 T- Z, @
{( H8 U* u0 C: D, y
if(mdt.hour == 16). F* r# ^0 k+ G- S' j. y6 U8 S( F% C, y
close_positions = (mdt.min >= 30);+ l1 s, Y1 x1 H7 Y# L6 B
}
" ]% L( X3 t* d: s}
5 f' B7 q; n' `& U7 z7 l, Preturn ret;3 J7 w9 [* Y1 Q( u9 P8 Q
}
6 }/ o8 e; y7 N5 C//---
; r1 {7 O$ q& J0 {bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])- V, h! D9 B) C8 H7 \" p: u' |
{9 @: w# _2 {6 C$ v1 l$ A, I
if(PositionsTotal()) // Is there a position?
$ C/ C: \- o; Q+ C% b' j{' n& G( k, z' U, ~* H
double offset[1] = { 0 };" F8 g- N8 Z' r5 w, ^
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied? o& y9 a- l" X2 a
&& PositionSelect(_Symbol)) // Select the existing position!+ s& J- ~9 J9 L) B( @7 Y
{: q1 b- D- j/ S9 [ Y, X9 U
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
. A/ V% l" s! d: Ddouble SL = PositionGetDouble(POSITION_SL);; ]# p$ G/ P T5 s
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
j2 n) X% z" Hif(tipo == POSITION_TYPE_BUY)
1 J2 ]% Y$ p+ H+ v{
~" y3 X# y" f9 h, e: Dif (cotacoes[1].high > cotacoes[0].high)
, z' m$ q% l, ~{/ ^/ H- [- r2 L0 s4 n9 R
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];2 O( |( s, B- E, U' u9 w
info.NormalizePrice(sl);7 v4 _5 |: ~8 z; I
if (sl > SL)
9 e' ^4 D) e# T& k" ^& I% ?: I8 Q{
! ~: q' u5 w( X( onegocios.PositionModify(_Symbol, sl, TP);
! I1 z! p% W+ q}
3 ` ]6 w$ ^% d' h2 b$ V}
8 F5 ~% `9 M8 p/ D+ X$ o}5 f0 X. n) X( n( Y2 f! P
else // tipo == POSITION_TYPE_SELL
2 M) i6 b) ~0 k2 {{1 u( f3 V6 O# F! f9 A) V, x4 }
if (cotacoes[1].low < cotacoes[0].low)
2 r D, p( D5 g3 \9 [' F{
* g) z- m" t- G( Mreturn true;% z0 X" \( I- ~ Y' }& s2 h/ l0 i2 U
}
% `: @# d: z M: K, x/ j/ G9 c// there was no position2 S1 D+ p$ j. N |# E
return false;
y3 I6 _4 F# m$ G) X}
* x g9 c7 y# T9 F8 D我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。& y! B4 y9 _2 x; o. C# h6 S+ y7 e
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |