启动交易模型,并构建 EA$ F4 e" B$ P( z0 b+ O" h' q
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
" [) [0 R# ]/ n) q& V5 H9 s' R9 l为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。# \. ?, v5 z/ _6 |
以下是制定这些规则的代码。% ^) [9 G/ V9 t( E1 y( ?4 c
//--- Indicator ATR(1) with EMA(8) used for the stop level.../ k2 f4 ^1 K8 h) z. x: p; W" n
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);/ e; O N; a N+ Z( l, }6 J; ~; ^' f2 G
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);: S1 G, F; R5 L9 _
//--- Define a variable that indicates that we have a deal...: Y' i8 H6 f; P
bool tem_tick = false;
- t, ]- ~6 C- X2 _//--- An auxiliary variable for opening a position3 u, m# Y, _% p7 i( W; N2 l
#include<Trade/Trade.mqh>
* e g: w r( _" @+ {0 j#include<Trade/SymbolInfo.mqh>4 A5 c3 p+ \; R7 P
CTrade negocios;+ g: P- r7 T; D5 M: R
CSymbolInfo info;
) j D' [, A7 b- Y# \//--- Define in OnInit() the use of the timer every second
$ E* ~. p5 e) w% B2 x//--- and start CTrade
3 B! w( n0 b$ x, Q* U5 Dint OnInit()' x3 Q H( l; F7 A! I! C# E
{
; j. \9 \6 n+ r//--- Set the fill type to keep a pending order
( o2 A5 c- X: P- U; Y" w: Q. ?//--- until it is fully filled0 t& X. @) R P4 Q$ a$ S) `+ t* L
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
U6 T) m& v+ @7 v2 o//--- Leave the fixed deviation at it is not used on B3 exchange9 N2 p6 q, Y( v) Y( a0 ^
negocios.SetDeviationInPoints(5);& U+ W2 Q/ f; R2 S, w f! e# d
//--- Define the symbol in CSymbolInfo...0 L# J0 _0 s0 s7 _2 `6 }, U
info.Name(_Symbol);5 z/ ?. v$ }1 p. b
//--- Set the timer...5 K0 ~& ~, d* f: Z* j' c: d
EventSetTimer(1);( Q5 B8 a0 h" g ^* N0 t* l L
//--- Set the base of the random number to have equal tests...% N1 e6 B l- Z9 }
MathSrand(0xDEAD);
) e8 S/ ]! q# h& r G4 rreturn(INIT_SUCCEEDED);
" B j+ f3 o9 z- y, I}1 ?# T& E6 q& w! I. y& h: @
//--- Since we set a timer, we need to destroy it in OnDeInit().5 W/ w! n& S9 z; [ b+ V
void OnDeinit(const int reason)
3 S2 L) |, }2 q+ M2 e6 B# {- [{: m4 j5 X/ i9 n4 [
EventKillTimer();1 j, \* |0 \) o2 F. P: Y7 ]
}& H6 q, ?' t1 q( Q7 n2 G& @+ v
//--- The OnTick function only informs us that we have a new deal$ j' i/ N) h, u" A, k7 n# w
void OnTick()- \3 l3 v8 ]; I/ @" q$ z1 {. u7 G
{; y6 C# K D. X; C4 w2 @
tem_tick = true;- w: P8 Z2 F$ S6 k) N
}
5 h0 o8 V E# _3 G. i//+------------------------------------------------------------------+, p- l" A$ i& @$ g3 V
//| Expert Advisor main function |) |* j8 F4 N* B+ `. ?1 N7 ?
//+------------------------------------------------------------------+
" p' {% [7 @2 R6 ^* Q0 Xvoid OnTimer()
4 \( n8 D3 K- V; J; l: e{
/ U+ @& f. o/ a2 M% oMqlRates cotacao[];
' a5 i# I6 U0 [2 @7 ?return ;$ ~6 E$ S, f3 K+ W
if (negocios_autorizados == false) // are we outside the trading window?
7 o7 H! _* E- ]' ]$ Y: S( Ireturn ;
2 F( c% M; D# @% H//--- We are in the trading window, try to open a new position!0 @: @+ j, P" m/ ^1 n
int sorteio = MathRand();
5 p( d8 U5 N" A8 _* t/ z' C9 n//--- Entry rule 1.11 S. b# M. L+ q+ a4 y f- ?$ r
if(sorteio == 0 || sorteio == 32767)
9 e( J- o* |& D" P! [return ;
& `% e' j/ |* V6 f+ C8 Iif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy5 p3 l8 _+ D5 P% Y! z, M: L
{7 u l3 E2 U4 A4 |
negocios.Buy(info.LotsMin(), _Symbol);6 K2 t. R/ M+ P
}
. P q9 @! z( Nelse // Draw rule 1.3 -- odd number - Sell( W6 E/ R. n2 x' u! }$ c& a( ?
{3 t. H4 t( H7 C3 C% \9 F. J# D
negocios.Sell(info.LotsMin(), _Symbol);: ], w: c9 }6 K
}. M& H# V7 K( `4 W5 v5 z8 F& B6 T$ }
}/ X- b$ s& B2 ~; S$ h5 Z0 j7 i4 n
//--- Check if we have a new candlestick...7 n6 [$ s: K' x' M6 E8 {' N
bool tem_vela_nova(const MqlRates &rate)
# E+ ?. C5 Z- s" @{5 x2 ?/ h% j) f
{" V. j: s3 \7 @* p
ret = true;; x* u( W# v5 B( m+ V2 O
close_positions = false;1 ]. Q0 @, j& k0 y5 J, N9 v
}
, F! Z# G7 E# v9 }& zelse
( M; e' P" c4 ^( @7 h5 B{( X+ l: z; i" t/ v1 b x2 l, m% ?4 R
if(mdt.hour == 16)
! i1 ^( H! v7 b6 i9 Eclose_positions = (mdt.min >= 30);
/ J1 X+ g( O% j( V$ U}: O. O3 k: G' `
}
3 a! d- o$ ~& H+ d( ^( M# Jreturn ret;2 q# J6 T# P$ X
}* K! h: A: j9 B/ k+ _- [
//---
7 o, Z8 p- O/ ]# rbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])& v! y, Y5 [* u2 G# ^
{
1 B9 _4 J7 p2 {+ G/ E+ Jif(PositionsTotal()) // Is there a position?
, z) P9 x+ s8 ]3 ^9 B3 ], S. A- `{; `* F( I& F7 E; C
double offset[1] = { 0 };! i: {/ \6 U: W
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
& p4 e( E( U- }5 i0 V: Q&& PositionSelect(_Symbol)) // Select the existing position!
2 w5 z" K7 e" \1 s# Y{
- N! p3 N- |) VENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
% @! P4 @: b4 M3 o' y! @* ?double SL = PositionGetDouble(POSITION_SL);
$ M' l( e# H T" Ddouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
6 @+ d% x) E) N# `# fif(tipo == POSITION_TYPE_BUY)) ]6 H K9 L( ?4 |( k+ `
{. b! _8 A/ n" y; D6 `
if (cotacoes[1].high > cotacoes[0].high)2 d" A- p! x2 A6 d6 W- z
{6 U( G& H( z8 i. t
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- v, o) y* J" \( n9 e U9 z( ^
info.NormalizePrice(sl);
7 E# R3 I, _$ Bif (sl > SL)8 J+ X) N! l4 G$ D
{
- b/ W/ e# G0 `& N: Z4 _# r& Onegocios.PositionModify(_Symbol, sl, TP);: V9 V8 F* P5 O! O9 r* r: U+ v
}( ]4 S1 \: o5 O
}4 _! H. f6 Z! d
}
! e' A/ o9 G( g) lelse // tipo == POSITION_TYPE_SELL
: H6 A: _: D4 n- c+ v1 U5 ^{
9 J: f+ q' H5 r* `. w2 Rif (cotacoes[1].low < cotacoes[0].low)
7 _+ _# S7 S7 L! t D{$ q8 X5 w. D0 C4 q. P1 @
return true;& j1 J9 h: f1 g
}
, V( H: E$ j7 V' A+ W! b/ P// there was no position
7 p* g* r) W p$ H2 Y$ {) \return false;
9 q7 a( a" v/ t! Z}2 B* B4 R9 R/ p, ?* ?
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
( H y6 _/ Q' I! S' ?/ W: \* h( X到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |