启动交易模型,并构建 EA) @* f" D2 d3 Z, w, j/ }0 c
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
# D8 Y ~1 s% l9 }$ H: |为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。8 P* V% }' ?3 s5 s) c5 L$ M
以下是制定这些规则的代码。& d$ [0 a5 I% T) v8 c
//--- Indicator ATR(1) with EMA(8) used for the stop level...
; E% U' {; j/ `+ S6 D3 J$ L7 cint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);; n) x! C' p* G0 n
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);' I2 w8 P# b8 p
//--- Define a variable that indicates that we have a deal...
1 }6 M" S, R& X) M" K! \bool tem_tick = false;5 w8 b6 U& M5 w1 j- j: s
//--- An auxiliary variable for opening a position
2 w5 `% m0 F8 c5 T4 ^' u5 ]#include<Trade/Trade.mqh>
* i* ]# Z: W* P; {# `& v#include<Trade/SymbolInfo.mqh>
& L+ y" t" [; `CTrade negocios;6 D9 J) `9 J' ]0 V4 \
CSymbolInfo info;
! B. o7 a! e7 d- f# t$ @$ U//--- Define in OnInit() the use of the timer every second7 u. a. _4 P5 z! e$ @2 n6 B
//--- and start CTrade
" h" }6 N0 Q) S8 ? v1 v9 x5 Fint OnInit()
; \+ [; u; w: V! P{
& G' O5 r/ n* J$ G, X2 b6 v//--- Set the fill type to keep a pending order4 m( D3 h9 ?& x
//--- until it is fully filled
% r. H# \4 b% L- c: Tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
, F3 P9 [3 S% c, H/ U//--- Leave the fixed deviation at it is not used on B3 exchange. G! r6 y8 m5 Z4 \! R) `# C
negocios.SetDeviationInPoints(5);) m0 s- w( ~; [; m, N! S ~
//--- Define the symbol in CSymbolInfo..., G' G% M; ~; ^6 P4 H
info.Name(_Symbol);: _/ r( E) r' n+ j+ w$ g4 }% [& y
//--- Set the timer..." K L9 `1 ^0 e- [ I2 P
EventSetTimer(1);
8 C; q1 B, w, U//--- Set the base of the random number to have equal tests...
9 I' F! Z8 g! A0 l' RMathSrand(0xDEAD);
0 L- b; I0 f, D2 w# D+ p Treturn(INIT_SUCCEEDED);: h" |, I' x W. z# \4 K V
}
' y. y4 ~4 V2 ~8 L( q! {5 k//--- Since we set a timer, we need to destroy it in OnDeInit().
; @& @& P/ p/ g' fvoid OnDeinit(const int reason)! j+ F) S& U4 x) N/ P+ E+ I4 k8 D
{( D6 h$ I, Q, ~/ c+ y% W
EventKillTimer();
) J0 ?9 X6 _/ A$ p2 L4 B! h}1 O5 J5 D; d- Q3 |
//--- The OnTick function only informs us that we have a new deal3 \6 Z2 J3 r2 e) n4 @9 J
void OnTick()
: R6 A; U6 [6 A{
4 g: U" k7 [8 c) ]tem_tick = true;/ P6 d6 s& H' [8 i
}
, _% g/ _! ]1 a2 L//+------------------------------------------------------------------+- |! B( m5 v! e' j4 c# L/ ]. v6 T; X
//| Expert Advisor main function |+ n4 h* m$ X& t/ n% d# E& }
//+------------------------------------------------------------------+% V6 V: x$ `& W, n* H& [# X3 K% V
void OnTimer(), w% W% R# Y4 L- k& _* w
{
3 T& ?' g" K; R8 V# qMqlRates cotacao[];+ `0 ?0 `: m* N. u6 B$ O$ \
return ;. r8 A5 z+ e% k+ n( v9 y
if (negocios_autorizados == false) // are we outside the trading window?! D- y8 j& b3 S7 B0 o( d
return ; }7 E8 d6 Y4 z. c
//--- We are in the trading window, try to open a new position!5 e8 a M! o9 h' J6 L& v
int sorteio = MathRand();( H, A+ h0 I$ y
//--- Entry rule 1.1) M9 |" ^* F% ]
if(sorteio == 0 || sorteio == 32767): `$ f# |9 S; t4 P! b
return ;
. ]+ c1 r) B ^7 |if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy3 {+ N( v$ @! i. n7 G6 I2 G" e
{" Z5 f6 e# b: K' j, `
negocios.Buy(info.LotsMin(), _Symbol);
J+ x: f1 ?4 p. u/ {}
5 G/ u$ u4 f. m; ~! g& jelse // Draw rule 1.3 -- odd number - Sell* O+ T E6 {7 w
{$ G( z5 ?. V) @* j m# Q* S
negocios.Sell(info.LotsMin(), _Symbol);
" h8 ?: d1 @0 H b4 e; _}0 f* Q( T2 N+ |. ?! T
}- a9 d' o; H9 d/ ^* D
//--- Check if we have a new candlestick...$ o. [2 e( ]" e
bool tem_vela_nova(const MqlRates &rate)
9 C2 `3 y- M, b" {{
. _' \0 r2 [8 L& m0 k{% D. u9 d/ g' A( G( t
ret = true;6 k" S; E5 H" E0 I' B2 o" h6 Y) j
close_positions = false;) f/ i: L' ?7 |
}# `/ [; C2 d: J- C
else
. [0 k' B, ]2 A{: l1 }# N( y0 h; ^
if(mdt.hour == 16)1 D6 _: D/ t9 G7 a q4 y6 w
close_positions = (mdt.min >= 30);
' O/ W% U& {1 [" e# Z0 r0 Y" O}& J( @" F( h; q) o( p- m
}: P- ]; F& S- ^/ n; ]: s
return ret;3 F% V: [. H' K; T
}; O- Z7 P7 j- V O
//---
# [1 j; t* I$ q k) {3 @/ t, x9 Abool arruma_stop_em_posicoes(const MqlRates &cotacoes[])# V- B9 e6 d! O" w5 p, t m, g
{
' k0 P' E0 d, o/ V" {* O# L) Aif(PositionsTotal()) // Is there a position?% p6 {+ u2 L3 `3 H7 ] M
{) a( \, n( o9 O4 d0 F- d# q
double offset[1] = { 0 };
5 H3 o8 |: A. h4 uif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?# M0 L# h: Z! J7 k3 a) P
&& PositionSelect(_Symbol)) // Select the existing position!$ @- {* N+ i( i y! E
{9 ]/ B( `' U- u$ O k6 ~
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);" _* ~/ N% A- a$ d d
double SL = PositionGetDouble(POSITION_SL);
6 Q8 x: T$ G, K: h& L/ @! Xdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));* [8 A$ G( C: o/ p2 E1 q
if(tipo == POSITION_TYPE_BUY)
0 B4 G3 c) A. a2 i{- ^9 n8 F- x: s0 u3 O; O
if (cotacoes[1].high > cotacoes[0].high)
$ M9 i5 n' ]* V7 U, l4 |{
0 E. X# f- U$ e* Z0 Y7 S ?. H) jdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
% L0 t$ q, n7 w8 v% T5 p/ Rinfo.NormalizePrice(sl);
[& `8 L- M6 o1 X8 Jif (sl > SL)" T; U1 G1 x, J0 u
{
, M: C& ^" M1 o dnegocios.PositionModify(_Symbol, sl, TP);7 o: N1 v8 n; h
}
' m+ [5 {# g0 K! z& L9 i3 p+ ~}
# x: o, n2 [3 E}* g, J! j- d: B8 l% Q, t! W
else // tipo == POSITION_TYPE_SELL
6 Y" f, P! O9 }- L{
8 N$ {! Q, O+ [- A% o# ` qif (cotacoes[1].low < cotacoes[0].low); B, ^2 r( q- P: x* b4 N4 [. i
{( X* m/ x3 Q) P Q
return true;
N$ Z) E9 o' K( R2 j1 t% u( H}+ _( ]/ L4 n. w! v
// there was no position
- J; }! e- I" M. p% Lreturn false;& V0 G2 T0 k' f* E, k9 X
}+ n2 a. O4 Q' a# P
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
8 k- v( T: t# u, v, P4 v+ h到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |