启动交易模型,并构建 EA
) X5 S6 l) q* [6 L! r8 v在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
' g1 e1 x5 Y9 ^2 P5 _; Q为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
6 I9 E- g! f4 s4 F* o3 y* u以下是制定这些规则的代码。/ [' A( @$ _/ S3 Q J
//--- Indicator ATR(1) with EMA(8) used for the stop level...
- h2 F' a) w1 y$ m7 @int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
* L, ?0 z2 m- \+ [. V; tint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);, r6 K" k" L2 o2 M0 q( R
//--- Define a variable that indicates that we have a deal...
3 G3 ?# w9 k& d7 y gbool tem_tick = false;5 M" S o5 k6 _0 \( e6 e7 w
//--- An auxiliary variable for opening a position
; \* f% l% b5 @9 t# h#include<Trade/Trade.mqh>: g* H9 O) K/ Z2 r8 S
#include<Trade/SymbolInfo.mqh>
! ~+ @5 J0 m1 A6 i; ^CTrade negocios;, `& f$ {! |5 a. O
CSymbolInfo info;
! |4 G/ S4 z; b" Q* x e//--- Define in OnInit() the use of the timer every second
+ E( Z) E+ @4 ~! e//--- and start CTrade+ w9 l! c# S" n9 w
int OnInit()/ e. e8 P" C2 n2 [& C9 T. @
{9 L0 q4 l; w. Z9 m) {6 O e# S
//--- Set the fill type to keep a pending order
# k) {0 p1 X6 a' t1 A//--- until it is fully filled
$ L: Q4 S8 F- m8 f! Z7 a& n+ gnegocios.SetTypeFilling(ORDER_FILLING_RETURN);; G# H) ?0 {% f j3 s/ [. ?; c
//--- Leave the fixed deviation at it is not used on B3 exchange
' ?0 H4 O0 K, y5 m) g- {* Vnegocios.SetDeviationInPoints(5);1 `: E; V2 @3 }, \
//--- Define the symbol in CSymbolInfo..." P! X" e" f8 s8 Y( ^! O! j2 }
info.Name(_Symbol);2 X! U; f) y9 c/ d
//--- Set the timer... r2 r4 W7 f X9 s; {
EventSetTimer(1);
7 Z7 m2 b& J+ i0 v# |# U4 w' Y//--- Set the base of the random number to have equal tests...
1 `/ D* u# [' W8 d. ]MathSrand(0xDEAD);1 M8 s! \ p, a/ x! }% i- j
return(INIT_SUCCEEDED);
- [) w/ [) c8 [1 x/ n2 w0 {$ A}
9 r7 T' @' J: R4 v//--- Since we set a timer, we need to destroy it in OnDeInit().
2 _+ `0 { ]/ h+ r4 [: I" g3 ovoid OnDeinit(const int reason)# z/ c, G+ I4 U" Y; q9 _0 I
{8 T8 {* T6 t- `/ i$ O& b
EventKillTimer();* C" m4 E# B. t
}$ g3 ^" |4 W9 s. M
//--- The OnTick function only informs us that we have a new deal
) j1 t# W; f' r4 c* n# fvoid OnTick()
' G+ p! w- ^/ n1 l' }{0 Y& n% k1 M% c2 Q3 e' f
tem_tick = true;9 z6 \" T4 N% Z2 z: I; s
}
* T$ C; V Q5 s' G//+------------------------------------------------------------------+
; N. ]+ G3 l' l6 F K//| Expert Advisor main function |0 w' P- Q$ k' m; ]/ [. t
//+------------------------------------------------------------------+
7 `! `& \4 G( r( n pvoid OnTimer()3 K* O$ I; v6 G0 A9 i& l
{$ a% t9 W8 h# i/ A+ o
MqlRates cotacao[]; X" q4 [' g, K; m1 S
return ;
1 U, U7 p% I/ N# p: Qif (negocios_autorizados == false) // are we outside the trading window?. y9 L3 b# W& e O) w
return ;
1 E- P: Z3 q0 g {5 q: ?//--- We are in the trading window, try to open a new position!
; U- T4 Z3 ~' @9 mint sorteio = MathRand();
" E: A2 C5 c/ W9 p//--- Entry rule 1.1. Y. H6 |0 O* w( j
if(sorteio == 0 || sorteio == 32767)3 _- s7 c% P' |' E
return ;
. _$ r8 y3 @& v2 oif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
+ |6 w$ Z1 g+ e" Y; s8 \) J7 R5 c{" Z( u1 k! S( t0 `/ h
negocios.Buy(info.LotsMin(), _Symbol);5 P- W3 p6 L5 b
}
% [! R- ?" E0 Y1 c1 b% u4 jelse // Draw rule 1.3 -- odd number - Sell
7 [* x! I% ^9 Y. R. u) I6 G6 E7 I{
2 v/ U! N* t7 x% {negocios.Sell(info.LotsMin(), _Symbol);
: Q- H8 `9 ~6 f1 F& ?# A7 C}
, y. S8 E# I, _( N}
# Y& L, @2 m" k& [) |//--- Check if we have a new candlestick...
. A3 d- u) s6 t$ Q$ Wbool tem_vela_nova(const MqlRates &rate)8 c n7 _6 b9 Z8 t1 U
{
! Y' c3 b0 x; \# ^{
$ Z7 j7 b! H% dret = true;
; B2 k& _( e6 ?close_positions = false;5 P+ c: f M. \. S7 W
}# |. d. B: ]# q; d. |+ t# x" D
else3 j2 E3 Z$ g( [5 D2 c* ?
{
/ V( t% j" }, G& V$ X% l7 S$ ?if(mdt.hour == 16)
" n( I% F% ?$ _8 E& G: Eclose_positions = (mdt.min >= 30);
/ s7 g) t* l- [0 h9 y7 Q7 d}
/ ]0 m7 [; f3 M9 z, f}7 t% ~/ L" `; N& o0 c5 j/ b( |
return ret;% t. L) @! \1 o" L. p5 `; L4 g
}
: p: n' m9 x1 o, d& ~3 b5 H//---
' o1 _: W' s4 N3 u. Z; F7 V2 dbool arruma_stop_em_posicoes(const MqlRates &cotacoes[]) I" @7 C8 ^8 `/ {
{
* R$ A6 y% R2 C8 ?if(PositionsTotal()) // Is there a position?
& d, N* r, I" V, M; i3 a! |; t$ M{
* Z+ z$ `' Y' W* {* bdouble offset[1] = { 0 };
5 g7 J$ s0 w# H5 A/ n' S) [if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 ]& ~' D6 W' l( w7 y! P+ k
&& PositionSelect(_Symbol)) // Select the existing position!
' k1 I2 c: l' a4 T; C c2 L{
6 b( D Y: G3 i* m- G) r2 ?ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 e3 u4 o8 ?, a! w$ J. i
double SL = PositionGetDouble(POSITION_SL);9 Y2 w2 O [( ^0 x
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));& F. Y0 T5 c$ b& V+ j& C
if(tipo == POSITION_TYPE_BUY)
9 c0 ?7 X5 c- s# i' P. j{1 Z, B9 a8 @4 P* \0 z0 R
if (cotacoes[1].high > cotacoes[0].high)4 s* O. h& X& Y7 Y; g& I
{8 {$ ~6 f) w$ t/ t% h
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];: W- W4 _* l) T! j/ X _0 s
info.NormalizePrice(sl);
4 c# h# t; U9 W2 B+ jif (sl > SL)2 a2 S7 o0 p) p+ { E
{
! L0 v" \6 l. _" z! G# rnegocios.PositionModify(_Symbol, sl, TP);8 x& D) k$ _- c6 P' c% [3 X/ v
}
: K0 u1 m4 C# B" \" V, y0 d! l4 g}
( J# L4 K! j% l3 i# }. }}: g* _7 K, o" }& } f! L. Y
else // tipo == POSITION_TYPE_SELL# D+ W; H" z. e* ?# C X
{9 Q2 D# m; [; U; w
if (cotacoes[1].low < cotacoes[0].low)
1 E2 I( n( |1 r/ A9 V- J4 R7 t{8 c1 e L/ h7 I) x4 {# F' u
return true;. s V9 T' W% h# K
}( [3 `, y$ N5 W5 q. {/ c6 ^6 z: O8 q
// there was no position
5 j, p/ L* J- L( Yreturn false;( \9 V. f5 v: \1 y; g% A8 @
}: B& N- g' Q) E. h; Z
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。. y" `0 p: B8 v0 g; S: j
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |