启动交易模型,并构建 EA
; ~6 ^( W2 X# A6 E9 G& F9 k在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
& ?* e5 Z: U1 S9 L- W" D为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。! g# v2 d+ b: {0 X N" a
以下是制定这些规则的代码。$ @9 P P/ h4 M* B0 \4 R
//--- Indicator ATR(1) with EMA(8) used for the stop level...
5 \6 |% l8 S+ c& Kint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
l4 y2 q& M" B3 A) p$ R! nint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);. D: k6 j {# o! s, G
//--- Define a variable that indicates that we have a deal..., X( Q& R0 w" u& T# e3 O. z* Q: l
bool tem_tick = false;
- m0 M7 p3 @4 J- l9 c5 f//--- An auxiliary variable for opening a position8 V7 {" b7 F6 i* D$ p) _4 x
#include<Trade/Trade.mqh>
: ?4 v/ R+ {7 w8 ~, n$ ]#include<Trade/SymbolInfo.mqh>& i4 h! l+ u2 y" e2 [0 q
CTrade negocios;5 G4 ^: r* E; Z! n- M
CSymbolInfo info;8 Y2 O5 c1 r# s( L: J$ W' A
//--- Define in OnInit() the use of the timer every second
7 O7 c4 K3 a/ Z* T3 p" q# r* _% O//--- and start CTrade
5 \+ q; I2 v3 z- S1 Jint OnInit()- j2 Y f5 c6 k
{
. ^ b1 e4 S9 \& e1 K4 a. k" `//--- Set the fill type to keep a pending order
. W! F6 K! l) @9 K//--- until it is fully filled& E0 U# C3 l& {* r
negocios.SetTypeFilling(ORDER_FILLING_RETURN);- h, \- b0 d4 V8 d. ^8 u
//--- Leave the fixed deviation at it is not used on B3 exchange) Q! H% w1 x4 T. y: F: ]
negocios.SetDeviationInPoints(5);: y3 Q! o# S+ d7 Z& U2 N. @
//--- Define the symbol in CSymbolInfo...8 `' H' r9 E& l5 r" i7 H% G0 O
info.Name(_Symbol);
- R' F5 Q6 e5 P' P, l$ W//--- Set the timer...
* [+ t, H8 r( I: A. Q: _EventSetTimer(1);- o/ V, R. `; j2 Q; S; G
//--- Set the base of the random number to have equal tests...! @. j! O* M; X: \* ^
MathSrand(0xDEAD);
# w; z' S( D7 a M# ^/ T% }return(INIT_SUCCEEDED);
+ M3 M$ h' I! g0 ?, c: E! `}
: k4 ~1 Z+ L# _, E. J; W4 ]//--- Since we set a timer, we need to destroy it in OnDeInit().
0 m7 t* g) k1 pvoid OnDeinit(const int reason)- z! t5 F$ o* r* S, ^* c
{$ ~+ \+ W W3 u7 N6 \6 n# x
EventKillTimer();
) I4 Q& b% }( r; L6 g}, M5 M" W+ c* C" q6 `+ y
//--- The OnTick function only informs us that we have a new deal
# _3 p5 m3 K, A& G5 hvoid OnTick()& r2 y9 Z; h: ^4 u' z1 X' h
{4 g; i) \, J7 V: ?
tem_tick = true;% K, O$ E! y; }" r8 r' V1 i0 U( A
}* V H1 G& A% l& P
//+------------------------------------------------------------------+5 P* W6 M" s$ F: u9 a0 G
//| Expert Advisor main function | i$ f% w5 k9 l. [9 L
//+------------------------------------------------------------------+
) j- P/ n! B' I7 H0 v7 r1 ]void OnTimer()
' N) S9 K9 O3 l9 z{
/ R/ e" A4 F" ^# mMqlRates cotacao[];9 a2 k1 A: k' N& g; b* u2 }( E
return ;
. g# ] {) N! f0 N7 W9 pif (negocios_autorizados == false) // are we outside the trading window?
/ y, V! o- [: w6 A/ y% freturn ;
* E) ?% W t) l3 \//--- We are in the trading window, try to open a new position!
) |0 ?2 c* S: eint sorteio = MathRand();) x/ X' j; z; U
//--- Entry rule 1.15 ?* a4 r' }* @, A8 Q
if(sorteio == 0 || sorteio == 32767)
4 P- b, S$ P7 @ {; freturn ;
2 r5 h: e. u X" w$ c s5 kif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy% a3 {2 z9 ~2 m% D6 q
{4 @- C. F; E' n/ T/ c: `
negocios.Buy(info.LotsMin(), _Symbol);
! P1 O* i( I1 \0 `& f3 K$ i}5 j. ^7 V) D$ p6 J# r5 p5 [1 p
else // Draw rule 1.3 -- odd number - Sell7 l, }/ _0 k1 V I
{
! V" Q O+ c9 ~& g9 Fnegocios.Sell(info.LotsMin(), _Symbol);) i8 {9 N4 Q3 G; Z
}, ]) p$ S- Q) z- g
}
; N+ _: }) D3 S/ }/ w//--- Check if we have a new candlestick...3 t9 m5 C. F. }" z l( I
bool tem_vela_nova(const MqlRates &rate)
u4 ~4 C8 d& X' r2 O{
: i& }$ w2 B# j4 L* }{
' Q9 j) C2 {6 jret = true;
5 {$ P W7 c+ Vclose_positions = false;
- t2 S( r( E4 Y9 \}
; n7 T) A4 {" V( \ ^# N7 @0 _( v; Kelse& X$ T1 p' U% h$ Y+ |; J
{' m8 Q# F, F0 Q6 S
if(mdt.hour == 16)
3 ?: a; ^3 e0 Fclose_positions = (mdt.min >= 30);
; B9 o5 L& O" _3 b0 U}* I$ _$ p3 O0 o
}
: S7 ?; U. f5 A* T# b' V' O1 Greturn ret;
/ g; `! ?# c, a}& @3 W: U& K% S; }2 H: |" y7 m# q7 u
//---# D: d2 Z1 H% P5 ?. B
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])8 r1 _4 t7 ? G" ]! x5 E
{4 j. G) C% K9 X1 \/ R
if(PositionsTotal()) // Is there a position?8 p( n, u5 Y. Z6 ^2 k
{& W4 M' ?$ k: X6 G1 p6 F
double offset[1] = { 0 };! j, a6 C2 K+ s3 h1 Z
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
- ?% E3 q- N2 x&& PositionSelect(_Symbol)) // Select the existing position!
8 [( {$ R" L/ b+ x{
; y! w _( P0 {( f+ y9 jENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);5 u- m U# T, k$ C& ^3 O
double SL = PositionGetDouble(POSITION_SL);, d$ ]1 n1 w, T) {8 R3 Y. E
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));, q6 }; ]/ `" W9 ^: l* G/ v2 ^/ ]
if(tipo == POSITION_TYPE_BUY) h \* h' u+ c
{" u! g/ y* T: S
if (cotacoes[1].high > cotacoes[0].high). @& c8 Z$ }( u- t
{* T) i' h- {0 @
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];0 h+ R4 I S/ a& B g6 R, J
info.NormalizePrice(sl);" B# T/ D( W+ Y: a z8 d
if (sl > SL)3 ^0 j$ W6 X- n0 i+ d7 F* I( }% O
{ G# }0 K# M: r4 V; a! A
negocios.PositionModify(_Symbol, sl, TP);
. {9 Y! l( D$ g: K# T; V8 h% p}
+ J! s: e | V0 Y* d6 c9 e( d3 s& B}4 q$ Y% i: [7 ]& }; H
}
: E: e' n' j4 b2 `8 P6 B, qelse // tipo == POSITION_TYPE_SELL+ B& K2 o! Q; G6 {" b7 n0 e# U
{$ E5 M! B, x; h" h4 c ^9 r
if (cotacoes[1].low < cotacoes[0].low), ?5 y2 y- O5 j8 M8 K( F
{3 _6 p# f7 w' y3 g3 c/ ]+ x
return true;
, Y0 A; ~$ Z7 E6 `: {( u" {}
' z: G, j; ~; W' X4 l; f- h// there was no position
) P2 ^, a. K. breturn false;
, W M1 c4 T+ E* I; l}3 F) m6 u* J% ~
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
& d) M" T; V( x5 Y/ t- X1 J% z9 @到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |