启动交易模型,并构建 EA
4 y" u3 S+ d6 f* J& w在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。4 B: K8 ?5 r* _6 `; c
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。- S: r# D9 U( X/ P* c: o
以下是制定这些规则的代码。
% P& c4 R; }& W//--- Indicator ATR(1) with EMA(8) used for the stop level...7 m! l$ N8 ~5 T! w3 U+ @
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
2 k9 J8 Z7 }0 S: U8 j3 fint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
1 S* E+ E6 K% C; b5 j1 _- K//--- Define a variable that indicates that we have a deal...
+ ] Y% m( l- C, K: pbool tem_tick = false;
4 a) q# p" l& y' O! P5 |9 W: r( k/ a" _//--- An auxiliary variable for opening a position
" c* i: O w! f" e! O) m3 [#include<Trade/Trade.mqh>
' D( s0 X3 A$ B9 q" }, @. `#include<Trade/SymbolInfo.mqh>
6 [& I* R8 Y8 }$ G: i& aCTrade negocios;/ p4 E( G: f3 V0 g1 b$ [6 P" l7 I
CSymbolInfo info;
3 [; X3 {( h9 G//--- Define in OnInit() the use of the timer every second
5 Q$ w# ~- h. Q//--- and start CTrade( ^7 @0 R7 ~7 J$ B3 J1 ?
int OnInit()
! l8 T) d' ^: K8 d: x5 b7 Y5 Z{
" c0 P7 O5 S# d( d* s/ E& m//--- Set the fill type to keep a pending order$ a; ?8 D$ n4 S) }" k
//--- until it is fully filled
9 z9 }" `; ]- w) E$ v Z( V! Tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);, W9 d% Y; U/ ], m0 F
//--- Leave the fixed deviation at it is not used on B3 exchange
& ^/ W1 J4 K- q0 o3 A+ r! g" Wnegocios.SetDeviationInPoints(5);
) y: s( r, L+ U! f0 m3 Y0 H//--- Define the symbol in CSymbolInfo...9 g( N- O$ g! e+ o6 f- n5 N
info.Name(_Symbol);2 i8 Y; }* Y2 [3 Q
//--- Set the timer..." I) X: Q3 q$ j4 j" E. c v6 d6 P
EventSetTimer(1);' z; b) {* p7 t
//--- Set the base of the random number to have equal tests..." Y7 y: U3 C3 F( S
MathSrand(0xDEAD);
3 [3 d! V* d: F; b+ L$ c8 Greturn(INIT_SUCCEEDED);) w7 F" y3 r' G# W; k1 Y
}1 R' u. K+ u) F* z8 a: ~
//--- Since we set a timer, we need to destroy it in OnDeInit().8 u- ~0 m6 d5 n- p' j: Z9 d
void OnDeinit(const int reason)1 Z& E- b+ Q' K) G+ f2 Q
{
6 X- a! j7 G9 ?1 a# K I; MEventKillTimer();. ~1 y. i8 r+ F0 O
}
9 n1 z" G6 v. d/ [//--- The OnTick function only informs us that we have a new deal; b2 C+ S% m: t+ n: X
void OnTick()
8 k* x2 h4 e- u8 U/ E# @5 d; X: i{! X2 r+ q9 u: ^6 s0 K- D$ \
tem_tick = true;! F: J% Z" s' j4 M# z
} D) k3 ^4 ^. e8 ?! e
//+------------------------------------------------------------------+. Y5 P Z4 J$ o$ e! j5 E8 b1 ]; `
//| Expert Advisor main function |# \* p! B% C2 h- B- U$ \
//+------------------------------------------------------------------+' [' D- e8 l. u; B% H+ l, n& k
void OnTimer()6 ^, m- T8 Z( x! \; A/ f9 L
{
4 O- v4 P1 h. m& g, FMqlRates cotacao[];
- W* J3 y# N; L/ rreturn ;# I6 e, O* V( ~, x0 V/ L2 |
if (negocios_autorizados == false) // are we outside the trading window?
; g c+ ?! k6 l2 L; Kreturn ;) b6 b8 r2 \. }, y9 W' J
//--- We are in the trading window, try to open a new position!
u( Y2 @2 F+ O! b0 sint sorteio = MathRand();
. L" d% a1 J) e* T- w; h//--- Entry rule 1.1
3 x) u- o) Z ?* |if(sorteio == 0 || sorteio == 32767)
4 F8 n N% v6 L3 K+ F7 Breturn ;( k9 K+ U" E" B, q/ t
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy. N; U& M; W! U) B" b: p
{$ k$ K% G& ]! b* j6 n$ G
negocios.Buy(info.LotsMin(), _Symbol);
* D- A- q+ z/ M, N t B$ C}% s1 H& c2 w0 x0 v$ ]; j& _ Q
else // Draw rule 1.3 -- odd number - Sell) o5 W* s% b/ f, K! f
{, r/ B2 \1 i7 v9 T' I! N6 S; i8 l. G
negocios.Sell(info.LotsMin(), _Symbol);
d. f7 C* u5 M3 Z3 z) m}3 r& `' ?: i; d; B: q' Y) l
}
' v4 E8 ? G8 K/ u" L7 z//--- Check if we have a new candlestick...
- B5 B, S; d9 s4 ? W: ubool tem_vela_nova(const MqlRates &rate)
. K" M8 z: p7 g; R5 K' T. p, T{
3 j3 u9 G w$ L{
% D' Q% S% V2 m. i$ k- oret = true;
4 m& t6 F, g" u0 e# jclose_positions = false;
6 u! I9 g: y8 b# m}$ y, I$ d% Q8 ^9 L
else
8 X* ]6 R$ I9 Y2 x$ M) E{
; a+ E4 ~9 y% O9 H4 r% j: cif(mdt.hour == 16)8 q0 z- U* U8 l' E
close_positions = (mdt.min >= 30);) o. K! M6 D1 c! c, _; f
}
( a+ }( I* `, K4 N4 U7 F. p}
1 d5 C9 t3 u9 i1 hreturn ret;
) n0 K7 W: g- D+ Z7 q5 l}
- ?" T' t* h' d0 m5 D) z2 S//---, U, I9 @# ]5 E7 s2 W O. u2 o
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
) n B) y! a. O( C/ ~{
3 s8 J7 d& _( \! H' S }* x, Bif(PositionsTotal()) // Is there a position?
# [' F! G6 n* t- v& \3 e{
) p4 M A6 P5 b+ jdouble offset[1] = { 0 };
/ n: M& w$ Z; t. |% Gif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
+ Q# W9 |- U" M. i( d&& PositionSelect(_Symbol)) // Select the existing position!5 k6 F. P6 A" B3 o! ~
{
% X& i0 Z+ Z9 w+ U; yENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);% \7 a; }1 z# }6 b; F; L
double SL = PositionGetDouble(POSITION_SL);
+ l% k! B8 t: s9 _" R7 cdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));' e# u! g8 s3 M0 V; k; ]
if(tipo == POSITION_TYPE_BUY)' w0 D |: t7 u5 F# y
{! r& O0 `4 ^' @2 K
if (cotacoes[1].high > cotacoes[0].high)
5 I$ O! S' `& I& [ }, I; s& Y7 A m2 g{3 }, ^5 J# l- l$ ~; b
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];* S; X7 G( o# D) k1 ?$ Q$ \
info.NormalizePrice(sl);
. Z# s7 z! k; F% O0 }if (sl > SL); B2 g1 l* B4 c% T Z1 j
{
+ s( K3 F4 a# X; hnegocios.PositionModify(_Symbol, sl, TP);
* W- `8 Q# q: t5 }7 E}
, C, i: h" ]4 l% v}4 G. Q! }1 N6 ^- H' L
}
- D. v; k7 {, Q1 \) I( ~ M, B; yelse // tipo == POSITION_TYPE_SELL# A( H: N2 s1 ?9 u/ w0 c6 S: W
{2 \3 T1 g' }; Y+ k u9 K
if (cotacoes[1].low < cotacoes[0].low)8 R* |. K- ]/ v% f& c0 _1 H: I! h) C
{& N5 i& d0 S/ z6 C7 I: p
return true;
, t6 N# @' W$ Q' b} K) }+ e5 w! v1 ^: y$ }* H+ D' q" Q
// there was no position9 D/ Y5 q% q% N+ H4 M" u6 Y
return false;6 {7 O$ B7 g7 w% A% G3 Q
}% q) a: W! n. i: `' _
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。# K% t& Z, M, W- C
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |