启动交易模型,并构建 EA
. N2 C0 I$ I' T在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。' B' }/ E" M( C' E' z
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。! p0 I- V6 R' r2 m3 @7 R1 _: n2 _( C
以下是制定这些规则的代码。+ F0 V$ f4 P H3 B" V* F3 W* D
//--- Indicator ATR(1) with EMA(8) used for the stop level...
+ h z. Q, F: d% Z. dint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);4 B9 k) B- r+ ]: N5 t" q0 S
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);: x& k. e, R% m; h; A: ~ _: f2 r
//--- Define a variable that indicates that we have a deal...
5 \$ I z2 @4 D$ ebool tem_tick = false;, n: s/ _, V2 W9 b2 j8 ]6 k
//--- An auxiliary variable for opening a position# n9 C2 K8 a8 Y! @$ x" K4 D/ J4 o
#include<Trade/Trade.mqh>
' w0 I: r" z- a X5 y#include<Trade/SymbolInfo.mqh>
& o' g, I# i3 w. e! ?8 fCTrade negocios;# t4 e$ P1 Z& {4 E3 s
CSymbolInfo info;* q4 }7 C& h4 E& X& e
//--- Define in OnInit() the use of the timer every second1 p3 M3 m5 w5 I- l
//--- and start CTrade( x7 f5 D9 {7 y/ k. c# }5 r
int OnInit()' f, j1 k5 U1 p7 t0 K* N
{3 H# E' F* Y, {
//--- Set the fill type to keep a pending order1 l* h& e) s/ W
//--- until it is fully filled0 B& b* k4 c* C/ @; j
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
6 p3 _$ Y- P3 @' p; h//--- Leave the fixed deviation at it is not used on B3 exchange7 _( Q6 |, B' B. M4 ^
negocios.SetDeviationInPoints(5);# M& @# @8 l; N/ j5 {' F# v x
//--- Define the symbol in CSymbolInfo...1 \, U2 h/ j8 }4 Z7 ^
info.Name(_Symbol);
" L5 `, P8 `# n/ N) b7 A$ D; L//--- Set the timer...$ E9 U4 }7 l: j' c" o% t' X
EventSetTimer(1);+ f- f& e# _: t
//--- Set the base of the random number to have equal tests...4 ?0 V, @9 s0 `/ Y( d
MathSrand(0xDEAD); _. Y$ p6 r, V7 x; x
return(INIT_SUCCEEDED);
5 @8 F1 [& f+ k7 m6 l# {$ @8 T- }. s}8 x1 Y, S/ F9 Z$ Q5 e! c3 N
//--- Since we set a timer, we need to destroy it in OnDeInit().
6 G+ j" h# Y" Q+ _void OnDeinit(const int reason)
! x* n' ~# x: }1 m9 z* d5 [. {1 f{
( }3 B( D* X5 j0 f0 UEventKillTimer();
8 I% d$ t# [5 ]+ g4 u8 ^- W}. ~4 ^ x5 q" t" w, E2 z
//--- The OnTick function only informs us that we have a new deal/ Y- T i: ~% p' o
void OnTick()
# j1 o! \* c' W# m8 o6 H6 \; A2 d{ E0 E: Y; D- e4 g; I. o
tem_tick = true;
0 b, [/ E$ y% b6 q+ ]}4 b6 w* V u/ Z7 ~1 d
//+------------------------------------------------------------------+- _# v6 V c& ^9 ^0 ?, q
//| Expert Advisor main function |$ S# X! I0 C3 q0 P8 C
//+------------------------------------------------------------------+
& ~2 z+ P$ f7 O1 O/ ?& Dvoid OnTimer()% m7 k( M- v6 \8 s# x
{
! Z( I8 s6 T& [6 s% e" _/ |MqlRates cotacao[];
9 S/ a: [, p2 J6 V7 treturn ;
2 b% L1 `) v2 h$ Y8 r: ~if (negocios_autorizados == false) // are we outside the trading window?
& S& m* }, @6 qreturn ;2 m- D; \3 i; L% v7 E A+ O
//--- We are in the trading window, try to open a new position!& ?* Q' D, L' B7 _6 `
int sorteio = MathRand();
7 e: I; v" s, I& y j//--- Entry rule 1.1
$ ^6 O: N Z# Eif(sorteio == 0 || sorteio == 32767)
* X+ m: ~. E) q( w& H! Treturn ;
/ R U5 H' Q& ?( n7 Xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
' u# B. E; h- W8 s$ d! s{5 H' x$ t6 `$ G }& @
negocios.Buy(info.LotsMin(), _Symbol);" r/ n4 Q# {2 ]
}
9 d: Z2 O6 E3 N8 `( N! [, gelse // Draw rule 1.3 -- odd number - Sell+ e/ r; I5 r; Z
{1 a0 o w) ~$ Q" B; k
negocios.Sell(info.LotsMin(), _Symbol);
, n) M& u% D. I1 O( u. D0 k}3 j! b/ R1 {! x2 t# M
}
* ]. A( H# l( x/ b//--- Check if we have a new candlestick...
8 a4 G5 e+ A1 m: Z$ E- fbool tem_vela_nova(const MqlRates &rate)
( A& G% t: p. u{! v* o* L2 {; b( K
{
# x( }7 P4 C8 [. V& Y9 H }* p9 Oret = true;% L Q g: }8 _' @
close_positions = false;
0 w+ c) a3 ?$ {' J* n}
* ?( l8 n$ W' delse
9 X& j. C& z. L% N/ e{3 l# h& j0 w# N" o+ B1 C
if(mdt.hour == 16)
+ n" p% N( n* g: j( G) k( t$ Kclose_positions = (mdt.min >= 30);" K4 G3 j$ _8 ^. k
}
/ Y* q3 B* Y6 }$ _1 @8 q( d3 V4 [8 N}
+ U4 o. o* f R: P" o# Greturn ret;
0 f# @3 a- K& l. O0 U}. T+ @+ ^% u2 v7 w; B( \
//---
9 Y2 H+ M6 ~7 | Q) Z6 [# p& ubool arruma_stop_em_posicoes(const MqlRates &cotacoes[])' ?/ h# C, r- `+ b( e6 \
{+ ]) A0 U: m& M3 x6 D% }4 S" S$ ^! ?
if(PositionsTotal()) // Is there a position?
# e r% W* r% y, I) f, Q# [{
! n0 \' w* e0 a1 Odouble offset[1] = { 0 };
) @4 p- F# u/ y( a5 J: _if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?5 s& T% g# |: W2 ]: G* M; l: Z
&& PositionSelect(_Symbol)) // Select the existing position!
7 T# F& y3 R1 O/ |9 j0 k{; m4 y& g! j6 \$ w8 a! x
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);1 j! k" C$ }7 |* [$ d
double SL = PositionGetDouble(POSITION_SL);4 z8 ^. X) p. q1 u3 P
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));6 v5 }8 z5 N( y
if(tipo == POSITION_TYPE_BUY)
4 O! A1 U: {0 Y$ X{( |) I H3 `5 |) L
if (cotacoes[1].high > cotacoes[0].high)+ B! B# a7 W/ n4 y6 {/ d* \8 H: @
{' J# c; M' |& Q0 k$ x& G; @: R
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
( B' }+ L) ]5 N {info.NormalizePrice(sl);
4 z* s3 o3 Z% V9 rif (sl > SL)- W: i4 g7 o$ ^- I" H+ u! P
{
: z! X7 Q9 z0 I* Gnegocios.PositionModify(_Symbol, sl, TP);- q% K" _% x7 K0 ^. N
}
# u( H! @2 N/ d! W}: w& N$ g! @3 S0 X: ? w/ U
}8 P; Z9 ^* d+ d5 N! U1 F: j- |
else // tipo == POSITION_TYPE_SELL- l" N8 c8 r6 ~1 i( Y3 S5 p3 Y! E
{
* T6 b. q/ {/ _if (cotacoes[1].low < cotacoes[0].low)
2 y, @/ ?7 P) @% D{
3 |- ~% s5 ^3 l2 `+ ereturn true;% X8 p' _0 N- M: U- e' r/ u% F
}
9 {$ k8 M: d1 M6 g: z! A& `// there was no position
- s4 X# i9 i( Preturn false;6 ^, @; G; Z" u3 G* r$ p- ~
}8 K1 v5 [5 M, B
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
, j3 D9 Q: s& _& m7 X到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |