启动交易模型,并构建 EA# v0 t) ^0 |/ [9 e7 R
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 T$ n/ b; g' i& K4 V为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 l5 P4 E9 V& Q5 n3 M; z以下是制定这些规则的代码。5 E" T0 ?3 g1 p8 J. U( A: \4 h- M4 D
//--- Indicator ATR(1) with EMA(8) used for the stop level...
3 H2 O. v2 ]( Y3 V; M$ sint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);0 e! e. R: h6 u6 E; c" V
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);+ h/ K4 Y) Q) R a5 C' Y: t
//--- Define a variable that indicates that we have a deal...
3 V9 A6 o$ f. N# ^; vbool tem_tick = false;
/ {0 Y8 Q6 ^% @, F//--- An auxiliary variable for opening a position
: I. O, w3 p' ]#include<Trade/Trade.mqh> o0 [5 P6 m. P! b/ {
#include<Trade/SymbolInfo.mqh>9 H$ e! j( G" I8 m
CTrade negocios;
: R) E# {; b W$ A z& fCSymbolInfo info;
2 _5 k3 h7 Y$ h% a, e//--- Define in OnInit() the use of the timer every second
$ N5 N9 r: D/ J$ \3 z! x//--- and start CTrade
- ~4 Y8 u4 S: wint OnInit(); m. F3 ?5 i$ k6 }0 M7 e
{( z3 E: }- d: R: F {" H% @1 {8 g7 H T
//--- Set the fill type to keep a pending order
2 H) s! Z/ i, l0 B2 g* I+ o4 J//--- until it is fully filled
, p: V+ ?2 G7 w3 {) a3 unegocios.SetTypeFilling(ORDER_FILLING_RETURN);, t8 o5 x$ w/ _! C& x- j% }
//--- Leave the fixed deviation at it is not used on B3 exchange
5 o1 {9 `0 c/ F/ l* z7 Gnegocios.SetDeviationInPoints(5);
) Y( A9 j9 H9 r6 t Q+ Q//--- Define the symbol in CSymbolInfo...# G$ ^1 L: d- R2 ?
info.Name(_Symbol);
8 }/ `/ @# P+ {2 d+ E8 I6 a, P//--- Set the timer...; y$ r" e) X1 O* p; L( T
EventSetTimer(1);, N" H8 n# g# z- u7 v
//--- Set the base of the random number to have equal tests...
1 }( b2 V e- T4 i0 g. K7 yMathSrand(0xDEAD);
s8 A; |7 B1 Hreturn(INIT_SUCCEEDED);( o2 U6 O$ b# V! B4 B+ i# S6 y
}
9 U# o# R- }1 h% u, d0 `//--- Since we set a timer, we need to destroy it in OnDeInit().# B* z; _8 w( S' m) I
void OnDeinit(const int reason)5 c0 V# s! u! B' P4 R6 w( C
{- K# V" o" t# u3 j, x
EventKillTimer();( j0 P: |+ [/ q- v) ]' M h1 x
}
, s, G) p# Y$ P! }) a' n6 N//--- The OnTick function only informs us that we have a new deal. {' t6 R1 K2 d% G9 E$ u
void OnTick()
# O0 ~( @4 g, W% M' ]3 r{2 Y0 \. v, Q- {4 g! n
tem_tick = true;- V9 g0 `( e1 T/ Y$ O
}
2 n9 ?; Z, G; J0 _, x* Y//+------------------------------------------------------------------+8 F' \& @( D: g+ @" c% a5 U
//| Expert Advisor main function |
" M3 d* u; l: J- g//+------------------------------------------------------------------+3 X# N4 B' y) T8 ?! c' i' y4 N1 N- }
void OnTimer()
3 V |2 q, \( \( R: H2 }- C{
7 U; }0 }9 Y, j$ eMqlRates cotacao[];
/ ^3 _3 |3 f! m& z$ a5 Ereturn ;% S5 ?% `9 ]$ X t, `" j+ `
if (negocios_autorizados == false) // are we outside the trading window?& c0 k' N6 o, U" a
return ;
3 k( E" n7 ^. @- h//--- We are in the trading window, try to open a new position!9 v, A- p! X$ O& @2 Q! v* S8 T
int sorteio = MathRand();
. T, |* M+ ~ {& _//--- Entry rule 1.1# n) r( ~! \. y, N6 t
if(sorteio == 0 || sorteio == 32767)
% {) B& g/ d, |. G. m9 X9 |return ;
0 O& ^1 |) r* F; D# a6 ?if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
) |. j7 n' r2 G2 K; ?' Z{& T" t. S4 b2 b6 f
negocios.Buy(info.LotsMin(), _Symbol);8 m* c) s. B* F7 E* q
}8 O, |% q: A! @' A$ s" W1 o
else // Draw rule 1.3 -- odd number - Sell, ^$ ?& i4 v/ g3 T0 I1 a
{8 M! o# Y% F) j9 Y
negocios.Sell(info.LotsMin(), _Symbol);
1 r! U4 c/ d: A, m/ o& ^/ w}
, P( m; w6 u5 D }" D}
. P; f# O+ K9 U$ T* ^9 Y5 Y//--- Check if we have a new candlestick...
/ |0 T) [0 p. D9 q3 H% Hbool tem_vela_nova(const MqlRates &rate)
9 Z+ m3 i% h# O& A/ y; b{+ G& C; a( S8 v" M$ `: F8 ^
{
) e/ I* d [1 Y6 Y6 h% V$ eret = true;
0 e0 K0 Y+ B& K) X# x' ~; w; cclose_positions = false;7 H& V+ W' W/ ^8 K; w Q- c
}
" b: Y1 ^7 f& a, T0 Lelse, ]8 }9 t8 u3 w5 r( [% r
{0 s0 k6 A# q/ E3 t3 _
if(mdt.hour == 16)) B1 N" c* s6 e5 V
close_positions = (mdt.min >= 30);
5 m1 r @. ?4 X}" c, Q* O8 S. u3 G. p9 H8 a
}( i4 h* r6 ?* p2 g {
return ret;
4 I& c; I6 F, G}
4 W& I0 K* y& P$ W: X/ V//---0 e: W4 Q- M0 b, I) f8 _; \# H! U
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])" K# N j- p" d- ]2 W% ?& m' T: b
{) ]& P8 `# S& I. _9 s
if(PositionsTotal()) // Is there a position?
$ W$ V1 H# u1 j$ t# k) v{
' g9 |( t& m6 \ x# O, adouble offset[1] = { 0 };
' Q* I2 J4 c+ Q5 a. |if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?% u7 k% ~4 i( E2 p
&& PositionSelect(_Symbol)) // Select the existing position!- {# B* S% k8 t0 t9 p$ N/ H
{1 N) [. c3 A: \- u0 Z# U" T
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);/ e) A( [: L; H) v' K; U0 x
double SL = PositionGetDouble(POSITION_SL);
& }4 S% \. s- A) Idouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));9 w* V# E! O/ B- }+ w
if(tipo == POSITION_TYPE_BUY)5 u L4 A% W% w: S, Y/ A$ W3 i* }
{6 ~3 Y; ^2 x) N
if (cotacoes[1].high > cotacoes[0].high), K0 P6 W9 K1 s( m, o, Y6 Q9 T
{( B# {! w5 i" n- l( I8 q
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
5 M0 l5 J* z+ {; }" Qinfo.NormalizePrice(sl);- Y, w3 }7 b9 k8 q% n: E# D
if (sl > SL)
3 P+ i8 e3 I- J4 a; V{/ s% C; Z6 k" a. n6 S6 |# r5 s
negocios.PositionModify(_Symbol, sl, TP);" h. L5 D; q9 `+ c( {* o7 Y3 d
}/ r6 b3 S |5 }% Y% _. n
}
2 U0 w& Y! w# ]% j}
1 N' G) p/ V; L! M# s# Welse // tipo == POSITION_TYPE_SELL
* H0 O) G4 p3 e; }) u9 j{' W+ |; \" |7 e* a( q
if (cotacoes[1].low < cotacoes[0].low)
) h `/ x* h/ [% {: B8 \1 @{
: G: g" p2 p9 H' t- nreturn true;
M- B* z* b# [}
; y, t; E6 I7 m% e" E, `2 G// there was no position, ?0 x8 N7 y! Q; N" L$ Q" O
return false;& J6 q7 p3 C4 @. f7 Z& s7 U
}
8 m( U0 F8 `! l" I我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。( H6 \; f* {4 d" ]
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |