启动交易模型,并构建 EA* l0 U& o# z6 x
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
# i% G' [5 b3 N; r$ P; o! t- c为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 l# z; H$ D3 u ?1 u9 }0 h5 I$ f8 I7 h以下是制定这些规则的代码。
( |2 a5 Q: @8 X% h! g* b' i+ f4 R//--- Indicator ATR(1) with EMA(8) used for the stop level... b- {1 r( ~6 Y1 n
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);0 P/ u0 g7 n$ e. b1 s
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);' V3 a: v1 C+ ?, z8 l
//--- Define a variable that indicates that we have a deal...
5 t7 S+ J6 W' \1 \5 @+ Qbool tem_tick = false;
3 J! E2 C8 g, L$ F, @//--- An auxiliary variable for opening a position$ v% u V/ J4 ` m; y6 M9 S
#include<Trade/Trade.mqh>6 @, H# z; T8 b* L& _
#include<Trade/SymbolInfo.mqh>6 M, S. E8 m1 a% L' w$ \4 N
CTrade negocios;
1 x. o* q# j( kCSymbolInfo info;
' m/ Y1 n8 C+ H& h i9 q% B//--- Define in OnInit() the use of the timer every second( q% J% D5 O. K; }6 G) F Y
//--- and start CTrade0 B. s; R' t3 X3 A4 m# ]
int OnInit()
! {. J* n% ]. |{
2 t4 C1 e% b) U7 c* ?//--- Set the fill type to keep a pending order
9 H- F4 p4 C3 i) q//--- until it is fully filled. E' p4 q6 H. U& ~, a) C+ O6 T
negocios.SetTypeFilling(ORDER_FILLING_RETURN);, E$ {0 Y# P5 s& t b
//--- Leave the fixed deviation at it is not used on B3 exchange& j3 f" f8 K$ O; X# z
negocios.SetDeviationInPoints(5);
3 S: s/ e. m2 }3 l1 m//--- Define the symbol in CSymbolInfo...
! _! l1 V; W8 `9 Kinfo.Name(_Symbol);
{. i2 Z% l4 N( P* E//--- Set the timer...) n" a+ O- O+ a4 C* L( E
EventSetTimer(1);
6 M* d ^5 B+ i: o/ a! _. ~- v//--- Set the base of the random number to have equal tests...
2 ~ Z* X) h! S. L! J2 r: k: `MathSrand(0xDEAD);8 M0 C# U7 s. D# j; Q6 E2 U
return(INIT_SUCCEEDED);& h0 s) u, |; ~9 x/ n' X, {
}
2 H6 o& C5 n6 p: k1 d" i7 r//--- Since we set a timer, we need to destroy it in OnDeInit().
' W7 g9 R# y& t( \. e8 zvoid OnDeinit(const int reason)5 F- F3 C# K/ c4 f* G$ I; o& K
{
6 Q5 Q$ `9 a5 X& p: bEventKillTimer();3 O) P- k3 Q5 U
}5 g) [( a( s9 ~8 ~
//--- The OnTick function only informs us that we have a new deal
8 F: [; U! [; A* Z' ?* R+ v/ ]2 ivoid OnTick()* m x: o8 W1 v- s& N
{2 a4 @( A# @! X" U8 ?
tem_tick = true;
3 E8 Q- S8 }5 D, P( O6 r( B}
% w6 L8 t# K+ p) E. _2 M9 F, a//+------------------------------------------------------------------+
/ Y9 F- S8 P% E% Z: q0 E" P8 O//| Expert Advisor main function |/ I [5 R5 S: J7 V9 @% ^
//+------------------------------------------------------------------+
8 `% d1 v8 Z: i" T! F4 }void OnTimer()
: P* s- b+ h: Q) f- T{
/ A8 W& A$ d0 E; d$ q, PMqlRates cotacao[];! Q7 L8 o, }1 `3 m
return ;& n/ _4 \" J4 i$ h
if (negocios_autorizados == false) // are we outside the trading window?8 k% |2 ?% x$ X0 ]" r: H4 @' J
return ;
8 f% n: M2 i; p- i0 q6 N( a6 D//--- We are in the trading window, try to open a new position!
: ~! t+ z" b' w4 b, `) U2 V& C4 G# Oint sorteio = MathRand();
; O: w' D; y' ]3 h+ X8 H//--- Entry rule 1.1
' B1 }# p; i0 r5 M2 Gif(sorteio == 0 || sorteio == 32767)3 o* R T# Q0 |
return ;. q( ~2 A% }+ L! m8 ]
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
+ J8 {) ~. O/ R4 x4 c: B, r{
5 G9 I4 J6 [$ A4 N$ M+ D4 pnegocios.Buy(info.LotsMin(), _Symbol);. d- L* M; g M9 o* h, w9 B
}2 h1 u( w7 \; X' A& x8 U
else // Draw rule 1.3 -- odd number - Sell1 l0 W' f; b9 ^
{
0 m9 ]/ H$ M' p4 w# _# \" Knegocios.Sell(info.LotsMin(), _Symbol);
+ m, T3 c0 b3 [' f}
- Z- A8 v7 e ^+ a4 Z}' ~* M/ F ?9 `2 n
//--- Check if we have a new candlestick...3 X, h' K- a: L Z
bool tem_vela_nova(const MqlRates &rate)
: g* c( f4 n9 i! D+ a# |{
* a3 @4 y) F3 h5 S5 [9 T{- Y- D4 ^3 X/ m
ret = true;6 \7 C) t, l% k0 V
close_positions = false;
( g, v# j/ q. f! p+ v* |& q}5 x8 g. M: {$ l( c$ `2 W; ?( o1 m
else% b0 a* {9 v* z! D7 q5 w5 x
{9 w# c+ t1 B3 F4 w" b. }5 F: }
if(mdt.hour == 16) a6 {- w% J6 a8 H
close_positions = (mdt.min >= 30);8 j: q& \5 p2 U* P5 W7 c
}8 v3 }% `, y( K
}
( \$ L0 ~/ u8 Vreturn ret;, Q. ~! f p" ?( V- r
}
) Q- R# E1 A+ C//---9 n0 v$ N, G- ~9 p) J; M
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[]): l- a* X8 A, l. t6 t8 T% }
{
% U/ s% o3 o! z4 _/ L! z, ^if(PositionsTotal()) // Is there a position?
+ Q" ?& G8 Q5 n" n- A5 e A{
& J+ X: P' F7 I# Vdouble offset[1] = { 0 };
. [ }3 l; H- e/ V7 Y$ ` Nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?" m+ r. [, y z6 i: e
&& PositionSelect(_Symbol)) // Select the existing position!- M" K" e: F7 y- e c* x
{
8 |8 e _( |7 [$ C) _+ q# B+ bENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; s( z( N) H7 |2 ~4 n
double SL = PositionGetDouble(POSITION_SL);
& V: T$ V) i0 r, a: m* ?- kdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));1 A, h/ o7 B0 D2 X6 I. A q
if(tipo == POSITION_TYPE_BUY)
, X T2 l/ ~- r! [{9 ~; H2 z8 X- s. P
if (cotacoes[1].high > cotacoes[0].high)
& d) e V2 @* b1 c* P9 L# B: p' e{/ E. O: |6 n; B- j _8 u: i. V
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
7 d5 ?2 k \' F! y. C3 I! A+ Ginfo.NormalizePrice(sl);6 l& ]8 M6 m; l% @+ q) w0 ?6 U
if (sl > SL). E a" `% O7 n3 M3 p% w! U
{
* @* P. e+ p: m9 inegocios.PositionModify(_Symbol, sl, TP);
: W9 o6 _1 M8 a# C}' n! {( H6 h1 w9 T. v# }
}% ^7 O. s. k$ c4 m% x0 T6 q
}
% l; C9 n9 @& r. |else // tipo == POSITION_TYPE_SELL' r K# j, G1 y2 H
{5 b& e0 P- e$ c8 q' l
if (cotacoes[1].low < cotacoes[0].low)( Z. |( c% J: Z3 `& J! Q& ]/ ?
{* ^& ]; N% l- T/ U3 Q. O0 Y
return true;7 @# ^! |( U8 I( l* T
}, h3 \3 K( S1 l# A( H# P E
// there was no position
. V& [4 b J% K# S& }return false;
6 B( ~: L: t' \, {}6 @& @: L" w5 S' G! D8 i
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
: S! M- E& i3 C; a5 Q( N到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |