启动交易模型,并构建 EA
( L, B4 G9 e4 _$ n1 S' @/ U在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。7 |% E, u* T# X& t. U
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
& D7 t* w+ C: v2 j/ x- A以下是制定这些规则的代码。( s; `, [7 ^5 l, A' j9 i$ R
//--- Indicator ATR(1) with EMA(8) used for the stop level...# d2 z; F; P b2 V5 F
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
) d4 Q- a$ m0 q. ^5 Q) Rint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);4 e1 z# z J$ d: X/ J. ]) U# q
//--- Define a variable that indicates that we have a deal...
& L: G+ @ @6 c2 P/ q) W. wbool tem_tick = false;! `/ S- s7 k5 i7 _
//--- An auxiliary variable for opening a position
: H7 o% K ]6 K3 o! A0 |#include<Trade/Trade.mqh>
) j5 G* h1 p! R9 o x/ d r4 z#include<Trade/SymbolInfo.mqh>) K/ I7 e$ l) X3 g* n' D7 O
CTrade negocios;
. X) x3 T0 a( JCSymbolInfo info;
: s# B; v& D" p/ B//--- Define in OnInit() the use of the timer every second: J, ^. C& T; w4 }/ u
//--- and start CTrade+ L$ Y' k7 o: b _5 _
int OnInit()
# C) ~) S- s! F, f{& l8 a& ^2 ?- b" o6 r2 S6 R
//--- Set the fill type to keep a pending order2 \% i6 ?5 d4 y9 b4 X% M
//--- until it is fully filled
* k' [- q' M& ^negocios.SetTypeFilling(ORDER_FILLING_RETURN);% | ~" C. c6 E8 g
//--- Leave the fixed deviation at it is not used on B3 exchange0 {; ^- o1 j2 W8 h: `1 r( n
negocios.SetDeviationInPoints(5);+ [+ l$ [ T9 s/ ^4 N
//--- Define the symbol in CSymbolInfo...
: i. H! a7 E% Zinfo.Name(_Symbol);4 g9 H6 i: F$ G3 v. b$ P1 K
//--- Set the timer...' |* O4 w$ ]* y) ]! @% a
EventSetTimer(1);0 d6 F2 G3 b% L/ p- s; O9 F* W
//--- Set the base of the random number to have equal tests...8 ]1 K" T& e" a X3 g
MathSrand(0xDEAD);
6 ]8 I! b6 ^1 b8 R2 S6 [+ wreturn(INIT_SUCCEEDED);
! O0 m1 f8 W: f" H}7 K" C0 {% D2 X$ z9 ?* @' V; V
//--- Since we set a timer, we need to destroy it in OnDeInit().$ D7 e4 i- d& h7 F; ]) u- x8 @. x
void OnDeinit(const int reason)
. x( a' u, j" s0 y{
$ s! U; C+ B9 H; mEventKillTimer();" m0 C- m) m' J* @2 O$ O
}
% L9 q" |" h1 c2 m//--- The OnTick function only informs us that we have a new deal
! B1 [$ t7 \* M, ?( }void OnTick()
- [( v( O0 O4 Z: Y{
, g E* o5 l7 A9 Xtem_tick = true;
) [* P- `8 E) L* _3 d0 ^$ R}7 `/ z; f2 R* P( u
//+------------------------------------------------------------------+
3 l( q N/ M# K8 t$ @! ]//| Expert Advisor main function |
8 b1 N& q* f; k5 }3 F- f# ~; Y//+------------------------------------------------------------------+
6 G5 X% L- B4 D* Bvoid OnTimer(), b' Z+ d. R2 f: {& [
{0 o9 w0 J( L: _- E' q3 S' m+ e
MqlRates cotacao[];" C+ G, B. S& z' E2 F6 ^( R
return ;
' s4 c, I% p+ {1 e) \" n4 D" Oif (negocios_autorizados == false) // are we outside the trading window?
- |- N4 R) N9 k7 }return ;! W2 Q' m/ y6 O2 G/ H
//--- We are in the trading window, try to open a new position!
1 F/ B. w6 Y( d- J4 E- Tint sorteio = MathRand();
5 e) R2 p2 z! { O) v: G//--- Entry rule 1.1
: V/ V0 a, r4 ]3 uif(sorteio == 0 || sorteio == 32767)# _$ `0 p6 I, I/ T) K
return ;3 P+ j( Z! ] n9 ?' X) u
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy! O5 @& H2 y4 n6 d
{; _: }8 k& S; D
negocios.Buy(info.LotsMin(), _Symbol);2 L" G. p6 o( {' _/ n. i1 {
}- L. t( J q; K# ?6 r$ E
else // Draw rule 1.3 -- odd number - Sell
. A* O/ w6 y' h& L P9 k{
/ V; V# ]5 I% X( `6 tnegocios.Sell(info.LotsMin(), _Symbol);
% G( o, v) V6 K, p& j# C}
+ e: J9 N% ~+ l3 p3 |}
2 k" y! D, _& {# i7 ^) t//--- Check if we have a new candlestick...0 i3 B' T- d6 D4 z2 T
bool tem_vela_nova(const MqlRates &rate)
I6 G9 U9 i1 M* y{8 `) k( v' t3 d9 b9 m
{2 S4 w4 Z5 G" G3 f" a$ p; w! g
ret = true;& H- Z) |( O1 k( p2 s% @
close_positions = false;$ K# v9 G. w/ t3 b- q
}5 t1 }. G) p+ ^, B
else* k' d$ Q* R6 h* m* D; S5 P
{, ^. u" I# F& J* A8 U1 _0 r7 z% l
if(mdt.hour == 16); L X# T: z1 A* S
close_positions = (mdt.min >= 30);! x8 ^8 I0 J5 }+ T2 H9 O
}
0 G$ R' q, b& S" @# N. a7 B}7 ] H6 ]! Z$ A7 z9 W6 E5 H
return ret;
' Z' X$ G3 F* S, x' I4 [}3 ~2 s; }: L! t
//---! E: L, L; A4 F& ~
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
/ G: ]% q+ {& D g5 ]{
! M* o4 l5 _' S7 n. ?if(PositionsTotal()) // Is there a position?7 \6 I1 T7 j8 b) p% n- D! \
{" t9 J/ \$ o9 L
double offset[1] = { 0 };
$ S$ c( S, j0 ~: c" a" _if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 }: _) Y! L; \* r ]5 r0 ?
&& PositionSelect(_Symbol)) // Select the existing position!
. C; M- X+ c+ X4 _" j0 A" O{% ^( p; i& B. \; u
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);5 R! @# @$ O2 p, X w! i
double SL = PositionGetDouble(POSITION_SL);
6 q. M" r+ N2 _0 ~- x$ M* ~double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));. e& D- ^/ I; W# I7 w- c
if(tipo == POSITION_TYPE_BUY)
3 c1 l( {8 v' ~3 {{
9 }! Q2 {# i3 U) ~if (cotacoes[1].high > cotacoes[0].high)
9 L3 ~) {' ]7 t{
+ I& O# ]7 k7 {8 Y$ idouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; |/ T0 ]; F1 T3 A" F" |
info.NormalizePrice(sl);' e) ^/ F4 c9 ^$ A2 t
if (sl > SL)$ E& X( q( `! x
{; f' b7 g _# g6 C S. ?" k" G" F; R j
negocios.PositionModify(_Symbol, sl, TP);; s; B; G- j8 F3 T# _
}
9 C0 p! E8 j" Z3 M5 w- }}
1 ^1 { T3 i6 J/ |6 y) f}
! n" V9 g( e ^! R' K6 E5 velse // tipo == POSITION_TYPE_SELL% r+ m% C; g2 P. [7 |
{
# {3 w1 f/ Z4 H. }; W6 P) n# gif (cotacoes[1].low < cotacoes[0].low)% i' \% |7 V" ]1 M Z
{) {" G% U. ` t9 j, D" M
return true;' a$ Q& _( Q- I& A8 e
}
! i$ v2 x" @! H. @' l// there was no position' [- ?; z6 v. c- z+ R: v
return false;
Z+ }8 s" v' ?, G! w# d}- x x1 R% t" J# k
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
( M: G B6 \# P$ @到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |