启动交易模型,并构建 EA5 W1 B, A1 Q% d* @6 {
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) A% D) [6 G4 g+ u3 ^% A为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 s+ X9 X. h0 Z9 d以下是制定这些规则的代码。
; `( i" N8 c& _- N, \3 `//--- Indicator ATR(1) with EMA(8) used for the stop level...
+ \2 k6 {8 l7 I) E' Y- mint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
/ L* \& Q t3 [* T3 ]" eint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);6 |" B8 t5 Y; G& p1 L+ P( E. f4 J
//--- Define a variable that indicates that we have a deal...
2 t2 Q* O+ Y, G0 wbool tem_tick = false;
# \5 a0 u5 S0 e0 A//--- An auxiliary variable for opening a position+ t0 A4 ~# c! N; a# G
#include<Trade/Trade.mqh>
4 y5 j# U" `# h, a#include<Trade/SymbolInfo.mqh>
8 k/ K% O7 _/ j7 u+ jCTrade negocios;
$ Y# g& n" z! H YCSymbolInfo info;4 \; o7 U* U' N( G+ O3 e6 v
//--- Define in OnInit() the use of the timer every second
! u! L2 u R' F- n- u) q6 v1 P//--- and start CTrade
+ L4 h# c5 L5 a9 wint OnInit()
5 G4 _8 K1 o6 L! W: v; s0 e{# [6 b. E/ K6 n h* B% k+ K* C7 \
//--- Set the fill type to keep a pending order9 f" s, x$ H/ m3 X
//--- until it is fully filled: L& o/ K/ d$ C N/ l
negocios.SetTypeFilling(ORDER_FILLING_RETURN); y' \# U$ B: i7 G4 r
//--- Leave the fixed deviation at it is not used on B3 exchange
' C- G/ ~+ m6 j2 c& hnegocios.SetDeviationInPoints(5);
% U9 d1 ^6 H9 L) ]$ N//--- Define the symbol in CSymbolInfo...& n. c, }( E/ [5 H& h) ^1 o- M
info.Name(_Symbol);. Z, ]$ U. v6 A6 G
//--- Set the timer...
; V8 v" s% k$ q( ~* UEventSetTimer(1);4 g& a6 o% c1 S8 O9 |$ s; s
//--- Set the base of the random number to have equal tests...
- u' | I, P8 { } F+ jMathSrand(0xDEAD);
6 T5 R- }8 Y I; Zreturn(INIT_SUCCEEDED);
9 p5 q. g& A% G7 E" d& N: `+ v}6 `* X0 x/ j* o; y3 D
//--- Since we set a timer, we need to destroy it in OnDeInit().
" h$ x+ s/ k) f0 X* {! ovoid OnDeinit(const int reason)
' x! N# j! F% V' G6 m3 [- G0 q{, r2 p) O0 J' u* r5 v; r
EventKillTimer();
7 u' f/ l+ r7 Q* J}; U6 l! z% p3 v, ?+ S
//--- The OnTick function only informs us that we have a new deal( S" u& x, a+ V: V" |/ R
void OnTick()* N* w* `$ B0 r5 o! }$ f9 J9 u' D
{% D7 d8 N+ v2 t8 `5 t$ J: g
tem_tick = true;
2 s! H% _( t. ]# F. A' q6 q* N}
j4 l( c, j% G1 o3 \* A' t//+------------------------------------------------------------------+5 Y1 u1 S$ E8 i7 r) C) X
//| Expert Advisor main function |+ A7 w) S! K. D" O& x
//+------------------------------------------------------------------+ y, v9 ?) g( A. Y8 Q5 w5 a
void OnTimer()2 J! O0 b' F( Y8 n2 k/ G, M
{
: p* Z' J, Y! XMqlRates cotacao[];2 i) d* S6 q8 y7 f5 H! y4 n E
return ;
8 v0 D7 m( v% T' l( Lif (negocios_autorizados == false) // are we outside the trading window?
, t, ]( z' W$ l7 Xreturn ;
) E& L, M; @& W8 t8 [' q//--- We are in the trading window, try to open a new position!* e# I$ O0 @/ Y' _/ V
int sorteio = MathRand();
- p4 _) f( {7 Y- X% x( F1 _//--- Entry rule 1.1
# u9 B+ c$ g3 |) P# R. l- eif(sorteio == 0 || sorteio == 32767)! q) t& s* t2 j# L: `
return ; _+ b; G& c8 O2 b# b% T! l
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
$ E7 W. b1 ^" x9 P3 [{; H1 ~+ b4 D/ J2 U
negocios.Buy(info.LotsMin(), _Symbol);& {0 E& j% O8 I* s `' N9 C: ^ ^9 {
}3 E+ c+ ^! C4 X8 R5 x
else // Draw rule 1.3 -- odd number - Sell
8 B2 J9 i) {. s( s( j2 ^# @{. s3 a9 j/ o) ~' K& g, W/ A
negocios.Sell(info.LotsMin(), _Symbol);
0 G, S# Y( B2 I2 \3 Q2 w}' C0 m. B+ P# M% w1 }" B
}' y2 ~2 Q' L" Y' e @# l
//--- Check if we have a new candlestick..., J3 p0 [1 u/ c- B. S2 g! G3 N
bool tem_vela_nova(const MqlRates &rate)
+ w; [/ q6 p* `8 B2 o{
( F# k# J W; f; o9 d& O' V6 E{1 U7 A! u& z" E+ m
ret = true;) B- P5 e: z- Y
close_positions = false;8 x/ a* Z) f0 l4 a( Y
}* r- t1 j2 _2 Y- M
else' b& K% u& L' N: K' G) A0 d
{7 _4 p7 ^$ N; t+ y% I% P% h; Y7 d
if(mdt.hour == 16)- w+ v' L* o( i2 @. j
close_positions = (mdt.min >= 30);
& f1 a. P, ^6 [# K+ z}8 e T* s% @# L! ]4 y5 @
}
/ k# H* L' `% ~: z ?) E! zreturn ret;
" {; I6 Y' n6 C6 g}
% v4 [ r( m9 f. s//---
% z" z8 v9 e# j; H8 I6 k5 \bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])1 ]) p$ ?( v# ?
{
, j: x- D) b% }3 w' Qif(PositionsTotal()) // Is there a position?
$ n. ? B' l n0 U{
# @6 h7 g# E7 G5 s. `4 y. ydouble offset[1] = { 0 };3 F% e/ A% [0 c7 ?$ y* d4 q
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?8 o- H! l& [4 j/ T& k
&& PositionSelect(_Symbol)) // Select the existing position!
, @( k' d6 X$ f0 P{
2 M4 Z$ B( ^* `" m# l0 s" I2 ~ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);- w$ C8 I) i3 ]0 i; Y9 S. e* R
double SL = PositionGetDouble(POSITION_SL);
# F3 `( N/ u+ ^$ N, y3 [double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
x: V9 w+ x0 a2 d& f) o$ Wif(tipo == POSITION_TYPE_BUY)
) d% \: c3 ^8 J _$ S/ f{- d2 [/ B0 z7 k
if (cotacoes[1].high > cotacoes[0].high)7 E# ^2 \+ t8 ] U* X+ ?
{
; ^9 N* o' }( E6 c( \( ndouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; @: \4 I, f# F2 V% n
info.NormalizePrice(sl);3 I8 ?: \+ f2 ^6 J/ d* v
if (sl > SL)
( I4 U! J" v: X9 H, S3 \) t; x{
2 V) g4 I) Q( t) u# w3 \) [negocios.PositionModify(_Symbol, sl, TP);, N: r6 B: ^, c( S) |. C; H/ L0 h
}8 P/ M3 C# \ {+ G
}
9 O4 D9 K. I# d* |}
7 \$ r* G' W" S* P, L1 h+ c% Jelse // tipo == POSITION_TYPE_SELL3 o8 U$ S. N ]
{, R8 Z2 l) @" W4 f& \
if (cotacoes[1].low < cotacoes[0].low)
& j( x3 t R7 A! ]3 F# s{& S1 F& U8 x' |4 F# ?
return true;/ Y7 v& b _$ G: G4 w7 t% h2 B, l
}
, I! d5 W* C7 K; l// there was no position! {" @6 h" J/ T5 w
return false;3 l3 N# U5 T8 S) w1 l
}
* V9 [* }" m, T0 J& }( f8 j我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 J) o" j! `$ W+ q
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |