启动交易模型,并构建 EA
+ X/ f) l. E. C% u) r/ P8 b在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。6 H5 J# E1 N9 s
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。2 _7 U+ W. `5 D# d% \; R
以下是制定这些规则的代码。
3 q* s w! J+ b/ y N//--- Indicator ATR(1) with EMA(8) used for the stop level.... a# ]/ O7 R9 C- s; K) l2 c
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);" P8 f, g, B* n( [+ f' E
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
1 _; e, e, |4 _* Q- Y1 z, n//--- Define a variable that indicates that we have a deal...
1 W4 P ?* M% x4 Zbool tem_tick = false;
6 R" Y s- Y4 }5 u//--- An auxiliary variable for opening a position
) E5 e) J q! U#include<Trade/Trade.mqh>" H( B4 U; L5 a+ k9 k! S
#include<Trade/SymbolInfo.mqh>
$ y* w0 l# Q1 H7 kCTrade negocios;
, M. ^0 V. c6 q1 ~9 BCSymbolInfo info;
* {* f3 `9 B' N3 O7 L c* l//--- Define in OnInit() the use of the timer every second% Z, d8 f! C0 j; g2 e- `0 R; q. ^
//--- and start CTrade- H4 T/ U2 k' m. L6 T/ r) q
int OnInit()
* i9 D' W: I) ^- g9 d# e0 v4 A{
, W/ U. D# i4 ]9 o* A//--- Set the fill type to keep a pending order6 ]1 F+ I- M# c" t4 H5 H
//--- until it is fully filled
7 {( h2 x( w2 T: D4 Wnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
2 w) z Z. z$ _4 u+ i5 b4 R//--- Leave the fixed deviation at it is not used on B3 exchange
" x% W& Q; z4 _, x$ h0 A# bnegocios.SetDeviationInPoints(5);2 A0 G8 {1 \6 i$ m# v. `; C
//--- Define the symbol in CSymbolInfo.... s. R9 h& h4 d
info.Name(_Symbol);3 m* \/ z3 s1 i8 h; [
//--- Set the timer...8 X, `6 p6 O. U) j- L% P, M; q
EventSetTimer(1);
& Z% O2 M, `, ^* s1 h2 Y' q" B4 o$ E% K//--- Set the base of the random number to have equal tests...
/ t' s% f( l* r$ `3 IMathSrand(0xDEAD);& @5 z9 [" T2 S
return(INIT_SUCCEEDED);
" K8 b5 C6 G, K4 s+ m5 v+ X7 t}
( _; Y+ u- k" u c//--- Since we set a timer, we need to destroy it in OnDeInit().3 j) D- E) q6 v' L8 [" c, |$ l
void OnDeinit(const int reason)$ X% D" R% w& N! Z! l/ N
{ j* O4 k% @! _ k7 B y- j7 B
EventKillTimer();
; ~; u% e* Y5 C0 s}
( b/ a7 {3 M1 M& w//--- The OnTick function only informs us that we have a new deal9 J. D- P/ a+ w3 W
void OnTick()
6 p! O3 U( @" z+ Y, h- q: \+ w" Y{
" m/ N$ J- c3 G+ h7 t8 h* Wtem_tick = true;
^ p+ t' ^6 R0 g7 E* j! k}
}1 H; w" g- U: t) j& N//+------------------------------------------------------------------+& \+ ^: z- m" k% X& u3 l
//| Expert Advisor main function |' |- w0 @6 j/ L; K
//+------------------------------------------------------------------+: R, L2 k5 T- j r1 H/ ~; P
void OnTimer(), v' c Y7 |% K# o1 c+ f
{
7 \5 P9 N. k" Q3 MMqlRates cotacao[];
; D( n0 V2 B( Greturn ;
# p$ J) Z/ M- l' {1 ^if (negocios_autorizados == false) // are we outside the trading window?
) p$ R( U! _3 B8 Rreturn ;; ?" X |& a/ ^$ c8 P
//--- We are in the trading window, try to open a new position!
' U# I$ ~' p! R' S) q( Dint sorteio = MathRand();! {# f- G, I8 O! i8 O( Z9 K. A
//--- Entry rule 1.1
$ ?/ f, f! M; R& G% i2 Lif(sorteio == 0 || sorteio == 32767)
, \1 Y! ^! X& qreturn ;: i/ K4 A+ R# W
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- _3 n: {, O: n% f( q) B A{
/ t- Q8 J, U9 t! w e4 I" @negocios.Buy(info.LotsMin(), _Symbol);" s$ d/ ^$ Q* u9 p
}# I5 [2 h4 ~* Y8 k2 P+ U, K
else // Draw rule 1.3 -- odd number - Sell
1 @) Y( ^) s2 Z1 `{' d- Q* j% { H0 f4 Z: O
negocios.Sell(info.LotsMin(), _Symbol);4 j5 Z- b% b' G8 m# @' J. {, V
}$ R M, j6 Y+ S/ H' ~& M0 Q# ] M
}
$ y9 a( c) k: O+ t//--- Check if we have a new candlestick...# v3 l) \! e9 D4 [
bool tem_vela_nova(const MqlRates &rate)
" k- ^9 a) m5 A2 Q3 r{
4 T) U- d( S( E9 {+ H* I{+ ]% r; R$ F4 H2 f
ret = true;. q* y7 `4 S! ^; w' b: \
close_positions = false;8 g+ y+ P: r. K+ w
}
/ _6 s5 B) ^8 u) Q0 L( Z/ j3 pelse
& H5 x" X6 U- k9 Q# q{! v( t( w' P2 g4 I
if(mdt.hour == 16)% C( Y: l/ b- f- [
close_positions = (mdt.min >= 30);# k* k6 j4 u$ o
}
1 r) L0 [/ E0 W( T2 g" N8 X' V}
7 m' U8 j2 u) areturn ret;
]* D* X( ~9 P) `9 C}: ?( R& y: v& y( P, P" z) e0 k
//---! q' i- | y/ v" ?$ a# n, `+ Z9 l
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 b7 }4 _( i$ h0 \
{* ^9 z6 M* m2 o- N# W
if(PositionsTotal()) // Is there a position?- W, V: B0 a: U/ c R- H. v
{
' ~: {9 m' z/ wdouble offset[1] = { 0 };
* ?) H; A9 r1 Q9 K$ Pif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?: f" ?; Y* D- B5 n. G, ]
&& PositionSelect(_Symbol)) // Select the existing position!
' H5 A0 z) Y6 b. E. s" t; o- O{
) r4 |* {, O5 b# e, kENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
8 ?# c0 m8 G* V) }0 wdouble SL = PositionGetDouble(POSITION_SL);! W/ a. o8 V5 D1 `) V) |
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));% _* X2 M% B# d f8 r" h
if(tipo == POSITION_TYPE_BUY)1 d3 C# S( b9 U( B) v6 U+ `) v; D) b! a
{
; q# M+ J( m9 Z# |$ |' d! D& Eif (cotacoes[1].high > cotacoes[0].high)& Z- Q; j& u2 w3 J0 C# q% ]
{
5 g Y; P1 u% ?7 u# d) g7 `double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
/ R; m$ {# S7 s' I. M/ Ainfo.NormalizePrice(sl);
; q6 Q. C f, ~* V2 f- J v+ ^0 D7 Xif (sl > SL)7 ]/ X ]& V4 R1 H7 E
{5 \7 d1 s( d. c% O! |( u s! t: x/ k
negocios.PositionModify(_Symbol, sl, TP);1 d: R) a* h" w7 h$ N2 Y
}/ w8 d, h$ i/ h1 a9 n5 P* |
}
O, U0 {) e7 C* f: N* r}
: E" M7 W/ g7 c; D9 telse // tipo == POSITION_TYPE_SELL% j% n3 a2 ? A- I3 k- U; x
{# K! Q: _+ m' l
if (cotacoes[1].low < cotacoes[0].low)7 d& W" P+ |! S1 f
{" W0 E- `' [! a1 p4 ?9 T% b
return true;& _/ d \, z0 H# _
}. Z& v+ R* n4 @% p% }, S- s+ J+ t
// there was no position9 B2 j/ S! e$ T& F. Q
return false;
. V: o4 x" m) M0 k. v$ C" k, r! b9 v}
: T d8 x5 A, q+ ^- ^0 B H9 f; q我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 y4 a! H* a& R; k7 ^
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |