启动交易模型,并构建 EA- A% l1 ^* ]1 X& d# y7 V. E
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。 l; G5 H% { s1 e8 |
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* J* ]& ~& I! V" s( Y
以下是制定这些规则的代码。7 z$ t) d" L& u6 l
//--- Indicator ATR(1) with EMA(8) used for the stop level...2 x: l ^2 c" _! ]/ f" y
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
9 r7 H+ O8 Q: ]8 ~( O5 |int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
# a$ _" `5 \; v1 ~( W: g7 S//--- Define a variable that indicates that we have a deal...6 {; e1 p+ ?2 N3 o
bool tem_tick = false;
0 p7 W7 u& p' A: T- w//--- An auxiliary variable for opening a position
2 a X' k5 b+ B+ k5 i9 C! u7 Z#include<Trade/Trade.mqh>
8 R9 L9 ^: u7 e. ~' |4 o#include<Trade/SymbolInfo.mqh>0 G, v% R9 o B: \& ~
CTrade negocios;
8 @' J0 L. G! Q! k6 Z0 CCSymbolInfo info;
6 c* G" ]1 x3 Y! H* c. `//--- Define in OnInit() the use of the timer every second
1 R7 V' K6 z4 i$ T* F& Z//--- and start CTrade
0 ^. t# E0 ], r0 Z4 L( Z; Bint OnInit()/ U( ^) O m1 s# k
{! c _2 r8 \9 i# T! r J
//--- Set the fill type to keep a pending order
7 B4 R ^" a( F. {$ l( d$ s//--- until it is fully filled A9 b- `. L# l: u# f6 G( j. W
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
9 C- Y! S. ~3 G6 I) t" `//--- Leave the fixed deviation at it is not used on B3 exchange0 M* @1 `. v( [+ J5 W
negocios.SetDeviationInPoints(5);
9 y2 S4 S3 d7 q$ G3 ?$ S% H4 |//--- Define the symbol in CSymbolInfo...
# k" u, r) Z7 o9 c6 Vinfo.Name(_Symbol);3 e. Q+ o# J! z' R, R N' k
//--- Set the timer...( W" F% R) c8 q* i' x& e% q' r
EventSetTimer(1);
" E1 H! z& A$ i* |( [& X//--- Set the base of the random number to have equal tests...* Z0 I0 V9 w+ \8 F9 M
MathSrand(0xDEAD);
$ Z6 ^# A/ x- M9 R! {4 U' preturn(INIT_SUCCEEDED);% A1 I8 N, W) ?$ G$ V; \
}
9 r) y+ l" Q% i2 w7 _//--- Since we set a timer, we need to destroy it in OnDeInit().# J2 a$ B! U3 z/ ~
void OnDeinit(const int reason)) A4 u$ K4 x5 x2 l
{
* A( `: W. Q2 |# m# EEventKillTimer();" e1 w5 Y& k4 ~+ S @9 h0 r0 \1 \( W
}
0 D1 q+ C( g. n9 q0 v0 Y7 l//--- The OnTick function only informs us that we have a new deal4 z1 Y0 F7 w6 g& A' h7 x5 ]1 H
void OnTick()
( f. @. f& L+ n8 F. `4 M ~3 q! p2 S{9 v5 l! G v. T5 y: {
tem_tick = true;
i7 E; }5 ]7 l" k& l& f1 u$ i; f}8 z# M9 |, c: t2 Z/ }' ~
//+------------------------------------------------------------------+
! u3 K( ~: E, _: Y9 y* S//| Expert Advisor main function |
% O! K0 g( H' y( [- b u//+------------------------------------------------------------------+
& z% e! g, p. L) ?- d4 Gvoid OnTimer()
3 w: o# B( e4 V* G, W5 ~8 R5 k2 D{5 `0 C e1 h+ a& n( l* B
MqlRates cotacao[];1 e0 q& R: M4 S+ e# G. {+ W& u
return ;
; `" T5 }% p1 ]- E4 {if (negocios_autorizados == false) // are we outside the trading window?
0 `: x* h, ?% ]# |( |3 I* dreturn ;1 N+ s( M" S0 m5 n/ G; n6 m2 m7 ^
//--- We are in the trading window, try to open a new position!8 i6 k- K3 p+ P1 [7 C
int sorteio = MathRand();
$ H+ C1 ~ V6 j2 a% P% _" C& v; A//--- Entry rule 1.1
* x& @4 C# y# t/ z2 A2 e& S# rif(sorteio == 0 || sorteio == 32767); z( a7 ~$ Y( G% E, y2 o+ Q4 I3 o
return ;$ [' ~$ x K. @3 X' u( e
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy( Q% T& S% }! n# a: b
{
6 b; q6 v5 O' d% c2 Snegocios.Buy(info.LotsMin(), _Symbol);) _) ?( X. Q( h! Z. e1 x1 L$ q
}
* B9 X' H; K9 x2 J2 {! [5 S/ H: \' I# e% |else // Draw rule 1.3 -- odd number - Sell+ i1 a" H. L5 P1 m) y N' J+ v( }
{
$ w7 B# x. w+ {6 u( rnegocios.Sell(info.LotsMin(), _Symbol);
3 D! m3 ^! U3 U' K$ K) O" Q} U8 N2 B& T$ Z
}" p7 k6 W( \5 s: k
//--- Check if we have a new candlestick...4 M) c- j) Y5 c7 b b
bool tem_vela_nova(const MqlRates &rate)* Y0 j4 r; v+ X2 R8 T+ D
{
: e7 m! |7 t9 R! _# U{
6 m% D9 m! M9 I5 ?# Aret = true;
! }9 S- l% U! qclose_positions = false;
' k$ Q2 I/ ^6 Z/ a}5 Y ~% F4 H3 t W2 I U" F
else
' m* W" z( M# P5 ^; J' |{
, x) k/ v D2 \+ H% J7 F* w4 {if(mdt.hour == 16)2 ~# c n! t0 h M/ k" [7 A, A3 N7 O2 t, ]
close_positions = (mdt.min >= 30);8 @ H" c6 {: N5 q" e
}
5 w1 o4 n# n* u}" @6 r* F3 Y6 i; t \! L$ g; R t4 z
return ret;
& o; s+ j. \; b, q) Y}
( c% n, `% O ]# f//---
8 w( d' m3 B; ^ i' [* t5 w8 w' qbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
2 o" i0 Q1 |2 a% I{
$ s& e3 O) K5 ?if(PositionsTotal()) // Is there a position?
( u& `5 p1 y* b# g{
8 q( j+ c7 G6 k* ?/ Kdouble offset[1] = { 0 };
, R8 {% E5 K5 g7 z4 N, G) V7 kif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?8 {4 x6 r7 o) r- a
&& PositionSelect(_Symbol)) // Select the existing position!- p) e$ K6 j |$ L6 |" X
{- e" z) Z9 j& q
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
$ C: u9 |* w# x& Z8 f2 l9 ^- r5 wdouble SL = PositionGetDouble(POSITION_SL);) h# o! p+ h9 B6 K0 {5 V
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));6 e: A' s4 [6 n2 |# L
if(tipo == POSITION_TYPE_BUY)
7 d; e$ h' B$ o8 o w3 n6 j: O{
9 b) J5 u" N3 i% \: fif (cotacoes[1].high > cotacoes[0].high) N0 l$ j/ ]( U1 h2 s
{
5 G! k6 R$ {7 m1 tdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
7 F5 U% S$ Q7 j, f+ B* _9 Hinfo.NormalizePrice(sl);
2 ?! w% c# u$ f: O2 ^& p6 Qif (sl > SL)9 s- s4 Z1 e; G
{
( t+ _0 |5 f* F4 c: g& Tnegocios.PositionModify(_Symbol, sl, TP);
' z7 p5 c% [% E0 ]" w) }}0 j2 Z5 ^- m. D( W3 w1 }# {
}
0 o3 X7 R) N4 U1 T8 c) O}
1 c* [, I5 U7 Lelse // tipo == POSITION_TYPE_SELL" W4 j, G# W6 e1 R$ ?* X( w
{
; [7 l& r' p6 ]/ x4 Kif (cotacoes[1].low < cotacoes[0].low)
' t! z- I. S/ U( \- z6 a- G{ D( t% {. [- p3 L4 k2 b) h- ^
return true;
4 ^9 n: p+ v& Z: g- @9 C}
" b$ G! V# t3 l/ g) z: ?// there was no position
1 W. p& p. [$ O% F8 I' i' }, ]- x% a, |return false;5 P2 f0 ]$ T5 X) a' ]( H
}: g/ a/ c. [ b$ ^- |
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。# o G/ P$ q/ [6 l. \
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |