启动交易模型,并构建 EA0 r1 I; t, T5 D s$ z6 p; J/ F) }
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。6 _! Y: ~+ b8 z: y3 H( a
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。1 @3 H7 Y# w# o, L2 k8 G+ s' v" r
以下是制定这些规则的代码。
5 r: Z. J% k- q+ k+ I; ^# T+ }//--- Indicator ATR(1) with EMA(8) used for the stop level...2 c6 D3 ~5 A: s+ x1 [
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);" D8 a1 d) t8 |5 Y8 d
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);0 d) L5 q$ d$ L
//--- Define a variable that indicates that we have a deal...
5 N1 r& o& B$ x& lbool tem_tick = false;
b" h! A/ z3 M0 `//--- An auxiliary variable for opening a position- _7 ~. @) x0 _8 K v
#include<Trade/Trade.mqh>
7 |1 x6 e+ {6 @/ H; X" s; u#include<Trade/SymbolInfo.mqh>: T4 V' J2 o" L, a6 i1 h2 b
CTrade negocios;
* T& N: E$ Y9 {' a, k+ wCSymbolInfo info;
8 z; ]% ]4 y* q$ c//--- Define in OnInit() the use of the timer every second
# r! O3 Y, t4 R' R! H. Q//--- and start CTrade
2 L6 i; I" H; G* y: s( n9 `: W7 V* Cint OnInit(). T# O" ~% l- {1 {- m% L6 |7 o% e1 J
{
/ a3 q/ c8 s" C//--- Set the fill type to keep a pending order
9 Z( E' I9 g' x//--- until it is fully filled
' |6 v7 R& q* T. N. ?- H3 jnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
0 O* b/ w2 w8 m0 @+ B" r//--- Leave the fixed deviation at it is not used on B3 exchange
6 \( s6 h' S8 onegocios.SetDeviationInPoints(5);# y8 |- i8 I; H7 U5 d- x
//--- Define the symbol in CSymbolInfo...! t5 x, z# p0 b' T: h! L0 g6 z
info.Name(_Symbol);
' T: N$ D4 t7 v# X//--- Set the timer...
" c. k% V# W1 nEventSetTimer(1);; D! I4 U2 h2 C5 t
//--- Set the base of the random number to have equal tests...
4 R( q6 t L5 s: S8 fMathSrand(0xDEAD);4 J5 |( ^5 n8 z2 W; W2 B6 ?* }0 \- K
return(INIT_SUCCEEDED);7 g6 Q8 o. m+ y% U+ Y$ B
}( k9 V; X% V1 v- ]8 O; F7 {$ s
//--- Since we set a timer, we need to destroy it in OnDeInit().0 c# Y7 w9 Q' K" v& V4 h
void OnDeinit(const int reason)' `+ {3 I9 n, Q* R
{7 \3 w4 Q, @' `0 ? ~6 U- F4 u
EventKillTimer();
' F5 n# e% m0 X: j6 J m5 [3 N}$ M' _, ^1 v- X4 U9 a
//--- The OnTick function only informs us that we have a new deal$ j4 A( H# Q1 N8 i2 Q5 q# J! U8 y
void OnTick()0 Z! A; J9 [7 N k8 z' ]7 g
{
' i7 N! a* f( H% x- Ztem_tick = true;
2 _, a" X% j$ c6 B3 _5 y' p}
/ p+ R$ ?& T! p: q$ I//+------------------------------------------------------------------+; q% P3 ]: ^, R" |# s0 g0 I
//| Expert Advisor main function |3 }% |) g+ R) Z! [) k" W
//+------------------------------------------------------------------+
+ [4 P. r+ v$ K8 H3 \% `void OnTimer()+ E8 s% u, n8 I' i3 S
{+ p' f) N0 X, d
MqlRates cotacao[];
3 F5 R7 @6 T. \return ;% w% a; F8 d! f3 Z- I* |6 L
if (negocios_autorizados == false) // are we outside the trading window?/ Q" F+ l9 ]7 K) q
return ;" Y6 s: R6 [, I" u( ^# ~
//--- We are in the trading window, try to open a new position! ^! P* K" @4 k
int sorteio = MathRand();. R3 X+ n" R6 t& G
//--- Entry rule 1.1
D0 w8 a: Y6 M# f# I6 a) P" Jif(sorteio == 0 || sorteio == 32767)
' Y6 f6 O D; m dreturn ;$ W$ B- ]8 v" X V" I
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy' D1 m$ P5 l! n! y
{
9 L! p& f! P" A6 X6 d0 jnegocios.Buy(info.LotsMin(), _Symbol);
% G, E! ^1 {9 q& x9 t# f}
7 N9 W0 m! q- O8 E Y& E/ d, Aelse // Draw rule 1.3 -- odd number - Sell
: K+ N, T* d% u3 {( ] f5 _{/ z' G+ X! K3 l
negocios.Sell(info.LotsMin(), _Symbol);
" ~8 M6 `+ E' O4 h9 @' l}' c/ P1 h: F& }0 z
}
2 N7 P- Y0 R3 r2 J4 O) j, v k//--- Check if we have a new candlestick...$ m2 U) a8 | r
bool tem_vela_nova(const MqlRates &rate); y/ Y: Z& f6 r
{
5 I) J$ f9 ?4 N0 h7 R{
* m, E% v. ?. Q1 uret = true;
! r- M k& v' R" t. @& V9 Q8 vclose_positions = false;2 B% y1 G, a* P/ H) L6 Z/ j5 O
}# \2 A; N% X. t
else
! M) I1 z" R; Z% y; W% \{
7 O( ?4 K5 B3 ~; c8 ?if(mdt.hour == 16), R$ L, h7 {% [* S( [8 j. b
close_positions = (mdt.min >= 30);4 I) }/ y7 y7 Q0 e* C
}+ @# I5 {$ ?! W# t E
}
; U1 J4 N6 U% @return ret;- ~" @, @3 a. U# O+ C
}
# o6 T( M0 j% }/ e6 }8 s# ]//---
. m$ ?: b6 O9 Z' E* }+ I" C5 X4 ]bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
* ?6 |' A% a3 F0 |{
( @' o3 E/ B# t3 E4 jif(PositionsTotal()) // Is there a position?6 q* y+ h$ A* `! w' D& _4 o2 y, S" f8 `
{
# l! |; T( ?3 K: S$ D9 B* [! \double offset[1] = { 0 };
# e# ]3 v, d2 H ~) W1 C2 [+ ?3 sif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
$ T; c4 o: q8 }. x&& PositionSelect(_Symbol)) // Select the existing position!6 Y" N7 H( ]0 x5 V& W3 P( D
{
$ _7 z- f" m, h$ WENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
. A* R3 F9 R: j! u8 @double SL = PositionGetDouble(POSITION_SL);. `8 c; H& ]$ x, K2 }# T0 |
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));2 R7 ^: ^* T( G# ? S
if(tipo == POSITION_TYPE_BUY)
( V6 F6 d' u; m9 m \7 z; U{/ o4 u" q6 S! L
if (cotacoes[1].high > cotacoes[0].high), x y) t9 U2 k$ H/ O( }; Z" I+ ~
{
) a2 R3 t0 \2 a& ~5 v3 Q) \# R6 Kdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
6 p: Y0 _# J G3 @1 V2 S) Finfo.NormalizePrice(sl);* \+ d! F% }8 O7 \: f! B
if (sl > SL)
- J6 O" y# X+ }4 y2 F{
7 U6 T4 [. y) N5 y5 ?$ R' \6 anegocios.PositionModify(_Symbol, sl, TP);1 c. v9 n! ^& |4 }" {8 C; y
}+ o) B# M' ?3 L* Z1 M6 ]2 S
}
) ]2 f" h, N1 ^& H4 k0 k0 |}
6 r, e- k1 v* J6 Q* c+ jelse // tipo == POSITION_TYPE_SELL
9 c& Q. [8 c) j+ k4 o7 G- S" m& b{( A- A! w/ i% R
if (cotacoes[1].low < cotacoes[0].low)
" v8 o" T5 W; l{
3 g: c# Y9 ?. c- xreturn true;
+ J3 Q6 @! u+ s8 Z2 z}
' @# [ \4 m' j* R" O// there was no position( T( ^0 z8 a2 H
return false;
/ ]: U; ]1 b; F; i) \! T A3 d}. j: A; o& d1 W/ b0 W$ K
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
. V1 x t- P, z m到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |