启动交易模型,并构建 EA
`3 e; Y& N5 W在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。' ~, O9 P( F( @& `
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* ~! B' y9 Z Q
以下是制定这些规则的代码。
5 \) C3 [! ]- v/ @7 i; E* ^//--- Indicator ATR(1) with EMA(8) used for the stop level...
- e9 _1 }+ j3 B( e; Aint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
- S3 {3 p8 c" Nint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);# A1 V$ q( K7 A% W: y8 n
//--- Define a variable that indicates that we have a deal...
& R: Z. g% Y; U6 O: Sbool tem_tick = false;
% Q6 {3 m' A& I. B2 z0 |//--- An auxiliary variable for opening a position
) f6 j/ K$ E* X0 h. `/ T: r* r#include<Trade/Trade.mqh>
: [+ p* m2 z+ y. j0 n* R9 f4 r#include<Trade/SymbolInfo.mqh>
L! h7 W6 B1 S9 N2 {0 e7 ?CTrade negocios;
- ~" ~& [, K8 |- c1 F9 GCSymbolInfo info;
: d7 I6 `- @: p8 C/ K5 d; F4 `//--- Define in OnInit() the use of the timer every second
/ N }) l* m& D//--- and start CTrade
$ }1 k/ `$ i1 j( {int OnInit()
2 c1 D1 q+ J8 z$ z{
) d5 z6 _! U; J! v2 q' r9 s0 c: S* i5 `//--- Set the fill type to keep a pending order8 s+ W$ b2 F5 I$ ]
//--- until it is fully filled
5 Y# H3 I* Q, L( U- {6 i9 I1 Pnegocios.SetTypeFilling(ORDER_FILLING_RETURN);! k$ s# ]5 H- t/ a! n: T: ^ J8 ~9 H
//--- Leave the fixed deviation at it is not used on B3 exchange
` w7 I, h* ~. hnegocios.SetDeviationInPoints(5);& }+ T* o- c( r# d: z4 |1 T+ H
//--- Define the symbol in CSymbolInfo...
7 m# c- S% x) j w+ ?info.Name(_Symbol);. P- f" b" Q8 u9 Q5 s' ~: c
//--- Set the timer...- D5 L& ]+ l) a0 s
EventSetTimer(1);, ? J9 R e, z; m& g+ m. X
//--- Set the base of the random number to have equal tests...2 m F' h9 N% N8 F
MathSrand(0xDEAD);) H6 u; D5 m. V9 M2 p& p! n
return(INIT_SUCCEEDED);0 ~$ u |2 l# J- `
}% Z1 A, V. R& p% ~& I
//--- Since we set a timer, we need to destroy it in OnDeInit().7 k7 O) j2 d- c) H+ |8 v
void OnDeinit(const int reason)
1 f$ r1 m6 m, w4 A8 F' s6 j{2 J, O3 d3 ?0 J) I* P
EventKillTimer();
% @" R- l. _5 S, h- S% t+ R. P}
; E& @4 [1 P1 C//--- The OnTick function only informs us that we have a new deal
5 F- @, N/ g- k+ avoid OnTick()0 i# r" Y+ y/ c: J: z
{* P" l! z9 s# h8 M4 M9 k
tem_tick = true;
?" y' A1 ^3 L% |& E}
* n! C4 M3 U3 U% ]* V4 v. J7 \5 Y//+------------------------------------------------------------------+
" r/ Q; x/ l# D& M, B//| Expert Advisor main function |( j! q* m0 k- {
//+------------------------------------------------------------------+
4 v% E! J& D8 t* yvoid OnTimer()
% o4 R" S$ Q4 x( S0 n T{- ^9 X$ v. ^9 f/ J' T/ U
MqlRates cotacao[];& y+ C4 a/ j9 Z" k4 `
return ;
0 A Z, ?, Q- D5 n/ P# Pif (negocios_autorizados == false) // are we outside the trading window?# u4 x4 a4 }. W5 w
return ;
) m% ?+ L6 }, ~( K/ k( y9 B//--- We are in the trading window, try to open a new position!
4 n# }4 m* p5 h: f$ `' G" p3 }int sorteio = MathRand();
/ t0 s9 T: [( w, ^# m//--- Entry rule 1.1/ [/ C/ Y# B) {4 j
if(sorteio == 0 || sorteio == 32767)/ J) f4 K* E8 I6 X
return ;) l' j5 t, W/ l( s5 N. f
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
. p9 ]) B5 C0 S6 b{/ ?9 O8 u, Q3 Y N8 J
negocios.Buy(info.LotsMin(), _Symbol);0 H+ h) X# c/ M [; R
}
, I, ?0 B$ j+ R& A/ Ielse // Draw rule 1.3 -- odd number - Sell- t* J+ }0 a* S* ]) C% V: z" ]
{
' C# p+ [0 {' O! z4 o; |negocios.Sell(info.LotsMin(), _Symbol);
9 ~& t0 H8 w; u}4 }/ ?- _9 x0 \. Z
}7 \ }+ Z5 g# J
//--- Check if we have a new candlestick...) L. F) v$ A! I
bool tem_vela_nova(const MqlRates &rate)
' W7 j8 \9 n! J* n1 S, w5 n% P{
; c. n( n& V/ x8 I4 B{
+ V' Q( o+ o O8 \7 I s% Lret = true;
+ F3 |. \5 v, _/ h" T% l1 |6 Yclose_positions = false;
' \: W! J8 C0 e+ Q}
. M+ m2 R2 {/ E( `& V0 t2 |3 K: G8 U* Qelse
' c) Y! w: g9 p9 x{
! r2 H! S) O9 f$ j- s4 R6 f' Pif(mdt.hour == 16). d& _: z% i4 p8 P% r
close_positions = (mdt.min >= 30);
9 x6 A; X3 m9 a7 y+ y: y4 q}
9 P& ^ N* a8 _}4 O% e1 S7 x' m( a' `! h% z
return ret;: c3 t. B% t; b) c0 @
}$ _9 s" c; l( r0 B6 }3 W
//---
0 L4 g( a% w v% n: ybool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
( b$ u" O( ~% {1 s$ X{0 N3 z; m3 \, h7 n* t
if(PositionsTotal()) // Is there a position?- b D! }% o% F, f" _& w
{
* Z1 P4 o* k `' S* i4 udouble offset[1] = { 0 };( ?2 E1 l8 b$ S2 z& ~, U4 |
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?+ }& d4 H X- B& f
&& PositionSelect(_Symbol)) // Select the existing position!
) r4 ~% F L+ S0 K$ R) H3 @{# ?# u0 h( B5 F% U! b
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);3 H, }- {3 Z* Q ~/ x& z: J+ A" h
double SL = PositionGetDouble(POSITION_SL);
$ n3 I9 G, B1 r. ]5 t; ?double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* j7 t/ x, C- _% B4 Cif(tipo == POSITION_TYPE_BUY)
6 \' e, P$ R; ^5 Q8 y( e{- X$ Z" ?0 b2 G9 p% L
if (cotacoes[1].high > cotacoes[0].high)! d0 D- g' ^. q8 S4 Y0 E3 L* n' ^7 g
{/ i, b8 ~4 Q* n& r1 v5 n
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
) V& c1 b5 i; ~* ?4 ^0 ainfo.NormalizePrice(sl);6 [, R! J7 i% l" J* F
if (sl > SL)& I' k& i( M/ v5 N# M) Y$ C/ W G8 @
{3 B7 p# }1 `3 y7 u8 ~
negocios.PositionModify(_Symbol, sl, TP);
3 ^. h! Z4 V! N3 N0 Y- M}
( K) D( i! G2 N l. `: [4 ~}, f+ W% Z5 _3 c) W9 j
}
' V% Y2 I- ~% O7 k- q# belse // tipo == POSITION_TYPE_SELL5 i7 o6 U* {5 c: f
{0 \' c! p8 I- }- V
if (cotacoes[1].low < cotacoes[0].low)
) Q$ K; Y3 s1 K: c2 z& S{
: W9 m" ?/ | b+ k7 W5 u4 qreturn true;1 \8 \5 R) O7 c2 m1 K
}
0 O c2 Z& l6 T2 ]' p2 q0 G// there was no position
4 H& |4 ` k: A9 preturn false;
0 L5 t, c" M4 W/ a4 m* w2 Z" c}7 ~6 ]! Y6 M/ i$ M' E0 ^
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
9 w; a6 I% L7 u到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |