启动交易模型,并构建 EA
9 r* k% v$ w; T/ T在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
8 o6 A, r) Y1 p) y# a为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。3 g/ w- n9 }9 B8 \
以下是制定这些规则的代码。
5 f" b _) I1 q G% `! F//--- Indicator ATR(1) with EMA(8) used for the stop level...
6 Z6 g. i! b; q) O3 aint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);! C& F: l- p+ `( G. c5 U
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
- L$ {; t5 o, F$ X6 K//--- Define a variable that indicates that we have a deal...( Z) U' W7 z! m! R
bool tem_tick = false;
9 [) C: @' V: s0 `5 K//--- An auxiliary variable for opening a position( l/ g) C+ F) D' H
#include<Trade/Trade.mqh>
% F7 ~# h+ ]' a9 ~#include<Trade/SymbolInfo.mqh>
f1 i) F. y9 G1 dCTrade negocios;
( h/ c% t7 g; kCSymbolInfo info;3 l( D/ A: k8 o* A- K5 F) \* }. ?) D
//--- Define in OnInit() the use of the timer every second. q& J9 E! k- o0 x% U, |8 m# x
//--- and start CTrade
6 w# p8 D' z. p7 w1 W1 \# zint OnInit()
; N6 V& V5 P o) ]- d/ k: ^3 B{
( e- P, |( S! Q' [! z) b; S3 X//--- Set the fill type to keep a pending order
! N$ J( e! B N) e% P+ y6 [$ c//--- until it is fully filled
/ h: e! \* E) bnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
( w+ p9 O+ d/ Q" c1 a8 G//--- Leave the fixed deviation at it is not used on B3 exchange' R @) S9 \4 W& |: ]/ `: a8 Q
negocios.SetDeviationInPoints(5);
) e( T# J9 l2 i" ?2 [. O//--- Define the symbol in CSymbolInfo...
% t; i% ~ H2 ?info.Name(_Symbol);
' R& I6 r& }3 Z5 l" W//--- Set the timer...
: x% M( [% Q- N+ WEventSetTimer(1);" ?, L4 Z6 _9 U0 p1 q4 w# w
//--- Set the base of the random number to have equal tests...
- I; Y( Q* z7 G7 uMathSrand(0xDEAD);+ n T/ ?, }/ W
return(INIT_SUCCEEDED);% q8 |9 f h. c2 A2 B! v' e' F
}
% u3 C- U+ v: ~* J//--- Since we set a timer, we need to destroy it in OnDeInit().7 [- A9 d; Y- S3 D
void OnDeinit(const int reason)
8 Q6 l1 @' H v2 D2 h{+ N: H# j* { g: p' t- K& b
EventKillTimer(); x9 s6 B$ T: ~
}
) b* v8 ~7 a0 T8 |//--- The OnTick function only informs us that we have a new deal& m% Z% a* | q) G6 y
void OnTick(): @9 \' y) N$ x4 m z7 \
{
X9 { P3 v* n u. I9 `tem_tick = true;
3 `& n. \! \! e0 [# l' U}
; d: @, ?2 s9 t S5 ?: ^7 _//+------------------------------------------------------------------+- S; Q" S- T- B- A
//| Expert Advisor main function |
$ e3 I) S& a! s9 N# W//+------------------------------------------------------------------+
# h1 i- b; H& J# s. dvoid OnTimer()% I% p+ a- G [1 T
{8 F0 e' Y m0 }
MqlRates cotacao[];% m4 X8 ^( {. D9 ~* Z9 h/ {6 j& ]
return ;
$ b) }6 e+ o8 x. A/ D- O& iif (negocios_autorizados == false) // are we outside the trading window?6 h4 y$ Y/ g& U, \+ ^8 |' ]+ F
return ;. Q1 _4 a; ~! W; k) ~" m8 [
//--- We are in the trading window, try to open a new position!8 I$ u9 B( s& ~; \4 c
int sorteio = MathRand();4 t' s) H, ]" ~0 ~2 {
//--- Entry rule 1.1
7 Z3 z: o( O1 v$ Z- L9 K! Gif(sorteio == 0 || sorteio == 32767)
8 V) k, Y, s* d Sreturn ;
W' @* N% H& F& l3 _, x" ?2 u8 ^if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy# b3 i+ w& e' ]6 c! i0 U8 X
{4 U% {) o8 ~' v4 l; l9 b
negocios.Buy(info.LotsMin(), _Symbol);
2 ]3 P# Z3 p, \} M% w, s9 u0 a9 m! ^5 u! `6 ]
else // Draw rule 1.3 -- odd number - Sell
, O V- ~* L5 ~9 y{' {( C9 L# ]8 G+ m1 c
negocios.Sell(info.LotsMin(), _Symbol);( N( Z6 Z2 ?- M8 R
}
/ r H9 s0 {5 j}" Z% R- z, `+ D7 o0 B6 \
//--- Check if we have a new candlestick...& V5 @. V' u% [- W
bool tem_vela_nova(const MqlRates &rate)9 s7 w4 v3 ~1 `, t2 A% K. h
{
2 A2 V1 {' }3 U/ v{; N) C: c+ O. t' A$ S% t1 s9 H7 I: x
ret = true;
, h! I \: h: x6 x: Hclose_positions = false;
& m$ X" Y+ F% B& z- T% m+ e}- d- R8 Z$ J, Q' O- ~
else
# H$ h0 \* J5 {5 r: Y/ o{! J9 K6 u Y6 U0 a
if(mdt.hour == 16)
) o O+ u3 o% `: s* p Xclose_positions = (mdt.min >= 30);" W% R' a: k6 g+ i; }
}7 F, [& U% N: |0 g4 Z$ {
}9 ^7 M8 Q/ e5 V( {! c5 h! n r
return ret;
7 T( x g- e, Z% f}
8 v2 G9 |/ a% K6 f, c3 c5 e//---
Z9 y0 z; q! h8 dbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])% E2 ^0 _+ L# H. m: {. m6 X, D
{3 a& M5 w. K; j4 R0 S) m% j
if(PositionsTotal()) // Is there a position?
: a' o ]+ a {2 v0 C1 n{& b$ M! |7 H9 N' n: O6 p _5 I
double offset[1] = { 0 };1 x2 M' \7 h3 a# Q
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
4 J! d: X2 o7 E) A/ c) P&& PositionSelect(_Symbol)) // Select the existing position!
% W6 c5 H) G, M3 l; `{
0 q3 f" Y8 f3 `& kENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);2 i8 a6 Y0 `/ q( x
double SL = PositionGetDouble(POSITION_SL);
% q' v6 M. @8 f8 u, \- edouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
5 V3 @0 G0 }) r% X4 H6 B4 `; ?if(tipo == POSITION_TYPE_BUY)2 s- S# v4 j- M
{' d" ?% ~9 t0 a" L2 k! W
if (cotacoes[1].high > cotacoes[0].high)
3 b7 E5 C+ v( V4 z2 Q! }{( O4 v! p# Z. g; f [6 g' l
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
3 R7 S- P3 h, c+ finfo.NormalizePrice(sl);
7 b+ |3 ]) X" F' v+ xif (sl > SL)# }+ ^# P, F) L( R% J
{
8 ^% H/ y5 H, Y- g8 j$ Vnegocios.PositionModify(_Symbol, sl, TP);
: J7 a1 X1 r8 _8 v5 e2 F}
7 D9 @4 I" X/ _8 G' ?}+ H5 }3 P$ `0 j+ ~, X# k
}6 v6 Z* P. o/ x& y8 |) E3 X: l
else // tipo == POSITION_TYPE_SELL
! O" g1 f3 t: ?0 ]- H4 F{2 i# @5 U1 z$ M) v4 W
if (cotacoes[1].low < cotacoes[0].low) c2 t' F2 r2 V" j2 R" y( V- _5 O
{
& e7 t! r9 R% Z+ H- ^# \' zreturn true;4 R' Y5 E5 `9 Q. j& k0 p
}
: Y1 m. }* s2 ?. h. _- K* v// there was no position7 j# g& f' j* [' l3 l
return false;7 Y8 M/ I6 G; j# x
}
7 z. e* c7 J" L/ {. G) g5 e我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
* y6 q% R5 _1 I+ Q1 G# Z到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |