启动交易模型,并构建 EA& K, K" s& J D- N
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。8 O& g7 ^/ Q: ?& I) M. J/ W# v
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
3 L4 O1 a2 ?4 i/ ?/ R( x; M% C以下是制定这些规则的代码。8 z: j2 O1 `# t$ k7 j z+ G5 y" N
//--- Indicator ATR(1) with EMA(8) used for the stop level.... C: ?0 a* R) Q" n o
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
' a" f3 c+ s) {% H3 \* tint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
, G& _7 N( W5 I+ T6 s& L//--- Define a variable that indicates that we have a deal...1 g) r% A- c5 i8 e/ F
bool tem_tick = false;" W1 N( H( H$ A' C0 J% g6 f
//--- An auxiliary variable for opening a position
; y5 s3 I) E( u" s" d" y$ J: K#include<Trade/Trade.mqh>3 {, I% \/ r9 p7 y6 D% P* n) k
#include<Trade/SymbolInfo.mqh>* d% a' e+ l G2 Q1 _" C! L& K
CTrade negocios;
_. a% \5 L8 g5 V7 ]. MCSymbolInfo info;
0 x8 x) W2 x) x+ @8 b//--- Define in OnInit() the use of the timer every second
, b# u$ ]" O4 Q u5 H9 F//--- and start CTrade2 ^; P/ l# B% Q8 v" }
int OnInit() B' {, a" M! g4 ?5 R
{! s; f# b& r! F; {6 E+ t7 ~
//--- Set the fill type to keep a pending order
8 r8 w' n( @) Z//--- until it is fully filled
0 W& Z3 ~- n3 e, ?0 A4 hnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
; \7 E2 k/ D( b. @2 X! u0 F//--- Leave the fixed deviation at it is not used on B3 exchange
: d: b5 P2 R( }negocios.SetDeviationInPoints(5);3 B z M9 n: C( R& q+ f1 s) M4 {
//--- Define the symbol in CSymbolInfo...
, O+ o" U2 S2 ]- Uinfo.Name(_Symbol);/ ], i" r( e3 i6 I1 u
//--- Set the timer...
. F5 Q/ |1 `, B( M; q) MEventSetTimer(1);2 C/ [) n1 ?* ?9 i! O: W$ H1 X
//--- Set the base of the random number to have equal tests...0 o) R$ K' x0 a) h
MathSrand(0xDEAD);
% ?. Z! @5 d$ k" ?9 w9 e3 Wreturn(INIT_SUCCEEDED);7 E4 t, w; |! j$ z# o8 z4 v' @ S
}0 @! S' n4 S' O' [* s. r1 E& L
//--- Since we set a timer, we need to destroy it in OnDeInit()." [' Q7 X- [: b7 ^7 p( _
void OnDeinit(const int reason)
# i7 i, X/ w' Q2 t; | A+ F{
2 b0 X# ^+ D; y# ^EventKillTimer();- C4 M: E/ O2 T0 r$ S# ~
}5 g( e1 O; t2 z1 W& R3 s
//--- The OnTick function only informs us that we have a new deal0 Y- P: V- ]* k1 E5 B
void OnTick()
8 k! C( v) a8 |3 x; L{
6 ?! P, a2 }1 i8 s( ^tem_tick = true;
( Z! ?* y9 i3 ]/ k}
/ F+ X& p! A! Y9 ^ X# ]2 r& K//+------------------------------------------------------------------+
* Q/ D" S7 y! |2 f0 B I3 s" j//| Expert Advisor main function |$ n' X) a2 }" P& m7 _4 H
//+------------------------------------------------------------------+5 u$ ^0 N# A* E5 g+ S: f
void OnTimer()
0 e2 X$ d8 K( p5 o3 D& V{1 f9 O, p8 E3 o# p1 @
MqlRates cotacao[];8 K) B: x7 X, h1 O/ m
return ;
- X! j3 I8 \ Q8 r8 z% eif (negocios_autorizados == false) // are we outside the trading window?
/ {2 Z$ ^+ D" E$ @# ]" Treturn ;
# L9 Y: E. {5 B; O$ a) L7 K* t: ]) e//--- We are in the trading window, try to open a new position!
+ H* X1 Q2 {. ^5 e2 t G+ k* U% Wint sorteio = MathRand();( s; W0 r! p1 V
//--- Entry rule 1.1
; C: t# i' y1 P* qif(sorteio == 0 || sorteio == 32767)
4 c) o" a9 c) L9 Rreturn ;
' i5 s% ^4 i/ V9 ]0 hif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy, t2 d' J Q. Y: Y9 B, V
{
$ ~6 Z, \" o( r8 u- y; {negocios.Buy(info.LotsMin(), _Symbol);
5 c2 [7 ?% \# M) v9 L}3 z+ z' c1 T# R' A! {+ t4 Z9 R
else // Draw rule 1.3 -- odd number - Sell
9 z) H( W) L4 b" z7 |, D{7 N) A- q7 H0 e, |; D+ q' p
negocios.Sell(info.LotsMin(), _Symbol);
0 W; n7 d/ g9 G1 i, A; T& w! d}" @, R& k+ N+ S4 ]
}3 f7 q) u& N) H3 s7 e1 [: V
//--- Check if we have a new candlestick...
: I. ]3 K B5 @) R4 Dbool tem_vela_nova(const MqlRates &rate)
, }8 a, L4 u. h. t. i( ?{
& O* H# ^) ]$ r0 ]{
; z/ b4 u- N* tret = true;
8 M7 e2 j# S- Aclose_positions = false;
- Z! B/ f! Q6 ^" W9 ?4 P}
. q6 j/ |3 y* I' z) Celse
: x4 R0 q' h) j+ b{: B7 [8 R9 P3 E0 w6 E" H
if(mdt.hour == 16)0 K! \3 S2 |$ L% J, N
close_positions = (mdt.min >= 30);! {1 a5 _- y$ U% l: X
}
$ [9 _ ~: }9 H}
`( y6 W( ^: V. l! Lreturn ret;
6 T3 ?6 b: C1 O$ {5 m% b! O$ o0 W}
& D) l( P# i, D//---
; L7 E, P6 y/ U, J6 O( ebool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
1 C2 A- u# ~+ L/ X9 r{
* h: y* y2 E. y2 a; rif(PositionsTotal()) // Is there a position?3 l" b3 n1 R6 k/ D- b" j
{. c7 L0 N/ t7 z; `- U
double offset[1] = { 0 };- r, y2 j9 s9 D
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied? B4 I& N: k8 f
&& PositionSelect(_Symbol)) // Select the existing position!
4 |8 V2 ]7 @4 U9 c( T3 Y{' E- y( O# R! y/ u7 ~
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);% @( r8 n3 p0 k. x v. |( L' V. S
double SL = PositionGetDouble(POSITION_SL);4 S }: d8 O; |( U4 h5 i& n
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));4 u+ _0 I% a% |' }
if(tipo == POSITION_TYPE_BUY)
- {$ D5 |9 H- ?! s: K: [3 n{
" c" P% c: g- z' J6 ~if (cotacoes[1].high > cotacoes[0].high)
- b3 t6 v" }& X5 I1 I1 {& l{
@$ ~( P( ]: @# c! _5 hdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
1 u4 P% g& B0 X! J) [9 uinfo.NormalizePrice(sl);
/ F* E5 ~' v* `3 qif (sl > SL)
1 N0 j" ]6 N4 A0 y$ D2 b{
5 K6 o% A0 I# ]' s5 ^' |+ ynegocios.PositionModify(_Symbol, sl, TP);
% Z2 l* m2 d" k3 |}. t& F! d7 r; |4 y R0 }9 u3 f- u
}6 N- p2 r) q8 a( v
}
. }. g8 e. f" L* Zelse // tipo == POSITION_TYPE_SELL$ C1 B+ m: u9 ]3 c: S9 V
{
; X- Y2 `0 c6 w* _6 Nif (cotacoes[1].low < cotacoes[0].low)% F# ]& N& j( V% X+ H" s# U; w
{
' |2 v) N% h) v$ U% ireturn true;1 Q+ @/ U1 M4 }1 N& p
}$ K6 _0 s+ O6 k2 Q
// there was no position# V) Z! O+ S5 v
return false;
" O$ L3 C; K# a, r* ^" j0 C}& P* q8 c6 L1 F' X/ q
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。, R' N% k/ I# w
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |