启动交易模型,并构建 EA6 Q% n. \- R8 u- E8 a, N
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
( F+ V" Z3 S% m5 i/ N: S# m6 X( b8 w为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
+ K% M' q4 L+ Z! G) X- B以下是制定这些规则的代码。( `8 Y6 ]+ F. T: z' P4 f5 F6 h
//--- Indicator ATR(1) with EMA(8) used for the stop level...# ` Q \$ L& t& w1 j
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
* N7 U4 \# v. l4 Sint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
- Q# L$ j2 q9 M' Y1 ]- U& {//--- Define a variable that indicates that we have a deal...
) Q% w) K$ n( H# [bool tem_tick = false;5 [* s3 Q; Z) r/ V" |
//--- An auxiliary variable for opening a position
( r5 P2 `0 B* c2 L0 n T9 i#include<Trade/Trade.mqh>2 H# [/ p7 ^7 B4 C% N
#include<Trade/SymbolInfo.mqh>
# @) s. D% `2 o% F* j2 W' O- I$ ZCTrade negocios;/ s. A) b. q! |4 J: L4 r, r# N' z! U
CSymbolInfo info;2 ^' k1 s; g: h7 c7 p
//--- Define in OnInit() the use of the timer every second
; C# W! a! T! H9 c' p8 h, `//--- and start CTrade: R. V1 v( v% k
int OnInit(). P: {& j, }) c# l3 S
{
4 a1 F. Y7 x3 j8 O//--- Set the fill type to keep a pending order
0 A4 S% P8 B$ O( h/ ?4 t//--- until it is fully filled+ Y7 E- T* G5 r% j, ^& p
negocios.SetTypeFilling(ORDER_FILLING_RETURN);9 I7 Z n9 c- o
//--- Leave the fixed deviation at it is not used on B3 exchange9 u' j7 [& x/ a' X4 w" H! o
negocios.SetDeviationInPoints(5);
+ r0 E, d# ?1 t% b//--- Define the symbol in CSymbolInfo...8 O% J) [. w) X9 H
info.Name(_Symbol);- I5 q) w% T1 T
//--- Set the timer...- A6 O: G3 W" s7 o( C
EventSetTimer(1);
0 l: C5 W4 `0 l, N4 \3 E/ K//--- Set the base of the random number to have equal tests...( H; z/ g) o6 g
MathSrand(0xDEAD);
; B' S5 M. y1 k, ~8 k Yreturn(INIT_SUCCEEDED);
6 N# c* ?2 R4 S0 Z: O}" H7 Q) J: k; [% J
//--- Since we set a timer, we need to destroy it in OnDeInit().
( E* m( f, e& i4 |0 pvoid OnDeinit(const int reason); C# o; u/ p3 s6 H
{. w5 ~7 \2 I, n
EventKillTimer();* A: N- r6 w. g; @1 a) S
}7 e7 h# C2 w4 E' o" ?/ ?5 C
//--- The OnTick function only informs us that we have a new deal
! w1 }1 _( X8 \- ?9 T% }$ n4 T. Mvoid OnTick()
, I- a) O, m& u" F: y$ I/ V{3 l: @8 Y& J# B5 M$ d4 `
tem_tick = true;
4 A9 P* J3 V9 S# L# ~4 o; O}
! U7 k M* M5 K- A) {//+------------------------------------------------------------------+4 U) N H; ^! v
//| Expert Advisor main function |
4 e3 L6 h( g7 I+ S! l9 |# }6 ], B4 J//+------------------------------------------------------------------+
! @9 ]+ C! z/ Mvoid OnTimer()
" H5 {8 N. ] D& `' ?{
. W$ B" m" G5 g0 t9 j2 q4 j7 a: v+ [MqlRates cotacao[];/ N* X& p+ A+ f7 `
return ;
# |: Z5 e, ~7 [ N7 P+ Xif (negocios_autorizados == false) // are we outside the trading window?
; E1 N$ e3 n6 }. d4 `* {return ;; W& i, x# _9 a" F' p6 n- [! q$ h& H
//--- We are in the trading window, try to open a new position!
: s0 ~3 Y2 z6 ~- R3 T8 s( p$ b9 Uint sorteio = MathRand();' F1 Y$ K3 s5 e* r- ^5 @/ d1 I
//--- Entry rule 1.1" k H) n: H/ v5 @1 Z( V5 u6 n7 ]
if(sorteio == 0 || sorteio == 32767)
A& J# Y/ ]0 J" y+ Freturn ;
1 z. C- V$ Z( }9 N2 b5 T# Iif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy8 q$ ~ X0 c4 z* b
{
% A5 b" C4 f' ]0 `negocios.Buy(info.LotsMin(), _Symbol);
# x6 b- Y3 w2 n+ ~- `( V}
( ~2 \0 l1 g3 q* w; ]& Nelse // Draw rule 1.3 -- odd number - Sell
, d6 A: y J$ h0 Q2 A+ W* K( ~{2 x" F( U0 \2 F3 u
negocios.Sell(info.LotsMin(), _Symbol);1 F+ ]' A! [, Q6 y, Q0 A
}
/ D6 u; L" h' B; Y! H}
) P2 |6 B0 ~- P3 I- B$ d% `//--- Check if we have a new candlestick...5 `4 s" L# h3 C6 k
bool tem_vela_nova(const MqlRates &rate)
0 ]" B# O' V1 D0 J( d9 G{
0 [1 d( k; N- J/ z+ k{9 r/ w: P9 J+ U2 _6 Y/ i5 m
ret = true;
4 |$ v9 v7 @# u0 T( J( o4 eclose_positions = false;
( r7 A# r: `5 Z3 D, d& n}
/ r( z0 L0 w; A9 a: d1 v1 qelse
2 C+ o- T/ }, T9 e+ y: i& b; ^{
* W5 S8 ?6 X, m& v8 tif(mdt.hour == 16)
* ?3 o& G$ ?* p J+ T/ E# K1 Kclose_positions = (mdt.min >= 30);% ~$ o) t" e: Y$ z* R8 b
}( m, o: q+ J) Y5 q# `
}
" b# \# ]5 C) \& Z" ireturn ret;) }% v& T6 B' `
}
, \$ o: O" F4 D# E4 R//---
! c3 X6 a/ g2 Q) q, w0 i0 ~bool arruma_stop_em_posicoes(const MqlRates &cotacoes[]); J7 K, n: b+ n8 R% B, ^- d
{9 R# N9 J, z4 k0 Y
if(PositionsTotal()) // Is there a position?; c; Z( v6 V; f# Z* n5 _& L
{: C, }3 o" o$ A7 E# c, ?
double offset[1] = { 0 };' L, R0 P1 L e" W* g
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
$ @! _5 M y4 U! d6 Q3 T* X# g0 g&& PositionSelect(_Symbol)) // Select the existing position!
* V) T1 a* A1 H& K* S% [ t{
+ L% _6 s% I Q; e" }ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
) ? M7 N8 u1 Q/ ?double SL = PositionGetDouble(POSITION_SL);- A0 I1 M! F/ g" t
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));! } d: I3 w) u( E2 V1 K
if(tipo == POSITION_TYPE_BUY)
; @! y1 {2 T# C7 l/ {' m) b7 ?9 I{; n# K5 H" d8 z; P$ f" M8 g7 y0 V
if (cotacoes[1].high > cotacoes[0].high)
; R. [+ r- u- v{
% M: V) P. ?$ Wdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
# U* j6 ~0 ?' C% n3 A! p4 Minfo.NormalizePrice(sl); U4 u2 R5 m+ z5 y1 z
if (sl > SL)" j% }* q& V) t+ Z, w* ^
{
; h1 W$ C9 P, f" E2 `' H6 knegocios.PositionModify(_Symbol, sl, TP);7 j* f% ^5 N; b3 W
}
/ N- S$ s0 `0 ?2 Y% ?& q4 W; o}3 F9 j6 c' R. k- F# U8 n
}
& s) E! y: G& @, n0 d0 K& pelse // tipo == POSITION_TYPE_SELL
, K& `& u7 X' r3 T{: R n' } r9 a5 `
if (cotacoes[1].low < cotacoes[0].low)& s: r) [- i- }2 p- X, O& \
{( f, _" l# [6 J
return true;
- u6 ~; V2 m. s0 Y}4 E& T5 \' m' x- @) J0 L
// there was no position
% v W; m9 w: v, x. nreturn false;
2 A3 G6 `- |5 s) R& {' L: e}) b Z$ U# e% k+ k, O& W
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
1 `2 z7 K8 s4 S7 r% M1 p8 J9 v到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |