启动交易模型,并构建 EA
4 d3 W/ i) f3 ?' @在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。1 Q# m6 J5 o& [& y
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
, N/ g$ z2 G% D' F* W, ~$ C以下是制定这些规则的代码。
8 b) }" h" ~4 J$ n+ B' v4 Z7 g//--- Indicator ATR(1) with EMA(8) used for the stop level...
! I# O3 }+ z( uint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);. W9 S) W* ^! F. g e; M" D
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
) s. [& H: j% ?+ f7 b, C//--- Define a variable that indicates that we have a deal...1 S' N* w6 { b* B+ v
bool tem_tick = false;
- d) a5 K+ U. Q1 n$ k4 S- u//--- An auxiliary variable for opening a position+ o% l ?: E9 ]3 ]! t2 B: W" u% v
#include<Trade/Trade.mqh>
5 O" K3 P: n+ [( F#include<Trade/SymbolInfo.mqh>
B0 ]0 w/ w0 E- F- u5 KCTrade negocios;/ C _2 S, l) I @& V7 L; i0 I+ V
CSymbolInfo info;
: \6 n2 `# C5 k# v//--- Define in OnInit() the use of the timer every second- C: o4 R h$ u7 k( ~8 }( R+ I
//--- and start CTrade4 s# T; @- r: g0 I' e% a
int OnInit()
* M- W8 n% I7 F- }8 e( P{6 ~2 O+ [4 Y; L: a( z ^
//--- Set the fill type to keep a pending order
7 S) D# e- }1 P5 g+ z/ T+ M//--- until it is fully filled
* ~* q$ |8 J/ l0 [7 {4 V* Xnegocios.SetTypeFilling(ORDER_FILLING_RETURN);8 L8 Y$ y' r# L: L
//--- Leave the fixed deviation at it is not used on B3 exchange
. P& b# E X+ Q, A% H; S( C0 ~negocios.SetDeviationInPoints(5);4 o' p9 Z! ~- k" F- c" J
//--- Define the symbol in CSymbolInfo...9 d! c9 b9 h3 J; _( c2 ?
info.Name(_Symbol);: K9 b2 I# D# J
//--- Set the timer...
. F$ I) Q {# [: Z. _EventSetTimer(1);1 g& u5 w/ o; O- K4 s
//--- Set the base of the random number to have equal tests...
4 k, }& l" s- @: CMathSrand(0xDEAD);, k E3 G) F7 J& ] T; i; N1 @; q
return(INIT_SUCCEEDED);
b- Q) ~! Q o9 d1 h}
4 V7 I7 s: ?7 N: W//--- Since we set a timer, we need to destroy it in OnDeInit().6 N! S. _# A' v3 Z/ f0 _2 w
void OnDeinit(const int reason)4 }, l( Q$ U, E: \0 `
{
) |7 g6 V8 {: p* Q* Y+ J! |" E* ?EventKillTimer();6 i) @, s; E" C5 k( q
}
! W) ^8 s* }8 _# G1 B# i6 W+ u//--- The OnTick function only informs us that we have a new deal
# f; q6 @9 w2 @6 R/ Y# Avoid OnTick()
$ ]/ n: l) w X+ a+ Q o5 [$ e{
& {8 Z. \9 q, N/ U# F0 g4 qtem_tick = true; C" ^7 n0 W, L6 p9 Q! z+ J
}$ {, X9 |8 r& s% u3 m
//+------------------------------------------------------------------+
) O& g, U3 h7 m; K//| Expert Advisor main function |5 k2 m( E0 I9 i2 O+ o
//+------------------------------------------------------------------+, B8 n0 @+ [% L5 D6 X" L; J
void OnTimer()% w* f' [2 e; D5 h M4 g
{/ |% Y, b2 i1 Z% F
MqlRates cotacao[];
& }+ J* b* a4 Y% U4 U- _return ;8 N! B" g! F% l1 K$ S! N5 B" v
if (negocios_autorizados == false) // are we outside the trading window?# X0 a: B9 g0 F6 M1 J% J6 `5 O
return ;
% B" y1 a9 _% C* p//--- We are in the trading window, try to open a new position!% E. |( O0 c, {) H
int sorteio = MathRand();: M# Y% _8 K, o5 F
//--- Entry rule 1.1
8 G- C$ c0 W& q* a! X5 }if(sorteio == 0 || sorteio == 32767)
, i/ t/ d' X+ h' r8 ereturn ;! ~% U1 B6 V' K, L2 A9 t( `
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
0 }! }( E8 R6 z+ e6 _$ \# \{
/ {% [8 C' r- u/ i: U, C h7 J* f3 pnegocios.Buy(info.LotsMin(), _Symbol); f& B. w3 b! L) p5 a) I; \1 @
}
1 _4 Q3 l0 g. z( J8 Relse // Draw rule 1.3 -- odd number - Sell5 f- \7 A. P& L/ H
{' L; C, [9 }* q8 v. m8 t
negocios.Sell(info.LotsMin(), _Symbol);
' E' i# y& C3 n- P}/ P3 ^8 b! L% T# b! m% d% ]
}+ u. W" d* \( \! v
//--- Check if we have a new candlestick...9 v. T& Z6 H1 c) _4 q/ \
bool tem_vela_nova(const MqlRates &rate)
/ n& }! r. P* G6 y; I/ j% p/ ^{, k8 u2 T" F$ w+ Y- b
{" i9 C! U% @( a" l y
ret = true;
2 V% K. F0 d4 ]close_positions = false;- Q w! f; P K- L0 L. Y
}
2 d: ]4 Z- {" x( `2 |1 g4 K: O! P4 eelse7 k0 v Z1 P7 [+ |/ B" ? ^
{, K' K; @4 }; Q% w9 t% \% N
if(mdt.hour == 16)
' R) Y1 W+ Y6 zclose_positions = (mdt.min >= 30);5 s4 E" q. F( A& P5 l% l
}
9 U6 q, l# E" x! }* N}
& _* _' ^9 O: B7 |. breturn ret;7 }9 I( I; w: p/ U6 f# @! w
}* q+ O* `; I7 h6 Q; I
//---$ _" p* B" e. W0 B5 o
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
+ X1 ]3 w/ }! Y+ C! X; ^/ Z{! P; I2 U& F% k. c8 }4 S
if(PositionsTotal()) // Is there a position?+ }7 P+ p: K4 p; R5 }' X6 w& A1 Y
{/ B8 w1 y8 q2 W b6 {3 o* h
double offset[1] = { 0 };. x W, M5 |7 H5 Y2 \- d2 D9 F
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?) ~5 r2 B+ e% k3 ~
&& PositionSelect(_Symbol)) // Select the existing position!: @0 u$ \$ T7 |8 P" d; v) I2 i7 X8 p f
{7 v" ~, ?* _2 ~3 M
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 b: x/ ^ z- ?' C, k( ~ i
double SL = PositionGetDouble(POSITION_SL);
7 f+ C, E3 I3 `" c+ adouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));! s9 a- F- \7 ~6 l& D; k. t. m6 a
if(tipo == POSITION_TYPE_BUY)
/ c/ i y2 U% O/ k% k6 p6 h{, {* D. _9 j6 r: f
if (cotacoes[1].high > cotacoes[0].high)! _' n+ H' o2 R1 Z: i
{5 z8 N1 ~. i2 n! U4 g
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0]; M z3 M, f$ |6 Q, H8 P
info.NormalizePrice(sl);5 O9 G. Q4 N) M# y
if (sl > SL)
2 T- m. B1 Q4 `9 j3 m" ^ f{
- t& Z8 Q7 p2 ?9 D% C: Enegocios.PositionModify(_Symbol, sl, TP);2 e0 b0 v, q1 a' w: O- S! \
}
0 q S6 P5 X1 T, i {: h}9 H0 S; U6 f: @: f) l' I
}2 g" d7 Z' g/ |1 N* J7 K4 R8 _5 K3 c
else // tipo == POSITION_TYPE_SELL
1 k8 q+ z7 S4 W( s4 g, s! s{/ x: y, Y- J2 Z) r A
if (cotacoes[1].low < cotacoes[0].low) A% t, v" r$ e. f4 r( Y
{
p& \7 b4 O) w4 dreturn true;, u* W6 h) v0 \3 B6 d; `) }. {6 a
}
- e" @- z0 Z) v2 v. t7 r7 r// there was no position
$ M' o0 }$ Z0 y. lreturn false;3 c+ R5 d$ W4 }- p7 h
}
) {1 Q, o7 z2 N, a- ]$ o我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 q# m: T1 l" x
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |