启动交易模型,并构建 EA
2 |/ L' e! U( S/ i5 Z: W, J在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
* Z0 h- M" h# d! o4 F7 C. k为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
( }4 |# F) G" I2 v- f1 U以下是制定这些规则的代码。
- Q7 ^& D+ v1 O; n) G9 X//--- Indicator ATR(1) with EMA(8) used for the stop level.... Z+ r! n$ y2 f' W8 K
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);1 b/ ]8 [, Y4 b; U J) p
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);1 \3 ^/ n% Q2 B) q
//--- Define a variable that indicates that we have a deal...3 [9 I! D" c- a' ~
bool tem_tick = false;
+ c8 q, h0 d) H. [//--- An auxiliary variable for opening a position2 S% ?6 X; A* `9 T6 ~) m9 D, m
#include<Trade/Trade.mqh>
5 R( y. b3 i: Q$ I7 }#include<Trade/SymbolInfo.mqh>
" G4 H" D5 L( y; zCTrade negocios;
5 O" E+ F9 l/ ? _! M! `: f" L) QCSymbolInfo info;
+ S8 i2 W! _5 U3 K! @4 P/ b% U3 F) ?//--- Define in OnInit() the use of the timer every second* M2 K/ e0 g& Y8 r- a4 x
//--- and start CTrade' X1 V! m6 t; G" p: @
int OnInit()
! ?4 T+ Y2 u/ u, ?) _" B" B+ j{, ]7 C6 O1 K/ x! l/ \2 ?
//--- Set the fill type to keep a pending order0 R: c: l- z) f1 Z& n( Y1 r
//--- until it is fully filled, w& _" k" F( V! ?, U! M9 G
negocios.SetTypeFilling(ORDER_FILLING_RETURN);$ \3 Q8 ?2 Z5 ?6 d$ s
//--- Leave the fixed deviation at it is not used on B3 exchange6 J* ^, {7 s6 j2 B w
negocios.SetDeviationInPoints(5);
6 f5 X2 U* e3 h5 \# @//--- Define the symbol in CSymbolInfo...
H- o/ I% \9 U$ y" q Ainfo.Name(_Symbol);
A9 M/ y) ~$ @, b6 B5 j+ K//--- Set the timer...
+ x7 G0 Q( Q, U6 R0 s$ E$ R, \EventSetTimer(1);8 U5 v( ?' g/ E" t+ j
//--- Set the base of the random number to have equal tests...7 r0 K7 s4 j7 m1 A8 i L+ k
MathSrand(0xDEAD);
( e+ m1 Q. Q! ?2 I" k3 freturn(INIT_SUCCEEDED);. P$ f+ _. s+ ^0 u! h9 ^ ?
}4 u2 l2 U( V: u- M
//--- Since we set a timer, we need to destroy it in OnDeInit().. Y1 u- m3 O2 k, ?$ S$ F0 \9 k, o! D1 g, M
void OnDeinit(const int reason)$ f3 E _$ L- y* G. \- y
{# \. D7 P# I" H3 ^' C2 V) s- H& x0 i! o
EventKillTimer();
o5 I6 D* k6 M: @}8 I. o& w8 `1 ~' g( n. k
//--- The OnTick function only informs us that we have a new deal4 t; [8 s, l' Z8 Z. t5 o
void OnTick()
+ m& ~2 F* b y8 q{
' F7 J2 Q+ u$ u- X8 [! B( Ztem_tick = true;
& b" p: \2 v7 f+ Q7 R: V}! n: I" N8 J# z0 H" s
//+------------------------------------------------------------------+
9 T: q% o1 D0 L//| Expert Advisor main function |
0 Y: E: C) \# i/ J7 O//+------------------------------------------------------------------+4 O, g/ v9 w* M6 C' x4 Q
void OnTimer()
2 `2 O* ]3 m) j{
1 u& }. n" X0 s) W- hMqlRates cotacao[];- S! b# i- Q! h% {# [
return ;
: s; @ N; r0 l- tif (negocios_autorizados == false) // are we outside the trading window?6 {; G; @) b' p5 b. x3 B8 K
return ;
8 M2 I* g4 o) @6 R4 t# A//--- We are in the trading window, try to open a new position!
( @, w/ }6 d N" H) zint sorteio = MathRand();' d. @5 R" N8 y$ y; N
//--- Entry rule 1.18 o- e" p' G0 H% a
if(sorteio == 0 || sorteio == 32767)$ l+ f/ m8 ?2 D0 I. h) ^5 S7 y; }
return ;
6 b# K5 Z: N' J+ {5 Gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
5 ?4 \0 H# I1 u D{# J+ c& |6 k( l3 T' R8 y
negocios.Buy(info.LotsMin(), _Symbol);
2 L6 T x3 E' l" z1 E}) i8 X* U$ x8 i# l) k. B
else // Draw rule 1.3 -- odd number - Sell
6 y7 }& }( n; [9 y{+ K: n$ N4 o2 S( Z& m% G1 s
negocios.Sell(info.LotsMin(), _Symbol);
7 T% i# z6 a& e2 b9 a, H ?- V5 b* ]}$ X9 f) U% J+ T7 z! ?
}' v+ [6 [5 R/ a6 B7 G
//--- Check if we have a new candlestick...% y1 ^9 H/ q; F, p
bool tem_vela_nova(const MqlRates &rate)+ L1 X4 z1 {" q1 A4 u' W9 F
{# n; M. s: n" v4 a& `
{
& `$ B: t% Q) l5 M3 eret = true;3 Q- q. e% g" P a- E1 }
close_positions = false;1 i- ^! d; N! S/ T* c
}
* s3 @2 K, l2 A) o* Selse8 q0 Q+ C/ o- {: Y
{8 N5 u: U( S) W
if(mdt.hour == 16)
* p7 @! c: h L; q5 m: v2 ?" _close_positions = (mdt.min >= 30);
- J' ]5 d3 |6 k/ B}9 Q+ |4 j! r! i8 z$ N0 t
}, X' I4 Z; i; G* w2 g4 d
return ret;
, K3 q' _) u' j, l; F3 V}3 E9 Q; x0 T2 j2 X2 u8 e
//---2 u5 l7 O/ O9 e( f
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])4 b2 g% V2 O: D" U2 P+ X
{- l. Q% ~; p/ i. ]# i5 \9 }4 I- W
if(PositionsTotal()) // Is there a position?' D- H z, S# e8 K+ R
{
& E; ?6 U" }2 Y1 G( {: O& G pdouble offset[1] = { 0 };
: Y% m# ]* m4 }& b) }if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
5 e |. @$ H- w4 k&& PositionSelect(_Symbol)) // Select the existing position!
) _! L. u. |& T5 C7 q- i{: n, m1 [: I0 x7 t8 s
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);0 N' K. O9 S% ?3 {9 P( D
double SL = PositionGetDouble(POSITION_SL);
' j$ o3 I1 j5 S: ~& ?$ L) T$ z: Edouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));- r3 Q# V, [/ F! n5 c! S
if(tipo == POSITION_TYPE_BUY): f" |& w! |. W, X* s, @( Y7 t
{
/ q! K: S& d) Q, J7 Eif (cotacoes[1].high > cotacoes[0].high)2 Y, h; u; t% [* L0 m% o
{
. A# j: S7 p x7 O) `$ {" q, Udouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];$ u- H' A/ U, J9 q
info.NormalizePrice(sl);
$ T9 V+ w' E2 |if (sl > SL)
$ ^. R( i% R: L+ }, O{* f6 S& g. N* Z$ [% Z2 ~: r
negocios.PositionModify(_Symbol, sl, TP);' Y; j7 i! ~3 @! ~6 {
}# f5 I0 A" R6 n- U) L/ X
}
$ ?& F, r. l3 h- a+ L}
9 p0 l6 m$ h" Relse // tipo == POSITION_TYPE_SELL( k" g+ ^0 U3 ~- }8 p: ^
{
& P" q% W$ S% @if (cotacoes[1].low < cotacoes[0].low)
' f' G- P5 U9 D: a: O{) A2 i+ ~) i7 B7 y s+ y+ y7 c. x3 H
return true;
2 H. l5 B4 r# p; t}
& P4 e$ i; U& T2 v6 x% Z// there was no position8 r: |8 y6 y( c8 ^9 q/ F
return false;
' Q9 [* z! c+ C. N: S}
6 p: P4 [+ @0 x6 ~' J7 v, ]" _我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; ^: O" n! m p! K r* A+ }% u
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |