启动交易模型,并构建 EA
& L! K* N) G6 W在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
% J2 |. a9 m+ s8 {6 P! z为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
7 f) |# r. \4 v9 i" E% }以下是制定这些规则的代码。3 v3 ^) \% p; @; y- J% I: J5 x7 f$ T
//--- Indicator ATR(1) with EMA(8) used for the stop level...9 s: T* j$ K6 v4 M! ?" D: y
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);" Q! @; f. k' {
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
% K/ m6 W3 K8 \" Y) M+ g//--- Define a variable that indicates that we have a deal...
7 `$ j5 p8 r0 D. b+ wbool tem_tick = false;
1 G( t- ^3 k( u2 v! b5 { D! y//--- An auxiliary variable for opening a position
. j d# r [1 E" g; C0 v5 u#include<Trade/Trade.mqh>8 e6 ^* F( ]2 z
#include<Trade/SymbolInfo.mqh>+ a9 h+ m) ^/ Q1 e
CTrade negocios;
* a: ]) R$ R% F c9 aCSymbolInfo info;$ ?% ]: d# L- i& C! {6 m
//--- Define in OnInit() the use of the timer every second
% K5 A; e) N% s' g//--- and start CTrade
' Q- T4 I$ ]" c9 k4 aint OnInit(): ~: Q- E, ?" M8 _# p9 G' G
{( m; T% Z* A* u& T6 c2 B: y
//--- Set the fill type to keep a pending order
2 A4 y+ Z% R' x* p( J! \, G2 H0 k//--- until it is fully filled5 ?, I! q' r6 c
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
& ^/ R7 q4 d2 X$ Z! e+ N+ F//--- Leave the fixed deviation at it is not used on B3 exchange* `0 W* P- {! }
negocios.SetDeviationInPoints(5);
" P7 }' G* S6 ]* v5 f( Q, t& c//--- Define the symbol in CSymbolInfo...
9 l9 I9 d& E. p$ H- ninfo.Name(_Symbol);7 h0 Q1 z! [; @" a% m
//--- Set the timer...& V+ L9 S& }& Y- u' k
EventSetTimer(1);
3 P2 I9 a5 ~, c2 {) A4 e//--- Set the base of the random number to have equal tests...
& J" x0 R8 s; I7 w, m' |) J1 _MathSrand(0xDEAD);
) G5 y7 `0 e! T2 J) ^0 Nreturn(INIT_SUCCEEDED);9 E/ |8 k/ A( g& Z( C7 B
}
. o, g5 n. J- o' l$ Y" E/ b//--- Since we set a timer, we need to destroy it in OnDeInit()./ I% \9 O4 }. j' r9 L
void OnDeinit(const int reason)5 \* O. k% r- X% u
{
5 X( q: m6 a2 SEventKillTimer();) E. ~1 L. g5 B3 C
}
% K& P" A; C y# S$ m//--- The OnTick function only informs us that we have a new deal
: K; P U) k; n2 ]& Svoid OnTick()
1 b$ _6 A. h' v( [{, D( p6 ~5 q* e! M3 d \+ m# \: P. N/ s
tem_tick = true;' x- A- s6 `0 J
} y7 O7 H- a( ]1 b# y
//+------------------------------------------------------------------+
5 U% g* b/ l' u! d4 Y//| Expert Advisor main function |& [0 |1 L# a. R" { a5 q0 I
//+------------------------------------------------------------------+
( X) o4 f8 n7 M1 `8 C0 t) @7 Cvoid OnTimer()) [/ ]& |( b" \' l' ~7 a' i# c
{
g' s1 i( y* E' b+ S* X* pMqlRates cotacao[];
" V( I2 u5 S, s+ B; R7 xreturn ;# F, a6 l6 Q" y7 j; E! \
if (negocios_autorizados == false) // are we outside the trading window?0 @8 c7 R3 T- i; T
return ;
' I; u- o8 O3 C( [) |0 ]//--- We are in the trading window, try to open a new position!
# @, `9 H9 N. K; T& `) Wint sorteio = MathRand();6 f: D, J3 m6 D( u: B
//--- Entry rule 1.18 f+ f- x1 Y. J# A
if(sorteio == 0 || sorteio == 32767)
# |5 r, b$ q! F1 Vreturn ;4 d8 _6 r8 r" d! w& V& X) [6 C; v
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy' Z0 d. U+ f3 }; O+ E# R ?3 I
{2 }/ Y- F3 K2 j; t H& M
negocios.Buy(info.LotsMin(), _Symbol);
0 Z2 ]% t a% m* V3 I f}7 a( Q, b- z, P+ S
else // Draw rule 1.3 -- odd number - Sell
) v/ o/ j& i5 G& [{
0 w" h! y# j. ?negocios.Sell(info.LotsMin(), _Symbol);. C, k: d' j6 v+ L) c
}
( y+ L' x; V1 I; a& m. ~7 c}
: U3 k! v& S+ \3 J, |//--- Check if we have a new candlestick...
1 N& u }/ k' Q7 n, s0 g$ X+ d' fbool tem_vela_nova(const MqlRates &rate)
" P+ Z/ n# P8 Z{
! I1 e$ F) x* o& f7 U{
8 p4 [, q# T$ ~ e8 v& X2 Tret = true;: Y* D/ E _( l5 K5 o8 n
close_positions = false;, X% S2 j$ `: J: o: N8 s6 \
}, A" q' I+ [9 E+ L
else
% {' b0 B8 ]) X6 e1 Z6 J{
+ m$ b8 c, q! S/ Nif(mdt.hour == 16)
- p! N: \8 B# ^3 }close_positions = (mdt.min >= 30);
" x3 }4 Z( i5 Q/ |- }}2 X6 n1 E! d# j. N) N l
}
: V8 R# t0 c' X* M* r6 qreturn ret;
5 }! X! I2 y- g3 L+ H" n, t( l2 J* n}
" R. n5 {1 w! X8 p( K$ T/ I- D//---7 H1 }/ _- S( [: J& E" h9 Z
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])+ x/ {* d0 P( E, C2 K
{
: A1 h3 J o2 Eif(PositionsTotal()) // Is there a position?
% G; z; T" e x- R" M{/ r! f9 x/ ]8 C0 X- E4 g# u) S! t H
double offset[1] = { 0 };
* S( n; z# M& rif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" J. j. w5 c0 f8 U* k&& PositionSelect(_Symbol)) // Select the existing position!
2 ~% z* e2 p% c0 [3 u: p0 t{
1 O: ?# D- l7 r) J. k5 ]. BENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);0 J; L3 a4 M+ u
double SL = PositionGetDouble(POSITION_SL);
/ i, A+ m% m3 C0 P0 Jdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
1 J7 v6 A& b S+ xif(tipo == POSITION_TYPE_BUY)( l' y6 A+ n5 k8 d
{; ~; h7 S/ Z4 L# O: r d. H
if (cotacoes[1].high > cotacoes[0].high)
6 o: u7 g9 j6 A* U% c{
) F2 Z. D* N& g. Adouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];2 Y! |" ]+ S5 q$ t% f2 ] ?
info.NormalizePrice(sl);
$ G# ^/ }3 c7 H! z# nif (sl > SL)
/ u$ ^7 J4 D! s7 u. U$ g5 G9 l{# J" q% h( }6 V) d7 g0 O4 O
negocios.PositionModify(_Symbol, sl, TP);; {" ]6 ?' Q* B8 Z4 Y/ p: \
}
5 o, c/ Y! j5 ^$ e. z( G}4 _4 |7 e4 o7 k( r
}
' X# r d8 f+ @4 n8 q+ }else // tipo == POSITION_TYPE_SELL
3 U6 ^8 l# x1 Y S{' q1 A" w- i; R
if (cotacoes[1].low < cotacoes[0].low)% Y7 T! l( G* g% o1 L" q
{
# s/ X* C! c- J! m' R5 {9 vreturn true;
& s$ C3 B, H0 E/ g. }}+ h( Y w' \6 _7 ?3 S& _4 a: D9 O9 u
// there was no position
" y! F5 u- u# o, ]/ ^return false;; y; O, o% U' ]: j" B
}
?2 x& @0 H2 e, k8 b我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。/ N' U' K7 I8 y* b! e8 U
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |