启动交易模型,并构建 EA
: x4 p; o4 o' d/ f) h在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 |4 k6 r. Y6 K) f; c( D/ T为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) Q# z' R* w/ r+ v$ R! O8 d以下是制定这些规则的代码。
( A8 ]- @; r/ A) _0 }% e//--- Indicator ATR(1) with EMA(8) used for the stop level...
2 F, f; ^. K( X$ F+ q/ [* _int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
+ A1 I1 ?7 J9 wint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
/ b3 o+ |. U% H8 w& r+ @, F# ~//--- Define a variable that indicates that we have a deal...& ]8 M/ P9 n2 n5 j/ V6 w! Y/ I
bool tem_tick = false;
' e9 u& z/ `+ z5 N//--- An auxiliary variable for opening a position
1 x0 `1 i8 X. n1 ~#include<Trade/Trade.mqh>" a% |8 ^: d/ H7 n
#include<Trade/SymbolInfo.mqh>
! i5 u/ _2 \, W% R+ W2 YCTrade negocios;4 \, M9 W; r0 @4 N$ W$ t
CSymbolInfo info;
4 ]' @8 c- B7 T2 b//--- Define in OnInit() the use of the timer every second9 q7 }. Q6 D1 P2 o/ m4 ?5 s: b
//--- and start CTrade7 t4 @" z0 G) ]/ I: [
int OnInit() q1 ?( e! t5 }1 r4 P+ y) d
{+ a v3 B" T3 W$ W0 K
//--- Set the fill type to keep a pending order/ T+ K5 V: b1 R9 Z( k
//--- until it is fully filled
& ~4 q& T; F3 wnegocios.SetTypeFilling(ORDER_FILLING_RETURN);6 {! d: I% @6 p* A1 m$ U7 `
//--- Leave the fixed deviation at it is not used on B3 exchange5 ]6 z% e, p# ^: Q' d; O/ U7 ]- S
negocios.SetDeviationInPoints(5);& ?) A1 u* K0 M# k$ [; C
//--- Define the symbol in CSymbolInfo..." [2 F1 e. j3 |7 W9 L
info.Name(_Symbol);" G% q+ A6 i: \! L, l6 p/ S
//--- Set the timer...# v' L2 V$ S E4 P% V5 D
EventSetTimer(1);
9 E) ?/ s, t( T* D# g//--- Set the base of the random number to have equal tests...' p- `; u9 I( `; K4 s3 c
MathSrand(0xDEAD);* O" a( a5 C% u8 E* I
return(INIT_SUCCEEDED);" j, b# s$ |( P. Y$ Z( c
}
# T. r M2 l( C4 D/ y//--- Since we set a timer, we need to destroy it in OnDeInit().
" a N' L) z# {# O/ Kvoid OnDeinit(const int reason)
" b2 s. f" C3 i5 p2 m+ R; D: X{. F; D9 }+ l+ D' ], [9 y+ g
EventKillTimer();9 D9 a9 x% @9 l
}9 @3 D0 u( R* `, \8 A6 L& N
//--- The OnTick function only informs us that we have a new deal
5 l7 I; g3 Y/ B" @ t Q" ?5 lvoid OnTick()
2 N; M7 u( a. ?{
7 [) f5 k6 p% q: m8 O" ltem_tick = true;
/ w0 w& U, ^; ~}
8 C& U* o, D5 J1 ?//+------------------------------------------------------------------+2 t. U8 L6 z. X; d* K
//| Expert Advisor main function |
P& M; ~+ {4 E) A6 v+ `: f0 s//+------------------------------------------------------------------+
Q G: e4 L- Z5 n# Z6 l8 yvoid OnTimer()2 S: d" {; \4 U1 N& k7 o0 D
{" l* `: n: N! H P0 L H' A
MqlRates cotacao[];
# W. w4 g$ t/ C \9 jreturn ;
! ?3 Z* E* a Q# a% \( Jif (negocios_autorizados == false) // are we outside the trading window?
; t d* z, M% `) A) e# sreturn ;" L2 }6 D% }% @9 h9 P* F7 o; k# J9 W
//--- We are in the trading window, try to open a new position!$ q& L: ]. x, V: ?- F/ R
int sorteio = MathRand();2 M2 K. x7 [5 C
//--- Entry rule 1.1
5 B( W7 z+ v+ H9 G* l0 ?) ^- kif(sorteio == 0 || sorteio == 32767)
1 t( d1 }( N% E, h4 h; N; K. y, }6 Sreturn ;
9 I" ]0 E5 r# C- |& y4 Y, Zif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
8 D# |/ [3 E& U( D) F" _# b, U" C( |{2 j8 P I; |9 K! b: A
negocios.Buy(info.LotsMin(), _Symbol);. u& g& ^$ f+ C: p8 Y& ?+ Q
}
! {, V4 C( J: [% q( q, v' Telse // Draw rule 1.3 -- odd number - Sell
! G$ _7 { o9 P; o# a* X. t{
; A4 p$ X. N; H- x( {/ Snegocios.Sell(info.LotsMin(), _Symbol);
/ _4 C: X. |1 Z5 m) C: ?- L}3 ?+ c! x% q' p: o( L0 i# K. m- F
}
9 e+ |( U5 g0 @0 o q- _5 G//--- Check if we have a new candlestick...
( q( R% O5 j) J* ?7 D9 |bool tem_vela_nova(const MqlRates &rate). i) N. o& z( r P
{: ]) Y6 R* X, \3 H9 a& |" R
{
& i* k) ^( S6 X( d: v9 b: h% vret = true;
5 o3 F I N2 H( s0 g& p- gclose_positions = false;8 Z5 Z1 w5 y# h) T' p: G
}
5 i( N" A& i9 w) Q+ z3 A( x0 [) Velse. w7 s$ C" y- h% a/ g' C
{6 U H7 l' N2 P9 \" h
if(mdt.hour == 16)
/ c6 G/ { B3 M/ A8 X, l! Wclose_positions = (mdt.min >= 30);
1 N+ T0 p# f" p. }/ ]- _$ v" d9 G}
' k5 a! Q- W+ `$ c, ]}% Q8 P% a3 x$ U c8 R8 C
return ret;( V$ D- ?+ y8 w% P
}0 S( Y: a& Y9 z; [. O2 B2 H1 @
//---
1 w. |4 T8 t& Z8 X. gbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
. B2 `5 z N/ P{3 u0 @7 m- S5 h2 r+ `1 y$ J
if(PositionsTotal()) // Is there a position?
* C, t1 `% m$ \7 V6 W{3 l! [- ~ h; ]( E4 r
double offset[1] = { 0 };& x2 ^9 i* a5 S
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?. z; z- e2 a, I, Y6 {3 J
&& PositionSelect(_Symbol)) // Select the existing position!
1 Z0 U9 z6 @% t/ T# e7 G% X- }{
$ @5 A: u+ h$ V: L. G; { j% sENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
+ u( p" N4 z) K- h5 B- }double SL = PositionGetDouble(POSITION_SL);
* m$ H- B0 y4 q- |/ S4 w1 W6 fdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
( w" [7 X0 u' \9 q& E( r' ^if(tipo == POSITION_TYPE_BUY)% I% j; C/ r) f) p2 Z9 P
{* |( o; g f. L0 I/ b7 j* I& ^+ n. Z* C
if (cotacoes[1].high > cotacoes[0].high)
' `, h' ~% F2 [+ Q{
' B4 A; k F. V; h) ^double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
2 E: d2 P$ V- zinfo.NormalizePrice(sl);3 n9 n, Y$ G5 U
if (sl > SL)3 b0 g) M. S$ \5 R% R
{6 v+ P c+ W$ O, E" J+ W
negocios.PositionModify(_Symbol, sl, TP);
9 Z0 q/ ]# q4 |5 T}
% b4 ^& ~ v- M& ~' m" g& S- h( g}
+ a5 {* X. x6 |}% h( R" g" @- F# {4 B0 _# s1 R
else // tipo == POSITION_TYPE_SELL
; v; T! K, \6 Z{# [$ J" o1 O" A& e1 P7 L
if (cotacoes[1].low < cotacoes[0].low) B2 b/ F2 q+ [& w" ?) Q7 J3 Q
{; ]6 Z6 h! i4 w( H
return true;
3 M; B2 M5 y. x9 V9 m$ U4 B}
: U! U" |) F" q// there was no position
# R2 b7 h& R4 ]8 creturn false;3 z& {: h2 w4 E) \5 P+ ]1 f
}
. L% Y- y5 u' [% p, E- S* j我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。9 `2 j0 D8 [( e: T( R+ G+ P, j
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |