启动交易模型,并构建 EA
* H( ?# o7 K5 f) [! ^在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
3 b( }# e- H( ~9 X" W ?为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
; r. g" i0 n0 |) _以下是制定这些规则的代码。2 c$ b2 H# c$ M( ^/ f9 N& {* e: \* }
//--- Indicator ATR(1) with EMA(8) used for the stop level...% C; w: n# `; s
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
, @$ B e# A9 Zint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);3 v ^. ?( H9 q+ q; \
//--- Define a variable that indicates that we have a deal.... @6 X; k4 @( O4 L
bool tem_tick = false;* J! C: n# y+ d' {$ ^% B
//--- An auxiliary variable for opening a position
- t5 T1 G0 d& z8 D& S& O, v#include<Trade/Trade.mqh>0 R7 _: H6 f/ j+ H! i5 v7 }1 b
#include<Trade/SymbolInfo.mqh>' ^' Z" c: \+ [( A5 b4 q
CTrade negocios;
% n/ z, p) p- }; i5 p$ B! l0 |* TCSymbolInfo info;5 d, N1 ]# Q1 O+ q3 P
//--- Define in OnInit() the use of the timer every second
; n: H d+ \7 P% f5 y//--- and start CTrade
" i0 Y( n0 R# U, k' ~int OnInit()
- }, I1 x- z; C W5 J( _, a{ L4 l1 @9 ~- q; \6 I4 v+ N
//--- Set the fill type to keep a pending order
+ l( t1 o i8 e+ X* ~! _9 ]//--- until it is fully filled
+ P+ V* T& l% M% c2 l1 znegocios.SetTypeFilling(ORDER_FILLING_RETURN);
$ o, t3 c5 j) Q" u* ^/ y//--- Leave the fixed deviation at it is not used on B3 exchange
3 F: \+ K8 W$ J: N7 _negocios.SetDeviationInPoints(5);% b0 S. E# G: j$ W# j m3 C7 ], _
//--- Define the symbol in CSymbolInfo...# O; Q- |" i( b6 \: T! J
info.Name(_Symbol);
7 d' c4 n) }% O//--- Set the timer...
: W- h7 r' `1 f! I4 ?. z3 FEventSetTimer(1);& D Z3 g2 e! E
//--- Set the base of the random number to have equal tests..." U8 B1 H6 W" A& b6 a1 c+ N2 n' Z. L0 G
MathSrand(0xDEAD);; B1 H p/ s" o
return(INIT_SUCCEEDED);6 M# S5 Y; D0 b/ o
}
6 \) u) j; b1 C" B( z//--- Since we set a timer, we need to destroy it in OnDeInit().
g2 E4 T S5 Y/ z1 P2 G' dvoid OnDeinit(const int reason)
8 W1 R: H% h3 U! c{
* u; D! b) o9 y2 kEventKillTimer();
# c! R% L8 |: Q* @8 A. Q}0 s: ^' w: u1 b |, z/ Q2 P
//--- The OnTick function only informs us that we have a new deal
) c) e# B" s2 m& T$ r# e+ ]void OnTick()
- o' {/ Y. t1 F( s{
! G d+ h5 \9 ]9 P4 p* Dtem_tick = true;
& Z; c6 [& l0 H}6 r! `) d/ G2 ]1 }% ?6 \
//+------------------------------------------------------------------+0 r- {& {9 J$ l0 Q9 Y. A
//| Expert Advisor main function |$ w9 p( G9 z: L/ \" V' y6 c
//+------------------------------------------------------------------+
" [, U3 ^8 ^# e* R( }void OnTimer()
5 @1 B$ H, N( c{
: Y& M/ O1 j/ H" OMqlRates cotacao[];' _( a+ I. ] B+ J: U+ A
return ;: k- J# W9 d* `+ [2 A m( @
if (negocios_autorizados == false) // are we outside the trading window?
3 ~* _" V$ x) l* Y+ X1 `return ;2 {" w/ t# Y9 y0 N# H$ a q) t
//--- We are in the trading window, try to open a new position!
* h2 a' w7 n) }7 yint sorteio = MathRand();' W$ B# v+ J# w1 A; w. l# Y6 C' }
//--- Entry rule 1.1
. m" o+ g1 N% w8 m# `' V/ Wif(sorteio == 0 || sorteio == 32767)
6 G7 T2 T. b+ g& E: Mreturn ;
# H) u$ R' W) ?4 }" cif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy4 g1 }) x! e X" M5 D
{1 _- D: q" o# i& s8 }
negocios.Buy(info.LotsMin(), _Symbol);" c- \' p% |" |% c" [
}: @* d7 H* ^" V. t2 `8 ]; j5 K$ q
else // Draw rule 1.3 -- odd number - Sell
5 W6 m3 @: t0 _: u/ n* r1 n, T{" y1 G: [7 c* k4 u2 @
negocios.Sell(info.LotsMin(), _Symbol);9 g( k) c- Q0 U4 N
}
+ ^% r0 W4 w4 s# G) }& P+ O}9 T& t' H% N" ~ c/ L* d
//--- Check if we have a new candlestick...
7 O/ P `" ^/ ~* y( G8 t& L7 bbool tem_vela_nova(const MqlRates &rate) v3 m6 E9 \- Z- O
{% ^; A% o) H5 H" M x8 C
{& t/ Z [2 E4 Z/ v" D9 e$ ` L
ret = true;' p) `, d: n6 F, a, p
close_positions = false;3 l4 F7 x0 h" ^: x1 k* A' ~# s
}4 T% B ]) Y+ [- _+ K% ?4 |
else G+ E5 S9 f9 Q9 y
{( s9 P( K, d8 C1 w1 `6 `
if(mdt.hour == 16)$ `* v6 V( D1 f( o
close_positions = (mdt.min >= 30);. j ~$ z( V2 m- v; ~/ z
}; M5 y6 S& h, ?* Y. }
}
9 j2 E7 M0 y: Z# b4 I# h" }return ret;% }- |: m {% j! C
}
1 I0 `$ @0 D; }/ ]. ?//---
$ O# q; Q! d. Abool arruma_stop_em_posicoes(const MqlRates &cotacoes[])8 V* j8 H8 h3 o7 I) e
{4 N! P, x$ }5 C$ i2 }, X0 _8 n: y
if(PositionsTotal()) // Is there a position?
/ ^0 f' s% h% U" V. {{- ]! s& x( g- U% z% e. u
double offset[1] = { 0 };) f# S5 h4 l2 u) s% k
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
- U9 H/ h6 j% Z9 n! Z. M&& PositionSelect(_Symbol)) // Select the existing position!
2 e7 }' p {- i B: n- e) w{
! M7 x: {1 _' F! GENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
4 h i9 Q6 g6 P& O, o6 Idouble SL = PositionGetDouble(POSITION_SL);! Z8 Z: i: l; t) w+ I* u
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
2 {* E; t+ V' S" \; g3 n0 Pif(tipo == POSITION_TYPE_BUY)0 h% z6 g% j3 h2 f n- Y; O, r
{* V; c# z" c" p3 E. |
if (cotacoes[1].high > cotacoes[0].high)
6 f, Q/ n P3 l{
- l4 J! x J3 l) ]4 n+ ldouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];% |8 S1 b0 P ^( }5 P' e) K
info.NormalizePrice(sl);
: }5 g% _0 `% J% ?if (sl > SL)7 R: I$ }9 V9 y3 I1 x
{
2 F! W; A# _, w8 W' |3 @5 Onegocios.PositionModify(_Symbol, sl, TP);
2 F! B! ~1 g a9 T; l. {}9 g( t- |6 F# N& H' n0 ^& \
}
( [5 ]( B0 A8 c' e}
+ M; l2 u# j& [, Belse // tipo == POSITION_TYPE_SELL
& s( M; Q# B( X" b6 L* Z; j& H{
4 l$ D; z$ i# A8 }if (cotacoes[1].low < cotacoes[0].low)
' l8 [; I3 }5 L% S& k- J/ M{
, |/ |7 J+ u3 a. y6 Q) lreturn true;
# }8 d, |5 d- `: T# ?2 _}* ~& o/ y9 a+ i. J
// there was no position
7 z' R3 m, I% d; G7 d& `2 y1 Kreturn false;
: V/ R; d8 l" g. Z* R}, g6 v$ Q7 e8 h
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
: I& [: b7 \1 O& R5 }到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |