启动交易模型,并构建 EA# o h1 A0 A8 g7 r4 T8 g
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
& T# t2 e6 D. B! \3 E" F为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 B8 ^) C; |/ n8 j
以下是制定这些规则的代码。
4 U* y9 c6 }3 `$ p//--- Indicator ATR(1) with EMA(8) used for the stop level...' P0 o6 S" {7 r4 X3 a0 w
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);0 O9 a% Y0 Y }7 e8 Z
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);7 D4 k; e7 r( H3 o: d' p
//--- Define a variable that indicates that we have a deal...) s# Z2 W+ B4 p# M
bool tem_tick = false;4 l6 K# _* d: `, ~! _9 v
//--- An auxiliary variable for opening a position! ^* C. h$ L4 t! T: l
#include<Trade/Trade.mqh>, h" a+ c$ T, X1 S& P: n+ q' {- }
#include<Trade/SymbolInfo.mqh>
1 A2 h6 J& k* P3 \/ HCTrade negocios;
h9 _+ _0 G9 Q+ ~, @CSymbolInfo info;
$ v! z; o4 Z* F/ I; j! |! G//--- Define in OnInit() the use of the timer every second
2 }$ g) P. u3 c% ]3 g9 P//--- and start CTrade) K, Y1 q0 i' c% a' O
int OnInit()8 r- p. Q" e$ `. n& a9 @/ m
{
' e) X5 o, l( e6 Z" G) g//--- Set the fill type to keep a pending order; h! a6 V2 P( Y a3 v6 |9 k
//--- until it is fully filled
. ?- X# s! l3 [: t( a) M, [negocios.SetTypeFilling(ORDER_FILLING_RETURN);- x# n' C9 ?: O
//--- Leave the fixed deviation at it is not used on B3 exchange
, D' p/ z8 G [+ B& |2 Nnegocios.SetDeviationInPoints(5);( a0 I$ ^5 y4 H, r
//--- Define the symbol in CSymbolInfo...
6 p) Y0 G/ b+ e/ @% einfo.Name(_Symbol);9 f* G7 a1 x3 B* S/ Q3 n
//--- Set the timer...
/ L4 H. y/ Q, f3 dEventSetTimer(1);4 |( y8 D ~7 ^! Q0 P
//--- Set the base of the random number to have equal tests...5 r$ Q3 w- I& G
MathSrand(0xDEAD);
, [$ L/ W8 j/ X; f3 Preturn(INIT_SUCCEEDED);- D: r6 v2 ?3 @/ O
}
: P' w' q& k* t5 ]0 W//--- Since we set a timer, we need to destroy it in OnDeInit().
9 Y, S$ j$ t( K5 H$ z# Q$ rvoid OnDeinit(const int reason)
$ Z5 }2 y0 |2 ~5 {{; ~; G& V; j8 S; c
EventKillTimer();" w2 ^# i+ {3 E3 l8 |( o6 c
}1 \# r6 n9 m$ t" x8 O7 ~
//--- The OnTick function only informs us that we have a new deal) L/ F9 k6 `: C" w1 P1 D
void OnTick()
) |1 @5 A) u- H8 ]4 U5 }' A{8 h9 P7 E* J/ E6 R- \. ] \ X
tem_tick = true;
8 f8 W+ N6 {2 g! Z& I# C}
5 d( C |: W( q1 h! n. E/ j//+------------------------------------------------------------------+: K; q+ y$ x2 o4 s2 F
//| Expert Advisor main function |
; W1 Z4 i: ~( n; G( u2 t( l//+------------------------------------------------------------------+
9 }( r$ G8 b- w* e5 H3 `void OnTimer()
0 N' A9 N: ~9 P& o1 U{
7 j; E: |7 a5 O8 j2 C* jMqlRates cotacao[];1 ?1 g2 g3 c$ @
return ;0 z4 A+ E" y5 W: A8 J9 S
if (negocios_autorizados == false) // are we outside the trading window?2 j6 o6 l% c- u; g* g
return ;
; Y! A1 ^$ t, G' s9 j//--- We are in the trading window, try to open a new position!
. f8 F( {: f; ?3 Lint sorteio = MathRand();: z/ j/ F" Q! s" @
//--- Entry rule 1.1* Z9 ^/ G3 k+ A: H/ u8 |) j
if(sorteio == 0 || sorteio == 32767)
" @3 a* H7 y, `) q# U. @& ^7 wreturn ;8 m# Y, O1 a6 [/ r! g
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
9 R1 E9 C7 h7 U' [4 X7 Q* }2 \{
4 r5 c0 T0 b/ Hnegocios.Buy(info.LotsMin(), _Symbol);( T- J7 m: A$ n0 T0 X
}8 g' ] r+ e0 I! }2 f/ ?; N
else // Draw rule 1.3 -- odd number - Sell
( E- l* X( U$ P0 l. b3 E{
$ Y* V- u( y* D$ _) b5 onegocios.Sell(info.LotsMin(), _Symbol);- t ^& f2 y1 y6 r8 e; f% i
}$ {4 K3 O; X. O; h& C' [* K& H5 y
}
_6 B% W% _) h" U9 Z& b" F//--- Check if we have a new candlestick...2 A6 Z/ k" ^! G7 b( q8 D4 U
bool tem_vela_nova(const MqlRates &rate)
# U, @' p* W- E. }7 h" E/ \{. \1 Q- d- ~% o3 j1 J) ?, Y2 x8 S
{
. D# x+ v% ]' f8 m( lret = true;9 z: |7 }, G/ y
close_positions = false;
" U- E8 d- C6 D% R3 y}
& _+ G8 V: E& T. L% B; qelse8 X3 a' O& n) K, o( h" _
{/ Q+ e% _. l r3 ~0 w
if(mdt.hour == 16)
. R. X$ t8 o" |5 n& xclose_positions = (mdt.min >= 30);
# [& \ ~9 f p: V( O/ o% b}; x# M0 S% S: [3 m
}
0 q4 g1 R8 W: i$ o. D0 creturn ret;7 M1 u3 E9 p9 ^
}
1 @: U2 K/ N0 B) _* o5 E! Z//---
, r' A* F8 W% j. ~( Hbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
" m. D9 P ^5 M/ \& m3 ^/ w% q{) x* h( I6 V4 [, i* I# W9 N8 y$ ?# j
if(PositionsTotal()) // Is there a position?
, l* L1 l6 L1 w) j; i{* B; ?- _) g5 O2 t+ B- x
double offset[1] = { 0 };; R9 t5 u& o( K z# H/ m+ X
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?1 s' j1 O4 W3 L+ C! j3 L' _# G
&& PositionSelect(_Symbol)) // Select the existing position!
9 X# b( M6 @5 u: H5 @% ]; }{9 h; M* ~& K3 _' \) ~, N4 q" A+ C
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);" u7 I$ q4 ?; k) T9 k, l
double SL = PositionGetDouble(POSITION_SL);
& k/ f6 y: g# H; {+ }double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP)); `3 y$ u7 } @" O) K
if(tipo == POSITION_TYPE_BUY)
. x. s5 [* S$ |% h. B{% i3 n- V7 ^0 z& I6 B3 a$ a7 Z
if (cotacoes[1].high > cotacoes[0].high)
6 v3 w( T* F( e{
9 u7 H* x, }% ndouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
& s& X1 X% S: _info.NormalizePrice(sl);! G) E1 u9 E" l8 T/ D/ \
if (sl > SL)0 f. d: |5 F! U; K; r6 L5 C
{
3 P n6 U- T$ x% {negocios.PositionModify(_Symbol, sl, TP);9 I+ s! o9 ^: u, U
}: q2 Q$ o0 N# z% m1 n
}
( n+ Q; k4 U+ e' y/ p8 K4 t3 o}; u2 f. K* D8 z9 r
else // tipo == POSITION_TYPE_SELL
1 T ]( B$ y. ~9 H0 G5 a, {{
; K2 k# x; h1 J& y6 Gif (cotacoes[1].low < cotacoes[0].low): P- g9 F! Y: n- K1 R$ K
{9 ]5 R1 c5 f- g5 B
return true;
' v. J" ~8 G4 w$ j/ Q* V}
- d. _* l4 p& {% q// there was no position- |4 r0 }" T( x$ j) o
return false;
/ ~0 L D9 M z+ d& s}# p1 o" f5 O* M! v0 x. e
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。5 F1 O* T. U4 Z; a+ o- J
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |