启动交易模型,并构建 EA
: {4 u7 @* ~. ~# Q在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
; }1 ^4 A2 D: i8 Y8 A" i为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
& m$ a! m4 d; A8 b$ |以下是制定这些规则的代码。
# G* V0 y L5 c9 `+ x9 v//--- Indicator ATR(1) with EMA(8) used for the stop level...% Q! X0 ~6 g3 j! @2 e
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
3 \ U& h+ {, l; [# @5 _. W- iint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
# E: B6 Z) P# S, V- u//--- Define a variable that indicates that we have a deal...
1 [/ e9 _5 e6 \+ @! K7 Q& o6 k% Qbool tem_tick = false;
9 `6 ^" y$ u# J2 S$ p//--- An auxiliary variable for opening a position
& U1 T/ |- @; ^$ ?" ^ t#include<Trade/Trade.mqh>
- m- }6 r) w. U3 Y; S# T/ l `#include<Trade/SymbolInfo.mqh>7 ?$ o; Z3 T: A$ W! C1 X
CTrade negocios;
+ E$ @( g" l7 I+ t' J6 SCSymbolInfo info;% X) P2 ?) c& u9 }
//--- Define in OnInit() the use of the timer every second
: o! d. |- Q) Q% |//--- and start CTrade2 [6 f3 v) G' Z9 [; Q
int OnInit()
* S n) D- Z$ K3 E' R{ W+ v. o! K, R" ~0 J3 r" s0 u" }
//--- Set the fill type to keep a pending order
, Z2 O( x/ ^" d5 N0 s2 H//--- until it is fully filled
5 {: {# i9 F, F& Z+ rnegocios.SetTypeFilling(ORDER_FILLING_RETURN);+ M% L7 V* j) G, l' @9 ?1 z
//--- Leave the fixed deviation at it is not used on B3 exchange
2 B3 n3 V X8 V: l' Wnegocios.SetDeviationInPoints(5);- h& {, q" w2 @ @% {! H6 U
//--- Define the symbol in CSymbolInfo...! ~& A( H5 j: w) l0 j! Z
info.Name(_Symbol);
/ e) q1 ]% A+ T- v; n//--- Set the timer...
. Y7 T( B0 K/ P( w) ~/ OEventSetTimer(1);( ]8 K5 F) u# J3 K7 \/ {' I
//--- Set the base of the random number to have equal tests...
a& s- ^* x' p# s8 ^MathSrand(0xDEAD);2 q c3 @; T4 `% ]1 {- `9 h8 `
return(INIT_SUCCEEDED);6 b5 K. j4 D& T
}6 D+ S6 x7 {0 l6 I* j
//--- Since we set a timer, we need to destroy it in OnDeInit().
) P; U9 q s6 I4 T4 x. cvoid OnDeinit(const int reason)
+ g9 ?$ P8 o/ V{% [5 n5 S8 _8 z" v0 H6 ~1 ]9 }( K
EventKillTimer();
9 B" A' }2 b% |$ O}! z, L1 M8 L! X4 |8 E
//--- The OnTick function only informs us that we have a new deal
' K% ^; P: _4 M5 I D1 q% j. fvoid OnTick()0 |- \* B; P1 M& W: W8 l/ O, \
{
6 ?- h9 O) V" X- v' ]tem_tick = true;
: X6 R* } y& W7 A( F. s0 H}# Z ~0 {7 b4 u8 B. {5 a0 N) v
//+------------------------------------------------------------------+& ?, }4 }1 U7 X& v9 q B
//| Expert Advisor main function |4 |# h! w# v' Z8 I% ~
//+------------------------------------------------------------------+
0 }& Y- y( |( x0 I7 N1 Rvoid OnTimer()9 Z, h; l# R7 d N3 c' q$ r. s
{1 G5 ~/ o3 H- k s& M
MqlRates cotacao[];
9 h* F1 T! N) i* T/ t# y/ ?return ;
3 V6 p7 m. d* M4 H- n5 t; Yif (negocios_autorizados == false) // are we outside the trading window?9 U$ f4 J5 Q1 y3 W9 s
return ;
1 ~: n2 D& ^/ D. k. r* n//--- We are in the trading window, try to open a new position!( D' L' e1 E' E9 `9 Q, m8 e# H+ z: _
int sorteio = MathRand();
- n: o, C/ h* V& t' l# o//--- Entry rule 1.1, E. }* b4 E2 A% G( P
if(sorteio == 0 || sorteio == 32767)
. u9 }& h) Y( \; H( M+ _/ Nreturn ;
6 m' d( N2 a+ M9 Z5 x, `$ hif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy/ w4 ^9 n7 W/ v% \
{/ i9 ]$ u h% r& T# l
negocios.Buy(info.LotsMin(), _Symbol);
7 O" G2 B5 d D* E( v2 H}
1 s8 p7 c( q K+ Xelse // Draw rule 1.3 -- odd number - Sell
' `5 s- z G0 Z B7 p{
) q' L2 @9 z8 G- M: F! P( B1 qnegocios.Sell(info.LotsMin(), _Symbol);
7 T7 P. w1 T: c}7 u* a1 E4 l$ b. H, }
}9 m5 @2 F6 ~# j2 I Y
//--- Check if we have a new candlestick...
( K2 s5 g% {8 [- P [bool tem_vela_nova(const MqlRates &rate)
5 d5 P7 ^- ^ ~% d6 H' [{4 a5 a# F' N+ `
{5 T0 m9 L8 d" @$ w9 ^
ret = true;9 e! I; R8 t8 Z
close_positions = false;
- h. k# g- _; T0 n- R4 t}
7 r/ [ K* x4 A# l3 aelse5 p% z: w% E8 B7 p4 G' O
{' a- B- Y! n8 L7 n g. Z
if(mdt.hour == 16)
; v2 s4 e7 p, C' |# G0 _* pclose_positions = (mdt.min >= 30);
7 Q& |5 `8 F6 v2 p}
0 C+ _+ a% Q; L& J# i& ~+ G- C}$ q. }( Y$ ?, o/ `
return ret;
* j* b) b/ Z" L. u! c}9 p8 k. f5 c/ m/ j3 n) P
//---
$ W' D# e5 c$ \5 C3 D% Vbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])4 y9 b' N1 v2 e/ ]- E
{
" x6 I7 w1 ~9 l3 v3 H! ?if(PositionsTotal()) // Is there a position?7 N8 E$ E3 S, i, S% }
{
0 R, U4 O2 [, pdouble offset[1] = { 0 };, f8 B Z/ m8 |- `
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
! Q f, G7 u6 j3 Y1 r% F&& PositionSelect(_Symbol)) // Select the existing position!
) P( d( [" P1 S, I+ M+ L; h{& l3 I ?/ k0 c5 U
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
% u& K- ] S1 K" z4 H( c0 L# qdouble SL = PositionGetDouble(POSITION_SL);2 ^! s) Q. n& U( d
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
7 O1 X4 K3 D" p" R4 x& }6 jif(tipo == POSITION_TYPE_BUY)! n, s$ q' ^2 _4 T5 T! m# @
{8 M \( H+ I4 t4 }9 ]. d
if (cotacoes[1].high > cotacoes[0].high)/ E0 {+ J5 j1 t( `
{
* Z* d9 ^% M0 U1 [5 wdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
* t0 x% R6 @" z4 [info.NormalizePrice(sl);% n9 S6 z {& ^
if (sl > SL)
+ c. b& [5 C3 U5 W; X7 l5 f{& L0 _5 c5 K# P: `5 W- |
negocios.PositionModify(_Symbol, sl, TP);" j& z1 u3 |% Q. Q$ |; W3 `
}
/ _9 Z$ Z% j* r& q- `}
/ \( _" x n& E, F$ H}
' n9 P1 f( i+ n7 Y' S, H1 Relse // tipo == POSITION_TYPE_SELL3 i4 H- R' t/ M
{9 t' j) L6 B7 D& i' D) e% I
if (cotacoes[1].low < cotacoes[0].low)3 g7 _- O+ K- N) D( r- |0 J1 V
{
6 s( w# @8 g$ ^$ U2 q$ K9 {+ T. Lreturn true;1 z/ V6 O# Z% z. ? _. U
}
, t- C& A1 \: }7 n: k1 ~// there was no position* s) @( `; e" W/ z* @9 t0 }
return false;4 d# i, i( k0 Y1 E& t- L
}
& {" a$ x, ?5 v我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 i( `" v- M; g, Z0 a
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |