启动交易模型,并构建 EA
: p$ C5 j z$ u在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。3 J; c3 ~& e. B& j! I8 o0 P
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
Y& p9 I: E8 v: D8 B以下是制定这些规则的代码。) n7 @7 d- N3 K
//--- Indicator ATR(1) with EMA(8) used for the stop level...
: [9 n) `" b% a; V1 Q0 b) O. Iint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 h& Q% x# t M+ G
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
/ m# g: ~- Y% I+ x//--- Define a variable that indicates that we have a deal...
3 h/ R! K. i; c K% ?2 F) q$ U- hbool tem_tick = false;
( a+ c7 l' }8 R. S, p4 G! r//--- An auxiliary variable for opening a position
0 O& r- H7 |) @5 N7 E9 \! w/ m#include<Trade/Trade.mqh>
9 {. W/ F3 D6 e( }4 F- n#include<Trade/SymbolInfo.mqh>
" S; P7 P0 E5 C& e, y) L+ bCTrade negocios;
* h9 @& g& H2 K5 l' V# UCSymbolInfo info;+ Z Q8 ^' F$ I% @5 _% D
//--- Define in OnInit() the use of the timer every second& z6 ?$ N, R# A! C
//--- and start CTrade* ~ x+ _4 d+ U2 q0 H' C
int OnInit()
/ s% _" Q% ]/ U7 ]{: d' F& E, p" z0 [( t$ ]
//--- Set the fill type to keep a pending order4 n p$ Y! h' _$ P
//--- until it is fully filled( Z" V3 G! l& {+ A
negocios.SetTypeFilling(ORDER_FILLING_RETURN);+ ?" X+ B0 s M, k0 R8 v( {
//--- Leave the fixed deviation at it is not used on B3 exchange
4 r2 a# x! R2 t0 I# e; bnegocios.SetDeviationInPoints(5); ], B( k6 [! x# y2 p
//--- Define the symbol in CSymbolInfo...6 f! U+ }5 h) g
info.Name(_Symbol);# }. \+ \* \# a0 S6 [; _4 `# e
//--- Set the timer...
# ?: g/ Z: _) D* @EventSetTimer(1);
4 `* P. T0 _) v P# G Y//--- Set the base of the random number to have equal tests...
6 y7 z0 z: ^' |; J( \- WMathSrand(0xDEAD);6 h2 P/ i6 ~" n( P \$ U5 k
return(INIT_SUCCEEDED);7 d. W" U3 |5 P9 g
}
, [& V. b/ l+ N; V' G! Y; i//--- Since we set a timer, we need to destroy it in OnDeInit().
1 S4 q) s# T V$ wvoid OnDeinit(const int reason)
: a. v$ S( J# V$ }2 A+ x1 t: E{( p4 ~$ i& S8 w; r
EventKillTimer();3 d' w) a5 ]! {' G R4 k
}7 Q9 Z8 I' V6 M* f+ j! Z
//--- The OnTick function only informs us that we have a new deal1 \. L/ o p1 c9 W5 f# }& {
void OnTick()3 H5 G& ]! t& y4 E
{
: r- R3 v2 C2 d7 S- [ ctem_tick = true;% |* D2 G* I s
}
2 S2 _! |- i2 f6 b//+------------------------------------------------------------------+
4 K+ R* x* [6 a' G//| Expert Advisor main function |/ b6 t% O% r! {" C, y5 O7 g4 j
//+------------------------------------------------------------------+6 V' [ L4 ?$ W5 j8 a
void OnTimer()
5 l9 h5 u3 D2 ?. l( u+ a8 e0 }{
8 G Q/ f7 v$ N: s, _MqlRates cotacao[];8 p) o1 T3 d. G5 V
return ;
4 |, N, S4 O* B2 l, Zif (negocios_autorizados == false) // are we outside the trading window?
: G9 d, Z w) p) `return ;- j) [! ]% ~9 a: q7 n" o7 E
//--- We are in the trading window, try to open a new position!; f" m' S E# X+ R7 S6 T+ H
int sorteio = MathRand();
- D( p0 g# x8 T, P//--- Entry rule 1.1% _% `5 o( s5 N8 M* _9 Q; K' x
if(sorteio == 0 || sorteio == 32767)) q3 e# V( F6 c! o8 B) ~( J
return ;( Y2 W% A; o$ T- c
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- M( Z5 w2 v! [" I8 b{
4 I: r- k `* W: S8 Onegocios.Buy(info.LotsMin(), _Symbol);
: X- Q. |; G Z5 [' v}
8 [5 W) I9 n c9 C- i3 aelse // Draw rule 1.3 -- odd number - Sell
5 V& z! J L; p0 b{
8 U; O+ V/ K& A, Jnegocios.Sell(info.LotsMin(), _Symbol);; ^2 V6 Q8 ^7 P2 ~1 m3 B8 {
}
5 b6 ~4 u8 N: Z) L2 v! J( |4 H}; n! X* x& B, A* c% @
//--- Check if we have a new candlestick...
3 h9 W6 n" v/ ~) |6 V, {bool tem_vela_nova(const MqlRates &rate)! X: e$ k3 W( Y
{
; K/ x2 e7 b7 {: `{
7 \. Z0 d/ K9 Vret = true;8 E1 |* F; D4 ~# T' s. X) }: l$ M
close_positions = false;8 K+ Z4 \! G, O$ {' _8 ~
}
( n6 \* A0 b8 \2 j5 ~else2 M3 W; p5 f" S; x
{
7 m+ }. W8 K, \% X9 wif(mdt.hour == 16)) S# v! ^' u3 `7 ?% L% Q
close_positions = (mdt.min >= 30);0 ~8 ~2 v% b" g% Z, t# f: G# j
}
* A0 q# M9 u0 N' p) h}' R3 v! C2 m& [& ^
return ret;
3 i3 y# n; `* ^& Y( E7 i}
+ `- a4 d* n; d//---
* p _; d* ~$ _0 w' O$ k( e/ qbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])7 J! w0 k0 m/ c/ w
{
( G" T! C4 V4 a: g* l/ k7 _1 Pif(PositionsTotal()) // Is there a position?
P; a" w: c; e8 t/ C3 f{
8 ], }% M4 r$ n. M- Odouble offset[1] = { 0 };
' o' I1 x' U6 z- F2 x/ j5 zif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
; L; J9 T( J; x1 r# Q8 J2 r0 f&& PositionSelect(_Symbol)) // Select the existing position!
! w# X$ o2 P3 X{5 o) q9 Z: M5 a1 L, l
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);4 v# R& v ^$ I6 D' e" R
double SL = PositionGetDouble(POSITION_SL);* @: u# }8 ~' R- t+ Y5 p. ^
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
+ E+ X8 K$ Y7 F0 O/ j. Rif(tipo == POSITION_TYPE_BUY), q- f0 D, L8 Y" d- K6 ?: U1 x
{
3 v! f: l# l A. r _6 Q' Xif (cotacoes[1].high > cotacoes[0].high)% P" g# V' _0 j3 i* O( G! A
{
$ m2 h( Z* h0 m0 h6 \double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];" N. t& {* S5 O4 ^
info.NormalizePrice(sl); O6 n+ s$ ^6 s7 d& _8 [1 |. @
if (sl > SL) N; E1 t9 o9 G2 R9 Q
{
; d% c+ S4 X7 ^5 q" b9 u! F0 U- rnegocios.PositionModify(_Symbol, sl, TP);( B- U% ]3 V1 h* ~+ h1 k
}$ x A0 t5 u& v8 [0 }% L' u
}/ O V, s5 B c& q3 {
}! [' l* V) {: g2 z5 r5 s
else // tipo == POSITION_TYPE_SELL0 ^5 h6 B( L. H1 g6 E! W
{0 ~3 Z) N; ^- B- M
if (cotacoes[1].low < cotacoes[0].low)
* I( I7 t6 E5 a) C* O{- Q. w- p. W2 ~- k
return true;' U' n2 J! q' J' w% A4 |; d# z: R: ?
}, L: @/ v7 Y4 I
// there was no position
8 V; r# I7 p1 ^2 Y9 ireturn false;# S$ n0 z) F4 F4 {+ B
}9 S& D$ Q( B' S- t, m! X* Z) N; V
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
2 g7 F M8 P9 N( X到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |