启动交易模型,并构建 EA. @' _% p, e" {. S: H" F' z& @
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
. V9 W% x0 p7 w7 z! ?- T( C为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
/ s. a; l, |" y& J+ Z; H/ n以下是制定这些规则的代码。5 X. U6 k2 s; W6 F# g+ |
//--- Indicator ATR(1) with EMA(8) used for the stop level...
7 G5 \2 Z/ c+ B' C3 {& \int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
( Z2 ^$ A4 n! d D; K" }int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);6 ^ a+ ^2 C4 i7 s$ t+ m( T
//--- Define a variable that indicates that we have a deal...2 p% z8 G! D3 S. {9 f
bool tem_tick = false;
- Y1 }2 C5 k: e4 ~$ Q. L- _//--- An auxiliary variable for opening a position
; W: I% h# V- ]8 @1 U1 V6 ]#include<Trade/Trade.mqh>+ _! W% I- M5 B' v
#include<Trade/SymbolInfo.mqh>
: y" w6 A4 A* ?CTrade negocios;& _0 h: a) ]$ C6 `4 u# W
CSymbolInfo info;
$ `3 x1 R. e" a) x//--- Define in OnInit() the use of the timer every second5 T( T0 Z( I U6 N! [% N2 D0 ]
//--- and start CTrade( {: f; Z9 U4 N8 H% x) J% z, y
int OnInit()5 e# s% z0 J8 n' u- X
{; G; Y* X* I$ x9 a6 |* W ]
//--- Set the fill type to keep a pending order
% V: Z- U9 K7 G% Q8 T L3 L//--- until it is fully filled. k* u, r7 S! J" Q5 x% a9 E! t+ U
negocios.SetTypeFilling(ORDER_FILLING_RETURN);+ Q/ M: y2 r9 ^3 g' `( L
//--- Leave the fixed deviation at it is not used on B3 exchange
2 _8 X/ C& i* }! q: Cnegocios.SetDeviationInPoints(5); H+ i3 C% ?5 {, I
//--- Define the symbol in CSymbolInfo...2 \- [) t% e% V" U
info.Name(_Symbol);+ I* q F% i. ?& ]" F6 S% l
//--- Set the timer...1 w* p f, u! Z* l5 w# G
EventSetTimer(1);
" \) l9 v* m$ A' r//--- Set the base of the random number to have equal tests...5 X' s, ?" h& G; p: S
MathSrand(0xDEAD);
0 s* L$ W1 S& c3 f3 ]( preturn(INIT_SUCCEEDED);
: x$ D: B) r6 @6 p! M, f) K7 i: G}
! l$ ?5 O8 i5 ] a$ B4 Z//--- Since we set a timer, we need to destroy it in OnDeInit().
8 y% f7 S! V1 t9 q' yvoid OnDeinit(const int reason)' g+ j: x0 ]1 h; q; P- a8 @
{1 V+ l# N* f3 T0 w( U
EventKillTimer();) v6 i- D9 u8 \ A& \6 ?( E
}- A, l* U: Y- `. `2 N% Z/ p
//--- The OnTick function only informs us that we have a new deal- o! \0 ]( V6 g9 C7 o3 B
void OnTick()) {4 Q0 h/ _* _4 H" A6 z
{. @( y+ D* _- J+ b& {/ d! Z( M; L+ O9 x
tem_tick = true;
1 ~ H9 Y; [/ D$ l/ X. h5 F}
# r T. p( F m//+------------------------------------------------------------------+9 T% X7 P* d/ l5 P8 e2 k1 e) ]- O5 l
//| Expert Advisor main function |) a* i7 G( V, a
//+------------------------------------------------------------------++ e# q% P1 E6 O* a6 u
void OnTimer(): ]8 J! T; _% V
{8 e, h$ A6 [1 k5 }: _3 J( b
MqlRates cotacao[];
; P, [# c) R" o- p' M) T& dreturn ;/ N1 g7 Q9 o" k1 [( v- |
if (negocios_autorizados == false) // are we outside the trading window?
) B9 @: a, L0 zreturn ;
( [( r2 z* X5 j+ u- w. r//--- We are in the trading window, try to open a new position!
% p6 }; y& [" D1 h2 x9 B8 f0 |6 j- W1 ?int sorteio = MathRand();
) m; c% P! o. E6 ]//--- Entry rule 1.1
8 W8 L/ w! u5 n& }; c- w7 ~if(sorteio == 0 || sorteio == 32767)1 y @: g. [! \. B- q8 F
return ;
2 _+ I( W4 x/ ~if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
: F+ T; ^& J( G0 b$ f" [) H3 D1 {{
. X4 b# U5 z6 l t) Y# j$ rnegocios.Buy(info.LotsMin(), _Symbol);) k% g! x) z9 u
} A8 U! }, O, Q
else // Draw rule 1.3 -- odd number - Sell0 U" I, O8 s& H: b5 G
{4 B- l4 _* T5 k
negocios.Sell(info.LotsMin(), _Symbol);' ^* |7 S* J# @* @% M8 y
}
- S% v1 P( L3 e8 f0 f* F. l. ], [}$ z/ a) X( h% e1 h& O5 y& Q
//--- Check if we have a new candlestick...
6 V: F( u; ^6 w; D8 ^3 Sbool tem_vela_nova(const MqlRates &rate)
, q! D6 c7 j+ ^7 L7 g{# C3 i' p2 {7 M/ ~$ T6 ?
{% w. z1 b1 p: q* T& ?
ret = true;
- V" e# q2 R, v1 ]7 ]' mclose_positions = false;6 M( w8 C. E$ L }2 ` ?7 Y' ]. q
}
) v. y6 x0 B, @else
# f! X9 S# e9 m# N r* u4 e/ O: f% A{
4 B" y, A) a. ~- c/ V1 [$ N6 ]8 S7 tif(mdt.hour == 16)
$ Y1 |0 f) U$ c' ]# wclose_positions = (mdt.min >= 30);
- W2 @3 d$ x: v, J/ }9 g}
+ d4 B) X9 a" i. M* i) y& }! _}( X0 C/ o8 ~; b3 a! Z
return ret;
5 [% o( q' R) w}
6 L" P& a+ i# S//---
! N/ p: O& W: ebool arruma_stop_em_posicoes(const MqlRates &cotacoes[])0 o1 Y( [ C: f: D9 [, j# F
{
4 m, n) N: L( @if(PositionsTotal()) // Is there a position?
3 [ E' R" L0 o# l- m{
& G: I P; I% k& y* |( \: O- zdouble offset[1] = { 0 };5 w. D7 u. t& u/ S
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?! E9 {6 @" y, n6 u) O1 V8 ]
&& PositionSelect(_Symbol)) // Select the existing position!( Z! `7 `( v' S' K
{$ K+ s( |2 I/ N5 j6 p0 R
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);$ x) @# k8 K7 p" g4 u) X
double SL = PositionGetDouble(POSITION_SL);: }/ \+ a5 b7 K" Z: b" N
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
+ e6 s( Q2 u1 `2 V% v1 V. {if(tipo == POSITION_TYPE_BUY)7 p9 i T# I. z
{
- v/ m0 a9 I* Qif (cotacoes[1].high > cotacoes[0].high)8 q/ @$ Y9 {! i
{: c9 G1 V! h5 w4 d: ^
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
0 B$ n$ O/ m8 F1 Y7 s- vinfo.NormalizePrice(sl);
. k0 v3 Z8 V7 X& _" F7 A4 wif (sl > SL)
' B2 g& ?# \- l/ E{ Y' g( C) m; w3 e; P
negocios.PositionModify(_Symbol, sl, TP);
* B" P0 w9 Z* Q( v+ i# _. \, r}5 ~8 p5 M; ` G6 M
}/ U g7 l7 n" A; W4 X6 _
}
; f1 }9 `' z% F% G0 m* I/ `else // tipo == POSITION_TYPE_SELL6 g( t0 ]3 C M2 c! `5 ]
{; o+ P# Q" o2 t1 }1 {
if (cotacoes[1].low < cotacoes[0].low); G8 G% V( i) u" Z
{
8 D5 \% M$ V$ d5 B5 C* F7 jreturn true;+ Z5 h1 v* h9 r" w3 G* V
}
' F7 u# \, g( d$ U" W8 o: w; z// there was no position) {% Q d1 _1 v7 B1 c, F
return false;2 n& R# n( s: y5 f9 W
}
) ]- N% N# s1 ]$ z5 o0 w我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。8 B4 ]0 r) E& P: b% E' F4 N$ d
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |