启动交易模型,并构建 EA8 J9 Q$ v, ] l" F) }
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。2 O- x; F% _! z1 S8 Z1 B* K9 E, S7 B
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
3 n+ E# j2 s# T/ U/ e& @+ k以下是制定这些规则的代码。$ Q4 y% F4 H1 O- o% D- L$ q
//--- Indicator ATR(1) with EMA(8) used for the stop level...3 K: i* {+ M; I- Q1 r0 g7 {
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);( T) `' p7 W5 k1 s' h
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);) \/ @( ]# g9 C# h
//--- Define a variable that indicates that we have a deal...
1 V4 I6 y/ B: |2 E6 Y. _bool tem_tick = false;! z. U. E% t& [# f+ B' j4 ]1 L) r
//--- An auxiliary variable for opening a position2 B9 O' t$ v( T+ t4 y# y3 m* a/ i
#include<Trade/Trade.mqh>
6 h0 ?% R6 X& R) P) N) y2 \# I. `#include<Trade/SymbolInfo.mqh>
$ N7 c4 x. l4 ZCTrade negocios;. z' f" s/ O6 |2 U: F+ I2 _
CSymbolInfo info;4 _+ F T. r7 a& Z
//--- Define in OnInit() the use of the timer every second" n. N: ]5 M! h% l& @( Q% D
//--- and start CTrade
+ r2 D# ? g6 R7 U+ {2 w1 e2 Vint OnInit()
' e' }- u5 b. b5 t3 v: z6 I0 {! I1 w{" \; [+ V/ o) R' r, d, G# C9 ?
//--- Set the fill type to keep a pending order
3 z" Y( |/ _% M8 H0 o//--- until it is fully filled) q0 x2 s5 ]' V3 g; J8 l9 L
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
& {' P4 e, D' g2 C//--- Leave the fixed deviation at it is not used on B3 exchange" e G- c* \) p4 L4 q. U
negocios.SetDeviationInPoints(5);( D! p( z+ Z7 S, f6 F9 f
//--- Define the symbol in CSymbolInfo...; s. C& S: S% d5 ~
info.Name(_Symbol);
# d# Q5 y1 R$ Z, j e( V4 B; G& c: o//--- Set the timer...
, H0 [8 e6 G2 n% |; Z+ iEventSetTimer(1);& i7 ^* h0 e9 ^) h
//--- Set the base of the random number to have equal tests...
% ~3 u4 q9 i9 u4 ~4 r9 |1 \" ^2 a4 AMathSrand(0xDEAD);( P% O4 y7 r' l/ o! B+ g2 ?
return(INIT_SUCCEEDED);
+ E- w6 a' D/ [9 N9 U7 N}5 a$ ?% s; }& l; a
//--- Since we set a timer, we need to destroy it in OnDeInit(). {" a4 B0 p/ w* B
void OnDeinit(const int reason)
; i, Z) E& e$ i: G C t( i I{
+ e. p2 E3 ~; k' p" p3 b0 W! T- MEventKillTimer();
7 ]) ~4 }- W! ~}
* L' m0 h8 _0 V4 L! F" |//--- The OnTick function only informs us that we have a new deal
/ e; M) K! \2 L" R% r& R3 J9 s" l8 Rvoid OnTick()' q* i3 ~ S& S0 H2 r
{
# |2 |$ C' E6 Ntem_tick = true;/ k$ E, m$ b4 w5 f# z
}& \' L0 g# d% f# A
//+------------------------------------------------------------------+$ h% V1 p s3 i: ]3 M% `
//| Expert Advisor main function |
7 P& F, s0 c. P+ G8 F! W( k//+------------------------------------------------------------------+9 V$ ? p0 ?* a+ u) c- @& F8 b1 I
void OnTimer()
$ Z0 k3 u& E" m/ \{
0 Z5 R) T; h. F3 ]4 g9 r( h- l. BMqlRates cotacao[];0 t1 L2 m' V: G6 ^$ R4 q/ Y( _1 {
return ;
7 S* X% t, L" t$ g+ h; wif (negocios_autorizados == false) // are we outside the trading window?; X# z. n! S9 L: O D; T0 K( d4 o
return ;/ ?, U- j X1 S; Q; B& N0 c
//--- We are in the trading window, try to open a new position!6 d! O1 X e+ h) V
int sorteio = MathRand();
0 Z8 K8 a5 }9 E2 T" ]; y( e, g//--- Entry rule 1.10 H* R7 J& Q+ Z3 b
if(sorteio == 0 || sorteio == 32767)
5 ~% F% X2 s- z2 yreturn ;7 t# t# I' I5 _% c* ?' }
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
9 _7 J! ]0 B6 v; o& j: D# ?{
- F9 k5 p: R. X0 y2 F8 qnegocios.Buy(info.LotsMin(), _Symbol);( ]# v- H' y+ T8 b8 ?9 B. @7 K
}7 Z& l4 d% {) R
else // Draw rule 1.3 -- odd number - Sell
5 I9 ]3 C/ }- G3 y{
! H8 w$ z4 w9 }" Nnegocios.Sell(info.LotsMin(), _Symbol);
+ j* B* ~2 g& C3 X3 A9 N}1 S4 @3 ~7 T: M
}
2 j6 ?4 i3 i4 [! H9 }//--- Check if we have a new candlestick...1 R8 ^, ~3 p/ S X5 a
bool tem_vela_nova(const MqlRates &rate)) `+ x, [- N W/ |* W" x& ?1 d
{# h: g2 r" {6 j6 H
{
! W0 g; W6 M0 u7 \' Tret = true;+ m; B: V: K4 K
close_positions = false;
2 k- O& u$ K8 S! `. Y/ t5 {+ `}! k: M$ k0 T7 u- H; j0 R9 n
else, L- i" G q4 n i1 z$ r
{
, ?) |; J3 c, F* U# D* p; F3 Sif(mdt.hour == 16)
& w( a* H& r% K9 U, h) {' B! B5 Lclose_positions = (mdt.min >= 30);
9 e+ e" I K% N1 X' c2 C, q}" [$ c, a+ j& t9 D6 q* ~# K
}
% F6 a5 ^5 J5 }" y% areturn ret;
: |: i+ J2 D# z( ]/ B+ e}7 E& [- i( [( q# U3 j' {
//---; ]- ^! O8 r0 ^/ h. \+ n2 R
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 T6 C& k/ m% \. V: [
{* s* L# V- ? \, u" g& k
if(PositionsTotal()) // Is there a position?) w& W$ [4 ^7 f
{
: Q( s0 [3 O% o0 A, [* N0 cdouble offset[1] = { 0 };
7 }0 a* ~1 q: \- c- E5 ]7 Z! H, Bif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
0 }- H" c& T3 W- Z; `( a&& PositionSelect(_Symbol)) // Select the existing position!
& h2 L( s. [1 l! N0 g/ _3 N{
2 w9 G4 W8 D( h D& b wENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);0 x/ Z: Y9 u8 ~ o
double SL = PositionGetDouble(POSITION_SL);0 y+ I1 L- o7 `. K, }' J
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));8 y/ {, E7 ^. o. I6 K
if(tipo == POSITION_TYPE_BUY)
; t8 g5 d: A; B3 H; `/ }8 U# Q: g{
. y3 M! M. ], c p: aif (cotacoes[1].high > cotacoes[0].high)
$ v; Y% ^/ {3 I" r{
) _: V4 m, n( u% y+ w, edouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
3 P5 F" c2 |0 s) G$ y" w6 z2 I! hinfo.NormalizePrice(sl);4 }% Y: y5 Q7 z3 G1 U7 D
if (sl > SL)
) v; r" R# ]: p9 Y( \{
1 q; P5 {. `) xnegocios.PositionModify(_Symbol, sl, TP);6 E& }0 b6 d9 O- a
}6 }0 V [( h' b1 ^4 z: X M+ C+ Z, k
}8 R% n; N: R" [" V. Z ]" |
}: l2 R& C! T, e2 u( @: i' U. q
else // tipo == POSITION_TYPE_SELL
" d% Q$ q& {+ R1 n4 O{
' c6 ^/ N) Y0 ]% bif (cotacoes[1].low < cotacoes[0].low)
5 w; U9 F: m7 g; n, b{& c0 z0 M2 D) H, j. l( w* D
return true;0 `2 x" c3 E4 a9 f
}. H! y0 P* \) X3 `' E
// there was no position1 q' a+ c, c7 p5 T3 c: T# ^
return false;: m/ S$ @/ q* v2 i7 p
}1 o% c$ f5 U$ X# C/ v' {3 V1 I" q
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
- ^4 } |9 n. B1 g2 g% O r到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |