启动交易模型,并构建 EA& t% [- Y \) ^$ B; b2 i5 x
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ c+ ?1 o$ h0 M% k1 p
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 q1 K8 v8 Y$ l2 z! H: B, h
以下是制定这些规则的代码。
; _! _: P- M8 N8 M! i+ g: w//--- Indicator ATR(1) with EMA(8) used for the stop level...) }0 T, L! [1 {% v8 _; k
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);0 @7 M2 J& t1 n6 S d2 e
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
3 v' R( F, E1 W. \; g8 V//--- Define a variable that indicates that we have a deal...
; M% c ]& a4 @& \1 }bool tem_tick = false;
" b) L- T8 _8 ?* W/ L//--- An auxiliary variable for opening a position/ W# h p; ?' ~3 p
#include<Trade/Trade.mqh>
6 O( r) P7 t& E+ K# k' F8 \#include<Trade/SymbolInfo.mqh>0 V/ p P z- k9 k' u& w
CTrade negocios;
4 t: N+ y4 X! w( Y% g" nCSymbolInfo info;
r. k8 Z0 j& I4 Q+ Z//--- Define in OnInit() the use of the timer every second! x* Z v y# M0 m: P) W
//--- and start CTrade
) V6 t+ c" S( e# ^' p S. ^( w+ ~int OnInit()$ r' F* T1 n5 O3 f
{
1 `9 s. O5 J/ O6 y//--- Set the fill type to keep a pending order' f: W d% s k2 e5 n% |
//--- until it is fully filled
& s3 k; h6 X- A& [1 K7 Inegocios.SetTypeFilling(ORDER_FILLING_RETURN);
* @& ~0 `" ^- O! t1 v//--- Leave the fixed deviation at it is not used on B3 exchange
( N( k1 e. S$ ?5 D/ {0 e' hnegocios.SetDeviationInPoints(5);
8 E6 s6 ]1 x3 _& D2 [' |//--- Define the symbol in CSymbolInfo...
; O* y0 ^' Y$ _1 c! G# f& r* hinfo.Name(_Symbol);
. J4 l! p8 X3 O* r- p$ O//--- Set the timer...
6 ]. L% u6 B- v' nEventSetTimer(1);
1 W9 L8 g1 h2 r3 l, j; H//--- Set the base of the random number to have equal tests...) V! @/ V; U1 n% Z
MathSrand(0xDEAD);( N7 ^3 _6 n9 d1 {, G) u* B( r
return(INIT_SUCCEEDED);- K- h# u. g9 t: j+ J9 u
}
8 G$ T! N5 S/ m//--- Since we set a timer, we need to destroy it in OnDeInit().
, L' I0 u, _5 u$ j6 E3 `- Svoid OnDeinit(const int reason)" G# O% h/ d! [" V
{" R8 ?* O6 U( @" U, e1 P- G
EventKillTimer();! b0 F, W) l/ Q
}
; l( j- I7 [) X, a% \//--- The OnTick function only informs us that we have a new deal
# R2 b6 f% ?$ s; r# ]void OnTick()6 a9 D+ a. e8 C5 Q
{9 W8 ^8 S: G9 v5 X
tem_tick = true;8 Z9 |: y. O* r2 o0 ^
}7 r8 r( d5 @7 T) O% o
//+------------------------------------------------------------------+6 d% \7 |/ ] q; L" Z
//| Expert Advisor main function |' C. c# j6 w! j {# ?& H7 S$ p- q
//+------------------------------------------------------------------+: o& V! J5 h4 P0 C3 d
void OnTimer()
" _% u% `. Z/ c9 D; R C; f{
6 ?" ~7 G$ f9 b; b/ e- ~* EMqlRates cotacao[];2 ~6 l) q4 |" E) O) V) w( o
return ;
8 ?+ u3 Z' ^% H. @5 p& E/ \if (negocios_autorizados == false) // are we outside the trading window?
, [; |5 Q6 A" X1 p, k' G. Vreturn ;
8 Y. Q6 X5 N' F# \6 U//--- We are in the trading window, try to open a new position!& w% j1 ]- x1 y4 Z! F, q3 p
int sorteio = MathRand();
/ ^. n' T& Q7 ?# L% l# M8 v//--- Entry rule 1.1
$ ~4 T: |" o1 G1 w' \if(sorteio == 0 || sorteio == 32767)
8 h" v+ y2 e/ _return ;2 [; U. H4 z+ k/ N) I- L
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy3 Z2 B. a( o$ d9 t7 Q2 ^* r
{
# d" W" F8 H/ {% [- {) ]1 @negocios.Buy(info.LotsMin(), _Symbol);
" F. Z* c7 ~0 N% b" l' x" p8 x}
2 t$ ?4 }9 v$ Q; Y4 Welse // Draw rule 1.3 -- odd number - Sell- i1 J- u% R/ [
{* f+ }) I9 E; ~- T/ V9 K1 F
negocios.Sell(info.LotsMin(), _Symbol);
4 \' c# s$ H/ z% z* e}
: u+ r3 P. y# e$ |}7 B6 Z v6 T% b% K5 r8 W! x
//--- Check if we have a new candlestick...% p+ P' k" H' y
bool tem_vela_nova(const MqlRates &rate)+ N- g* o: l% S% J/ v
{0 t+ t4 _5 i/ ?) S; p, ]: \6 e
{6 q9 y, c9 n; T! M1 V' ~2 C
ret = true;: Y: n8 X/ T% }0 t% ~ }5 K2 z* [( w- y
close_positions = false;
6 A4 E8 @7 U- f7 A4 G* V* \}
; }+ U& M2 B' L9 melse
( J% u3 Z- S3 P* _: v6 L& t{# C; s1 d, N @0 O! E6 A- e6 I
if(mdt.hour == 16)! w$ K3 A: t' v
close_positions = (mdt.min >= 30);2 l/ J, ~4 F; F6 s; b' e
}" v3 j7 s$ v! a2 W" A; l
}+ A/ k0 ?. _% ?" S; v/ Z5 X
return ret;
+ N+ b4 S) y, y3 ~8 R/ f3 d% h2 O}" W: G/ Z) t" y. k8 m9 ?
//---
) a$ e9 O& I# K2 @2 ?% F) M3 H$ n- _bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])2 W R/ K$ U( U' e* |
{ ^" A7 W; g& T5 v) R
if(PositionsTotal()) // Is there a position?8 e* x( }. Y3 V/ ~( r5 I2 w P
{
* K9 H# i( F' pdouble offset[1] = { 0 };
6 @% A8 Y7 G& d* z. r" iif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
1 I' Q) z; C. ^&& PositionSelect(_Symbol)) // Select the existing position!
$ b) v3 Q1 ~% @& ?# I# U( Q2 n{
+ Q( k1 J/ x/ V+ f: T. SENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
- ]: [* T. p' d3 i5 ldouble SL = PositionGetDouble(POSITION_SL);
# D! ]' U5 h% ~" m! D) U. pdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
' e* I; n- J: }% ^if(tipo == POSITION_TYPE_BUY)
3 J0 Q% w0 n9 y- v1 _{+ _' S; M( J* V
if (cotacoes[1].high > cotacoes[0].high)
L h+ f2 G# Q8 G{
; \: m9 L# ~( h% w' J3 [double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
# G3 T$ Z7 i" N+ Q; m9 yinfo.NormalizePrice(sl);% p2 X {& [* \2 ^
if (sl > SL)+ P$ o0 k Q: ?) Z* w: d9 c6 e
{
9 q6 P% T; }; u. T3 s8 Lnegocios.PositionModify(_Symbol, sl, TP);
& t+ x) H1 m0 W2 j}
- n+ o, J" l1 z3 m4 y}
- `' K3 j' x2 N. A' x& t5 u! H5 |}
6 \- E3 E: `, w; J2 @! j- J b1 i' ~else // tipo == POSITION_TYPE_SELL7 J# I4 O0 a; e5 q3 \# R6 j
{
6 U0 T& D, \) }3 ^if (cotacoes[1].low < cotacoes[0].low)
$ _9 E. w7 u/ C5 S* s2 Q{; A$ c. E( g& ]" M+ o; i8 z I
return true;
$ z# \. ]+ t6 y. a' p3 ~}
" [$ z9 W. a3 N( j m// there was no position8 q( S, [- f( `1 L$ d
return false;
6 ~; C( l& o0 |( h}- V& Z) j" d* h `' v
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
; B0 j# t9 M0 P( `. v到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |