启动交易模型,并构建 EA
6 d! T4 T# p, O& P在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。5 E; M( o+ }5 j2 F) O: a2 I. s
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。4 G. x+ J; S; T0 Z& W* D! R
以下是制定这些规则的代码。* [1 v0 _: m3 Z7 E* H
//--- Indicator ATR(1) with EMA(8) used for the stop level...
- x; x+ U/ ]' u8 Q4 @$ r, zint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
; C+ `! _" i, O" ? p' d9 wint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);4 a* P2 C# i6 ~
//--- Define a variable that indicates that we have a deal...5 b1 I0 y7 W3 X" K
bool tem_tick = false;5 J t4 E# z2 l& p2 F1 u. z L
//--- An auxiliary variable for opening a position
+ b" L% f6 N& W& T#include<Trade/Trade.mqh>) n# T. R7 Z/ o! ]. |8 c2 ]
#include<Trade/SymbolInfo.mqh>
; L* o- d/ g4 {2 @# y7 g+ aCTrade negocios;2 u9 Z7 X. w1 q. H- Z, }
CSymbolInfo info;
7 N( \ O4 j6 Q6 U2 }7 o//--- Define in OnInit() the use of the timer every second/ B2 M( t& f7 z5 k6 A* U
//--- and start CTrade1 S; s6 K3 v1 i
int OnInit()8 Q0 x- ?6 e$ x O
{! U6 T/ A' } F
//--- Set the fill type to keep a pending order! ]- q* Y& r7 _5 S7 |
//--- until it is fully filled
! [6 R) o0 X3 i# Y6 Inegocios.SetTypeFilling(ORDER_FILLING_RETURN);' [" m7 n7 e p/ e$ W& m2 S
//--- Leave the fixed deviation at it is not used on B3 exchange
; }: k- m2 ?2 Z* xnegocios.SetDeviationInPoints(5);3 \! J. H, W' s- I! M
//--- Define the symbol in CSymbolInfo...
' T+ }% q7 Q1 dinfo.Name(_Symbol);
8 t! h( S+ w/ k) v- z4 c- F `; X$ V//--- Set the timer...3 D( D7 I! T! t3 V; A" V
EventSetTimer(1);
5 O$ q, t( m( [( q//--- Set the base of the random number to have equal tests...
& ^& k. g6 _1 S$ }6 J' T7 bMathSrand(0xDEAD);
& ]: c1 J# N$ |& F! ?8 {# xreturn(INIT_SUCCEEDED);' B6 ?& l7 S. c' @5 q) t* X! q
}7 W) {7 w$ I" T7 S* A0 R
//--- Since we set a timer, we need to destroy it in OnDeInit().
) k( P4 B. r# A) w: Xvoid OnDeinit(const int reason)1 o* b; B" ?* W+ G; {
{5 ?. V5 n/ V: U T
EventKillTimer();8 O) a. V! _! v- p/ L- p9 X. `0 q
}
/ B% J4 C0 |& A5 k8 n' g//--- The OnTick function only informs us that we have a new deal
: }9 f: x9 C3 G; l: vvoid OnTick()3 h- G E4 o" n3 m) M( r
{
/ B9 u7 |) k# Jtem_tick = true;
3 j+ |: X4 ?$ s( Y1 T1 r}
U$ B) |* C. l8 d t- e. `! d//+------------------------------------------------------------------+' Q9 K" h1 }7 H4 Z2 K8 g
//| Expert Advisor main function |9 c* K4 ]& d" ^7 d2 |
//+------------------------------------------------------------------+
( n0 I+ y( ?" L) v xvoid OnTimer()* t; \, b$ C# H. Q* z* D2 n
{( T, b3 [( b& @& L
MqlRates cotacao[];; \! l O1 l2 F" J5 W( U% r
return ; j+ Z7 }4 h, R1 ?
if (negocios_autorizados == false) // are we outside the trading window?
# P2 K: Z$ S7 S( ~# oreturn ;
0 V: l5 f0 g1 q& `6 P//--- We are in the trading window, try to open a new position!
% |. z- b0 Y1 J }/ e0 Nint sorteio = MathRand();7 d; Z1 Y* i5 q, P+ ~" A
//--- Entry rule 1.10 O& |: s7 w( Q3 j; h
if(sorteio == 0 || sorteio == 32767)) F& A% X1 e3 _" F" I
return ;
3 F( E" w" G: b; @$ W+ X4 Rif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy4 X, v3 T p6 ~8 v! u6 ?: Z
{- x# `: I( V3 \& ^
negocios.Buy(info.LotsMin(), _Symbol);) y) k9 i! q. e3 t
}- L+ ~% l2 |7 Z6 ^: q
else // Draw rule 1.3 -- odd number - Sell
6 V. c" C; q a: p4 t{
, T, W4 w+ `* Snegocios.Sell(info.LotsMin(), _Symbol);. j& b; H' T; B4 V
}: J& c0 p5 E8 Q9 s
}
8 S p$ V2 b. J& I( H4 ?//--- Check if we have a new candlestick...
( n( e. X. k; z! Wbool tem_vela_nova(const MqlRates &rate)
t$ b1 T, g" u" w9 Y7 P8 n3 u% `{
5 o' }6 ~. j7 e% F9 u- L{0 W9 ~* {& {2 M; g
ret = true;
$ W9 t F0 U$ o0 c8 e8 i, o! nclose_positions = false;1 M/ ^8 ~: \6 y: x# J# C* u
}" Q& H& @4 [; a& C8 M; _
else
9 X& M* }9 ?$ H0 _ C; w{- D: ?5 F- a! Y9 G. o
if(mdt.hour == 16)( y) d6 U% I5 J. a$ X
close_positions = (mdt.min >= 30);
* l7 l6 u; l1 _}
1 ^4 D5 e1 k4 r% [* ~}* }" r5 V8 r) z6 L$ p; h# l
return ret;
! K5 u* \3 X# |}6 C4 I6 J' @$ R, o3 }
//---+ i( k2 q3 h* T7 M L
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[]): S1 T- Y( `* X( q/ q3 C
{. Y0 P6 b9 R/ \$ _! V$ ^
if(PositionsTotal()) // Is there a position?$ r/ W7 n6 p: E. e- g/ r& l4 t3 }
{
2 k1 J) q6 Y2 w! O+ w3 }double offset[1] = { 0 };7 i( M m; N1 y
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?/ h/ H: ~5 x! G x% A; ^
&& PositionSelect(_Symbol)) // Select the existing position!5 A, ]$ n$ W% D, U
{9 \1 N/ R+ C" x' M' |' u9 c
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
8 n( N% ^* @/ x" p8 P1 R2 _! [double SL = PositionGetDouble(POSITION_SL);
2 s( r7 d9 `. g! |6 {. I+ r% mdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
+ z% a/ M4 I3 E: r( d( \& Zif(tipo == POSITION_TYPE_BUY)
6 {( W4 _: ?9 p$ E{4 r) v" e( r/ S m8 L
if (cotacoes[1].high > cotacoes[0].high): Z% L+ q6 Z3 \! f( Q% L+ d5 f
{1 b/ J; q p8 m/ N$ l
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 S( L, L$ Z0 z, @* G9 c! e
info.NormalizePrice(sl);- N% d$ a, A$ H
if (sl > SL)
, f0 G- X+ s1 M0 _% d% s{7 J' S( E8 `6 l1 u" F8 t" b; h) s5 o! e
negocios.PositionModify(_Symbol, sl, TP);( d! b4 T- M7 C' y! t/ {2 j
}
% L9 e% {1 f' ^/ J, s; U}
( C( J' L8 [" F+ E7 P. ^3 ~}
' G: y/ }! P- B$ j; q! k: Xelse // tipo == POSITION_TYPE_SELL
- L# Y! C- I; w: s {{
! ?0 g6 H$ H E# w( }1 y% Pif (cotacoes[1].low < cotacoes[0].low)
2 H5 n+ K3 T5 I2 v+ a{
' Y$ X' g2 n( ^8 i; W5 e/ R* [- Ereturn true;" {7 O) ]* h5 J( E
}7 [: K6 ]$ X7 z+ Q
// there was no position9 l1 a1 _2 l U
return false;, |; U' s9 z w6 N; \) o8 g
}2 a0 b% x* c6 `/ s$ y8 m5 l
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。3 r$ N- y! G: ~8 s' u8 j$ Z
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |