启动交易模型,并构建 EA
, P9 Y4 q* ~# ]' J在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。6 {3 R1 u$ K/ O' o: O
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。! U: Z, Z4 l |* R
以下是制定这些规则的代码。
% Q' ^; t3 }3 K4 K3 `//--- Indicator ATR(1) with EMA(8) used for the stop level...( H# C0 S3 U3 c( G3 o) S$ `; s* N
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
9 \* V) O! J$ k- b- g2 f- k8 s+ e ?2 hint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);3 \" v& C$ G3 A3 A+ Z1 r
//--- Define a variable that indicates that we have a deal...% I" w1 e# M) ]. A5 ?. q; H2 Z
bool tem_tick = false;
4 M, O' t( I% D: U+ [//--- An auxiliary variable for opening a position6 F% ~" Y1 M7 v* F( a. B
#include<Trade/Trade.mqh>0 s& C, {: W8 f: B
#include<Trade/SymbolInfo.mqh>
3 T' B' ?3 E- |$ x2 _7 ^CTrade negocios;
. d- [% q% ~3 I- i& G# O2 Z! [CSymbolInfo info;
4 W- I( V5 x9 j1 x//--- Define in OnInit() the use of the timer every second
! ^ n l5 Z; C- g* ?//--- and start CTrade6 j/ }. w6 G. A& k! m! _' f
int OnInit()
% q9 s ~5 u8 c1 U* x7 ^4 Y{6 h. Y1 B9 N7 g& t* t& }
//--- Set the fill type to keep a pending order+ v0 F8 N- y1 A; O |/ a
//--- until it is fully filled
( T1 h+ f3 _7 m$ l* R5 E) \negocios.SetTypeFilling(ORDER_FILLING_RETURN);
( b3 F3 N p. B2 W( }9 T7 b//--- Leave the fixed deviation at it is not used on B3 exchange+ B( f) C; g; B0 Q1 m
negocios.SetDeviationInPoints(5);0 d. G/ B- O% l8 _% p7 S' q0 O: \
//--- Define the symbol in CSymbolInfo...
7 J, A! p* ^6 M" }) Q4 y! f# x2 B! Jinfo.Name(_Symbol);7 b: n! S E( A4 C: v4 R8 r+ A2 j2 L7 U
//--- Set the timer..." Q" q9 \* n) t; T6 ?: P
EventSetTimer(1);
: F/ T2 S; n* u) Y+ t' a- S- ~//--- Set the base of the random number to have equal tests...
, u3 j5 S* A2 ^9 f8 i3 \MathSrand(0xDEAD);
( O4 z, G% N" W5 ~) s: ~return(INIT_SUCCEEDED);; v' Y2 I% l- R% i$ X2 C( w U
} e7 s1 F4 l" B& q9 B
//--- Since we set a timer, we need to destroy it in OnDeInit().
* G1 s% O8 W8 z, o0 `* qvoid OnDeinit(const int reason); m; L% s% c6 l. G* H+ @
{; G3 q: S" i( x% a9 W: z
EventKillTimer();
7 k& S0 p4 m4 O5 V/ s}
2 X8 w, c c% }5 B7 Z//--- The OnTick function only informs us that we have a new deal* U& k3 U# O+ m; a" b) m4 V
void OnTick()
: {$ Q% m. ~( |0 r' `. Y{8 ^' H% g: _. d& C5 o
tem_tick = true;
3 d$ _0 K* l& o- M+ _}+ H( r- z" L5 M% t
//+------------------------------------------------------------------+
% J: x' Q" j8 L8 o1 \8 R( i//| Expert Advisor main function |
: q: o2 Y3 |3 A/ }/ l//+------------------------------------------------------------------+2 [' V- S9 B0 P8 h5 a
void OnTimer()
S# ` V5 D$ z" V( N: Q3 {6 x{" b1 D$ F5 f, Y" P M0 l
MqlRates cotacao[];1 h3 A( G5 W8 k+ f0 K
return ;8 {+ W' ?2 J" q# _8 h+ ^7 v
if (negocios_autorizados == false) // are we outside the trading window?- e9 g3 e j# F& W8 I: y
return ;1 U) W3 @ b0 w. `4 S) C. Z
//--- We are in the trading window, try to open a new position!, L) `, l1 v, V# K2 N# c/ M
int sorteio = MathRand();% @) V4 V" N G% |( b3 `
//--- Entry rule 1.11 m* L' K0 ^ {. `
if(sorteio == 0 || sorteio == 32767)7 X" C0 C3 \0 P4 F# T3 f
return ;# V$ A q3 J2 A) f" W2 p
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
! f9 I) W z7 S{" G3 l9 }& U8 e* p/ ?0 Y$ L
negocios.Buy(info.LotsMin(), _Symbol);. y- @+ {/ D- D9 l6 L L" ~0 {
}
" |6 F: }' n. g4 i* e9 I: ^* {else // Draw rule 1.3 -- odd number - Sell% Y1 x+ e5 f5 J6 @- j" \
{5 i# S, y+ R& U+ X
negocios.Sell(info.LotsMin(), _Symbol);' A2 h, ?& J5 h( k# V* r
}0 j- Q6 W6 u# C0 A, m
}4 b- @- j/ G* v4 y
//--- Check if we have a new candlestick...
' ]4 o: E8 O4 ubool tem_vela_nova(const MqlRates &rate)0 f* U3 B) O2 z* n8 b8 g# T2 i
{
0 r7 c( ~7 _; z8 [2 l4 `6 ?6 d{: G* C9 z7 d! x; G# ^5 N# o' S! X
ret = true;$ o( h9 W a! r& ]& ]: H
close_positions = false;, L5 H% b# G9 I+ E2 _# T
}
8 k1 w; J5 z+ _' I" }" \* q6 t1 Velse
1 a! l( d; C$ {{& F1 O5 m1 c+ z" q7 P2 g
if(mdt.hour == 16)4 a6 Y+ x- e( a* ?% _
close_positions = (mdt.min >= 30);
! a% J7 Z) J! S7 q% d0 f, X}
$ u0 z$ O p# K% t}
$ E6 P, X* O) E0 w( r+ O9 Qreturn ret;
+ w% x! l& ^7 f, Q) P}: v* a& B: ^# K
//---
" L1 W# P( r. X0 R+ |& ~bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
; F3 Q, Q, s1 ~$ B) t9 r+ D7 [{
. c; N+ c6 X3 g- l; S: nif(PositionsTotal()) // Is there a position?
4 _5 u# F$ ? h{% ~. G/ v$ [5 s* Z
double offset[1] = { 0 };! u( h# h4 w9 {4 u" `
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 b5 ?* ]3 e/ f1 ]7 B
&& PositionSelect(_Symbol)) // Select the existing position!$ y( y( j5 E7 V. Z" i
{; E+ {* j1 N- L; m2 ^1 `- u$ O
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);" O: s3 @ b, {2 _( `4 L8 X
double SL = PositionGetDouble(POSITION_SL);
6 T# v) a8 A1 X0 n3 S' Wdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
# [5 q ?' p1 \' y" T3 p& ]2 cif(tipo == POSITION_TYPE_BUY)
( @" t o1 }3 U& T# O{2 v: i6 P! T) @6 B$ x
if (cotacoes[1].high > cotacoes[0].high)
4 }% ^( C. b" w6 G7 z{
! b- {0 X/ A3 d4 M/ p: _$ _double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 d% Y+ I7 X9 g" P7 }, L
info.NormalizePrice(sl);; \0 H5 W4 `3 j
if (sl > SL)
: W- s- u% g: _, M% e* I/ w, k{' k" x- K# |7 ~0 f+ |
negocios.PositionModify(_Symbol, sl, TP);
) `& I& F3 \( W, @* \" T, r7 a}+ h; S( O) u4 n8 [4 x, ^0 E- g
}6 p) W; k y+ k3 B* R, v5 W+ ~
}
& f+ a/ S0 @0 C* i# i8 u0 Relse // tipo == POSITION_TYPE_SELL6 Y7 Y4 D H- z. {+ ^; D+ Q, x
{6 ~+ I3 u0 x7 V. z
if (cotacoes[1].low < cotacoes[0].low)
% m z, s3 m; B5 B1 S" T7 h{
" k) R U, b9 k: X" i! Ereturn true;
4 G Z8 ]2 U2 T; L) c7 a6 l}9 S8 Y2 g9 W+ Y, P ?
// there was no position
. Y0 X8 d4 M" Q. b0 yreturn false;6 ]! e) S# w( H7 C( T
}4 x5 t' p( b. U( U6 W# a
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
/ Z* M, K4 t) ]1 c, B* @到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |