启动交易模型,并构建 EA5 v% d6 C3 z) X2 g! R( k
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
7 i7 \. m; b2 R3 f* ]" B" p为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。2 d2 c# T; c W( p# A
以下是制定这些规则的代码。
. i+ `3 T" w1 m) Y8 E2 ]//--- Indicator ATR(1) with EMA(8) used for the stop level...# q* H* j# V+ v0 V0 B v
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
- y8 k8 z! G% W) nint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);9 V7 [, P# c9 T4 o, h* Y7 |
//--- Define a variable that indicates that we have a deal...& o Q( X {) d6 o/ C8 B5 h: U
bool tem_tick = false;
+ P! g& ]) f2 [+ B7 N4 Q- Q//--- An auxiliary variable for opening a position; ^/ W v5 I" |. a
#include<Trade/Trade.mqh>
$ |. _8 o& g2 f# ]9 {#include<Trade/SymbolInfo.mqh>. T, y$ |; ?* a; w
CTrade negocios;
/ @' T# V# h$ E o: N1 y: GCSymbolInfo info;4 |& v2 e" Y, [
//--- Define in OnInit() the use of the timer every second5 x6 q9 w2 P6 y( n( r: U2 w
//--- and start CTrade
5 Y" r3 P7 L! ` R! Bint OnInit()8 J% ~; _7 ^; u+ p1 D/ U# d
{5 x, H4 G8 n2 q0 e# f8 P P
//--- Set the fill type to keep a pending order
. a3 `) N4 m* U1 z6 y//--- until it is fully filled
/ x# h1 B, C5 {: Y- Pnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
, l/ J! b* A) q& @2 `7 o//--- Leave the fixed deviation at it is not used on B3 exchange
/ D! W9 t: W- Onegocios.SetDeviationInPoints(5);6 u' @* s' Z) S8 X
//--- Define the symbol in CSymbolInfo...
7 N& o4 t. o( U! t% l! Q% Z' A2 G+ _% Minfo.Name(_Symbol);$ ~) o R7 ?. ?6 b2 M" V
//--- Set the timer...
9 S% u, R" n7 lEventSetTimer(1);
. a/ z4 T7 [0 A* a* [//--- Set the base of the random number to have equal tests...5 s/ P' L+ V5 y' f; @+ q
MathSrand(0xDEAD);
3 z6 Q" @: b5 preturn(INIT_SUCCEEDED);
' J! T" r# _( g$ J. K}
( v8 e! W5 ~3 K" q$ A2 \5 G//--- Since we set a timer, we need to destroy it in OnDeInit()., F. u: P3 _8 { R1 f
void OnDeinit(const int reason)) [6 Y5 W6 k. S: F& r) `" C' g
{% g( z- B3 D2 l4 u
EventKillTimer();
; n, p% O& p6 }& N& D1 x1 S& V}
( H0 g I0 B$ Q; |0 X//--- The OnTick function only informs us that we have a new deal; s% u" m6 l& z- m; u A5 v: x
void OnTick()# U2 z% u9 c1 H0 g6 F
{% [; X0 f1 O2 U
tem_tick = true;
R7 E9 `+ m0 K% A}# E; S. ~7 u3 z4 @8 B2 Y) B
//+------------------------------------------------------------------+% {! ~" n- m+ r1 r' W& ?5 l1 v' _
//| Expert Advisor main function |
' k/ A' d; v0 V) G//+------------------------------------------------------------------+
( m7 t4 P4 Y3 u Yvoid OnTimer()
& J( ]& s/ Q, I' s* z{
5 x. g* |5 t' eMqlRates cotacao[];8 J* x2 a9 U5 f; U7 S0 T0 p
return ;2 ]4 @# P0 X8 m5 M1 H
if (negocios_autorizados == false) // are we outside the trading window?& z$ U- z" s/ d" V0 l
return ;
$ x& W* A3 T% l. F) ]$ [3 ~1 s//--- We are in the trading window, try to open a new position!; z; Z7 T5 q% ], T8 V
int sorteio = MathRand();' |( C/ D! T& z/ D- b$ _9 J, I
//--- Entry rule 1.1
# i& ^& q1 w4 j: P: cif(sorteio == 0 || sorteio == 32767)
_5 L! e5 c4 jreturn ;
' z/ [$ k' e/ ^if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
% U) _/ e" I$ F! J' a& K{8 y' A/ N* F, \
negocios.Buy(info.LotsMin(), _Symbol);0 m( z/ g- P/ U; T7 Y5 e
}& P- O% W( A; r! R
else // Draw rule 1.3 -- odd number - Sell
& q* A2 o: J" [{
8 g7 k7 o3 v, g& C; K7 |negocios.Sell(info.LotsMin(), _Symbol);& X6 D) _4 e: i$ L
}
+ F A! I, ?' N, {" f$ e}
, Q: _" A( S% l" ^# \0 m//--- Check if we have a new candlestick...
, F u1 b u0 Ebool tem_vela_nova(const MqlRates &rate)
) f: U: t. Q8 y; ?# q0 ]: [{& o4 A w2 Q4 R) n* D: I- g) V
{
' L) B3 E# O6 h" Y i0 F- b( ^ret = true;: H+ V6 |% o) u' l8 }7 S9 A
close_positions = false;5 M7 K& k1 U/ y% N
}
- I- `( ~% p% W, a3 [" c/ s+ X6 \else0 R3 E( @7 V* Z
{
& x/ n7 ~3 l, y" h" Mif(mdt.hour == 16). \# L: P0 N5 l$ L" s; k0 y# |
close_positions = (mdt.min >= 30);
. L/ U( t! r% u% Y2 j0 }}: f: ^. g3 X7 o: m
}
8 M; E" q: o! W1 j4 A- D$ q" ?) nreturn ret;% a% f" N/ q" Q) e5 U, z- C/ ]- v
}
( {4 m% K; Y( e @) @3 p# P' f//---
! ^- r* B3 ~" l$ a6 Jbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ Z1 b. e2 R, E' ~% F. k' b: F- }
{; o3 n/ v$ R' f% Y! U
if(PositionsTotal()) // Is there a position?
- d( ~4 c) {& {{
( F9 B2 I2 ?0 q1 mdouble offset[1] = { 0 };
% I, p$ E9 e6 _. vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?8 b0 |$ ]% {2 w0 r1 @) d
&& PositionSelect(_Symbol)) // Select the existing position!
9 C9 m1 z& S; a' @{4 u W9 F( w/ H, g. m$ J
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
6 { G: [1 W( |( ldouble SL = PositionGetDouble(POSITION_SL);
1 x* y) k7 h4 z, D( [8 Xdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* B2 ?3 h: X9 y, E+ u8 n! `- Vif(tipo == POSITION_TYPE_BUY)4 z" \5 q4 }) [$ @5 ]
{& W; x. d2 m, v
if (cotacoes[1].high > cotacoes[0].high)
2 d$ H$ y* Y' e: t/ K5 D9 \7 L{+ D& g: i& t! L1 y6 i
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];( k5 d- l5 r+ D V
info.NormalizePrice(sl);4 O4 V3 [# B. N" C- Y
if (sl > SL)/ s0 g- v* r7 u, W9 ?- l# b$ F& @
{
+ ], X( ~) |9 T: v! }1 v. }5 Knegocios.PositionModify(_Symbol, sl, TP);
: j- {' |) N. k3 x4 |% Q" T# b}' Y# M3 B7 j& ]; s" u- H
}' U( D2 |& ]1 m3 \7 C! V( I. h( l
}$ N j f8 S6 Q) E! T
else // tipo == POSITION_TYPE_SELL
! y' Y- N+ ]6 Z, f* E& t) s{: c$ V/ U3 a7 x0 E7 {' H4 ?7 b
if (cotacoes[1].low < cotacoes[0].low)- C0 }3 G; I, J Z
{
5 [) }. i* `3 y- I) e- k: kreturn true;
: H* f" N0 t3 S8 ]}
: V$ ~/ K U! s- L7 G% j @// there was no position
: Y7 o) X1 P3 u0 ~# Yreturn false;
* ^1 r+ c$ f) J/ b}$ Q, W# @3 u: b2 m7 E' K
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
3 z! Q( h9 S1 h" C5 U) X2 i4 d; I到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |