启动交易模型,并构建 EA9 q/ t0 f& k0 x5 f
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
& `/ f/ ^9 [3 \8 l为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。+ j4 \, Y& f$ x2 V3 {6 R
以下是制定这些规则的代码。
$ A' z( U5 Q f1 d. U# T//--- Indicator ATR(1) with EMA(8) used for the stop level...' q& {0 U0 |$ a; ^' m3 X* ~
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1); C! F- q0 \5 Y! ~& y9 w
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr); [2 M2 Q7 l" P; E. ?+ W2 j
//--- Define a variable that indicates that we have a deal...0 }$ {0 H2 ]& I1 G1 v4 C+ {
bool tem_tick = false;: V! q) e9 a0 ]- j
//--- An auxiliary variable for opening a position
9 S! k% Y4 _3 K#include<Trade/Trade.mqh>0 E! ]- L. ~+ R4 d2 M
#include<Trade/SymbolInfo.mqh>. J, g; o- p# f- ?0 T& b" {8 s
CTrade negocios;! K8 v3 j1 m, p! o! V! S6 s6 N% u
CSymbolInfo info;
8 Z$ I3 h v5 N8 C% ?//--- Define in OnInit() the use of the timer every second! g2 l0 [/ j2 z6 e) U! P
//--- and start CTrade" ^3 i7 f) |# ] Y# T `/ T
int OnInit()
0 ^0 Q6 \! a p' B( [! ~; a4 t# [{
' r* v4 z6 U/ B- l//--- Set the fill type to keep a pending order
9 a) j% J5 U9 A5 E+ G: y//--- until it is fully filled
- g6 l% z( D6 Z; Knegocios.SetTypeFilling(ORDER_FILLING_RETURN);9 d0 V. `' w9 `2 N
//--- Leave the fixed deviation at it is not used on B3 exchange: t! s1 s. x' I3 L
negocios.SetDeviationInPoints(5);
/ \! M- C$ e, f8 v7 l3 q//--- Define the symbol in CSymbolInfo...
# Z" U% k" t- ^8 w0 P3 Dinfo.Name(_Symbol);
( S* m- l, _( B, V/ w8 g//--- Set the timer.../ [1 ], h; z( p
EventSetTimer(1);6 y5 z& u- S+ l, d, r
//--- Set the base of the random number to have equal tests...( q1 T$ v8 D; I. Y& _8 a
MathSrand(0xDEAD);
( S* c) {9 ?9 L+ A- m3 ireturn(INIT_SUCCEEDED);) h; f- @8 ~& H2 C
}
4 u2 }0 Y/ h* E. x% \//--- Since we set a timer, we need to destroy it in OnDeInit().
1 O) t+ n. o q2 C8 j0 pvoid OnDeinit(const int reason)
' z$ Q4 U; I; o$ j{
# x6 [3 P+ C# c O" \$ ^9 d! r+ sEventKillTimer();
+ U( I, c7 k R7 G* E: W% h}( ~/ w6 V- K* w/ C: f- C; q0 X
//--- The OnTick function only informs us that we have a new deal0 V& [+ N, ^8 \
void OnTick()
3 }$ w2 m% \$ z) u3 K{, E2 v. S) r/ z v+ K+ }
tem_tick = true;
, a% i# n, O! p; s}9 E- M9 M+ r. N% R. |1 m5 f3 D
//+------------------------------------------------------------------+
1 V: [. Y& U' C. A7 K4 }$ w, T//| Expert Advisor main function |* M/ ?) X9 f" L0 |6 q: x h& ^3 P
//+------------------------------------------------------------------+" F- _6 o0 k' c) T$ _6 L
void OnTimer()
- K' ?' p# B7 @- v( Z* a{
: O# m- v# ^2 ~# VMqlRates cotacao[];
4 e; t( K% s, Q7 Wreturn ;% f4 t, o2 _* V7 }2 v: Q1 X
if (negocios_autorizados == false) // are we outside the trading window?# U. Q+ y. [7 ]- `- ^
return ;
) \7 ~" w6 v& k//--- We are in the trading window, try to open a new position!8 A- p& j% c) F" y; K2 O, V
int sorteio = MathRand();: F5 @4 O# I% W) Q6 A7 w
//--- Entry rule 1.1; ?( [# ~) |% O5 m+ m q- s
if(sorteio == 0 || sorteio == 32767)
0 E# E3 n5 M+ R4 z+ E/ }9 Lreturn ;
6 ~2 }4 K5 F4 e* K/ cif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
: ]5 z( O. i0 ?{
9 S" n5 G1 U; J9 z4 Lnegocios.Buy(info.LotsMin(), _Symbol);
- l" p6 | P8 M) Q/ `$ H3 ]}2 Y! }/ }: c: y1 T9 E8 {, p
else // Draw rule 1.3 -- odd number - Sell
3 G: c' ~% F: _6 K; f{2 a9 [8 i- g# R4 d, ^6 p
negocios.Sell(info.LotsMin(), _Symbol);
! D5 D1 s9 h2 Q" U8 a}# T6 j/ m3 j2 r. }! @' X0 ]
}4 ^$ n( S1 z) ~) l% X" T9 R3 S. W
//--- Check if we have a new candlestick...
& _, c0 Y6 B# O' @! k* Rbool tem_vela_nova(const MqlRates &rate)2 Z( z' c0 d8 @3 k! {% g. A
{
5 w ?) i3 D, a& J2 j( I2 f8 s0 N{
. S, `2 K9 ?6 M6 Yret = true;% [7 X; o. Q1 X8 F' A0 p( T# q8 a
close_positions = false;
/ w% a/ v* m( x9 P% B}
2 z. q1 I4 D1 d# H* @else( B( u& u$ q4 @1 |; w$ d
{
: S( t( h9 C5 I; W4 B. O% p$ C" Cif(mdt.hour == 16)# `) w* g* ~/ I+ U+ E
close_positions = (mdt.min >= 30);
" } |7 y4 K7 A# n}
' q' z1 k" q: X$ r, o}
# ?6 f C3 t) P Y0 kreturn ret;) B% c: J4 m* N: Y: `4 F
}
6 ?2 i% }6 W+ h3 [: h$ k//---
- C6 U( y; m! } w. p0 Pbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])4 V) T& o. t8 R
{
2 \" b( V7 R* u3 @ C; V* l3 }; Jif(PositionsTotal()) // Is there a position?8 B5 ]& B7 [/ Q5 l) N
{
* ]& g) m) t9 V' ~+ g6 \0 ^double offset[1] = { 0 };& _& a' i5 V* ?* R
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?0 Y, L" Z4 J3 i5 \. u& j" @# r
&& PositionSelect(_Symbol)) // Select the existing position!& m6 [ J( P8 M* P% s" J
{
$ X+ M# ^+ j0 V; L# \9 w, ]' eENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
* g& z, G- {; ]' M- h- h! vdouble SL = PositionGetDouble(POSITION_SL);
# R9 J @- \ U. }5 ^" Ddouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
J) ~" W- `& w2 q6 E {! o; xif(tipo == POSITION_TYPE_BUY). o; d' t6 s/ l* |5 h: s2 }
{% a3 o# L) z, {
if (cotacoes[1].high > cotacoes[0].high)
" E8 n% B; q# q( j{: S! S5 p$ ?$ v Q2 ^% m
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
/ d, A, Z8 R/ r9 Uinfo.NormalizePrice(sl);# _4 P" X) A) W& O+ J! u7 w: L
if (sl > SL)* P8 L7 A1 p9 }# [* C# r9 y+ N% d# J
{
) X6 B( @' `, h% ~negocios.PositionModify(_Symbol, sl, TP);
; e# e5 G" w: {7 K) X}
9 [; a8 e3 h7 \' K1 l4 H. s}( F* k: Q& B7 n+ }9 r8 g
}
& a' F" a2 `- t# p1 j, t# ^% kelse // tipo == POSITION_TYPE_SELL4 d6 y0 G$ @& d! q8 @9 C
{
$ u0 O, l$ D2 _& Gif (cotacoes[1].low < cotacoes[0].low)
- |% g/ Y' T9 o( [9 O& P{8 G% F5 ^1 N9 t) D$ P
return true;/ _# y: i. y1 @6 d4 c
}8 I) }+ E) |/ Y/ B$ a
// there was no position6 V# E+ g( o, K& A0 E+ {
return false;& q; B: ~$ O$ n5 ]- K
}
5 y% |9 a) z. y0 ~9 E8 Y我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; Q9 m3 W: j4 x2 o/ w
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |