启动交易模型,并构建 EA" R. X1 f8 Y1 E" T) p$ r
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。5 p0 r1 V. z7 L5 H: i; b7 i! h
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) ?% X" f* }: {( v+ b- m- u8 |以下是制定这些规则的代码。: }$ V8 D3 ~6 L4 `
//--- Indicator ATR(1) with EMA(8) used for the stop level...
) a/ W5 r! q6 K7 M/ J, bint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);* n# r1 ~/ C5 `
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);3 P( x; A* m. Q- M+ s7 W- z4 c
//--- Define a variable that indicates that we have a deal...
2 ?- ?' F! R# P2 X7 ibool tem_tick = false;
! r8 o# m4 H) Y) W/ z3 D! V: b' Y//--- An auxiliary variable for opening a position9 I) d% _: v) Q
#include<Trade/Trade.mqh>" o5 N# B% ~; M; O& ^
#include<Trade/SymbolInfo.mqh>
8 A$ ?8 b- l) CCTrade negocios;
" O% K4 l9 g' p+ {: }$ d# W5 u" bCSymbolInfo info;
. n- J( \4 C; b, J//--- Define in OnInit() the use of the timer every second
. z% H* B$ ?5 ?/ h8 G//--- and start CTrade
: L: a2 ~+ O$ v# wint OnInit()3 O7 e1 {/ f/ f8 V2 w& [+ H' Y' ^+ {
{$ J. {* O6 B" }$ v; z! b
//--- Set the fill type to keep a pending order7 K# \- I" p9 q3 M
//--- until it is fully filled
, h, J7 }* k0 Q% `: K, tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);7 X- O# G. s4 P
//--- Leave the fixed deviation at it is not used on B3 exchange% e# V [0 J# C' y: ~
negocios.SetDeviationInPoints(5);
; \* _0 p9 _+ p- C: L+ x; e4 Q( b//--- Define the symbol in CSymbolInfo...
0 O5 N, v& l# D. \* N0 dinfo.Name(_Symbol);/ e' i# ^9 H7 X8 ], }4 S
//--- Set the timer...
+ q( @/ h7 C. ZEventSetTimer(1);
& Q# n% D$ X- Y- C2 u//--- Set the base of the random number to have equal tests...( A* P5 X- R# M& g _& q% C4 W
MathSrand(0xDEAD);
0 r( e, q! |$ l7 R4 B2 Breturn(INIT_SUCCEEDED);
9 s; t- P+ D& Y* }}
# [+ k/ @. L& C4 |5 o//--- Since we set a timer, we need to destroy it in OnDeInit().
, j# I. h( U/ ~0 [3 p* Svoid OnDeinit(const int reason)
0 m" F7 M) [+ T/ ` R ]4 j" n( a{$ ^( X& \( b( F- T- `
EventKillTimer();
0 d8 F- O0 H2 n: b}
1 h) z/ N b7 U, m* y. `" c7 g1 e//--- The OnTick function only informs us that we have a new deal, H. Q' x, t2 L6 G6 c+ q0 k+ M
void OnTick()
; A: c/ G) N4 I1 @! m{
+ c) n* J, b) [/ h: Qtem_tick = true;
! {6 H+ V+ F' O$ `( B6 ]0 J: G}6 ^0 k% N8 {8 Y' E( J
//+------------------------------------------------------------------+% P* k5 B9 z0 G" d
//| Expert Advisor main function |
. g0 @/ w0 s; a$ s//+------------------------------------------------------------------+
/ K% b3 Q3 M5 s; g5 w8 Ovoid OnTimer()
# V, z5 i- Q+ p. l) x{
: O# h4 D6 }$ h% D1 i( [MqlRates cotacao[];
7 r! H- U$ J# O0 e; u g7 E, [$ ireturn ;
1 ?9 B* t7 \% n5 u: Jif (negocios_autorizados == false) // are we outside the trading window?
. ~( ?& e; h% ?# X2 `" l \8 Kreturn ;
[" C* M/ M& ?% t//--- We are in the trading window, try to open a new position!: x2 m/ h/ s0 H5 @
int sorteio = MathRand();$ B- K+ e! {& N. P
//--- Entry rule 1.1
- w) j9 q. k8 ]; Z6 b5 |$ W2 vif(sorteio == 0 || sorteio == 32767)# n4 i5 b( c* h8 m! D" G0 p
return ;
1 r% E b4 t3 B4 S5 sif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy- j* H& C1 a3 G( ]7 b- ~
{
- W! N9 o% I. y1 D+ `% Onegocios.Buy(info.LotsMin(), _Symbol);
( E7 a2 |4 {- n7 W: D5 \}: A! o) D% i* s
else // Draw rule 1.3 -- odd number - Sell
0 n: t9 M/ y" a4 z: t{/ G1 z' u% @2 E
negocios.Sell(info.LotsMin(), _Symbol);/ Q2 M9 B! i5 q: y+ P
}
+ K! C* ~7 l9 R# R: `( N}
& [; f( Q0 _: M* f) ]1 O" g//--- Check if we have a new candlestick...% ~7 {( p( M( |2 @7 h
bool tem_vela_nova(const MqlRates &rate)
/ l! W: T+ T" c: J; W{
4 I( d7 u A' \' ?/ K( _# J* {{
1 h P7 `' P; Z$ y2 t9 i/ m# ]! Sret = true;; V2 ^* w! B* T% d! H2 h# ?) Y
close_positions = false;2 E) C8 b% f9 H" T+ u, H
}
' B$ h; O8 S% x4 w) qelse
) V6 }2 m% ] }0 u1 p{
% m- I% @, L2 O5 d0 Xif(mdt.hour == 16)
, H, X. P+ d/ n5 d! X* aclose_positions = (mdt.min >= 30);# }+ @8 f" ?- A+ U, K; d
}
2 X% @' U7 G0 [- S( g: \5 u}
) T5 L) t$ M! W; a6 E# ?0 h- Lreturn ret;
, z1 r$ `9 ~: ? y( d& K) G} j" j2 ?( I* { @" o
//---
/ x: y9 u: o' Mbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
, r/ \0 C" c8 K5 Z3 S/ ]5 a{* w; D Y# @/ c2 s- B. |; R; L
if(PositionsTotal()) // Is there a position?) N( n$ f% I. c$ X) y2 h2 y% y7 k
{- o( v: f* F: L( ]
double offset[1] = { 0 };) Q; O3 H5 @" ?) R: a
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?4 H# e$ s k, w
&& PositionSelect(_Symbol)) // Select the existing position!& C2 A- X/ e, i
{4 O6 g( H) | z
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 ~1 W" A" S2 _) O+ s
double SL = PositionGetDouble(POSITION_SL);
3 r R) A n+ i2 ^+ n1 ]6 H9 a: u6 wdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));/ I# H1 C+ H2 ]6 ^
if(tipo == POSITION_TYPE_BUY)8 b( J/ e% o- V; B6 j3 o
{
1 K, c5 G- Y! cif (cotacoes[1].high > cotacoes[0].high)
2 G0 f0 a; D% c4 n+ m{/ x% |' x6 z' s5 U& |" E
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];8 L) ^) [6 N6 r
info.NormalizePrice(sl);7 v/ r5 A2 d/ |6 a8 V9 m
if (sl > SL)
6 _ y; L7 X8 G4 y{
4 d2 _5 r. d% l# c7 i8 n" rnegocios.PositionModify(_Symbol, sl, TP);& y7 Z' o' c, r5 B7 E
}
; Q# a L0 s, _$ J* B [8 a1 q}
7 {9 e* R8 [& C}. g( K/ E/ w9 U2 O+ t a
else // tipo == POSITION_TYPE_SELL; F" R6 U. ?2 @4 Q
{
# k% s% K( W( Cif (cotacoes[1].low < cotacoes[0].low)
3 x* O4 r/ V" s" D{/ O/ S. J9 ?5 |: I( C4 e( Y8 \. V
return true;
$ x) N* ^, A m3 G& c}
8 L& Z7 e/ L- o" `/ x, m& ^4 P5 W// there was no position8 @ _4 Y* M% G7 d, x6 S' }
return false;
; d% ]+ u K# G3 S" R% U; P/ d/ T}# ~ e, P. A ^; z* a# \. y
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
' H, y- i D& {) `- Q到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |