启动交易模型,并构建 EA
; ?! Q A( [0 _: R- }- s# p# p在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。, P$ ~7 y! T! x# M6 H6 y6 n# F' |
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
4 X( x6 k; s* v$ ?5 A以下是制定这些规则的代码。
1 ?2 l" M3 P b, G//--- Indicator ATR(1) with EMA(8) used for the stop level...
& |! u4 x7 I7 ~3 rint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
6 G( M3 l! y5 n/ m5 K' |int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
/ `7 N8 J) K+ p" u4 U//--- Define a variable that indicates that we have a deal...
7 i" E/ K5 z- X: Z i5 T; ?. Hbool tem_tick = false;
- C. y8 \& ] {$ R! s- t0 b; ]//--- An auxiliary variable for opening a position; r& p, h* x) ~* }
#include<Trade/Trade.mqh>+ D E3 x* i% B2 V% a C
#include<Trade/SymbolInfo.mqh>
/ p+ Q: W6 o; `5 r6 ACTrade negocios;# {* b2 c- S; p. L) [4 v! F: A/ A1 M( v
CSymbolInfo info;) a/ Q4 A: q; C5 M' z, e
//--- Define in OnInit() the use of the timer every second' Q) b# f6 ?, _3 {% q. m4 w0 ]! {- c+ p
//--- and start CTrade) q& Q6 d( h' ~
int OnInit()
9 \, K. }7 E- L* q: e2 j% D* v{0 F* Z5 r8 `0 H5 r j9 @# q
//--- Set the fill type to keep a pending order/ ]1 |# L& }, f4 V! ^9 m' ]; h" M
//--- until it is fully filled
2 i* A/ A6 v( P' K/ p; ~# enegocios.SetTypeFilling(ORDER_FILLING_RETURN);
( U* d8 S( q" ~, o//--- Leave the fixed deviation at it is not used on B3 exchange% N" Q5 K8 c& A5 k, }) k
negocios.SetDeviationInPoints(5);' ]( P! D/ n1 H% V9 W& h
//--- Define the symbol in CSymbolInfo...
1 I( J" | f6 Kinfo.Name(_Symbol);( t P8 J/ L+ s2 d/ E1 f- u
//--- Set the timer.... y3 c5 i" T0 G ]6 |( |; l( G" @1 \
EventSetTimer(1);! S' u6 p) N; Z( D* i
//--- Set the base of the random number to have equal tests...
; Y: }' @- ], oMathSrand(0xDEAD);) I( }& I4 q3 q
return(INIT_SUCCEEDED);# ^" u% j* Z7 c# T0 M
}8 f! P/ h a0 `* C3 f
//--- Since we set a timer, we need to destroy it in OnDeInit().
4 J8 }/ K) I, h9 R. _9 Rvoid OnDeinit(const int reason)
6 F5 x" b- p* I" {) ~9 I{
4 e, p# v T) ^EventKillTimer();
( T! b, m; ?& w! X}
+ q# z, }' A) G+ W7 o//--- The OnTick function only informs us that we have a new deal, X' O( m1 o4 n# i! z' r
void OnTick()+ h& N2 M& L" d2 F0 ]: u4 `# e+ I
{
% X( }: V" P$ k6 K4 Ntem_tick = true;
2 C$ g5 ?8 ]2 h1 S}, r' g5 M9 H/ }$ d, E n
//+------------------------------------------------------------------+. C. r2 D& W+ p3 i+ W6 B
//| Expert Advisor main function |
( _, n0 L* t$ N$ p% o//+------------------------------------------------------------------+
1 q( e0 Z: q; a* y! ~% C/ `void OnTimer()
) r3 g- w0 k# A J6 R/ [! J{/ j4 J, @ y) x( G
MqlRates cotacao[];
5 {4 N- c8 ~# R L" Y2 B: ^return ;" r6 |, w1 ~" u; l2 m/ D
if (negocios_autorizados == false) // are we outside the trading window?# d" i! S1 _8 E8 ~; `9 J8 P5 W% D+ V
return ;
3 c4 z* Y3 t( O( F9 q//--- We are in the trading window, try to open a new position!
3 @3 e6 S, J) r* |( Lint sorteio = MathRand();
t; s5 J7 h. E+ D% M//--- Entry rule 1.1
1 P& ], }, {4 Gif(sorteio == 0 || sorteio == 32767)
# R1 V: L0 b/ D: Oreturn ;
/ @$ {$ T7 W/ P, A; g* @if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy2 | u3 F8 R. E0 x. j, C4 K; y9 R
{
! d2 i8 `2 V2 O! G2 A# c$ u! v: ynegocios.Buy(info.LotsMin(), _Symbol);" k/ l! t; o) v8 s- r; U
}
# k( P9 a! R( b7 v" Z6 melse // Draw rule 1.3 -- odd number - Sell! i' d) N3 ?6 q" P& _+ W" x
{& l' W; o1 D' V! V( o9 N& e) k& N
negocios.Sell(info.LotsMin(), _Symbol);
) V4 |& x$ t: s. v3 i& [; p$ K}
, Z1 x0 T V4 F" Z}+ P. g' G; G. N5 s7 d5 c9 F
//--- Check if we have a new candlestick...3 m5 t0 M3 B) p
bool tem_vela_nova(const MqlRates &rate)
4 A' g4 Q f0 [% Q% d5 [& d{# T! m3 d$ o& V1 A: O
{6 V6 v9 H, F9 ~5 V
ret = true;( l! t+ ]+ y7 c2 ~$ t& V: d
close_positions = false;
. [2 v [* d& D8 u4 B3 ^' M6 w9 Z}- ^: q6 s9 T! v, G2 g
else" s5 T' w3 }( \6 j; B% Q- n! i
{
0 c. v$ f% R3 g7 d O3 F0 {if(mdt.hour == 16)$ _3 w" Y/ T2 f$ a& I
close_positions = (mdt.min >= 30);
! q6 z' q q9 D+ {}+ r) T m+ O% W! ^) Q7 h
}6 c- f& d& e, k) G# n+ j+ U
return ret;0 ?0 u b+ O8 O! o+ ]8 U
}+ e$ x, t8 M$ m2 E/ V X: H
//---- c) U; N4 v$ M1 @
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
( a3 {1 p% P8 j9 i. k) @: }" w! B{
1 s& S% C2 I$ V: \5 _" @1 \if(PositionsTotal()) // Is there a position?' n6 V; H: \9 V! Y# n
{! }6 V* t }$ B- S1 O/ X3 X
double offset[1] = { 0 };
7 W, W2 v+ w9 c6 U. ?6 f0 i- Nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
, x3 Q/ i% V* T3 r8 U&& PositionSelect(_Symbol)) // Select the existing position!
+ t2 s& [2 d* ]+ K/ u{4 m, j% s- Z5 y( J1 P& N& T6 c
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);' Q. D8 y3 }2 {6 ?) D$ B+ v: z- v& @
double SL = PositionGetDouble(POSITION_SL);, b% t. y. W9 j* r" X
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
% l3 v! _" b) s+ T" x! N9 `* nif(tipo == POSITION_TYPE_BUY)
2 z |( _. L. X" ?, {{6 w a* k' j9 u+ f( [. X# A
if (cotacoes[1].high > cotacoes[0].high)# r( u2 L* a& c3 t9 j
{
/ _5 \$ y4 w! Bdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];( H& E; O4 Q2 j7 z4 o0 y N# P" }
info.NormalizePrice(sl); W5 m+ J z2 C8 o
if (sl > SL)2 r' i; v2 m; l# s7 m3 b' K
{ X' E9 V6 z! z; S5 l7 O
negocios.PositionModify(_Symbol, sl, TP);9 n; K4 X- c6 r" v
} ?5 ]$ ~( T# D
}$ Y7 `& X6 Z! n9 y* l
}# W! R4 z) d* h% Z
else // tipo == POSITION_TYPE_SELL
# l' X& R* o3 N2 `1 a1 |$ C1 b. j/ d{* ~7 I2 k3 I& |" }" B3 l
if (cotacoes[1].low < cotacoes[0].low)4 x6 S" L6 E/ O" B
{
$ T7 e+ m; T3 g. Q+ {, areturn true;7 R% X( K! n) H3 U; y" v: G
}
- z7 B5 ^ V3 \1 P* ?$ Z9 y+ Z, _# ]2 J// there was no position
. L) H0 A* p5 e- q* U$ Dreturn false;
7 F' y( A+ b$ s}
! }) c& ] [0 c# y我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。' e( b% c% ?5 |+ o* }! Z+ R
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |