启动交易模型,并构建 EA# E) ?3 {1 ~. V( V. o _
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。 c" f4 l; r) _1 T1 h3 n3 f
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 K! X5 J5 Z1 E E( H
以下是制定这些规则的代码。
+ g) u. u1 I/ ^& R//--- Indicator ATR(1) with EMA(8) used for the stop level...3 @0 u( Y3 E' R& Z8 Y* T$ R
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
( G+ b+ k: Q$ C/ ?$ U0 vint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
5 H' m+ A0 f. Y, }+ o//--- Define a variable that indicates that we have a deal...$ o0 ?- ?7 j( a! i) f7 G+ J9 ~
bool tem_tick = false;
# m6 ~( j/ h" r8 Z( U; ~5 Y//--- An auxiliary variable for opening a position4 m7 N- i$ n9 V( e
#include<Trade/Trade.mqh>' h6 L; B' y' [7 @8 S
#include<Trade/SymbolInfo.mqh>
8 {1 z L) }2 t0 CCTrade negocios;
! ~- T" E" j+ T* v3 b1 PCSymbolInfo info;
1 Q7 e$ @. O C//--- Define in OnInit() the use of the timer every second
; x) N% h/ j; b% F, s//--- and start CTrade! @- \( d& a r
int OnInit()
" \- x- P, o; q; }5 h/ v{; z# o7 `0 F0 L1 h* C: z
//--- Set the fill type to keep a pending order" C7 h0 |% S. Z
//--- until it is fully filled) o+ G Q. n" f" [% w' A6 E5 |
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
1 Y1 H! h& b/ M! d: v//--- Leave the fixed deviation at it is not used on B3 exchange
' l0 M7 ^2 O! a8 K0 }% ^, vnegocios.SetDeviationInPoints(5);/ I/ v7 X& U" V4 C) K1 d0 {) ^; |7 _
//--- Define the symbol in CSymbolInfo...2 d, \) ]; n9 V+ N
info.Name(_Symbol);
/ [6 Q5 |" A" E1 G7 l//--- Set the timer...! [* _' U7 K6 L' g# D
EventSetTimer(1);# a, Q5 ^3 s! }, B& o& N
//--- Set the base of the random number to have equal tests...
% E; H! P* a" F0 X( G6 v* x9 D1 v) sMathSrand(0xDEAD);
' A6 r2 N. ]) Y) zreturn(INIT_SUCCEEDED);% `2 A4 c( i9 e( W, C! U. F; E# o
}$ o) L6 q, E1 L# m- O
//--- Since we set a timer, we need to destroy it in OnDeInit().
0 w0 ^* T# \9 Z# o' }8 h& t3 kvoid OnDeinit(const int reason)! N3 v. q, o5 i$ R! @' p2 N
{
( V6 S; ?, F; w) i2 cEventKillTimer();' r4 P+ v7 Y/ \* K* Q
}
/ r* O& l" V) |* L//--- The OnTick function only informs us that we have a new deal
( E/ a: W+ \; evoid OnTick()
; K% H3 `6 n, j: q% N{+ z6 }) Y, X' ]9 e$ v/ O* c! g! P
tem_tick = true;
/ A8 ]4 c- V5 Z}: }, Q$ P2 n$ S
//+------------------------------------------------------------------+
+ k% |% R% S, t: @ C6 v8 }//| Expert Advisor main function |1 p& T. }1 n- K1 i6 T& K9 k& n/ X
//+------------------------------------------------------------------+& d4 E( u. I) u
void OnTimer()7 R! w) s% o: u7 f% X/ d8 v
{
( q1 Z, h+ A m6 P$ E9 K" ~; n% [MqlRates cotacao[];6 `8 o f/ U6 B4 L7 _$ ^+ g: b }
return ;
: Q* z/ ^- {7 l1 z2 G* oif (negocios_autorizados == false) // are we outside the trading window?+ G1 M! Q3 @5 ^3 U/ Z. ^
return ;' _# @1 S! S3 X# |/ }1 H c
//--- We are in the trading window, try to open a new position!
) k* ?- B+ ~2 p! W Z( _# ~' e3 yint sorteio = MathRand();
! i: H+ M2 _0 b+ I7 Z% u) p" P* K//--- Entry rule 1.1+ H0 C' C3 q* Y( u1 K/ t; n) p: s6 T
if(sorteio == 0 || sorteio == 32767)
. M$ e! x) ?! A2 [- T% G" I" Nreturn ;4 \6 S/ Z8 p4 V
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- q( t6 s% M, q! B{9 C: ^. `" K( t! W
negocios.Buy(info.LotsMin(), _Symbol);
" @* @. D( o! j& l* B}+ w8 g% G% T% _
else // Draw rule 1.3 -- odd number - Sell# L- E7 O7 Q- E7 Y
{: u0 g: B! I3 M9 R- A
negocios.Sell(info.LotsMin(), _Symbol);- V( y% ~# o% g+ t( d# e- }
}
9 X- V0 a* D5 ]' \}! ^6 T( R% h5 J" f
//--- Check if we have a new candlestick...
2 ~( ~. t7 I7 Z5 A) J; vbool tem_vela_nova(const MqlRates &rate)
+ q5 F8 n6 Z1 k/ F0 R$ ?6 Z) S{2 n5 R2 M3 t) K! Y, _
{( E9 d" U- ?9 s
ret = true;% I, i7 q9 c" R- n/ I
close_positions = false;" b3 g9 W/ I6 Y
}
2 N: `) ~6 |4 `0 c0 celse( w1 C. q, h/ K' i/ a C
{4 `! L3 M6 J+ G) @0 S+ [; M# [
if(mdt.hour == 16)
% F' t, {; |2 {, V% a* r& K( ]close_positions = (mdt.min >= 30);: i/ I! w8 g& z
}
. ~. \. E! R3 m4 A% h/ M}7 Z: w/ T. y* D) V: K' S
return ret;
5 R% P% I$ G- F. D4 V i}
q, h9 k; H$ S8 J( \6 C9 R6 h; o//---7 x9 ~1 _. I4 C) ]
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])4 x4 N' P! j* x3 }3 g
{
! W7 k1 |$ ]; m" Oif(PositionsTotal()) // Is there a position?
/ m( [4 N3 [- V{
) d! _( ?2 M$ Y7 v. D. Idouble offset[1] = { 0 };* B3 J A5 l, k8 y' _2 o @% Y( G# W
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
: c: i4 q$ u! u&& PositionSelect(_Symbol)) // Select the existing position!
; Z0 x0 i( A% P) R{
o* \2 Q/ l tENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
" s/ o$ q" Z# w- ddouble SL = PositionGetDouble(POSITION_SL);1 I8 m' U8 y% N% S7 |
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));. ~; m' s; |' R n9 K( Z
if(tipo == POSITION_TYPE_BUY)0 c3 T( \6 k1 k( i7 o/ G
{
& x G! d U2 J- f/ [4 z: Bif (cotacoes[1].high > cotacoes[0].high)
" u/ T8 j v I4 t+ ]' {# x& k{$ B0 A( A w- ] |* ~
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
6 r, a5 J, U# V' pinfo.NormalizePrice(sl);
+ [9 K, d6 ?& N3 oif (sl > SL)& r& Y$ T" ]9 x+ B
{& t, K; q$ Z5 t6 M' ?; V
negocios.PositionModify(_Symbol, sl, TP);# y3 f6 A& U) E0 g9 p
}; G2 u8 ?% g& E( m: V" N
}
: q5 M* w9 `- n4 J( A4 V}
6 @9 m. g% h6 ?7 pelse // tipo == POSITION_TYPE_SELL, g6 b9 d" s$ Z# `2 N1 {1 M! z* m
{
# f" Y1 S% Q9 a5 E* n5 I$ O3 Nif (cotacoes[1].low < cotacoes[0].low)
: Z/ \; ?7 g: K( W3 _- I" c{
& _$ I( X" b kreturn true;1 w0 e3 w5 }) j& J7 B- K# U
}( A% {+ p: [1 }+ v
// there was no position
: J3 m' M8 P! ~" C- S: u; t0 Qreturn false;" n+ [2 p, C( S0 Q4 {
}( V: M! j: z8 z' u$ R3 f
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 c% S2 K5 c1 R; x* E
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |