启动交易模型,并构建 EA* a) A3 W! m/ M3 A9 {- h
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
3 g0 V- \% ~2 b* j7 d( j& _为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* e6 V, {1 Z; p9 f v$ F" W
以下是制定这些规则的代码。) {4 \& Z. N! z" t3 X5 d4 Y! a
//--- Indicator ATR(1) with EMA(8) used for the stop level...8 {$ B0 ~, _& A- F$ F5 b
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);8 E8 ^0 Y) U) Q# v/ ]9 D
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);: M! `" f3 K: R4 B0 n$ m
//--- Define a variable that indicates that we have a deal...
/ `+ u9 ~) @ V9 i# x: Qbool tem_tick = false;
, A+ E# }" c$ |4 l//--- An auxiliary variable for opening a position! g. Z/ r( }: w4 n, A
#include<Trade/Trade.mqh> h! ]* A9 d. a4 I# m' a3 k
#include<Trade/SymbolInfo.mqh>
4 b8 v; g2 Z2 Q5 H0 J( i) v, o0 ^CTrade negocios;
# ^9 }. s8 r9 I5 l2 DCSymbolInfo info;9 E% e! r8 @7 V) D4 n2 a
//--- Define in OnInit() the use of the timer every second
2 b0 `! M6 Y0 `1 s# S//--- and start CTrade! N) r" ]- Z2 J; O) M3 S8 h
int OnInit(). i9 \' Y( B1 N0 ~9 }" I' v7 j ]. Y
{* G7 ^ G8 _% h. a; J5 G% q# K1 t
//--- Set the fill type to keep a pending order
4 f% V# ^' W6 ^4 E- b//--- until it is fully filled0 f# D" l' U* n, e
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
6 u) s/ [' O* Z* ^( ~' Y" t r//--- Leave the fixed deviation at it is not used on B3 exchange
: ~: y2 E% ~$ _negocios.SetDeviationInPoints(5);
0 {: A% O p L# L$ b. ]! }//--- Define the symbol in CSymbolInfo...2 n; `3 X' Q/ {8 L1 V7 V
info.Name(_Symbol);
0 T9 p# D5 m' D' A j//--- Set the timer...
! |$ f) t4 F. h; h: i' @EventSetTimer(1);
4 g' X0 T6 Q8 P0 q. h8 Y$ i3 n' b//--- Set the base of the random number to have equal tests...5 s$ C; ~. L9 u
MathSrand(0xDEAD);
+ p: B7 C$ L* r& F& l preturn(INIT_SUCCEEDED);
+ L( k( y5 p! u2 M3 f}" \6 {3 W7 A# c% Z
//--- Since we set a timer, we need to destroy it in OnDeInit().
8 r. H; S: T) T" Dvoid OnDeinit(const int reason)5 j/ X0 x. t! `: X3 }2 X; i
{
`& `6 b$ Q8 b& k9 a6 c% [4 p+ zEventKillTimer();& e! C, x) _8 l" @& h2 U
}
7 j0 g2 ~" T* A: ]1 }//--- The OnTick function only informs us that we have a new deal
% D' P" @/ \) c. N+ m! L0 \void OnTick()0 O# H1 |' \" S
{' Z# U+ W* B2 G6 L
tem_tick = true;5 l* g- X& R* e( `( G' [
}% Q( D% O) r. [# ?
//+------------------------------------------------------------------+: C- z) [9 x+ Z1 }- }8 g
//| Expert Advisor main function |
8 ?5 k. I- s1 U2 J4 j//+------------------------------------------------------------------+" I5 Z/ D& {# x2 V( c0 ~" d
void OnTimer()# S6 o. V# U) I2 ?
{
! d: B3 i; H W* tMqlRates cotacao[];+ J* t! G+ V0 i' k7 _
return ;1 g7 L) v8 H, p
if (negocios_autorizados == false) // are we outside the trading window?' v" X/ Z% Q' D) V# v1 W& h. G
return ;* m# X2 Q" O! e
//--- We are in the trading window, try to open a new position!# I) x% x: x3 Z! p
int sorteio = MathRand();2 h) r) }# }) q& F8 X$ D
//--- Entry rule 1.1# y2 k0 R, G6 w1 m' d9 }
if(sorteio == 0 || sorteio == 32767)
+ n+ U$ w( f: J9 Ureturn ; b- ?( G$ a$ |3 K5 z
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy9 t& u( t5 {* B
{" X( g3 G5 H$ e9 ]8 ]$ x P
negocios.Buy(info.LotsMin(), _Symbol);/ f% a5 I4 P1 A* D7 O: _: \0 o. f
}* r8 t: h6 o) _6 F: V" h+ ~
else // Draw rule 1.3 -- odd number - Sell. v E) c. ?& i& p" Z6 ~
{
( A' r+ @9 X4 {' cnegocios.Sell(info.LotsMin(), _Symbol);. c; G0 O8 r* i n9 D
}7 ~ P, K! @' e2 l A3 o
}
6 e7 d$ l3 d5 D//--- Check if we have a new candlestick...
9 ~5 Y# Z+ O1 \! nbool tem_vela_nova(const MqlRates &rate)5 Z5 V8 H) P1 Z s0 F; @+ |
{
2 n/ S5 u0 x: G$ g3 I{
! H1 w! R: H: J+ }. Y% e$ U, Z3 {ret = true;
' R$ k! Y! H. }# hclose_positions = false;
' g* t4 q; V+ [' _' [* t8 W}" z9 M- v( K' f! T' m- w
else! u# A3 l1 r# \6 I7 j
{! z! S! y7 U2 ^$ O
if(mdt.hour == 16)
. Z* ^6 l5 D. r) fclose_positions = (mdt.min >= 30);# ^) I7 y' G0 H
}( U% S b% H! b
}
9 }, r; X3 W" hreturn ret;
) ~$ Q) u9 u3 M4 w; A: d/ d! G3 v}" D2 ~8 q! c/ l
//---7 ?8 h$ [1 X5 f, S3 Z+ q
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
0 J8 F4 r* b5 [0 B{8 n0 z: p- m0 I9 J8 P
if(PositionsTotal()) // Is there a position?
% B* T7 e1 y. L( X* v: y{
8 h. G+ o: q, q6 ^double offset[1] = { 0 };2 ?0 S( ^5 ^6 ]4 C
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?& h$ D7 i- w$ q, o3 g* ^# Q6 f
&& PositionSelect(_Symbol)) // Select the existing position!
# o( b+ k! r5 N{2 w2 x* T6 C5 b9 o D
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
; ?5 R o# B g- G9 Pdouble SL = PositionGetDouble(POSITION_SL);/ W2 X5 S6 i' R" X, y B
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* f! v% r( j2 x! n9 W3 n, Bif(tipo == POSITION_TYPE_BUY)
5 O5 b1 v2 N/ z% T/ M# `{
' S( S0 B/ g6 ~& z) L' ~if (cotacoes[1].high > cotacoes[0].high)
8 N$ ~3 l, O1 p8 d7 m" u{
4 ?% {% r8 ]( r0 f! D) ?# Ldouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];1 F" L4 _4 x' Z
info.NormalizePrice(sl);
8 x5 g6 m# K- h, X; Rif (sl > SL)
& @! r. N. @: ?# X4 y{$ I# U5 g: A* ?9 ^
negocios.PositionModify(_Symbol, sl, TP);
- U" x/ p& h r- w) }' x- n# p: q" |}
$ U1 j9 E5 ^; t9 ]9 M6 @2 o! b}& G( U: T2 b# E% B. R- z( b
}
( R/ {& E: A" O! U' i5 J, _else // tipo == POSITION_TYPE_SELL
1 y! R9 P! u9 q{" z3 m' M! z+ [1 ~+ s
if (cotacoes[1].low < cotacoes[0].low)( z8 u+ A( b' G7 V4 z. f) `' g) @
{
4 X4 W7 y# o) G: wreturn true;
1 d9 V+ T. k( z. n}
( {6 u3 ], S$ K! X0 E. H// there was no position% z' q/ G# p. j% c2 g' I" W& ?
return false;
# P, Y0 o5 U- a# C}
$ ]7 E. | F# B7 v9 s' E4 E% x我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。$ K6 j. m: U1 G; N9 m" w9 o/ H
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |