启动交易模型,并构建 EA' z7 k+ }' O B% \% x- z0 Y
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
8 o( p! ^" |& n/ `为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
4 ^- t# E1 H$ h9 f% E# \以下是制定这些规则的代码。
$ [% }- B# }3 U: G# T( q//--- Indicator ATR(1) with EMA(8) used for the stop level.... y) P3 c! Z% I$ W4 `3 f/ d
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
7 s: Y6 r4 ~" F- X! M0 k7 }+ {% i) ~" rint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
) B' }9 z/ H' f2 V |& ~//--- Define a variable that indicates that we have a deal...
# k8 p7 `" _& i6 e6 ~7 n! ~bool tem_tick = false;
2 J' F5 Q0 E# S# u, p' H//--- An auxiliary variable for opening a position7 g0 W8 ]' y! [/ i6 d5 B
#include<Trade/Trade.mqh>6 b% d+ {- J' A1 e! z/ b6 a
#include<Trade/SymbolInfo.mqh>% \" M# p2 W3 R \/ y6 l3 S3 W; ~
CTrade negocios;
2 L K! f, E8 L" y+ y K1 gCSymbolInfo info;* k2 a) O& E* e* G* R
//--- Define in OnInit() the use of the timer every second4 X, ]: `- c" x
//--- and start CTrade1 l( `5 B* @- W! |$ c; G% X
int OnInit()
# L! @7 F1 {! J, \( J{! w+ B. A2 j2 V, b: K
//--- Set the fill type to keep a pending order: D! g9 ~9 I. k5 h
//--- until it is fully filled) A9 q9 d! }' b/ n' V
negocios.SetTypeFilling(ORDER_FILLING_RETURN);: U$ t# J! v3 N3 I3 D5 f
//--- Leave the fixed deviation at it is not used on B3 exchange
- R# d7 U. Z8 O0 X Q$ Qnegocios.SetDeviationInPoints(5);; q3 k; Z/ f' h2 _. Z& Z5 E
//--- Define the symbol in CSymbolInfo...7 Q6 m0 d. A6 y4 u" J7 n; c
info.Name(_Symbol); Q: A! {. ~1 u ^* r8 M1 N% h- ]
//--- Set the timer...5 Y& ]+ s9 S5 d) v' V
EventSetTimer(1);1 k) Z. Y ^; _1 t% ]8 o
//--- Set the base of the random number to have equal tests...
. R( Y: `4 @! A- g7 e4 n* JMathSrand(0xDEAD);
* l, U. f4 b1 ?& ~1 Freturn(INIT_SUCCEEDED);
8 R Y- h( e2 V; y% ?- i( X6 R}# v9 {( E; L, F! [( c
//--- Since we set a timer, we need to destroy it in OnDeInit().
: p8 J, s/ q( q: Q# p( K+ Wvoid OnDeinit(const int reason)/ w& R; R0 G! p1 y1 \" _5 k3 P
{9 c" Y* o) b8 G" \1 z/ ?6 @" D
EventKillTimer();
( ~! p' d7 M# t- T& d4 q}
7 D$ M& h( T3 w( V+ {3 m* a//--- The OnTick function only informs us that we have a new deal
8 G% P0 R/ M7 Z. [void OnTick()
5 b" e8 ?. h8 e H% \& s{
, F$ |( p* Y0 G3 Qtem_tick = true;
/ g. w( f, B3 R* Z" |) w}
: g: `6 p- g/ g* b; L//+------------------------------------------------------------------+3 G; w; L6 i; e. p
//| Expert Advisor main function |3 L$ k; r; c9 R! n; D
//+------------------------------------------------------------------+
1 g% v6 u: b0 G( Y+ Nvoid OnTimer()- A& g: f+ f2 }) k# a
{7 z2 Y' `0 D; f4 L5 H% f
MqlRates cotacao[];
- R# G9 i: T* t9 D4 \+ O* O( h6 nreturn ;. j/ [) I& C2 h- @1 N7 p& I
if (negocios_autorizados == false) // are we outside the trading window?
8 R0 o: D" j: S* n( {return ;
. Y# l7 j, {6 g" T9 }. T) {& c& `//--- We are in the trading window, try to open a new position!
7 j0 k6 Q$ Y7 e1 G; B, s( vint sorteio = MathRand();
3 x: f7 W6 ^5 `& t4 x3 ^! {//--- Entry rule 1.1 r$ y) r+ q8 y/ W( U
if(sorteio == 0 || sorteio == 32767)) c; q3 f- t" _, a) b0 ~* j& U* v
return ;
; _! x- W2 |6 c2 R- qif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy; Z! R9 r8 D; l3 a) B# n" h
{9 Z) p {% R% e2 k; i! X* S9 ^
negocios.Buy(info.LotsMin(), _Symbol);& T3 Q4 i+ k, p7 ~, m9 g% ?
}9 {& d. M6 n% J* ]+ B2 j4 o
else // Draw rule 1.3 -- odd number - Sell
0 `2 ~" h& {/ @/ d2 R9 b d{7 D$ |% @) I; m* n+ q3 L
negocios.Sell(info.LotsMin(), _Symbol);
" n0 H2 h1 v2 f}
x6 {& m* K4 e' P}9 B) R5 B8 N. q2 J+ P; `) D
//--- Check if we have a new candlestick...
* s" l) I+ p0 D% N7 k* x y0 [bool tem_vela_nova(const MqlRates &rate): W$ R* W' o% d, k! P! S" K
{; `0 ^) @. a% X6 H6 |+ J
{
) W, F5 V: j7 }) [6 {, {' Nret = true; ~/ u I# ^: F' g! `3 _7 m
close_positions = false;
6 B `) Z* l( g6 X a Y- ]}$ }. q3 B/ ]0 y3 w
else
6 ~5 ~/ ?# t0 F8 k{# L4 N7 R4 C4 U( L' \" S
if(mdt.hour == 16)+ [0 v& l1 s7 n* _6 ~& F
close_positions = (mdt.min >= 30);
: \" h1 w2 f0 `& E}
# u+ P3 R$ {* q7 u+ W}" N9 } d$ x& r/ l
return ret;
; I. X( T1 p1 M$ M6 `+ ]/ w}+ R$ Q- X) Q& H) {
//---% Y$ K' o; T& ]3 z( |" o0 C
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
* n9 z% H& T) W1 b7 g{
2 w7 b. [/ N k' f( ^if(PositionsTotal()) // Is there a position?: {( ?9 ~) b, p% y7 [: z m
{$ h5 O ]* Z+ \+ G9 H
double offset[1] = { 0 };
8 h- ^) \) ?9 }6 u' [if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 J; s5 a7 ~9 e, V. [: w, y
&& PositionSelect(_Symbol)) // Select the existing position!: P/ ?% g4 g N3 J& R8 D
{1 r. e) s& K+ z/ p% r1 ?
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);# v+ g1 Y( w% ?
double SL = PositionGetDouble(POSITION_SL);& L' J. J, G( V
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));/ V. v+ C1 ?; [$ [9 C, V9 x5 A
if(tipo == POSITION_TYPE_BUY)& m- O, W( k+ z# x2 Y7 N- T
{
8 H9 S4 z* q- f6 Y/ }" [ `3 Dif (cotacoes[1].high > cotacoes[0].high) |+ q0 [$ w% R. L0 d) h
{
# {9 Y* I9 Z( Y$ `' |5 D; _2 ldouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
4 `- V# a' h3 c" f) v" }# Linfo.NormalizePrice(sl);8 g# R/ C g8 M* E( i
if (sl > SL)
) A- M+ T. k0 U0 d6 j{
; R1 k! o2 U5 qnegocios.PositionModify(_Symbol, sl, TP);4 t: l0 N+ d6 o
}% g2 b$ Z- y+ v" L3 m
}
3 _; O1 b9 a8 b5 h}
' N0 S( z, `+ o* c: {( E; \! welse // tipo == POSITION_TYPE_SELL8 g4 p. H+ \: j4 b' X _
{" S; G0 Z3 a: O" \2 L i# }
if (cotacoes[1].low < cotacoes[0].low)
9 R+ R# d- b4 R! G b0 q{
9 f. Y$ r# b5 w+ s9 Yreturn true;% B3 x7 f: H6 n0 N( `* U
}3 R; A) e% w! B; u0 D
// there was no position
( n/ P' N, A8 ?% c5 j0 S6 F$ b$ a+ Creturn false;- a3 d, G! C# I! J+ _) M5 O1 N
}8 l* U4 w& `$ D5 r
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。7 }# }! J% F- L6 }8 s. p8 @
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |