启动交易模型,并构建 EA
' V- L$ b5 t# v9 W* _$ K在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。& j2 s9 r) `% e# n1 D' q* A6 ?
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
* T! D7 g4 M. e0 A& t; t3 g以下是制定这些规则的代码。
+ s1 `" a' K- P" W$ s: i//--- Indicator ATR(1) with EMA(8) used for the stop level...
5 o" v( f% M, H, Kint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
0 v, {( F- P8 U6 R$ c" {. O" hint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
6 t3 s& G8 A8 X) m9 P//--- Define a variable that indicates that we have a deal...
, ~( A4 Q8 G/ A( g0 bbool tem_tick = false;9 m ~) {' |% J) S! \' L
//--- An auxiliary variable for opening a position
$ s6 F' {: V8 h `5 a' W; v#include<Trade/Trade.mqh>" }- f+ q" |# ~
#include<Trade/SymbolInfo.mqh>) p5 S2 v! @2 r$ s$ u
CTrade negocios;
) W, H- j9 K* uCSymbolInfo info;
+ a1 {% B9 T0 q//--- Define in OnInit() the use of the timer every second# e& q3 A n5 r+ I6 _8 L9 ?+ g
//--- and start CTrade
; z9 x; k( X# A' \7 Eint OnInit()9 u# B1 G& W" N& @' X5 W
{( N1 {$ B5 h( [; c/ K
//--- Set the fill type to keep a pending order6 u. a7 s0 D+ v" u
//--- until it is fully filled2 C' v% ~: Q7 C
negocios.SetTypeFilling(ORDER_FILLING_RETURN); l6 ]6 N3 X6 h+ y) k
//--- Leave the fixed deviation at it is not used on B3 exchange; [; S: }- N/ M5 I6 u% m: P5 p
negocios.SetDeviationInPoints(5);3 U% C6 A% a8 Y# x: H
//--- Define the symbol in CSymbolInfo...! C" o' D! {8 m& q' P2 u
info.Name(_Symbol);2 K+ x) w$ d* j& R" _& Z
//--- Set the timer...
/ T5 H/ ~- y, E+ BEventSetTimer(1);
% s' M6 P* ^0 [3 K/ Q4 `) b//--- Set the base of the random number to have equal tests.... I: M9 k7 t- x) G
MathSrand(0xDEAD);
8 c1 r! G) L- l+ preturn(INIT_SUCCEEDED);' f1 Y* B3 \1 T! i# M! r* l% A
}
* U- @+ ]9 h4 q4 K3 d, u5 l//--- Since we set a timer, we need to destroy it in OnDeInit().1 {/ T8 q, }3 ]
void OnDeinit(const int reason)2 v& T5 T& J- d7 }- _/ I; G; ?, z
{1 b: j( Y L4 ]/ M6 `& H
EventKillTimer();/ U. {& D; G& x& U
}6 M- S& Y1 s8 Z9 o5 F
//--- The OnTick function only informs us that we have a new deal: T/ g: T* ~, |" z) `: L
void OnTick()
; d' A9 ]; d5 B3 @{- T0 q) b* D6 t5 M9 o0 P/ p8 F
tem_tick = true;5 W2 I2 M- V1 V4 S# g2 H
}
) @$ ]! z2 n. o% o& E//+------------------------------------------------------------------+2 l) q( ~3 G( l8 U
//| Expert Advisor main function |! s, y. C$ u. e$ W1 G
//+------------------------------------------------------------------+4 T: T( I' E# M0 S
void OnTimer()
+ j* t8 ] [+ B9 R' ?9 u) p# \{
, w& |- i6 y9 mMqlRates cotacao[];
5 W" y% O; s A3 w u$ ureturn ;* W- q; Q8 A2 z% x6 i* O9 W! N- c6 w
if (negocios_autorizados == false) // are we outside the trading window?/ ~. b0 W3 A: _, f8 p8 c% P" y
return ;
9 @: L+ M1 ?$ h+ Y6 L//--- We are in the trading window, try to open a new position!" Q4 P0 d! C1 R7 w7 h! J N% ^, j+ i
int sorteio = MathRand();
" q$ x6 ?+ d$ r u//--- Entry rule 1.1
+ G% `% u0 y- b- zif(sorteio == 0 || sorteio == 32767)
. _! b" m* {2 e* v6 @return ;
1 }; u \5 |6 [; E. Iif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy6 G4 J+ n4 z; C
{
* a% U8 A/ ~9 lnegocios.Buy(info.LotsMin(), _Symbol);! P# i; Q6 j4 T) p2 U6 d
}5 _3 T( q' Y0 o; E2 _
else // Draw rule 1.3 -- odd number - Sell
0 L, K) \9 g9 c/ |$ l{
0 p! p; J7 K- n; s) nnegocios.Sell(info.LotsMin(), _Symbol);
* `. k' Q6 A8 F0 v* c/ k3 c}4 ~6 U; x# q% p4 R3 _
}
+ s! {7 W( \3 o7 Z//--- Check if we have a new candlestick...
' C. f* ~6 \5 q7 [bool tem_vela_nova(const MqlRates &rate)3 Q2 t9 G4 B4 j. Z& p' ?/ z( O
{9 a6 M6 ]% z9 b& a8 V+ X: m2 K* e
{
4 m7 i; e0 x8 Qret = true;
$ s4 G; i6 v" Yclose_positions = false;
% j% u2 w) X- Q* @+ ^}$ o" G; P% Y: C) U
else. U8 W, D Z6 f3 o8 k; N8 s: v
{5 d6 N, P4 e/ H# |" S$ C
if(mdt.hour == 16)
$ `5 T$ }. v# t% v! ^3 _* yclose_positions = (mdt.min >= 30);0 D& E8 F1 H2 r
}
5 \# P4 [- s7 l0 a5 U}
/ N! Z; K& b" \/ | Mreturn ret;7 d" S; ^0 D, z8 k+ f- B0 ?, I1 {
}, l! \- N; U3 W2 _+ D6 L" z
//---2 ^; Q9 \5 X J
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 g, V0 I. O1 x) p7 M* Q6 y
{. k8 Y$ J# P$ b! o0 o9 T
if(PositionsTotal()) // Is there a position?
+ t7 q& `& |" v) T* W) t7 |{
( Z$ \) Q5 ~& l( ?1 R) ]0 Jdouble offset[1] = { 0 };
# z, f7 D! w. v; K7 gif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
4 \: S) g9 a4 b' W&& PositionSelect(_Symbol)) // Select the existing position!" E8 S- K/ K0 `7 p" M& O
{, P7 ~% x- b6 S8 B" |/ k& Z5 W. z
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);5 H4 N8 k. q7 N+ c2 `
double SL = PositionGetDouble(POSITION_SL);' J! h+ G* z% p- M/ q! {
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));' t. Q; {) V0 g" ?" [
if(tipo == POSITION_TYPE_BUY)
$ { L. K9 l& w4 y{ ?3 r+ H' S% i8 r, I/ V* q
if (cotacoes[1].high > cotacoes[0].high)
8 _9 Z0 t3 s9 T$ Y! m! j. e V{
X$ y0 K, _' N" I k, B6 _+ M) Kdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
& a8 R1 G' ^9 N5 U4 K3 [info.NormalizePrice(sl);3 ^% M6 q \/ @6 ~# I7 {( z* _/ f; \
if (sl > SL)
5 C& a$ o( k, Z, s9 s{
# i& k# C) }$ J- C( R3 qnegocios.PositionModify(_Symbol, sl, TP);
# o- ]3 G- m# x4 Z. w& d ^}
& s T' ~2 b/ R6 U: f}- X* J4 |' e9 M, H; g( }
}
" \' X! V* a8 ?+ c% I jelse // tipo == POSITION_TYPE_SELL( v+ h6 r# ^, U; W9 ?
{% j4 u( D1 U2 O
if (cotacoes[1].low < cotacoes[0].low)9 d: r+ p b5 ]& k2 b5 D6 A
{
+ f; u# Z0 }- V breturn true;+ e3 N/ i I( c `
}6 M9 M) u a6 O: o! Y
// there was no position
" e' X( n" Z9 {% t/ w+ `6 Y/ |return false;
3 U5 |" H/ h' X8 J: l' ]}9 P5 x) N- n6 _2 B4 F
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 [( `% o2 e: K) M8 J7 _* z
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |