启动交易模型,并构建 EA
4 U' q, k1 V& n在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
0 j! R7 v) q9 L6 Y |' N为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
; R h# X# d% v: I u2 |以下是制定这些规则的代码。9 }7 n, B1 U, R% X9 a7 b6 A5 B
//--- Indicator ATR(1) with EMA(8) used for the stop level...
! J& T' {2 `0 cint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
# l q+ K4 I! B3 ~: d: yint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
; H* L# {! C( ~: F4 y' a//--- Define a variable that indicates that we have a deal...
, [. C- S+ V5 i! y; qbool tem_tick = false;1 k, c+ s( X2 v2 f0 [) ~
//--- An auxiliary variable for opening a position
* J* y4 ]2 f* d$ L. q. @ I" n#include<Trade/Trade.mqh>
7 K+ ^3 _8 P7 B6 P# q- l#include<Trade/SymbolInfo.mqh>
( Y4 q0 i; t% |( O- ^) H7 fCTrade negocios;
8 P) Q3 c) |, C6 D% n& nCSymbolInfo info;
5 w. x9 `; a J5 {1 S" S8 E" ~//--- Define in OnInit() the use of the timer every second
. z! b% f5 r0 t S- ]& C% v//--- and start CTrade1 c6 l& \0 _% j4 C
int OnInit()% ?1 Y: @8 r j
{" _6 O% `$ T. w& K; Q
//--- Set the fill type to keep a pending order" d1 a8 {! T+ _' ~
//--- until it is fully filled
8 n: T( d% W# R; Pnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
1 m% S/ j% o, h//--- Leave the fixed deviation at it is not used on B3 exchange4 r# r/ ^/ y. f. ^1 ^, @
negocios.SetDeviationInPoints(5);; U* @, H1 c0 W
//--- Define the symbol in CSymbolInfo...: Q4 j4 X0 t: m; b; C$ Y
info.Name(_Symbol);& H) Q L) ]2 j9 k* f
//--- Set the timer... ?: A7 Q5 D+ r' q2 u. N3 k
EventSetTimer(1);( D1 _! Z! X6 G
//--- Set the base of the random number to have equal tests...
! S" l) B' ]5 WMathSrand(0xDEAD);5 W; R2 U4 [9 g. f6 w. |0 r
return(INIT_SUCCEEDED);! h) Y+ O% v. C) g. G, d1 g) ^
}
' ~+ e. L& I' i2 y//--- Since we set a timer, we need to destroy it in OnDeInit().$ x- P( c. f5 B- ^
void OnDeinit(const int reason)
$ D( [6 k. F! @# S* O{
# b0 R7 H$ V4 pEventKillTimer();* [$ {. B: |9 G0 ^
}
, }, w- ~9 Y) L- ~, o/ N. I" ], h$ h//--- The OnTick function only informs us that we have a new deal Q' b( m' _, _" `1 v$ m
void OnTick(); o2 M) G. |. w5 D( W* ^# t
{/ K) Y6 V7 X2 B# W5 P5 r/ A" D
tem_tick = true;0 t- e( P0 M9 p# |
}. k/ L* |/ A9 V
//+------------------------------------------------------------------+6 ?# f6 U1 p* x1 A; h5 Y% m. N9 n
//| Expert Advisor main function |
* {. {8 X- w# v* d0 M6 n! `+ O//+------------------------------------------------------------------+& }0 j% E) e( `/ m5 J
void OnTimer()9 i+ f, y) d+ i$ d" S
{
1 T, Z$ m% D- a1 ~) uMqlRates cotacao[];
/ h T; C) T5 n) _* f+ Xreturn ;
( \# z8 i8 u h: D/ z% Nif (negocios_autorizados == false) // are we outside the trading window?3 @% U: k6 s# O5 b$ W1 l& @# e7 {
return ;8 o+ O8 O5 U4 Y! t7 O
//--- We are in the trading window, try to open a new position!
+ T& w7 j0 ?8 \6 g* kint sorteio = MathRand();' }! i3 @" _( _: V* w+ B& L
//--- Entry rule 1.1
2 K6 E/ Q+ [ \if(sorteio == 0 || sorteio == 32767)
. w* z, W a) l, k8 m6 T1 _" y3 qreturn ;$ G! s% F6 `& k$ ]7 ]
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
6 T$ E; B) V4 r6 J, q{
u6 b `# f; V$ o) P4 znegocios.Buy(info.LotsMin(), _Symbol);" M u2 o3 t7 H2 \: B6 w9 d9 f
}6 a$ V) z3 o6 z3 A" A- ?# d
else // Draw rule 1.3 -- odd number - Sell* N" `" y6 w4 f
{
/ b$ t7 }$ F3 D9 `- Gnegocios.Sell(info.LotsMin(), _Symbol);* A0 T/ g, x1 j% n; f2 R0 m3 H ]4 Q
}
: }" f* ~$ T+ @' T, b}, p* J# ]5 f/ @6 n ~. P) u3 ]
//--- Check if we have a new candlestick...
3 J) V' |9 g+ W$ h+ g0 Y% \bool tem_vela_nova(const MqlRates &rate); k- ~7 v- ~; Y6 `8 N
{
# `8 _- w4 o# q+ h' [1 r$ D8 c$ w{
1 T) x% G- ?: \- E# T8 G4 s# Eret = true;0 u0 f g3 S( G) G+ b
close_positions = false;
% c& n, i' @4 Y' j& p: a}( B# M& _; I2 A3 l: w( W
else
' D+ B+ t/ J0 a( M; H0 h4 S9 O{& f) d M, R% q/ ?$ ?, [
if(mdt.hour == 16)
+ B4 S# P3 x' M P8 R6 k$ s5 aclose_positions = (mdt.min >= 30);
% x7 H& n8 H; h9 M}
7 \7 m8 Z5 F$ t f0 e; J8 l; z$ ?7 b}
$ x! i, b! p w# Y- [4 E' @- k/ C2 Rreturn ret;
+ c# v, A0 d9 q) O7 z}9 L. h z* U( k
//---
. v0 F- P8 u/ h; @' L2 T: Xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[]); I+ n; p3 K1 _4 @! ^
{6 A6 @( s: i; z8 a) b7 x
if(PositionsTotal()) // Is there a position?& g! d1 x | ]/ ^# c3 y/ l
{' u6 A: H. |/ ]% [9 k
double offset[1] = { 0 };4 r" y M: }" N8 `( R, y
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?: A$ G& q5 R1 e; H5 @- ^
&& PositionSelect(_Symbol)) // Select the existing position!
& H+ ]5 h3 K! i- D3 L{
5 o+ n0 x! w. d* J* YENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 z6 p# A3 g- S8 W
double SL = PositionGetDouble(POSITION_SL);" R- Y- D: _% u, s
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));7 l, y, S7 Z' j! F
if(tipo == POSITION_TYPE_BUY): L/ W. _1 ^2 c7 q* }1 e
{& F/ R) Q& z% v: T' R# v
if (cotacoes[1].high > cotacoes[0].high); Z( z: C' `- w( [; n
{
( N! Z1 ?0 C- l1 i) n/ gdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 s/ P+ B/ u9 _* u) e
info.NormalizePrice(sl);
# P+ P. L8 E2 ^, m4 f' w' a% }if (sl > SL)3 s0 r. }7 G) ~9 \/ s. J
{
2 U, F+ }3 X6 C- W: p+ ]+ ^3 Ynegocios.PositionModify(_Symbol, sl, TP);
6 m% _& k$ R; U; z}
' c8 T J2 q" b/ w6 ]: E( Z}- H' O" X' T0 r% i2 ?
}
- M5 l, \ D% a0 ?9 s. K4 N+ \else // tipo == POSITION_TYPE_SELL# w2 x8 v' |" \/ }5 B6 V7 I e- q
{, \, s. A- _9 o
if (cotacoes[1].low < cotacoes[0].low)( }1 T* T# [% N. y2 g
{; E( p( r5 Q, i
return true;
9 W0 E# l) V$ t' s}, y" g6 A' g e& v( x; K( t/ I
// there was no position/ Y0 x1 y( g3 k& e! u O3 h4 K
return false;$ o f9 v' n9 e5 c
}1 a% |1 ]3 L5 z4 d
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
- \. Z5 a/ I, U h到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |