启动交易模型,并构建 EA
& v3 r! E% j% j( d6 h在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。2 g; \& ?, k- A: J1 u
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* d# R/ f7 o! I3 Y" d; d, U
以下是制定这些规则的代码。. w- `! `3 c4 ]" m* y
//--- Indicator ATR(1) with EMA(8) used for the stop level...
+ G- Z) E' b) {0 iint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
/ S) H2 i3 L3 w! q$ R) T* nint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);, B- Z0 ~9 _) z$ q( t4 X
//--- Define a variable that indicates that we have a deal...5 n: |1 F1 F" u3 N; U
bool tem_tick = false;
( }7 K N7 ~" Z. Z//--- An auxiliary variable for opening a position
& H8 O v# ?, Z+ {; d8 t9 h, Y#include<Trade/Trade.mqh>4 z! k0 } o p# R8 f" r
#include<Trade/SymbolInfo.mqh>9 c; ?- q% R1 v/ y
CTrade negocios;" `4 f: u8 Y$ x# R; o0 D
CSymbolInfo info;
/ {8 E( t1 B8 B8 E0 X0 D! j//--- Define in OnInit() the use of the timer every second
& {. ^! k% x- I M//--- and start CTrade
+ h! q7 p+ D- h; D! w& u2 v; t$ vint OnInit()
( `* M7 R) u6 {- ]{
5 d @0 H3 d4 i- U6 n% s//--- Set the fill type to keep a pending order
! M0 S+ _) x' S9 n! g//--- until it is fully filled
% a" z# W- ^* K( G! `negocios.SetTypeFilling(ORDER_FILLING_RETURN);1 U) A6 @# [0 T# O! e( q& Q5 V
//--- Leave the fixed deviation at it is not used on B3 exchange
- X, o7 d; ]- W5 h6 U( a0 @ Pnegocios.SetDeviationInPoints(5);1 j; J9 ?" [4 t6 p% X* l
//--- Define the symbol in CSymbolInfo...1 i' a1 A( W s* z! x0 ]) }
info.Name(_Symbol);
& C& @7 N U- p$ _6 w: x3 `) _//--- Set the timer...0 n7 l& \5 T1 ~# l
EventSetTimer(1);
D" Y7 p! w/ j. Q6 Z ~//--- Set the base of the random number to have equal tests...; j7 U& i2 ]9 N1 q
MathSrand(0xDEAD);
3 r% g1 R2 q6 i m8 L* @$ f. Ireturn(INIT_SUCCEEDED);
6 q5 V8 A4 k4 ?}
( h5 C% E9 |" p, K# V: F//--- Since we set a timer, we need to destroy it in OnDeInit().. X4 v' h7 v7 U9 H% }5 ?
void OnDeinit(const int reason), z4 i, b- C& {# s8 b( b: a- C3 X
{
) K" m% W( a, MEventKillTimer();
) L4 k4 Z" N. L. y9 T1 i5 M}. [% \# k3 ?, y1 V1 C, S
//--- The OnTick function only informs us that we have a new deal
. S% a# J" X6 xvoid OnTick()
; j3 f1 G- J- f# R{
" t; \- c, B; |4 \: X) `% M, T- [tem_tick = true;
8 u' K5 s. R6 o; A! {" U}9 f0 g+ v h* ?, O& D! @) Z
//+------------------------------------------------------------------+8 z& j% }2 N( I7 ?+ ]8 i8 i( a
//| Expert Advisor main function |* d- v, O0 b F
//+------------------------------------------------------------------+
/ _+ P0 L% u0 N1 V3 `void OnTimer()
" f5 ?( m+ ]8 _) A{) [- u l0 V' d8 F0 {
MqlRates cotacao[];
; s0 H8 ^1 y( Breturn ;
" L! ^; L) U1 j8 g4 Nif (negocios_autorizados == false) // are we outside the trading window?
, n' I6 q9 f; ~return ;
* S3 Z( Q2 Z. A& w6 } I n/ s# Y5 E//--- We are in the trading window, try to open a new position!; b M8 r9 X$ Q9 Z
int sorteio = MathRand();( H1 I" p5 {! ]0 r7 Z, Y
//--- Entry rule 1.1
1 c. l4 I& L4 \- j5 o! A: wif(sorteio == 0 || sorteio == 32767)$ f: G9 N% q* |2 i2 s
return ;
% a2 A; ]4 F9 `/ o9 Z2 ]/ H. ~if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy. p* y: E% v1 G# D4 z9 }0 ^
{
l( a3 B* t4 C, U8 Vnegocios.Buy(info.LotsMin(), _Symbol);) Z9 g' B4 I3 I- p9 {/ q
}
1 |( _6 F* V1 \else // Draw rule 1.3 -- odd number - Sell1 b" x" |# E! }# G; e/ @1 Q
{& H& O3 @0 n: {/ e. J
negocios.Sell(info.LotsMin(), _Symbol);
( ]0 M8 }3 \9 B' g+ v2 n}
9 S- V! r7 ^) @* U x} R( W4 Z2 b2 e7 r
//--- Check if we have a new candlestick..., l% \8 |0 F* g- M1 ?2 s
bool tem_vela_nova(const MqlRates &rate): ^* A& p+ m1 k: f: b. R$ a
{6 \. F- d- K- V* K, d0 A; P6 P+ T
{
3 \: G( [# m7 k- V1 ]" `ret = true;0 W# {/ g5 A. C. D! r6 F, G4 ^
close_positions = false;! P6 Q6 W t! T O3 ]' S
}
5 a j4 G% Q" _8 a8 zelse
' y, L6 r9 I+ u) \4 a9 ~4 c{1 l. F( s) R+ J6 Y2 c! s/ X; ]
if(mdt.hour == 16)4 z" h, _; M+ f4 Z7 H
close_positions = (mdt.min >= 30);$ N' q& I5 X; C! {0 Z
}
- x/ j6 h, Z6 ~7 N, O/ }}' k+ s6 V0 K: _# \. p* w
return ret;8 a5 i1 V' t3 A: O4 @2 Z$ ^( |
}5 w/ c% R% J! J6 _
//---1 G8 S' l/ s2 @5 Y9 R$ u
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ V/ R3 _5 F; Y9 h1 P" a
{
: A8 |2 q* {2 y; D& S$ hif(PositionsTotal()) // Is there a position?
* D* F7 O0 z+ H# Z2 A ^ y{
+ V4 j$ z# I" _$ _' bdouble offset[1] = { 0 };. U) C6 s$ O3 w! p! L) J) Y5 ~
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?& R" Q6 u# f' c7 V2 z! b+ x$ Y C
&& PositionSelect(_Symbol)) // Select the existing position!
, }/ n/ a P$ Y! I{
' k( o F5 t# U w% w( \9 wENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 K# N9 n! O4 F6 ]
double SL = PositionGetDouble(POSITION_SL);
, q3 @4 g% g& _3 H8 z: i0 f v7 ]double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
/ D n+ A1 b" @if(tipo == POSITION_TYPE_BUY)4 q$ Q! d8 P. |+ f6 X) x ?1 c
{
4 ~5 y9 {) x6 g1 [+ ]0 @if (cotacoes[1].high > cotacoes[0].high)
, t" q. J& Q B8 l: e" k{6 x" C" k9 n a0 ?5 X5 T, M
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];7 N" Y7 b- \0 M: Z3 o
info.NormalizePrice(sl);
( G; S# z/ ^: M! }! S/ Lif (sl > SL)
6 z) e! H; N3 Q- ~' [) e{
; L5 `- {' o% k: Fnegocios.PositionModify(_Symbol, sl, TP);. ^" F% T g/ X
}
+ Z. \) k6 q. k4 I' w5 _6 U$ F4 W}$ _! X( y) e( `, w! K' |! d( e
}7 n$ ]" j: c: I
else // tipo == POSITION_TYPE_SELL
1 q" j f; L( ~1 b* {4 a0 R3 c5 L{6 a1 P! V0 }/ k9 K6 o; m# q
if (cotacoes[1].low < cotacoes[0].low)# y2 ^6 M# P0 Z1 ]4 w
{
1 X; g3 D- _4 `0 x4 J' b4 jreturn true;8 v) P$ N: U3 V
}
$ r4 b3 z1 M' G// there was no position
; N. R [& m& n4 freturn false;
; F/ v: M7 F( b}
0 q& S' n# _7 r/ W6 W( g+ o; L我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
1 L+ `+ W/ E. }# Q, o到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |