启动交易模型,并构建 EA/ |2 [8 S# o, V! y. B' H4 h
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
* Y/ P, O* j7 {: L6 H为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
1 L' r! l$ Q8 v* ]5 ^. ^# Z以下是制定这些规则的代码。- i, D$ u+ u" c4 Y; o( J
//--- Indicator ATR(1) with EMA(8) used for the stop level...0 R @$ p* b o
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
# b+ g* `. @. M' }1 B P: xint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
9 g/ Y8 E+ U6 r: r! u& |+ s//--- Define a variable that indicates that we have a deal...+ }# _0 S# p/ W4 a% f; ?" z2 Q
bool tem_tick = false;
1 v6 O4 K4 S, X//--- An auxiliary variable for opening a position1 k) q$ g7 h9 i- P
#include<Trade/Trade.mqh>. |- w' _* g8 j
#include<Trade/SymbolInfo.mqh>" l$ l9 b/ E% C
CTrade negocios;
! E# l& d% u% I7 z- ]/ pCSymbolInfo info;
! v5 O+ z" s0 B0 n2 H& n7 T//--- Define in OnInit() the use of the timer every second D. [' _7 d+ O) T
//--- and start CTrade1 H6 F4 c" a% O+ y6 o% N
int OnInit()
' a- t2 _) R$ U" ]; [{
7 _% T# X' \4 `! a6 C7 a//--- Set the fill type to keep a pending order3 g; b5 e7 G' m. S" x
//--- until it is fully filled
z S1 F6 p1 K1 q" Tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
/ q5 e C0 |- W7 m//--- Leave the fixed deviation at it is not used on B3 exchange; p& X* X8 y W* U# q# F
negocios.SetDeviationInPoints(5);
; C! i/ q2 p- w U6 Z! \//--- Define the symbol in CSymbolInfo...5 i% c9 N/ r4 C v
info.Name(_Symbol);3 Q# U1 C- t* k ]
//--- Set the timer...
" i( [- T( z4 h- I% }. j# a V. N; REventSetTimer(1);2 f6 e }% o: P4 ?* a' `
//--- Set the base of the random number to have equal tests...
4 o6 m# }9 b/ K ZMathSrand(0xDEAD);
. ?- A$ D3 m+ f% s7 C, @3 ]) ^1 dreturn(INIT_SUCCEEDED);
0 S9 l" `% ~" e+ ] L+ J}" E& v5 j& V+ T# {2 J$ u9 H
//--- Since we set a timer, we need to destroy it in OnDeInit().
1 ]3 r' N! k; R4 X- t) H- Lvoid OnDeinit(const int reason). P/ I4 R1 a8 p# `
{' G7 }; Y k" X8 n
EventKillTimer();
2 n2 \. V, O/ ^}
1 D D- w6 x: u3 r+ s0 a( `& i//--- The OnTick function only informs us that we have a new deal
3 t+ |* r/ I( w& J6 [- r5 n3 bvoid OnTick(); y1 n1 Q# k0 u ~. C* ~
{
6 o+ W7 G: o8 p* ~' Y# e u; ktem_tick = true;1 P. l! T! }4 Q5 A
}. Q* R$ V; f2 s; i, S
//+------------------------------------------------------------------+$ e8 @0 i6 H; A% [" e
//| Expert Advisor main function |
9 `6 z, V6 B* q: X$ U" h//+------------------------------------------------------------------+8 `0 l5 P+ S/ @/ U! \$ A9 v4 ?1 Q
void OnTimer()
: P/ C8 @; |- x3 D) H* }. C+ {' x{ a0 Z) m$ Q( K7 I, \
MqlRates cotacao[];5 Z8 E9 E+ R9 O) Z/ {
return ;8 u# e. Y0 S) o$ E8 c& g$ Q
if (negocios_autorizados == false) // are we outside the trading window?
1 ?3 X. P# L/ Z, M+ b" R/ E5 \return ;$ c1 z- X' e5 x0 k) {
//--- We are in the trading window, try to open a new position!5 k8 D* }2 @* A
int sorteio = MathRand();
( A& z p+ x7 H& P# [: _//--- Entry rule 1.1
" C% m# f8 t7 }: v* l) U Sif(sorteio == 0 || sorteio == 32767)
0 p( E) Q2 y3 ?return ;; ^% e# u5 t6 P% ~3 S
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
5 e8 T% C9 \# \) R4 g# X, m7 [{
( X1 o# R# Z, S# `negocios.Buy(info.LotsMin(), _Symbol);% `% P$ A! H9 i# S8 g
}8 K8 O# r/ ~ {, ]+ w
else // Draw rule 1.3 -- odd number - Sell+ w: b' d; G1 d7 w
{
, `; u) Y s$ h5 Nnegocios.Sell(info.LotsMin(), _Symbol);1 S6 l1 z% ?8 D2 j
}' R: `8 ^- E" G# S# ?
}' Q/ }# O' ^6 `3 z
//--- Check if we have a new candlestick...' A, F- c& u, |; j9 `* @
bool tem_vela_nova(const MqlRates &rate)
3 ?$ c, O. A. A- U2 M{
! S* k, z' a8 T7 g* l7 D- M{& B1 R; q( N* v: h
ret = true;
. U! I: L6 W6 @: Jclose_positions = false;
. u" N$ Y3 A/ j8 {. n}: c% l" c4 s& D& ]/ w6 B
else% M9 f/ }2 u+ a; U
{# s% O, ^( i+ g }/ ^ E5 `6 T. E
if(mdt.hour == 16)& n9 h3 R" x3 E1 Y
close_positions = (mdt.min >= 30);% Y' a/ j1 l( A: e1 |
}* }* V6 W& E2 F8 q- b: s( T; ~
}$ {6 k- Q* ^- T# r9 f" Z4 _
return ret;
. A" {; u9 L; R# d2 p7 @, x8 X}7 B* V, P" Z; w7 n/ F
//---
6 c3 ?; Y* \8 e, V, z4 @; J7 q7 Gbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
8 Q2 [8 q- n- P% `/ W8 {{
* Z& g' c* |' \/ i$ L7 Bif(PositionsTotal()) // Is there a position?% o3 ?7 K* o2 s% q4 Q
{: o9 x) y, \, b; ?2 m' C
double offset[1] = { 0 };
2 @" |2 e2 B, A: kif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?; W! L9 W2 n2 e4 O
&& PositionSelect(_Symbol)) // Select the existing position!% z) j( i( h0 v! w2 I* o& l
{
0 x% [/ I3 D2 [9 ?8 T( ] n6 j" |7 GENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
# O. c- a1 r4 ~* Sdouble SL = PositionGetDouble(POSITION_SL);
5 F" e8 t9 F H+ L. tdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));! ?- l( I$ ?# _4 H7 K, E
if(tipo == POSITION_TYPE_BUY)
& c" `1 @% g* k9 _) ?- ]0 v{
* N. I0 }( ^ ^2 Y! nif (cotacoes[1].high > cotacoes[0].high)
" g% w- C0 q2 m{
. D$ {/ e8 y) ?; @% c& Ndouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];$ a/ f8 O: h" f2 u: P
info.NormalizePrice(sl);
9 T/ d& R" A, g) n2 dif (sl > SL)
; ^3 u; |" u; D7 Z{
; V2 W% J4 g: x) F- M, K0 lnegocios.PositionModify(_Symbol, sl, TP);, \8 D# }9 }# ~' V2 z0 a4 w
}- w+ B. f: F7 I* |7 k* N8 Y' Q! [
}% t" i5 m$ O- O0 z; S1 D! l
}# q/ {/ Z5 p4 t0 x/ @3 a! a
else // tipo == POSITION_TYPE_SELL
* r3 Y. D$ I$ r+ S, ^- n6 x{
& N0 c/ ~( q+ r, n1 A6 N' vif (cotacoes[1].low < cotacoes[0].low)
$ }6 W" p: j" A{0 x; A4 j$ c: a- K
return true;! i! T2 A D) n2 `; v) c1 f
}
, v% V2 ?- A3 |! M& `// there was no position. d9 ]% J2 d/ ?
return false;" [, T O# J6 X W
}
( G; t/ k1 x n我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
9 \9 W, l5 X" f5 r, |. y; ^" i6 D# |& y到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |