启动交易模型,并构建 EA
3 r6 O# n2 X l1 i$ Y- c在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。8 I, w0 r2 }+ x7 @8 X3 X$ u
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。' @+ L' s) x7 P; c
以下是制定这些规则的代码。
& y& P' g$ a5 i8 F# i" q//--- Indicator ATR(1) with EMA(8) used for the stop level...% z+ `2 `" E& L( i
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
& ]3 C4 U" g1 `5 m) C0 Hint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
3 x7 y) G. ~+ F& M% M+ s- A- C _//--- Define a variable that indicates that we have a deal...% }0 |8 z; z* J) Z' w# ~8 ?+ A
bool tem_tick = false;- |) m: \/ X; O A4 @' F$ y2 `
//--- An auxiliary variable for opening a position6 B( f8 y3 n9 I& q3 H! N! G& P* X
#include<Trade/Trade.mqh>
7 S4 ^" `9 o9 M1 L3 m8 B#include<Trade/SymbolInfo.mqh>
8 V" `; |4 h0 U2 l$ @+ h6 g" d# N3 eCTrade negocios;/ U* o5 i9 C/ a4 j. s
CSymbolInfo info;
' u+ x& S' Y( |) I% r//--- Define in OnInit() the use of the timer every second' p/ n1 f' ]$ t, I6 u* D9 F
//--- and start CTrade& M3 I0 ?# D' N( `- L
int OnInit()
; {& |2 t% n: K7 X& ^{+ c% d- j2 g# [1 v+ e O: f, [$ t
//--- Set the fill type to keep a pending order
. a5 s. q3 E* l# U' D# n/ U//--- until it is fully filled
* i/ x- P" @& y1 W$ a! L1 Knegocios.SetTypeFilling(ORDER_FILLING_RETURN);
% d$ P) y. J1 j4 p//--- Leave the fixed deviation at it is not used on B3 exchange( z5 z+ |6 m3 u
negocios.SetDeviationInPoints(5);9 o# W, H3 I0 O7 c! I* G1 j
//--- Define the symbol in CSymbolInfo...
/ k, ]% @/ u; L7 O S1 K( i, v1 Hinfo.Name(_Symbol);
0 U' x' \ Q: `) _) i4 ]//--- Set the timer...3 k6 L m" R5 J, ]
EventSetTimer(1);
9 g# G$ V: ^2 a1 I: o8 E. N) m+ d' y//--- Set the base of the random number to have equal tests...( D8 N$ H& N' y
MathSrand(0xDEAD);& I0 j8 @) A' j4 m
return(INIT_SUCCEEDED);. F2 ^! R, Q# }3 Q4 d3 H$ J
}; J9 O) b4 p |
//--- Since we set a timer, we need to destroy it in OnDeInit().7 U' e! ]8 b# i! x
void OnDeinit(const int reason)
0 t+ @0 t' a# i{
1 g% h4 ]; j: l" B5 EEventKillTimer();1 [2 c2 f h; i2 o. L5 F
}7 K: V( Q! T: T, a
//--- The OnTick function only informs us that we have a new deal4 H5 D; Q. Y0 u6 Z1 y
void OnTick()
7 M& s# a: v; m% H8 z{
' [7 ~- t+ G# y! z/ dtem_tick = true;
4 l$ G5 A" [( b}
# I; o; s% t7 B, `) ]' Z% D//+------------------------------------------------------------------+
9 c' L9 y5 j6 W" ?4 e//| Expert Advisor main function |. Q- p: t5 S8 Q6 U9 Y
//+------------------------------------------------------------------+0 R. N7 N! e; T& x( t
void OnTimer()# V, S9 ~9 c+ j5 @& f; H
{4 q O h4 s$ {& C# q
MqlRates cotacao[];
v) v, i- d; ?% Q. areturn ;2 U1 r4 M& C+ {6 ?( O6 Z6 k
if (negocios_autorizados == false) // are we outside the trading window?9 o+ V: H9 I5 c( h; v
return ;/ U, R& Z. @) Y* P) ?" b+ c
//--- We are in the trading window, try to open a new position!
; M8 ~- B/ e) h; O- A! Bint sorteio = MathRand();
/ U W( L% D% o- N0 n//--- Entry rule 1.1: g. z& g M: ]) X1 r3 {
if(sorteio == 0 || sorteio == 32767)
' F! O* Y- n2 Q& I6 Kreturn ;% g" L$ n' _# d( w
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy! i6 E% |# D# H( I* l6 J
{
' m% L' Z' Y4 [% c( lnegocios.Buy(info.LotsMin(), _Symbol);8 `0 j) a7 B/ D6 |, G O
}
X; X: g5 e, d. ?$ {3 y* delse // Draw rule 1.3 -- odd number - Sell
- R$ j7 L& `& i% H6 E9 K {! h& Z{
/ n/ C0 O* W- ]negocios.Sell(info.LotsMin(), _Symbol);
0 P1 X& t, e% z+ Q9 W}
/ R. W0 o' p" R2 ]$ |}
t3 l1 k% |4 L- p1 V5 Q//--- Check if we have a new candlestick...
3 d# O6 u2 n1 `' H2 Qbool tem_vela_nova(const MqlRates &rate)2 B; ], D+ S- _: U8 T
{7 _- s* L5 @1 h' W( O$ m% ?
{* Z2 l6 q/ U; D. [& q7 d d# ]
ret = true;' ~8 w2 R4 {( g) t
close_positions = false;
# F$ E# Y1 `" G+ F& A$ S}
) M, v( P& {) |* v0 ~8 @else+ q% T# {2 d" q( Q: [7 t2 Q
{ T' w; Q _; z4 _# Z& `
if(mdt.hour == 16)2 x- ?! V1 Y1 `# O' K6 F8 Q3 w
close_positions = (mdt.min >= 30);
1 U1 y7 s3 j2 o4 ?}$ ], T/ B0 X0 b _/ z# T
}0 T* I+ z: B2 S+ D$ N2 o
return ret;
|+ n. P7 G0 x5 {4 ~0 T}6 ^% q/ ?& n( W9 V$ k% Y
//---
4 v# u& F0 E/ u! b/ S" ubool arruma_stop_em_posicoes(const MqlRates &cotacoes[])3 H: L; q0 n0 h/ Z; o [+ a
{
+ i% |1 S" i8 [$ l. c/ L7 tif(PositionsTotal()) // Is there a position?
+ J j" }; U/ L" F{6 Q4 `, A$ b3 H, \% g7 r9 {
double offset[1] = { 0 };8 B% X* Y* s2 V/ {3 s: y
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
9 L! _0 b4 A9 c, |&& PositionSelect(_Symbol)) // Select the existing position!0 ~2 k- l1 L, t+ `
{ V4 v! y. O0 z. \! f) I/ h
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
; [! Y7 J4 v* sdouble SL = PositionGetDouble(POSITION_SL);6 K$ e2 ]( Q% M5 V0 _2 G( b* {
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));# _) ]6 _6 d( w$ i! x4 {
if(tipo == POSITION_TYPE_BUY)
* A" \1 b0 Y8 s' c+ p" X9 J{/ Z# d: P! ?0 |4 [6 |! k, N
if (cotacoes[1].high > cotacoes[0].high)
; L0 J% I' x0 G6 l7 @. V; [{$ {7 m) {# O& j9 m C
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 d, o: L; i6 I- w
info.NormalizePrice(sl);+ e5 a. R' h- d, |) D) l. ~
if (sl > SL)2 o+ S+ i3 \# m4 D6 m! t
{5 g0 z1 J/ v& m5 j5 W
negocios.PositionModify(_Symbol, sl, TP);5 g4 a% ^' A7 H& n
}7 U) L% W- \& E9 e! G8 B1 o
}+ w5 c0 B$ W) k" s4 d2 E
}: l0 `; J5 c+ ?6 G, ], N) o! F
else // tipo == POSITION_TYPE_SELL# {4 F3 ]+ `9 k$ N
{8 s% M* {3 ]+ s: R- G' u2 {, s! p
if (cotacoes[1].low < cotacoes[0].low)( H% \! w' a' W y6 r
{
4 A( {4 Y( p* x( H2 g* |return true;
4 v2 Z$ B+ p( E6 c6 l}, l9 \) m G7 e2 U
// there was no position
( @2 H" k0 e2 A, v7 V- ^% Ureturn false;9 h4 I$ n" |& T
}+ o% f+ k x8 @, Y) D; G' c5 e
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
( |5 q8 n/ f. r" j4 |5 J6 @" v到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |