启动交易模型,并构建 EA6 k4 D4 M2 y/ ]0 A
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。1 v! `# w- a6 Y8 R. {+ L
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。1 i3 s2 a6 U' p7 O2 ?
以下是制定这些规则的代码。
5 I$ u8 U( v) d* \+ J' |* \8 M//--- Indicator ATR(1) with EMA(8) used for the stop level...
1 I4 Z- W# }' J' Y( Y7 v. ^int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
) U: Y5 A6 G0 I8 J5 Pint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);! S5 Z4 P% w, ~4 U$ u& S$ p
//--- Define a variable that indicates that we have a deal..., ~$ _% j- M( |/ g0 M# @
bool tem_tick = false;
3 C* H( k" s4 j( X, D: Q$ |3 h//--- An auxiliary variable for opening a position
; O- S2 R" g- `, g0 W#include<Trade/Trade.mqh>* c* W4 m+ E1 K& Z! J
#include<Trade/SymbolInfo.mqh>
' b! _. G4 u/ i, G6 |7 v6 KCTrade negocios;0 s& u1 u# m$ w: _
CSymbolInfo info;: y* | T$ c" Q
//--- Define in OnInit() the use of the timer every second" }$ X$ \3 L, V; g3 u
//--- and start CTrade
$ k2 I R9 ]; g8 _4 _; a# nint OnInit()
, _8 L. b! o+ q# u3 a4 H1 v& J{
5 t0 B3 ? r, p r+ \//--- Set the fill type to keep a pending order
$ q; |, l* b& @6 c c5 a//--- until it is fully filled
4 f' J9 J7 h, O/ A/ l- Lnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
! p9 j$ f3 x$ V# p//--- Leave the fixed deviation at it is not used on B3 exchange
; g* f" w6 E4 {+ ^( i5 Znegocios.SetDeviationInPoints(5);6 u5 e8 j. k) r& [( N3 l
//--- Define the symbol in CSymbolInfo...& p$ ?& b$ | F) W8 I+ h0 D& Q
info.Name(_Symbol);
) |" e; p' Q; Z+ H3 {: u. n//--- Set the timer.... G" |2 M/ g! `1 L9 V+ C2 z
EventSetTimer(1);
9 E. }* G; O& p# g//--- Set the base of the random number to have equal tests...
Z( J% q2 i+ P @6 O$ y& Y- aMathSrand(0xDEAD);/ N0 A- [* J' A e+ M+ y+ E* T5 N
return(INIT_SUCCEEDED);
2 ]' J* t' ~/ B9 ^! O}
( R4 C4 [: |- W) x2 x//--- Since we set a timer, we need to destroy it in OnDeInit().
/ T3 D0 |$ o( C* Q9 g0 i" q$ `void OnDeinit(const int reason)
$ d8 v+ `, Y% x1 n0 y; J{" B5 V i3 _7 x4 Z
EventKillTimer();
9 X' y# H6 x5 c}
7 u, F, X: w& P+ ?//--- The OnTick function only informs us that we have a new deal& R; @+ Z/ o3 r, ~) Z4 J! ]( Y- g
void OnTick()0 b8 R' i. z4 |
{' Z* v6 W7 L, g! U
tem_tick = true;
7 ^& Z; S0 a+ j! l* z! G' \8 }' ?}
" }+ y4 m# t5 [) n& ^ T//+------------------------------------------------------------------+6 q. `9 y/ v! w
//| Expert Advisor main function |
5 j5 C& X7 x4 z9 I+ o9 z//+------------------------------------------------------------------+! y7 p6 H0 @2 f+ q. k
void OnTimer(). {) k' V' _2 K; I4 h
{
6 v+ u: P8 R. d# o7 w0 F# }MqlRates cotacao[];5 M' G& F q1 C: Y; [4 N
return ;/ B) w, v' }' F. D8 {
if (negocios_autorizados == false) // are we outside the trading window?
$ y; T$ T: y2 N" t+ p( Yreturn ;5 c6 d* Z7 C# H! e$ S: q8 n
//--- We are in the trading window, try to open a new position!9 X; e( Q* b1 m% R# Q! X+ m4 W
int sorteio = MathRand();8 @% p0 f8 \$ I( \
//--- Entry rule 1.1
2 L& {3 _, Z: Tif(sorteio == 0 || sorteio == 32767)9 h$ X2 p4 v: G. |) O% T- n; t
return ;
. a. \" ^' J: u8 b* R( y" Mif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy0 i% s h( r. @- V& M+ z
{) S9 f' S( W1 b( N5 Y* F# K2 U
negocios.Buy(info.LotsMin(), _Symbol);0 i7 X, |: b$ Q" c
}- A6 Z* \; d8 M' q p
else // Draw rule 1.3 -- odd number - Sell4 s+ g) i3 w E7 d
{
) |; X, F \2 ?! Cnegocios.Sell(info.LotsMin(), _Symbol);, n# x7 r" r4 F
}: `0 f9 b! m) _7 E. K' v" j- s
}
6 \" i# {9 M( N, s//--- Check if we have a new candlestick..., V* j4 b3 k& w& |; u
bool tem_vela_nova(const MqlRates &rate)8 G; t* L8 Z9 R ]
{9 @: }' I" O4 J! m
{
0 f! k% F' z% Wret = true;: N; u3 {9 ?1 k5 s9 C
close_positions = false;
4 D2 H$ T- ]. s G}) l3 _# G4 u, R1 o
else4 x7 X$ `1 b+ n, I
{% R+ B; s" J+ X$ d
if(mdt.hour == 16)& h3 X* M8 _, s& R/ a# D# p
close_positions = (mdt.min >= 30);' L2 x: x+ ?& p" S- [! y* G1 L& P
}) @) H' W& T' K1 W9 U
}$ j0 A- P; v- W/ k' R
return ret;' Z$ N& T6 Y& M7 J9 b
}
$ _' ?% v% u. n# q//---+ u2 Z4 |1 c- C
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[]): N- j$ ~% K4 ]+ q! |! V' t
{
# x' Y( h' u, y J4 g* ]! `if(PositionsTotal()) // Is there a position?
; Y6 O+ G7 Q1 S{9 n( k& T" [. P2 [5 ~$ t# [
double offset[1] = { 0 };) }! S: E: e9 y0 `. Q6 v2 `
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?. a0 M$ l* A; W: T
&& PositionSelect(_Symbol)) // Select the existing position!
1 c0 ^9 j' B* F{
* j n5 d1 Z- [3 b3 u: ?ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);- ~# E4 U; o) T2 U# q: Z
double SL = PositionGetDouble(POSITION_SL);! L- n3 O- u/ U9 g
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));- r v# v' B+ N; w$ i# p
if(tipo == POSITION_TYPE_BUY)0 K; j* Z+ P0 d9 H
{ ?- a7 J+ {2 n1 ?% i
if (cotacoes[1].high > cotacoes[0].high)
T" g* h. |+ \# r{+ \8 R9 X5 m9 O7 F1 L0 h
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
6 {, O A. ]1 S0 m2 k5 q. P+ _6 xinfo.NormalizePrice(sl);
+ E3 |+ m- r3 {. R) B0 wif (sl > SL)
) u( ~% m6 h8 X$ O3 U& A{
$ t( d; U5 Z6 ^+ ~, V: a( [! H$ gnegocios.PositionModify(_Symbol, sl, TP);& Z& g0 }! h" t% ~5 e! }
}- ^9 D6 w* Q; F3 {% z
}
5 _& C! g; O* w% V+ F! S' |% U}% z) ^ V, ?, l: n Q5 o/ ?
else // tipo == POSITION_TYPE_SELL
6 ]; V0 F! B& c) ]{3 ^3 R3 I/ i5 c, |
if (cotacoes[1].low < cotacoes[0].low)8 A8 h) A5 L$ t7 e- z& w
{$ [' Z* w4 `7 S* o. J
return true;+ s7 I# w7 e+ I5 b; c
}
. W& F: D" ~7 }: X+ N% Z& a// there was no position" L% \# n1 }. R8 m/ k/ Z7 d' ^% b# {; z( v
return false;
$ i' i8 c, e0 n: u0 ]$ \+ ?# u}
* y: p* C! E: V* N% }1 n我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。1 ]2 o' ~6 }* X% H
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |