启动交易模型,并构建 EA
$ ~7 F4 q1 s1 i, i A" _在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
- W! Z% s k1 y5 D& t$ W' r$ F* n为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。7 z0 |3 U( l9 C, c5 l, I
以下是制定这些规则的代码。
: {: c! b0 j7 R( k3 @& `1 u' K//--- Indicator ATR(1) with EMA(8) used for the stop level...
) A& {$ n" L: D5 D5 yint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
4 \% P9 p4 _& n8 J+ i+ h% [int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);5 j; c' c) [% x5 v" T* ` c$ A
//--- Define a variable that indicates that we have a deal...$ ?9 R' i ]8 P# n
bool tem_tick = false;
; V& g" |3 F3 S' B3 c6 z//--- An auxiliary variable for opening a position, z5 Y3 Y7 s, m2 S8 J" P" j! p
#include<Trade/Trade.mqh>
3 m4 w Z$ W9 u1 F, j#include<Trade/SymbolInfo.mqh>9 `1 H0 Z1 l& A# f$ A
CTrade negocios;6 s7 g; B ^/ p6 r
CSymbolInfo info;
3 W# p* }, f& t2 `//--- Define in OnInit() the use of the timer every second3 X% A( J& J& u1 B
//--- and start CTrade
. X/ b# a8 D* F6 Uint OnInit()7 ^. I: \+ }( |8 F
{" U, i& P* u' M1 a& q% D6 ~
//--- Set the fill type to keep a pending order1 j; |4 M8 ~9 y4 R1 z
//--- until it is fully filled
$ {+ H" N1 |- N& c& @$ F+ Znegocios.SetTypeFilling(ORDER_FILLING_RETURN);7 \) ^8 u& _% Z$ j2 N# r. m6 [" a
//--- Leave the fixed deviation at it is not used on B3 exchange0 r+ V& T! j0 G: x0 g
negocios.SetDeviationInPoints(5);
3 Y6 @( p( B- p( i//--- Define the symbol in CSymbolInfo..., b( y% W6 o j. p) a
info.Name(_Symbol);
! t9 q1 O5 Q R//--- Set the timer...
" f4 O# F( E8 z) A% N$ uEventSetTimer(1);
) G3 O F/ s% i. R//--- Set the base of the random number to have equal tests...
* |, j, {8 D, C' M2 p) L- ?4 rMathSrand(0xDEAD);
: e% N# `8 m% i) U8 `- X+ n) preturn(INIT_SUCCEEDED);$ I. s2 P) y V) Z* Q3 { L f
}
1 L: A% j" `! J$ k//--- Since we set a timer, we need to destroy it in OnDeInit().4 \* b* L9 N: Y8 u P" C# K9 M
void OnDeinit(const int reason)
" |+ R+ q, b4 G{, X5 O1 u0 C, t" x0 g! L
EventKillTimer();
7 V" g/ b# v' w}
. K9 O6 o; R& }8 w//--- The OnTick function only informs us that we have a new deal6 V z6 g/ b# |+ p
void OnTick()
0 {* j0 d, W6 W0 `{
7 l7 p+ V! p6 T# G1 [ ^tem_tick = true;
4 l N) E/ w# C; G}
h! L0 ^% F. ~0 q% I8 L" a//+------------------------------------------------------------------+ I) v+ t8 e0 Y9 S2 C! D
//| Expert Advisor main function |& W) P# k, t2 `
//+------------------------------------------------------------------+9 j# n4 {& L3 o7 y& w. p k0 F
void OnTimer()
9 D) M6 a- }# o5 v9 r{ |+ |& `; J0 ~- ?; c- f: t! I7 }
MqlRates cotacao[];
+ I5 d( _, }$ M; Ireturn ;8 b+ a! v, k5 e# f
if (negocios_autorizados == false) // are we outside the trading window?; z: n2 o# Q; s r3 I3 X
return ;3 V3 H+ f$ O% m5 p2 N5 Z
//--- We are in the trading window, try to open a new position!9 h7 ?, i$ J6 e# v! `9 f/ ?" [
int sorteio = MathRand();7 j8 @0 Y, [; w8 i1 g
//--- Entry rule 1.13 W$ ^; Y( f6 z4 L. u6 ~
if(sorteio == 0 || sorteio == 32767)
( B7 ]9 G7 h1 s7 y8 _return ;
6 C& k) \- j1 {0 Dif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
: l- v! M% g/ ^7 }* W/ ]{& Y# Q+ d8 I* [. R1 q, l" z5 y
negocios.Buy(info.LotsMin(), _Symbol);- X( E; H, p9 Y5 \$ x; C
}
7 n# p* F5 R( z5 B9 h$ W# r5 Celse // Draw rule 1.3 -- odd number - Sell- ^$ ^: A% `7 }/ `5 H- G# A ^3 m' K
{7 k3 ^, z+ J% N" y3 W9 q [
negocios.Sell(info.LotsMin(), _Symbol);: g- { Q8 e# M" `
}
5 P* J( Z2 f7 m) b( P( E}+ A/ L- I$ |0 z
//--- Check if we have a new candlestick...
+ P& T4 t g7 @bool tem_vela_nova(const MqlRates &rate)
1 l. O. L8 d# W6 A' W$ k{
& q+ x6 W" z) f: C. P- R{# E3 @+ t. a J+ }& \2 R( ?5 K
ret = true;
' d4 o1 [! s+ I: ]( Uclose_positions = false;
; b9 v9 U4 ~8 C: g8 M}
: v; Z f* w A! S6 ?- D8 H2 o! \else
0 C# Y7 u' v, F, `0 h5 Z4 B _7 J2 G{# ~& c) P" H3 a
if(mdt.hour == 16)
6 @$ G N4 i- ] ]) E/ l0 N7 I9 tclose_positions = (mdt.min >= 30);# S, \% x, Q+ {9 ?
}
1 r- P+ M/ X& q8 }$ w; H( V}
( R' w. x0 E( K; Yreturn ret;
2 J2 e8 B( [& C+ z! U" h" f}$ l3 e, Y) e" N
//---8 {: S, o5 P- p: N' C
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])8 F* h0 c" v0 ?
{
P! e$ n# r7 e* {2 d2 Tif(PositionsTotal()) // Is there a position?
0 A3 u$ n4 a; {) B/ L4 e{
2 x5 a4 i% d R2 z+ R3 H: Ydouble offset[1] = { 0 };& a; t) h' h2 H: [: i& M) m- `
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?( Z" j4 n: ?4 s6 {, s. q
&& PositionSelect(_Symbol)) // Select the existing position!0 R, O1 c1 s4 a0 I3 f
{1 f. D2 k' _! L
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
. k! e( v" v% q9 A' xdouble SL = PositionGetDouble(POSITION_SL);4 g6 e- n! q/ O0 ?% } F$ o
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
1 A$ v, p- Z* \4 gif(tipo == POSITION_TYPE_BUY)% I' N6 e! ]6 q6 C) |( O, j# X
{
6 C2 X" Z( |/ o zif (cotacoes[1].high > cotacoes[0].high)
; `9 m0 s9 L6 p' A/ \' {{* @4 M8 b6 a- c A
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- r% W. M5 x1 |5 F" I, {0 U
info.NormalizePrice(sl);" P9 @& r" m6 V1 c
if (sl > SL)
6 ~7 h/ M3 v& M( P* j0 N{
* @/ i/ \, E) p |; f+ qnegocios.PositionModify(_Symbol, sl, TP);
7 O& h7 e( G, n, B ^% C7 A6 S# l}) p! F6 t7 z' }% J& e# L
}: j! R, r: b9 C: ]- Q1 f* z8 ~
}
/ }% F& z; ?- e; Y0 t2 ]) Selse // tipo == POSITION_TYPE_SELL: g4 |& w( {9 ^: P, E
{2 x. b( i7 c2 H# s- `5 w
if (cotacoes[1].low < cotacoes[0].low)% h9 Q- S& e" E) s% \
{
c( ~! f W+ K( L1 Preturn true;
" W) C3 V$ D+ [2 H* P& t) ^}/ g* K/ _" ^ J. j& c$ t
// there was no position
/ Y8 g5 V: D1 }' _return false;. y0 y$ H7 M; ]) k5 L+ o7 s
}- X' F4 \7 Z/ P7 M. x1 y
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。& B# P: I, g) y- i
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |