启动交易模型,并构建 EA+ d0 `) b+ e+ I! @, P6 X
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。2 g: O( K& { x) x8 q( C; F' \
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
0 z! f+ L$ N4 c* R2 O以下是制定这些规则的代码。8 x& O, Z' x/ l! A9 J, i+ n1 ^
//--- Indicator ATR(1) with EMA(8) used for the stop level...
& K, ]9 {3 q! S% A& mint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);% N7 R( L1 A8 C2 M' ?
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
. q3 e( y, r- q7 u0 G$ u& ]" v//--- Define a variable that indicates that we have a deal...
+ H8 {* e' K7 i4 f5 s1 w6 r0 ^bool tem_tick = false;8 w. C" R. P' o2 v& S
//--- An auxiliary variable for opening a position
$ e9 H# M0 c5 R* `2 u# E#include<Trade/Trade.mqh># E! ^4 W: }3 ?- P' \- f; j
#include<Trade/SymbolInfo.mqh>! _ M# G! G7 c
CTrade negocios;. a0 n3 a" {6 m! f1 t
CSymbolInfo info;/ Y9 ?; R: A" g6 @9 O
//--- Define in OnInit() the use of the timer every second% w" D0 Z9 J( c
//--- and start CTrade
% ~. g7 Y7 V R% U" wint OnInit(); ?5 L/ w# d+ P! ~8 a$ o
{
# H5 Q* z- C: H$ {//--- Set the fill type to keep a pending order
8 Z8 h# i, q0 {1 _5 @- a//--- until it is fully filled
7 @, s5 }. ^" ] J" @8 E$ \' z @negocios.SetTypeFilling(ORDER_FILLING_RETURN);/ [" h; w* m. h2 m# b
//--- Leave the fixed deviation at it is not used on B3 exchange Q3 [: T9 ]9 }: i, z
negocios.SetDeviationInPoints(5);
# A7 f# t* V/ U3 t//--- Define the symbol in CSymbolInfo...
( O4 e, U1 d" Yinfo.Name(_Symbol);4 P: D) }% ?. C$ L
//--- Set the timer...8 c/ l# J6 `% q4 a9 i( X( P! X# s
EventSetTimer(1);
3 R1 n- o! T+ ]- s7 j) i0 f: K//--- Set the base of the random number to have equal tests... @3 J. ?0 ^+ Q) Q. f* M# ^' p
MathSrand(0xDEAD);
/ X4 q/ `* E" P J }* L- Dreturn(INIT_SUCCEEDED);
' h# S: W1 R/ C5 V! e}
0 a' C* Y" `2 c% S2 l//--- Since we set a timer, we need to destroy it in OnDeInit().+ o4 q1 \3 y$ U
void OnDeinit(const int reason)
, G* p2 k8 |5 r. l) b( ?{1 N3 t9 u2 ?6 H5 h4 H# g& q
EventKillTimer();- G7 [" k! s0 i7 C" f
}
8 u- }5 K" C- w2 n, O//--- The OnTick function only informs us that we have a new deal8 @1 n" s x. a0 S: x
void OnTick()0 J3 s8 u5 _- F1 c; n g8 G" z. F
{
. n. v, W; V8 Q6 C0 h- R7 ktem_tick = true;( b+ S% o% ]; j/ b
}
1 Q5 c0 I S3 N1 X6 N+ a; l//+------------------------------------------------------------------+
$ e8 n4 r: K3 e5 z9 ^//| Expert Advisor main function |; G) H9 I9 n! M- f8 [
//+------------------------------------------------------------------+
4 F4 T) Q8 ]7 o8 z, l) {$ M$ zvoid OnTimer()
) K+ Q' H z2 O# f{5 \& |! n6 P3 ~
MqlRates cotacao[];
- R) L# y0 N7 I; hreturn ;
4 F0 I& \ [' w% tif (negocios_autorizados == false) // are we outside the trading window?& W. K/ A* K7 x% |3 D' y
return ;
+ l' |- u/ G. z. e9 c//--- We are in the trading window, try to open a new position!
" {6 {+ X* t* @. |( Q7 G! eint sorteio = MathRand();
8 t1 @4 v1 {1 `: A* r//--- Entry rule 1.14 b: p8 I, g; v2 J$ G
if(sorteio == 0 || sorteio == 32767)$ m( N) e# {% ]' w
return ;
7 y" X( m9 N* L' b& |4 K1 m; m/ Y* o" xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
, K, P2 L+ i2 S. a7 ^{
0 U+ X5 t- |8 o* Cnegocios.Buy(info.LotsMin(), _Symbol);
& x$ d7 V7 J3 B; o- e# V c6 G}
# Z- G5 E6 O1 g0 B4 ?0 Selse // Draw rule 1.3 -- odd number - Sell
F. \7 q/ M% G; r" ^6 X{
0 x7 v2 d* d5 C, u* P$ W( B; Enegocios.Sell(info.LotsMin(), _Symbol);
3 [( O! m! l8 g/ t% I: {}
* w" l2 M+ @% Z2 k- X) e1 J}
1 x) l( g) D( }* X( c! R//--- Check if we have a new candlestick...
# L- v! U; S% L- E% ]/ W5 \! w$ `bool tem_vela_nova(const MqlRates &rate)
& j" h8 ]; J/ [# j8 N9 ]{
# J0 J3 R* T2 B{
) R9 t' _* `! `5 p0 R& x- ]8 e& K) }ret = true;1 \0 i; f+ ^+ ~3 T& F/ d
close_positions = false;
# j5 X t Q- z( V6 n}
{* X1 {7 ]8 {/ z! Y4 Velse# U8 [, S. j- r* l
{0 ^9 P9 P+ \) ^* J6 f) D. n/ l
if(mdt.hour == 16)
) G; @9 p4 K0 t1 ]2 c% T: Mclose_positions = (mdt.min >= 30);$ r* x& p4 u- n) e7 u
}
3 u8 N' {* `2 |! h* N2 O}# t% S# C. T0 S" e
return ret;# ] ]; w5 E+ p2 O
}
9 w" X" c" U% ^- |1 V//---
7 @8 s1 v3 \. ?bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
5 b6 {1 ^. O% ~ `1 o{! L3 r1 o9 z! q3 ~5 s, l ]
if(PositionsTotal()) // Is there a position?
8 B7 g; U1 i P0 y, `8 {# M0 n{
& m$ \! d0 ~& h4 N jdouble offset[1] = { 0 }; o4 N* J9 e: p; i# ] z! m
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" W6 E b, B' a! e# R0 Y- \&& PositionSelect(_Symbol)) // Select the existing position!
9 C1 P2 `, J' V2 R( I6 @7 B! ]{
: z: O8 d/ u2 h0 I1 DENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
! O3 q! _3 K! f1 O. M2 w+ tdouble SL = PositionGetDouble(POSITION_SL);
" m" d- L& M4 Q8 c+ P; n0 odouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));3 y' i( |! b, ] g$ h H2 K
if(tipo == POSITION_TYPE_BUY)
9 o5 V. [. |3 s7 T% e# b3 q{
6 N* x6 I, ]+ F& P' @if (cotacoes[1].high > cotacoes[0].high)
1 K( m% D% ?, F3 R- q{
9 a0 Y1 X0 [/ w2 X2 z$ w. n3 b) zdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
0 W8 j. e2 ^5 q0 n( |- Vinfo.NormalizePrice(sl);
$ e( ?# e6 {+ Sif (sl > SL)
* t! X" C1 W1 ~5 ^1 x. @! M{0 E( s: z& P U( f& y8 }% B
negocios.PositionModify(_Symbol, sl, TP);
( O( J7 g$ p* l" {' C1 o}8 H+ j# E3 Q2 F1 X. D/ h. m7 c
}$ q( P! @ C! t Z( i$ g
}0 k% d* e# c& m6 T
else // tipo == POSITION_TYPE_SELL7 K4 k; n6 d1 n( D$ \- V {
{* s: W! U# w, }$ E
if (cotacoes[1].low < cotacoes[0].low)
+ ~2 I; G' t$ a- }: v: D2 L{; W& U9 u2 r( Q. `) J, ^' N. p
return true;
: ?! p0 f- Z; Y/ n. s* d}. M! S6 Y7 m4 Q+ }9 }2 c
// there was no position
0 I5 h, t, O. I, B6 y. i% Creturn false;
/ D' j# X2 o- } l+ t" L}/ C8 u& L" H' [
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。# P( Y; L) I. l3 G
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |