启动交易模型,并构建 EA" z2 I6 D- H6 O& H5 T) m; ]5 w; g
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。+ L7 [9 S9 M2 I" B
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。1 a$ |. u) }) r6 x
以下是制定这些规则的代码。8 Y" m0 O4 o0 A1 R
//--- Indicator ATR(1) with EMA(8) used for the stop level...
2 o& B5 W$ m }int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);) l, S6 v% W0 O* ?( l7 l3 d5 {- E
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
; y; c$ O" G5 m$ L//--- Define a variable that indicates that we have a deal...
8 l; |% X% s; E& Fbool tem_tick = false;
- F1 C( Y7 C K! g5 a//--- An auxiliary variable for opening a position
( A- ^& |/ o. T8 D$ t#include<Trade/Trade.mqh>
- s. |3 F' V4 ^( r+ P5 x& ?#include<Trade/SymbolInfo.mqh>, T. Z! O2 M1 A5 N2 u0 x1 c/ {( y
CTrade negocios;
% `% Y- d- c, J, d& pCSymbolInfo info;& i: y( M3 R6 e1 q# z8 q; f
//--- Define in OnInit() the use of the timer every second y) f8 \, ^' [( b- G7 ~1 d
//--- and start CTrade
: m: Y: B k# A, _" kint OnInit()
f2 v# n( }5 ` j" |{
' {: S2 L$ r5 _' }//--- Set the fill type to keep a pending order( `) |5 ~& ]3 e: c! c7 a8 @
//--- until it is fully filled2 n I: [. ?& q( ~7 [
negocios.SetTypeFilling(ORDER_FILLING_RETURN);+ J7 H8 G" o! T) u. [8 U/ B
//--- Leave the fixed deviation at it is not used on B3 exchange
: {1 S6 B2 ~( W8 wnegocios.SetDeviationInPoints(5);
. Y- s6 T" i" j//--- Define the symbol in CSymbolInfo...
9 ^$ q% k/ h0 p6 w' `info.Name(_Symbol);
% j7 f4 `8 o- O6 x: \, I//--- Set the timer...
+ H. \& r. p& K" m. N! o* @EventSetTimer(1);
' L: m5 M# k: F" ?8 g- ^8 `//--- Set the base of the random number to have equal tests.... a3 [# \% U5 U9 p2 j6 Y
MathSrand(0xDEAD);
0 C8 n/ [0 X. J# v, Oreturn(INIT_SUCCEEDED);" m; `2 O) _# ]
}
: A) `4 v5 m3 t% _# q s//--- Since we set a timer, we need to destroy it in OnDeInit().
. _6 o1 A! P- X' K4 w, @- {3 vvoid OnDeinit(const int reason)
, O1 `; n) i! b. e' {{
: e* ~0 d0 V, I5 o; K9 |EventKillTimer();9 i1 t# @( W& i0 v7 H# g
}6 w' l% h' g& }
//--- The OnTick function only informs us that we have a new deal
8 S6 w; O. v) ]4 f( gvoid OnTick()
- M: B q, m" ]% k% w( `& _. ~! U{
3 k! N- [3 M1 A2 h0 M# Ltem_tick = true;/ g9 y0 e g1 L, G- O' J
}( m" o$ w# O" A2 |$ P5 {, ?0 |" \
//+------------------------------------------------------------------+
, t8 x! c# J% U; u9 R/ V# P//| Expert Advisor main function |
$ H& b) x9 H4 r* z/ p; O//+------------------------------------------------------------------+8 T3 c0 n9 Y$ w- t
void OnTimer()
0 g: B, ?5 J+ M# D- m9 o2 v; C8 }5 |{$ y' p' e! W* w, T' N
MqlRates cotacao[];
4 v) z+ h* A# \7 ?4 V6 q4 A. |return ;
# Z! m/ I8 f6 Z$ H2 E- {if (negocios_autorizados == false) // are we outside the trading window?! c7 V5 x+ N1 K9 b; M
return ;
5 s1 G7 r6 k+ j2 F" @- v2 @# A/ s//--- We are in the trading window, try to open a new position!
& \1 W. J* s& [( e% zint sorteio = MathRand();
/ Y0 G, |, q) q1 G# \: g/ u9 ]//--- Entry rule 1.1
. l* A& j, M0 E5 ^if(sorteio == 0 || sorteio == 32767)( l9 Z$ G1 Q$ l+ g& Q! y
return ;
; O& m3 d# I' o% S. e) \' y; Z2 hif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy+ y, p7 x% T+ z+ J6 A# F
{) }' q/ X& \4 I; l2 f1 b' r! [
negocios.Buy(info.LotsMin(), _Symbol);* U% i8 _/ L$ ?9 t' Q: A' N
}6 u4 I9 m7 w2 _- o3 x
else // Draw rule 1.3 -- odd number - Sell0 Z+ s- _2 z. K$ k" l
{
3 N6 W+ |& ]2 e3 a [/ t" Hnegocios.Sell(info.LotsMin(), _Symbol);
& ?% T7 M( b$ s5 V$ n; U9 w}
# k3 [. f {5 Z/ u+ H3 U; D}
& | B, {3 r4 u0 p- O//--- Check if we have a new candlestick... Z& F# x# S. u8 ?
bool tem_vela_nova(const MqlRates &rate)0 j" |) _3 Y5 {( ^/ r
{
$ S5 j( D5 |' k: w{
6 S5 }2 O7 s$ h" {- v! J! X$ Kret = true;
! T8 x! D5 h' M4 Iclose_positions = false;6 l. ]# l# E1 ?# x
}
5 b1 d7 T+ |; v1 Celse& H4 E' Y+ T3 J8 G# r1 z! Z
{# {. P& E- l+ f( ]+ g8 G
if(mdt.hour == 16)% m' I6 \. S, t' l
close_positions = (mdt.min >= 30);
+ Q. L! k' @) V0 N* m+ E1 n}
( v( D6 |9 {9 s}
& ~8 z4 E$ y/ Z; B" D# T; G# L. [return ret;
- [0 a% h% C' y3 D N3 f3 z}: o" [( W+ W6 g J' z: @# F
//---; ?6 y& L9 S6 S% C/ R* \/ \7 ?9 C
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
/ e! h6 N1 t, P{
1 ^2 S/ ]( C7 [. O6 Yif(PositionsTotal()) // Is there a position?
. l5 ^- x' ^4 t1 u{) x1 d7 I9 c. s" y
double offset[1] = { 0 };' S" J5 X2 n# G
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
m1 j' p7 h4 m2 C2 C&& PositionSelect(_Symbol)) // Select the existing position!
$ m! o5 {; o7 G" Z* R2 s! p- k* P{, c! a/ W5 F9 w0 q$ G2 o
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; K# Q/ i5 |% _" N: l$ v
double SL = PositionGetDouble(POSITION_SL);
4 [( g% e5 w" g% Z, Udouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
% A' M3 w \4 N4 N* v1 qif(tipo == POSITION_TYPE_BUY)
1 t/ u* a. A7 H' X0 X! k{. z# s f, m* b; I/ i8 I
if (cotacoes[1].high > cotacoes[0].high)
& E4 _3 o5 W# o: g6 ?& y{+ p3 Z7 X3 A4 c3 H# v$ q
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
; H. V6 K+ w& F/ `) Vinfo.NormalizePrice(sl);! h8 u8 b D( ~5 [" Y" z7 K# t
if (sl > SL)
) ^2 M0 s( _3 M o0 z2 c5 K, O{; p# n! j* W" i: I0 |* w# w! _
negocios.PositionModify(_Symbol, sl, TP);
" E0 M; J+ M* W, m& X; Z: p6 M+ G6 R}; x! c7 S6 h9 O5 C; r$ `
}5 F2 u" D9 G1 q1 G* I" g
}! b$ R; X9 l0 H6 @/ L2 H
else // tipo == POSITION_TYPE_SELL: M- E) f/ N' g# e
{
- y0 g( X* N, g' u' }if (cotacoes[1].low < cotacoes[0].low)$ @. I' |( _* q0 |6 n' T1 s7 J
{7 H4 O! P) h: O% h, r
return true;
& P4 F9 b) v! |6 R}
9 [9 @9 U6 a& @! Y& ^. \// there was no position
" C1 E) U1 i0 Freturn false;
( k$ s' v* B5 v}' b8 M1 x1 W0 h& w5 c. f. x
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- ?2 V; W) Z! D# u+ e& {) p. C
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |