启动交易模型,并构建 EA: ?. ^9 F9 y! E6 F9 ^
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。, L: \# s$ f+ I
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。 L/ X J2 @( _4 L
以下是制定这些规则的代码。. u/ b4 j' D0 i& o$ `$ R
//--- Indicator ATR(1) with EMA(8) used for the stop level...# M% A( l0 g" k/ L' R
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
3 e! H( @* [+ f9 X# t& p: Qint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 E7 M- b& j7 d, z/ K7 V) c//--- Define a variable that indicates that we have a deal...
: o" ?* T. l6 ^ y% ?- Dbool tem_tick = false;
0 ~1 h2 M" U- Y0 |5 c* q9 _//--- An auxiliary variable for opening a position+ _. C' D: m0 l- s. g
#include<Trade/Trade.mqh>
/ }6 A) U8 X5 [& K/ Y5 Y3 V! Q#include<Trade/SymbolInfo.mqh> B" l% p. _( |4 G ]: n
CTrade negocios;3 k5 U( U" U/ k; ~$ H! j$ M
CSymbolInfo info;
3 K; U/ S$ L( O5 ]) c4 E' e# ]//--- Define in OnInit() the use of the timer every second# h0 R2 ~1 R" O
//--- and start CTrade# R! m1 p- e, i
int OnInit()/ W- \! s1 a6 P4 n( h
{
: n1 N- E) m' H& c4 O. c! \//--- Set the fill type to keep a pending order
/ j7 A% Q2 A) p) l6 S- Y//--- until it is fully filled8 ^/ U) R. e8 w7 B, [) X% v
negocios.SetTypeFilling(ORDER_FILLING_RETURN);; [, ?; K) Q1 ^
//--- Leave the fixed deviation at it is not used on B3 exchange
( t* W/ U6 o( R( t& anegocios.SetDeviationInPoints(5);
. I* @6 z2 L* x ?9 _//--- Define the symbol in CSymbolInfo...1 o) i$ f5 ~) `0 T6 T
info.Name(_Symbol);7 k" P2 O5 Y, o! f7 r% h
//--- Set the timer...! a$ E/ K M- ]# p
EventSetTimer(1);
( e, {& z; z- ?//--- Set the base of the random number to have equal tests...$ ~" X# t( J9 o9 z& R, Y
MathSrand(0xDEAD);
[! G* O# G" g; P# }return(INIT_SUCCEEDED);
7 s8 N* D+ w. Z* H, S}
; ]% ~ L( N+ A, R//--- Since we set a timer, we need to destroy it in OnDeInit().
7 s* m# r" G! z- e* U: R: ~* ]( ]# svoid OnDeinit(const int reason)' O6 C; v3 e K( _3 {9 A X: I
{
7 V d! u* ~7 E2 p# H$ J4 rEventKillTimer();8 Y" n% }- }" V9 t9 \
}! j7 X* l: j) b6 y. ]6 N }6 @
//--- The OnTick function only informs us that we have a new deal
- v$ E9 R" }* {* `9 i1 n1 h" Dvoid OnTick()5 O+ H6 H/ u# @9 r% v
{
* v9 X, b- g( R+ ntem_tick = true;
. h; G# i ]% Q% `- A0 r, {}
Z* t- z+ m! V) |- X4 B4 K//+------------------------------------------------------------------+
/ t$ q; a: x) W( z% {. a//| Expert Advisor main function |
) i5 @$ [/ N( p ?' U/ o" C1 q8 H//+------------------------------------------------------------------+
4 r0 H7 H, u8 g! _9 avoid OnTimer()
2 V K% e" Z2 V9 [1 w7 d{
4 M9 b+ R+ M2 b# p& m, yMqlRates cotacao[];. a9 y5 x$ G9 S. n" u4 s6 o Y
return ;/ ?0 X) C+ D! z6 j6 g% {
if (negocios_autorizados == false) // are we outside the trading window?
( f* g3 r' R& t, Q& zreturn ;+ ]- t9 O# w D6 o3 O; b9 N
//--- We are in the trading window, try to open a new position!$ ]7 C* t1 {$ n/ g
int sorteio = MathRand();
# C: U5 f5 n9 i3 j# \* T3 \//--- Entry rule 1.1
# y, s2 P( B! F& M& E5 c9 O3 D6 kif(sorteio == 0 || sorteio == 32767)
8 w/ r! `, \. ~, s6 @return ;4 Q1 h! q2 m5 W
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy# q- t G" V0 z/ @- T* s- [% r, O
{
+ l& m) ~( w2 c( Q. n' Q( X6 pnegocios.Buy(info.LotsMin(), _Symbol);
- e) O& L# B; {- x1 u0 N' M; q}0 ~9 I$ W0 d d8 m4 j
else // Draw rule 1.3 -- odd number - Sell7 N# \4 B! T6 \- t* s+ u
{* K: p) {% Y+ Q/ ^1 d
negocios.Sell(info.LotsMin(), _Symbol);
5 c$ G, v* Q0 y2 b; w}8 v4 e. U# g b% y e( W2 l: v# `
}
' Z# i8 ^$ G! y//--- Check if we have a new candlestick...2 T8 d( c4 Y( v$ V4 u
bool tem_vela_nova(const MqlRates &rate)
5 c% M# _" b4 ]$ M9 W- m( {0 ~0 N B{
& h! y0 L" ?* ?8 J{
; N3 u! Y( ~. C3 Bret = true;
: L, W* d2 e4 z. Z5 K' u8 Kclose_positions = false;
v& v" J' b. Q0 z5 q$ ]1 m1 q}! k4 j: d3 o. V! N, G
else
9 ?5 c$ {# V$ Y/ R8 X{
! y" i5 i' m* h" ~4 O: W- T eif(mdt.hour == 16)$ k: ?% t+ E+ R7 C
close_positions = (mdt.min >= 30);
, l6 g- A' T8 v e0 U5 S}9 }8 F: A1 i2 M* b) B8 N' x" S1 X: o
}
* D2 Z$ V+ s# z" W1 ~return ret;4 N, e% u3 F; W, x; O- a
}3 f* N4 t: C3 c
//---
' B3 X" F2 h, @) kbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
7 e9 J$ v6 `/ X( \$ T) Y{
1 n, a, p0 X8 v S/ T2 l& L3 Uif(PositionsTotal()) // Is there a position?
! r$ A4 l6 ~" L o- n* U{
0 v" }* P8 |- R* R( ]double offset[1] = { 0 };
& I6 @/ [* c0 G) v1 J- D3 }if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?7 D6 W2 h! q E4 I0 m: m b
&& PositionSelect(_Symbol)) // Select the existing position!
+ ]- C( Q/ o ?+ |6 ~: h1 S{& p: s, U) P5 R: q; \( [
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
- L; P; y! ?1 r! N. Z3 Ddouble SL = PositionGetDouble(POSITION_SL);" |! ?; e0 G' v. S
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));2 Q v: e. h' M2 s8 a
if(tipo == POSITION_TYPE_BUY)
: T# C, ]6 [: T$ U! ~4 p{
( @: Q: y; `/ O8 O: Nif (cotacoes[1].high > cotacoes[0].high)4 Z6 N, Z$ B4 u0 M/ \
{, y1 B9 L% e3 |$ L1 W* j c9 U
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
# X8 v5 i G1 f% H! N- z. U* sinfo.NormalizePrice(sl);
3 ^9 b; m- H' F5 k F( @, `if (sl > SL)* Y" _/ Y5 d9 H! O
{
# g3 P2 B, L. u. Y anegocios.PositionModify(_Symbol, sl, TP);
+ T8 |& A, P3 ~7 C3 |. x/ ~& }}
2 N' @% ^+ N' @ X; e) [}
- ?, ^% t$ G2 \}; G$ V1 j0 x1 Q: t
else // tipo == POSITION_TYPE_SELL4 V! ]6 ]2 n F } p+ x9 f; e
{% }0 C! y; ?: E" J) Z
if (cotacoes[1].low < cotacoes[0].low)
- r% Q1 R) W0 x! ?{
6 _$ r3 E; V5 u& K8 }( ]1 lreturn true;
+ m# ?1 I2 F7 z) `! n7 \' `}
! B$ f2 h. O. l7 s+ @# V( M5 n// there was no position
, Q9 B$ r! o6 S1 p% rreturn false;3 a. P- v" i- h& o' C) @. b! j5 q
}
5 L* C2 Z4 I/ v% K' J5 F! D我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 u' X X1 ~( u
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |