启动交易模型,并构建 EA
! ^+ s. U; T. H- ]! t: w- [在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。# w. f" m2 L. Y* b
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
& R S& C2 p5 c以下是制定这些规则的代码。
1 K$ D7 k. H! l# a* u( f; t//--- Indicator ATR(1) with EMA(8) used for the stop level...
* {6 V( m$ q- D$ fint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
" F( f/ |' i1 Mint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);$ `% t) v" X% K | G! E- }, k
//--- Define a variable that indicates that we have a deal...
) m4 u, D8 _' o# I- zbool tem_tick = false;& L0 f) S; m0 C' x: Z9 ^4 K: A4 o& H
//--- An auxiliary variable for opening a position; x9 g. ~3 K" p; L& {1 ?' l
#include<Trade/Trade.mqh>6 t1 C: m& \- f, y0 P5 p8 E
#include<Trade/SymbolInfo.mqh>. C0 X6 }: U2 k/ M) t
CTrade negocios;
3 O$ q; i Q2 e/ m: HCSymbolInfo info;" N# s- w9 A$ c( |
//--- Define in OnInit() the use of the timer every second5 \% e2 f& ?. D0 A
//--- and start CTrade
" M& f$ m/ x! T$ K+ eint OnInit()
8 Q, U0 W1 A/ Y{
, C, ^3 r! b3 p9 u# U- J* a//--- Set the fill type to keep a pending order5 H1 U7 k+ b& G, N9 ^# R1 \/ `
//--- until it is fully filled
$ ]4 I- F' _% q4 T; lnegocios.SetTypeFilling(ORDER_FILLING_RETURN);6 E0 N3 f% w C$ p
//--- Leave the fixed deviation at it is not used on B3 exchange
6 Z2 P5 c) {+ S" A& N# [" K" D/ A inegocios.SetDeviationInPoints(5);. D0 ?2 h3 L# ]3 C' `. ]0 I
//--- Define the symbol in CSymbolInfo...
# i n/ n" u6 {; yinfo.Name(_Symbol); Z8 f; `: `# d
//--- Set the timer...
2 Z9 K4 E! m4 e8 [: dEventSetTimer(1);$ W5 F- U" s) B; I" a
//--- Set the base of the random number to have equal tests...# o. y6 n e z
MathSrand(0xDEAD);8 @( m# Q& X* h! g5 A2 \
return(INIT_SUCCEEDED);/ j, @* i, s1 q* M5 ^
}
; U; L3 I9 @# N7 z* X) v9 s8 R//--- Since we set a timer, we need to destroy it in OnDeInit().
. F f5 k9 p+ `3 f! r: @0 S Svoid OnDeinit(const int reason)
$ z2 @1 F- J- ~% ?" E: `- H; F. j{% U0 R. |; T! d6 W) |5 F: \
EventKillTimer();% c) S M M( S4 ^! ]
}# c: N' ~. x; w1 ` K
//--- The OnTick function only informs us that we have a new deal8 }; E- D* p% h: n- {/ J
void OnTick()# N% r, f! M% t% T
{8 d- i9 E ]5 Y- T+ P6 V. L
tem_tick = true;
. P0 q0 N8 m+ m) N) N' j$ e# d}- l. [& i! H" M& ]7 k4 e8 N
//+------------------------------------------------------------------+7 v8 w7 B% }* D; D6 y' y4 }
//| Expert Advisor main function |
( D0 {1 L7 @9 ]2 T& d i% w//+------------------------------------------------------------------+5 b% Z+ D, _# @& U! P. o
void OnTimer()8 w8 l( ~. Z5 m2 I4 P2 E5 b4 k4 y# r8 ~
{
) }% l4 y+ g5 qMqlRates cotacao[];. V8 k3 w2 b& n. F
return ;
3 ^7 @2 T& P c) H# Z3 E) C* Gif (negocios_autorizados == false) // are we outside the trading window?
# q* T1 D. r9 ^+ \+ Preturn ;
b5 X4 v& p6 ~1 o1 c( n//--- We are in the trading window, try to open a new position!
; m& O8 ?+ V, I9 g/ Z* Uint sorteio = MathRand();
! h) N* f2 Q1 g9 i/ [- [8 ?//--- Entry rule 1.1
4 {8 L2 z* u) ^4 ?# z1 `, X$ Q8 fif(sorteio == 0 || sorteio == 32767)3 [( u# i' v6 z# D- W& r- b
return ;! f$ B, o3 t& m) g
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
; i/ ~7 i) Z9 j( q* |, |# p7 X7 K{' h% ^, k3 f* |5 ?5 U( \5 m
negocios.Buy(info.LotsMin(), _Symbol);
* i7 t J5 V4 ]; I2 V}) \2 \ T3 e5 @1 n+ B
else // Draw rule 1.3 -- odd number - Sell
: F% V3 S; A' k/ e t5 h* J' n" G{
" n, R% X y4 Y2 Hnegocios.Sell(info.LotsMin(), _Symbol);
* t l+ D% m/ Y1 `}
8 Z0 {, T6 ^4 p0 x- q}
" Z# }) @% k% M" R6 Q//--- Check if we have a new candlestick...
2 V0 B) O l* {+ n, c# {' {bool tem_vela_nova(const MqlRates &rate)
6 t, {' D7 ?# x{, x6 v l7 a1 q" O, l1 i% s
{# M# C* @6 N7 ?
ret = true;
& x2 X8 s3 }% f6 }/ t, a% }1 C( Eclose_positions = false;
0 H& g) h( B2 K! M1 D7 Q! t}) D- @8 p/ y& D) O( O
else
2 B7 k) _5 g, {9 l: }/ @+ e{
& e5 R5 A: q, G1 L L# C: ~' Qif(mdt.hour == 16)5 \5 h" e3 r3 n# I
close_positions = (mdt.min >= 30);
7 \2 I, J) c, i9 ]}3 S" U5 w& S, a* {- p- u6 T! Y/ D
}. Q. ^, r8 C. S9 x) V/ p
return ret;
0 M+ c2 n5 l( y/ x4 |9 R7 ~; S8 U}" E# V9 q) i$ @
//---. I5 i( Z, l0 q9 o
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
+ w1 a* f( J9 {. u8 F{$ L5 @9 @) l# f; P, D& h9 ^
if(PositionsTotal()) // Is there a position?" |. R i7 b1 _; X
{ U+ ?" A% b* w' w, b9 e5 T
double offset[1] = { 0 };
( F) e3 d, R7 C, C1 _3 J0 w3 Iif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?; S2 ~; [3 a# E; H
&& PositionSelect(_Symbol)) // Select the existing position!' ]8 _5 O& W9 p% \, b( x
{
?% n/ E# ^4 d+ B+ u2 |8 U# O* zENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
# n# P% Z& X: d- i: J1 ^6 idouble SL = PositionGetDouble(POSITION_SL);
, ^; Q' d$ }3 o3 {+ gdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));( d8 A+ x/ G% \# x9 v
if(tipo == POSITION_TYPE_BUY)5 x J- Z( n' T$ K" S$ U5 S3 R
{
# s1 E0 {2 r) L- L% zif (cotacoes[1].high > cotacoes[0].high)
* \. }! m1 q5 [5 X+ e+ K; ^{
^& E K5 \ H, N& Q' mdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
# {1 Z1 Q; C" P0 D5 x7 jinfo.NormalizePrice(sl);2 K) c* i7 B% ^
if (sl > SL)
) K8 f. c; K3 n) b8 H+ c* w/ g{- s9 u; [2 q, v) J$ Y/ F e
negocios.PositionModify(_Symbol, sl, TP);( {# s: j7 l' Z$ n: V8 j! p
}( Y4 R `; |6 d3 W3 [- v, U$ j
}8 \% O3 l5 p+ Y; {4 l H$ t
}
4 W5 F) v. I3 s: g W3 Jelse // tipo == POSITION_TYPE_SELL
& T: c) Y" \$ V3 Z{/ y: K0 {7 F, ^( `% u8 L. D
if (cotacoes[1].low < cotacoes[0].low)! X. P/ E/ `3 K6 g, a
{
" D3 K3 \( P8 X* Breturn true;8 U- K. ?2 {! g- G
}, N3 V* _9 }) F! N7 y! ]
// there was no position( @* F9 m' q& J$ F
return false;
8 A/ E3 N1 u/ M}
1 J) T+ I% }3 ?# P Z' O: o我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
' N' z' @% K( ~! T" N到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |