启动交易模型,并构建 EA2 q6 q" V/ J |9 ? x
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 n2 A! e' V6 ]7 t: k3 p# z& x为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。3 R5 x1 R/ s$ p! Q d' A @
以下是制定这些规则的代码。& F2 N) y" \2 X; ]. Y
//--- Indicator ATR(1) with EMA(8) used for the stop level.... Z9 M8 F( V/ i2 f0 P7 G3 D4 e* z
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
. `: F2 V1 N$ T* C& Sint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);! a( p ?8 F. K* O
//--- Define a variable that indicates that we have a deal...
, V$ u5 a5 z0 U/ I4 T, wbool tem_tick = false;
: m. P0 M% U3 `' Y) w//--- An auxiliary variable for opening a position8 H& f0 ^0 _0 ?5 F7 _0 {% s( A6 M# G
#include<Trade/Trade.mqh>
5 x, |8 m m- Z#include<Trade/SymbolInfo.mqh>) Q7 c+ e6 a% r4 q0 q
CTrade negocios;
- ]" Y }' n+ j: o( NCSymbolInfo info;
& L: P& q- ^; P# A3 S$ D3 L//--- Define in OnInit() the use of the timer every second
% X8 Q0 e" z% g; T* m; e# z//--- and start CTrade2 q e* t& @) W/ S/ p
int OnInit(), k5 J5 J" W' v! v
{
/ R+ F. y& S5 u0 z: c5 X5 h//--- Set the fill type to keep a pending order
- a- e) j+ }7 g; Y1 H, i8 D" d//--- until it is fully filled
4 v* |" q1 Z0 v# w0 x$ T1 Qnegocios.SetTypeFilling(ORDER_FILLING_RETURN);! }$ u. k' W8 Q* i# v, ~
//--- Leave the fixed deviation at it is not used on B3 exchange
; C' p, Z! t( Inegocios.SetDeviationInPoints(5);
3 T' l0 C6 u& q8 O* B% J//--- Define the symbol in CSymbolInfo...
% K0 {& s9 E+ G! E1 _3 sinfo.Name(_Symbol);3 W: `) i0 M6 [, }
//--- Set the timer...
# n0 l4 \! k( w. AEventSetTimer(1);( |! i$ g, b4 B% l2 E' ^
//--- Set the base of the random number to have equal tests..., @& q% M/ x- W& {
MathSrand(0xDEAD);
2 i2 X+ B0 J" T* G: E, }return(INIT_SUCCEEDED);% N0 F5 C F( |
}
# Y& w! z* ?% P3 F3 ?6 a: U* N# x//--- Since we set a timer, we need to destroy it in OnDeInit()./ p9 i! F/ D+ h8 v- d1 x( A
void OnDeinit(const int reason)
; A/ h e v9 _{
3 _: b) X& `6 b! m) qEventKillTimer();* H ]2 ^2 Y: K& y
}
& D+ b; Y$ \! m$ Y' h//--- The OnTick function only informs us that we have a new deal8 Z, X' i$ U# I4 O
void OnTick()
9 q" l u- D8 g4 s% K{! d1 v% U# ?, z* i# P# t
tem_tick = true; v/ q& V, }" Y W; a1 G
}' W; M# F Q+ N, |5 U. y6 t
//+------------------------------------------------------------------+( M( M' u/ _) b. z! \. G3 D
//| Expert Advisor main function |) D) W5 o0 U+ s7 p
//+------------------------------------------------------------------+
" }4 U* A$ `0 R; ^6 zvoid OnTimer()
" ?$ l. q' \3 ^% s9 @. ]{
5 z2 |& n" b+ ^ ~+ @, X# `5 AMqlRates cotacao[];6 r. k% _6 p. N& l
return ;' L& n& D+ {% F6 c s% z6 N
if (negocios_autorizados == false) // are we outside the trading window?, d5 `4 S6 c; O; @+ T. O
return ;6 r" Z% V7 T) Z% ~% u% E* W% s
//--- We are in the trading window, try to open a new position!
& m+ y2 I% r; B p' g5 fint sorteio = MathRand();
2 P# f! j0 m' r1 h% ?' z//--- Entry rule 1.1
8 L; X$ W. E% x3 Aif(sorteio == 0 || sorteio == 32767)
( i% W: @( y6 w: d$ e" {3 G/ H2 preturn ;
+ l8 ?0 F/ z; I% \! ]; y- Bif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy' m8 q5 y2 X0 \9 L) X3 r
{
* @+ E, H" j Y- Xnegocios.Buy(info.LotsMin(), _Symbol);8 `1 M# S" I% k
}6 n: M( m" i1 T4 C
else // Draw rule 1.3 -- odd number - Sell
/ e- _7 ?' a# i0 H& ^0 x{: R4 @$ H) x r0 F& E* K
negocios.Sell(info.LotsMin(), _Symbol);
3 L! `& h$ D+ l6 f5 O}
# v* k+ P. X5 ~ k* L2 C2 |' k}4 |; v; j# R5 n9 {; P( B) t' O
//--- Check if we have a new candlestick...7 H9 p `1 S) G0 a, d. S
bool tem_vela_nova(const MqlRates &rate)7 h8 D! j! q" M3 S8 }# C) w6 E
{
. }8 {5 J. S. V$ _2 S, F0 G- n{
$ t3 c/ G9 b2 G* K; B- m. Kret = true;. E7 g, _1 y4 |$ B* R9 O
close_positions = false;7 L D& ^& V' ?8 e
}5 U/ R4 g8 _$ G1 Z; ]
else
) l' I% i4 G0 i1 l% R: d! v{5 t0 `( j1 D+ v. M; z
if(mdt.hour == 16)
- F0 j/ j- _8 K) |close_positions = (mdt.min >= 30);/ u1 S K; L- N( g
}" A. Z, v+ H7 @9 t4 F
}
1 \. U6 ^5 h8 u V3 U4 K8 v+ sreturn ret;4 k2 \7 k, X/ N. t( @$ X$ R
}! L- F4 j/ [6 [! B
//---
% \" V) v5 `3 e! r/ hbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
' {, J7 F( _4 \/ x. m{
/ d+ [ M. @+ Pif(PositionsTotal()) // Is there a position?
3 g% t. v2 i ^6 Z5 B{6 D4 ?; `/ K& X6 ^
double offset[1] = { 0 };7 X+ L8 ] _# t6 P6 @; t/ y: V( ~
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?; ?9 Z3 q5 Y. U
&& PositionSelect(_Symbol)) // Select the existing position!1 l6 Q s9 Y3 e$ H
{' ~ `- t8 I8 {: `
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
+ p9 s. _$ E8 ]* E6 w( m6 Tdouble SL = PositionGetDouble(POSITION_SL);
1 Q4 {2 i# R& y- `* _9 H: edouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
- x2 a. ~- w0 G% t! Q }if(tipo == POSITION_TYPE_BUY)
$ j7 n& q0 G' g{
; v. O, D& V9 p" ~! C2 q( b% w+ Rif (cotacoes[1].high > cotacoes[0].high)
z6 o+ E1 D8 t& g{4 {" c5 P, s8 q: x1 d% G( K7 G
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];/ H" y4 H Q g$ a7 N( N; M; W
info.NormalizePrice(sl);% o) M1 r. ]7 U/ [ u
if (sl > SL), E9 M+ E- Z; ], s
{
+ @ n- S# i" I" Qnegocios.PositionModify(_Symbol, sl, TP);
! M) f# t4 F/ F. t0 i}) ?8 ^2 [7 a5 h- P7 E+ v5 B! d
}
; K- v& |+ t6 d6 E" |} b3 _ t; a' k3 n* o
else // tipo == POSITION_TYPE_SELL
. H% R6 S- T/ p: U2 Q" c/ n: H1 z{
; @: a- n G& k$ z. yif (cotacoes[1].low < cotacoes[0].low): A1 `0 T1 `5 V1 B" Q* R: R0 h
{
9 v! k9 ^1 `% ?% `- ?) w% hreturn true;
8 a) X3 f2 i5 J% I1 y0 [}/ A# ^ C4 |- ~$ F( d; X7 C6 x5 f
// there was no position- o% p& b# F4 _: P# U4 S
return false;
( a% Z( }& D1 `}
# ?2 g2 T# _4 |6 D5 k我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
& v7 P8 K7 w+ d5 ]1 i到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |