启动交易模型,并构建 EA
$ G0 p# b. r! O3 b$ j1 i+ q0 B在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
" V2 c, n' X3 l0 d% i m为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。) C2 u& I4 g. k, A
以下是制定这些规则的代码。
: _+ A& W: i2 S$ m) ]: b//--- Indicator ATR(1) with EMA(8) used for the stop level...
1 l6 w. P# S6 Z) S+ X( ]int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
& L+ }& X4 B# _2 a# ~. a" S- l7 vint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);9 W, X6 L1 ?, v) ~8 t Z
//--- Define a variable that indicates that we have a deal...
, ^0 ~2 M; t5 d* `bool tem_tick = false;
9 B6 Z1 }6 i" Z5 c//--- An auxiliary variable for opening a position) @, p8 Y4 N) o# J
#include<Trade/Trade.mqh>7 w/ m; i# f# ]$ O; o5 W
#include<Trade/SymbolInfo.mqh>
! O2 Q4 K( ]5 Y1 u+ Q8 _1 B# I6 K' }CTrade negocios;
5 B# A; ^/ Q8 X" t0 t0 gCSymbolInfo info;
. u! x- Z6 Z% }& {3 D, Q//--- Define in OnInit() the use of the timer every second- M7 n; F0 O e# y
//--- and start CTrade# S6 o. r! H" t6 u* S e/ L2 D& a
int OnInit(); G9 s: O: |) c0 c
{
4 H; V' l: L3 ]% m- s//--- Set the fill type to keep a pending order( \2 I. C) N9 K2 ?. O0 K. b- C
//--- until it is fully filled% x C' C+ s0 n6 j
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
8 m' q, M+ \' Z/ m( Y( f//--- Leave the fixed deviation at it is not used on B3 exchange) s7 W# Y; i% Y1 F
negocios.SetDeviationInPoints(5);
T2 ^+ P8 Y0 @; j; x) D6 S% j/ f( j/ d4 ^//--- Define the symbol in CSymbolInfo...
" \* ~, M o9 v7 m7 E3 I4 H' |) Q3 Jinfo.Name(_Symbol);
$ G5 D/ Q6 Y8 ?, L: L9 B//--- Set the timer...
. P6 |) o' ^# I+ f. YEventSetTimer(1);
# \& `! }' y; p1 J6 E3 Z4 L% z//--- Set the base of the random number to have equal tests...6 o& A1 n- G T5 c
MathSrand(0xDEAD);
) f8 e: A* ~. ?) z/ A2 Qreturn(INIT_SUCCEEDED);4 P9 e# b5 l0 I1 A
}
. @, ~* ?; m% i* ]//--- Since we set a timer, we need to destroy it in OnDeInit().8 D' D- q6 v& k5 ?3 J) [
void OnDeinit(const int reason)
: w" ], Y% Y$ G% Z( f. r8 ^{. L0 i0 G2 W; e' v5 }5 W
EventKillTimer();/ n' [) R7 C- A/ I# A
}" w- Q. e: }: C8 r# P; Z. ?
//--- The OnTick function only informs us that we have a new deal3 i% c! r; k) M5 c, K2 R: y
void OnTick()' P }4 c9 W0 `) c
{
0 b. m6 `4 U* }$ J, [/ D, e. A/ f/ O; ctem_tick = true;
" u; f; M! z8 q- l! I: Z! u* O}
& c4 q$ }' y3 K8 m# [/ Y; N2 f//+------------------------------------------------------------------+
f4 i0 J- h& q4 K- s' D//| Expert Advisor main function |' Z) C9 o% f9 W! I
//+------------------------------------------------------------------+
0 H% L* l+ p! L+ r: `void OnTimer()$ A+ J- A; g' b( k' j d
{) d$ t% k+ M. P- S2 c
MqlRates cotacao[];
/ B* N# t* g$ G0 l' Nreturn ;
) u: u6 S" m4 C4 Z6 p3 N- A1 A( eif (negocios_autorizados == false) // are we outside the trading window?
) H6 h# r M4 h! g8 m9 C# creturn ;
+ G& {2 h+ B* @7 n) T//--- We are in the trading window, try to open a new position!, ]5 S9 R+ H [. s( \+ r( h
int sorteio = MathRand();
2 d9 }; J# B6 E# s, m6 t! l//--- Entry rule 1.1 U, K2 ~! |* y8 e" y8 d
if(sorteio == 0 || sorteio == 32767)
3 M: h& B. y9 E9 ?9 j% p- D, R$ Mreturn ;
! N+ ?, h1 `+ Xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
& A8 A& A, b" o( n' N j, M( k7 v% G{& z# W1 c# S3 c
negocios.Buy(info.LotsMin(), _Symbol);
" h _+ S G4 i; t% u Q& K}+ W1 X$ m+ ~0 v- v, y+ g! U
else // Draw rule 1.3 -- odd number - Sell
& R: n* C) ~' z! e, m6 v; W# H{
: l8 p7 R+ o- Q3 g, Y% {negocios.Sell(info.LotsMin(), _Symbol);
+ p6 h& }# K& A2 E8 K0 E}
& L7 v! h- U$ Q4 U. {( U} S) s. U4 c2 G9 g3 x* F8 J
//--- Check if we have a new candlestick...0 q, A; j0 d: A1 E
bool tem_vela_nova(const MqlRates &rate)& j5 o2 A3 B# J' d: a
{
$ @$ I0 r8 A% T6 W$ N{! ?0 i( W3 @2 k; R
ret = true;
8 q; y: i! h$ E5 r: q2 aclose_positions = false;
1 A5 }* W. ]1 J5 S# A# p}! e1 l H1 Y" t+ d
else
3 J- G6 ^9 {% f* P7 L{- v' Z: ?; C8 Z9 F8 K) }
if(mdt.hour == 16)- d( o+ r2 @1 {: M: _
close_positions = (mdt.min >= 30);
4 h& a6 m; L D! V8 P) l}: Z' W d% l: {! i7 e4 @2 q
}
3 R; }, l; S2 ~' |$ ?' u5 Rreturn ret;
" C* L3 G( n6 l& Q: j/ V9 w1 o}7 h* {# q+ {/ g( I! |
//---
. I9 K8 s& f/ \( O( b+ X* n/ v% Gbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])9 @# U5 l5 z7 E& c1 y4 x" Y# w
{' G" I9 G2 B9 f6 J& I
if(PositionsTotal()) // Is there a position?/ w8 o$ x; t4 Z
{9 H& v2 r- [9 I& P
double offset[1] = { 0 };# g: d; u8 t4 U; `+ D( L
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
! o0 r9 U* O1 E5 D, i&& PositionSelect(_Symbol)) // Select the existing position!% |( D+ b0 L& o# E# M3 h+ @( P
{* ^/ a6 {: Q- @3 v( |; ? Z' W7 I
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
0 I/ b- u& N6 B2 H& c7 }7 xdouble SL = PositionGetDouble(POSITION_SL);5 m. H z" J7 `& S" y: a
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
3 b. h3 G6 S2 b+ d. V5 kif(tipo == POSITION_TYPE_BUY)
* ?- r# J7 I- Z{9 ]# G. ]( ]9 i4 x5 C
if (cotacoes[1].high > cotacoes[0].high)
1 ^- k; E+ o9 ^, F; c{
. m8 e) k+ V5 `0 h( }+ s% k5 @double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
: n1 C$ M8 Y z/ G9 v- `- Ainfo.NormalizePrice(sl);
+ J4 }& D r# g/ s/ ?' Aif (sl > SL)
1 d7 c# v* \" q- [1 }* h- u{- ~' V% t; p( y6 U9 u0 a0 d: J
negocios.PositionModify(_Symbol, sl, TP);: C W* r" |6 G8 X6 h: i( n
}8 X9 Q" I2 Q* Z
}
5 {( m+ q; J0 w3 W/ W8 p* ~2 a}; v3 u; ]/ S$ D h8 i( G: J
else // tipo == POSITION_TYPE_SELL/ H0 _8 M1 @ ?2 X1 \) F
{
% w: ^0 W) z& v4 yif (cotacoes[1].low < cotacoes[0].low)
4 o" R% u9 U+ T. q, `8 Q{7 ]% I5 {8 r2 ]
return true;
1 u1 ^/ o3 N, P" N" _6 l; M}" N- \0 O b4 X. H7 d) {, u
// there was no position! L* V& t% J" {# b" ~! B
return false;
0 r) p1 p7 A8 e7 q' N: q2 x5 ^% M1 s}
3 i# ?9 w u- R0 e我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
% }% E) B3 A. C; \ M. B" u6 z到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |