启动交易模型,并构建 EA) N3 K- }+ |) M4 y5 H3 B6 L+ I
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) s( M1 h) m A, W# n9 n! ?$ y为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。$ q+ f! w$ w" l! c- N
以下是制定这些规则的代码。
9 @! U% Y6 d7 R' \0 J8 B//--- Indicator ATR(1) with EMA(8) used for the stop level...2 c. c# B+ ^* a( k( d
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);; A- \3 o4 h% m5 u6 V2 ^" Q
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);/ P! l' C0 d9 t9 k" Y3 l
//--- Define a variable that indicates that we have a deal...9 b" N4 B/ u% }! a
bool tem_tick = false;! x. v9 l( B/ V6 p2 v
//--- An auxiliary variable for opening a position
' G4 D7 ?% U' i5 m#include<Trade/Trade.mqh>
, x7 I' s* D; b#include<Trade/SymbolInfo.mqh>9 [; O% T8 G4 o+ ~/ o
CTrade negocios;
) ], t7 k& d: ]. WCSymbolInfo info;
# L, ?+ z3 X# h- ]! g* J- g5 q, p% A//--- Define in OnInit() the use of the timer every second
8 p8 k# H; N2 c. X# M3 H+ d//--- and start CTrade" y+ M; V# w* E" R5 ^
int OnInit()
6 z- k- X% [1 P4 ] {& Z{- t, Z% Y2 k' K7 P, D: q
//--- Set the fill type to keep a pending order
% D L+ ^* D9 b B/ V//--- until it is fully filled
" U# J- e" t$ u) t; ^& j% Znegocios.SetTypeFilling(ORDER_FILLING_RETURN); F) X. s9 j& u6 N+ m
//--- Leave the fixed deviation at it is not used on B3 exchange
/ @$ m: `% J. f5 t8 b3 {negocios.SetDeviationInPoints(5);& E2 a2 x* J5 G' r: N
//--- Define the symbol in CSymbolInfo...# T* F% ?8 Q# B9 I, J/ I
info.Name(_Symbol);
+ D" x$ g, n7 [: L1 C. u5 X//--- Set the timer...
" o7 r9 r! a& Z5 S; S7 CEventSetTimer(1);
" B1 g: p! O& G9 l) ]; s2 w//--- Set the base of the random number to have equal tests...6 A; g; D! c, H) K& a0 J
MathSrand(0xDEAD);
# y) `1 i w# xreturn(INIT_SUCCEEDED);" ]$ p/ d! p6 e! s
}
% C/ D) R W" N8 \, J$ d//--- Since we set a timer, we need to destroy it in OnDeInit().4 Z. C2 }: V6 C3 Z# }, s( l
void OnDeinit(const int reason)1 n6 W3 m O6 P6 J% K# u! h7 R
{2 h" i- @3 _. K
EventKillTimer();; J! ^& F% ]2 q
}
/ n% S1 k n% w! ]3 ?+ A//--- The OnTick function only informs us that we have a new deal/ B/ e2 }; q' x- p% B7 t' }- [2 @+ P, |
void OnTick()2 q8 t6 X# G8 A7 E) O
{, z# T4 o! w8 H$ U& M: b$ H
tem_tick = true;
7 n% |7 F+ U" E1 r; W2 _( o}3 O0 ?+ n; h9 G' G
//+------------------------------------------------------------------+, H8 U1 {$ l! A$ X- g/ a, O( A
//| Expert Advisor main function |; f# I5 b. z0 J$ ]* y3 z: H( e
//+------------------------------------------------------------------+
% L0 Z4 e4 B4 c9 hvoid OnTimer()
. v3 a; R1 h; E3 Y5 G( @/ {" [: \! V8 \{
6 d2 D& q/ A9 F: I3 J4 x9 bMqlRates cotacao[];
. w3 w, _ o: n1 qreturn ;
8 a1 E' U& j1 @) P" X5 e) Aif (negocios_autorizados == false) // are we outside the trading window?# G4 g; D7 |( w. L# s% W/ s- c5 q
return ;
( z' t" T/ I- K3 B [//--- We are in the trading window, try to open a new position!
3 I: N; G. _1 V) ], Lint sorteio = MathRand();
- g: G0 N2 ]7 j! B( m//--- Entry rule 1.1
: G% z+ t# G" F2 Fif(sorteio == 0 || sorteio == 32767)
3 j7 F( }4 r: Kreturn ;% d4 g( T8 x( d$ S, p! B4 [. T
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- p7 v: k3 G# ~- E- x- l{
. ] |, V' a Mnegocios.Buy(info.LotsMin(), _Symbol); v4 T2 i/ s* _( V: m
}% N9 X- G7 H& i) e) ^
else // Draw rule 1.3 -- odd number - Sell7 m' H& u/ S/ X7 O+ d, D7 m2 ~$ r
{; R0 j+ K: J. r# O# Y
negocios.Sell(info.LotsMin(), _Symbol);! D7 c6 t6 q) M; I" J( H) q0 |
}
2 L5 g+ c* i8 f) U}
! q. w$ N4 ?8 [1 u( p//--- Check if we have a new candlestick...
1 d1 c& g0 n) e5 ^7 \* X$ hbool tem_vela_nova(const MqlRates &rate)3 n; L7 H, y9 T8 s
{
& O1 ^4 i8 G3 L{
$ A3 ?; b9 A" ]9 b" Yret = true;
* ~$ f2 V. v5 b* U; g& k& W( kclose_positions = false;, [9 d& Z7 d9 Y; f
}; |$ s9 t6 T& c: P
else
4 t$ ]( a1 D# D+ r7 ]6 k6 v" L{. V3 G% d" k* O- |4 z
if(mdt.hour == 16)
* \' U+ g' v5 l4 l% iclose_positions = (mdt.min >= 30);
. S5 l* [& W; j0 D}
' i" n0 Q! z; Y% P) N/ U, C}
6 G/ o/ p* R8 Xreturn ret;, h4 V8 {* \; s# Z- I
}
, R; T% W# K7 m5 I//---
* j: S# I: _1 z$ b9 s& Z$ U, W; Wbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
^) p. c& s) s$ w5 {{
/ y8 j% V0 E- ~6 o; X4 X% _if(PositionsTotal()) // Is there a position?
2 L9 V4 `) z- @, t+ ?! ]{2 O3 D3 p( M+ @. {" }# o
double offset[1] = { 0 };* a; m/ a/ p& A9 o7 f+ Z, n5 z5 S
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" \/ C& t) \$ \&& PositionSelect(_Symbol)) // Select the existing position!
& b, `$ ^8 j: u9 ^2 o{) g1 {5 @4 R7 w+ h/ `1 t5 _
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
' `2 w' @1 v1 k2 y' q7 bdouble SL = PositionGetDouble(POSITION_SL);* H; k, T1 s$ `! R& L
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));/ h, R x' v& M7 G0 m
if(tipo == POSITION_TYPE_BUY)( K# b% W- i7 _% u
{
* x3 F" k4 J1 fif (cotacoes[1].high > cotacoes[0].high)
, h9 M: r' | N- }, m{
+ F+ Z1 b& `; m% C+ }double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
( ~' q( Y D ~* x' Dinfo.NormalizePrice(sl);
; z0 P/ _, s9 O; M9 dif (sl > SL)
: c" V, m+ ~' Q: f, g3 \{9 v; J7 }* j( ~. J; k
negocios.PositionModify(_Symbol, sl, TP);
2 o" S R. ]6 J; K# U}
9 c# J* x; {" G2 h$ A1 H}
$ k* l% C# w: }# {' H8 Y3 j; \/ ?}/ h1 [6 b$ i7 t( f9 L% l: W" V
else // tipo == POSITION_TYPE_SELL
2 w8 b9 Q+ V7 o6 y{
. m+ w: q0 @$ V) sif (cotacoes[1].low < cotacoes[0].low)
2 r" f h7 H. e- A3 X' C: f0 ~{
' r0 ?. P5 ^3 L" G6 |, Lreturn true;3 f% F; X' [7 h0 y6 k+ \+ o
}' b$ X. M) n' e+ ^: W7 x( H
// there was no position$ k! e. m! h+ [6 C8 E) x
return false;
9 A5 x% Q: t7 Y3 O2 C& V}1 c4 R* s4 R; f: P
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
- [1 j; n# [2 }% m到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |