启动交易模型,并构建 EA8 w: f" C8 j; ^# z; J
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ o- I2 n/ T0 J7 ^& z- i& U0 J4 V
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。! ~* M6 ^5 o& W ~ y
以下是制定这些规则的代码。
7 _1 s. } o" B0 I: L5 q5 L//--- Indicator ATR(1) with EMA(8) used for the stop level...
( |" A1 \' Y( t: _9 G+ X$ b, Q% |" J+ _/ Nint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
5 l4 a5 |1 V9 k6 c; lint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
$ Z, Z. p; M* r' z$ P) \; i7 e//--- Define a variable that indicates that we have a deal...8 w. V, l4 l6 t0 C# B( B+ A+ _
bool tem_tick = false;
9 }& X+ n9 z& h% a" Y/ |6 s& [//--- An auxiliary variable for opening a position
6 R R( J9 u9 ?9 x#include<Trade/Trade.mqh>
$ B w+ ~% q0 U. H) e. {1 [* W#include<Trade/SymbolInfo.mqh>
M+ N& Y: c6 U- F; NCTrade negocios;; M! f5 A4 u' X
CSymbolInfo info;
. n W4 V9 E0 x$ W//--- Define in OnInit() the use of the timer every second
+ b, c. i* z* e K! r3 Q+ i//--- and start CTrade, S; W1 P. V4 ` G+ F4 ?
int OnInit()0 o" |7 w$ A% P9 P' A
{7 s9 U1 @: F0 Q1 e
//--- Set the fill type to keep a pending order
, H+ j* s3 @' R2 L' }6 I% _6 b1 M//--- until it is fully filled
: B ^, X; b8 ~negocios.SetTypeFilling(ORDER_FILLING_RETURN);5 K4 H) T; a# n$ W! r7 X" \% V
//--- Leave the fixed deviation at it is not used on B3 exchange
o* V7 p6 ]2 _5 c8 K6 `negocios.SetDeviationInPoints(5);5 c3 _+ u3 d' ~% t- _
//--- Define the symbol in CSymbolInfo...
& E, H& \/ T# z+ o& ?3 uinfo.Name(_Symbol);
, w7 R- c) n" o2 I4 ^) A//--- Set the timer...& ]. h$ g$ b( L+ _
EventSetTimer(1);/ Z. X* v% Z# \% r( }
//--- Set the base of the random number to have equal tests...
8 s2 b7 q& ?! d# R% dMathSrand(0xDEAD);
( F6 c! p9 Y/ vreturn(INIT_SUCCEEDED);# Q( k, C3 j$ ?; k: N* Z' \0 m
}* M) f- d6 N5 o
//--- Since we set a timer, we need to destroy it in OnDeInit().& P$ ^; k; p+ t! N3 @7 X
void OnDeinit(const int reason)
0 w7 z. p, d5 }. b- W" o{
9 p* X9 p* J& J7 D" l8 s5 HEventKillTimer();
3 ?( t" }, l( @6 F) B- x}
5 Z9 E L* y8 z- q8 s p//--- The OnTick function only informs us that we have a new deal
4 ]5 j3 Z3 [- Y F( K! [/ ?# zvoid OnTick()8 k4 ~$ e2 l7 W$ {0 W* E, i
{" h* f2 P" M( Y/ h# R2 H
tem_tick = true;
' v3 T1 f" r8 y1 d. ?; S! l}1 j8 k. j8 a* @+ z
//+------------------------------------------------------------------+. r9 c* O- q; n( @- w" K
//| Expert Advisor main function |- t4 }; E) b8 A
//+------------------------------------------------------------------+
0 ~! X* w7 I0 U7 x4 r/ e( xvoid OnTimer(); W7 o( ~/ |4 S1 x8 Q& K
{1 F3 \/ D( {% f2 E0 M/ r
MqlRates cotacao[];4 d; I$ }; U# `
return ;$ z8 }: A( x: i. z
if (negocios_autorizados == false) // are we outside the trading window?
: Q. D# D9 L! J. treturn ;3 o2 e7 c$ h0 O0 o+ s9 p) w
//--- We are in the trading window, try to open a new position!5 I7 U! C! ~2 @; `3 v
int sorteio = MathRand();' h2 _( ^* U8 }" e9 S2 A
//--- Entry rule 1.1
+ V5 @/ d6 ]* B$ p% C/ Sif(sorteio == 0 || sorteio == 32767)* y3 o- S7 m1 ~
return ;+ Z% g+ b' R( h2 f4 J
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
1 J& m, I9 A) Q4 G* C0 z9 f! q{) G$ G6 S9 F7 \/ i
negocios.Buy(info.LotsMin(), _Symbol);8 C$ W0 a6 K3 R& l+ z) u
}) D; C7 @* c8 v5 a. P
else // Draw rule 1.3 -- odd number - Sell
: f$ `! V' q' W$ r% w7 N! X{( B j2 n9 a/ k2 b9 f/ @" H
negocios.Sell(info.LotsMin(), _Symbol);
- a: K0 V' I! j) E% ^# S" K: c}
/ N* {5 V x3 [, L- r}
2 d5 Y% _" z8 t' l6 d& H# W) Y$ x' h//--- Check if we have a new candlestick...! }7 P$ a$ | z2 D
bool tem_vela_nova(const MqlRates &rate): H3 S# Y) R3 b
{
- x6 x) Y6 x' I! k{
7 l. r* o6 ]( B# B* N& Lret = true;
" Y$ G7 R$ f+ E e0 B$ t3 {; Bclose_positions = false;
* V# a8 c# p& _+ E}2 b/ q% e% o9 k. b2 A
else
) w8 m; f8 W9 W4 f& w{9 l: @7 J: {. B: ~+ s+ L( v9 e3 I
if(mdt.hour == 16)
! K, ? d$ n! Kclose_positions = (mdt.min >= 30);
# L5 y, h8 G9 q}. O# n% r0 y) O7 c5 I
}
" O j% M' a6 h5 P6 Breturn ret;
; V0 M) Z- Y' H6 i, L}2 j$ v+ \* C6 W. @( R! K- ~: r
//---
5 O0 b7 |) E8 A/ C8 gbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
0 c8 {# z( @+ V/ e7 y; L0 R{* ?1 y" H* ]( I: ~* n
if(PositionsTotal()) // Is there a position?, X4 j. t5 t+ K
{
4 ^4 D* Y* u* A1 l+ d$ Kdouble offset[1] = { 0 };6 m+ R8 o4 i& b$ O( Y5 a
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
2 | i6 L" M8 Z6 k&& PositionSelect(_Symbol)) // Select the existing position!
7 I( j, g2 n, A5 }4 w{
7 i( C$ t' `% J/ jENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
. j4 y* a+ A; P" B/ J# b" r% c, E- idouble SL = PositionGetDouble(POSITION_SL);
- w% z7 D+ c5 Y: T& Hdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));) C8 @9 ?) s6 W* R; M) b
if(tipo == POSITION_TYPE_BUY)% a$ N) a( G' P. L: z
{
8 V1 S: i3 e" T& N9 `if (cotacoes[1].high > cotacoes[0].high). s% {9 N# e# Q; Y
{3 M- y' R4 T# e3 h4 G% p
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; o0 B; x" c, b" a
info.NormalizePrice(sl);
( @5 z; n% i7 y3 Pif (sl > SL)# W0 `2 C: c; j3 L0 Z' W# f9 e- w
{3 Q1 {& [* l+ ^6 x, p( |$ Z, K8 ]
negocios.PositionModify(_Symbol, sl, TP);
8 H, l, g7 s, ?}" _6 l3 M: `8 [( L$ e
}0 q4 [ i! m) I! Q! B; ?
}
g: l# }0 |* `# @, welse // tipo == POSITION_TYPE_SELL
- Z' o; n6 I. I/ L{ p, j3 A" O: J# M9 g
if (cotacoes[1].low < cotacoes[0].low)
+ N8 l' e$ I4 |; K& H w1 ~{8 Y, n5 \/ K b
return true;' Q! T9 E7 J9 J8 d
}
# s$ H$ u' c0 ^' K// there was no position
( I/ S9 s' a# P {% g7 r# nreturn false;, W6 H8 q, C$ {0 H5 U$ \2 ]/ l
}- y5 _$ }+ N# Z( q7 k: O* a" r
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
+ l" {. W# e: ~( s到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |