启动交易模型,并构建 EA+ l% h' h6 F) @+ `% O$ H. i
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
% X8 [ r6 f' m s0 r6 ?为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。3 r; p9 s4 c c# g4 `1 n/ z3 {
以下是制定这些规则的代码。$ O/ h7 ] F/ f O& ^
//--- Indicator ATR(1) with EMA(8) used for the stop level...
" O- u# g6 z- |9 @8 fint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
* X( f; A, ?% G% y8 L2 ]int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);$ A0 J+ ~3 p$ m) ]- f
//--- Define a variable that indicates that we have a deal...
8 ?' s2 n6 U o9 A' ?8 A1 ebool tem_tick = false;
0 w2 J7 g" D: P8 f$ K//--- An auxiliary variable for opening a position' s/ l. b, V \9 R, p# z
#include<Trade/Trade.mqh>
2 X) ^5 Q7 `/ \4 X#include<Trade/SymbolInfo.mqh>4 `: C, d% e; m9 l; p) a$ V5 t! C
CTrade negocios;3 }# o/ w$ T# B8 X4 i) x9 z$ ]2 v
CSymbolInfo info;* j4 m0 m, C% c- @( p
//--- Define in OnInit() the use of the timer every second
$ M* S1 Q- z7 {4 J6 M6 i$ p//--- and start CTrade& x3 M9 A8 Z# F% V7 z* Q5 Y
int OnInit()
+ N9 ?0 b/ J" D{
) ]5 y# P: t( ^//--- Set the fill type to keep a pending order
4 p4 R: V1 ]- g' j* d//--- until it is fully filled% l/ k8 r; ]" B3 G
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
! l7 u, a/ n& ?' Y: p//--- Leave the fixed deviation at it is not used on B3 exchange. b- o0 _) b0 D/ V
negocios.SetDeviationInPoints(5);' Y8 X. p h4 m, g- P% ^
//--- Define the symbol in CSymbolInfo...
2 {0 }8 t/ m, e5 H' [4 w4 B! zinfo.Name(_Symbol);+ d& w& t1 ?+ l
//--- Set the timer...
. w9 r. K8 w8 @$ Q. E, |$ d) e! |EventSetTimer(1);* K9 a6 k! M: V) t& O- _
//--- Set the base of the random number to have equal tests...
/ |3 H1 Y% {& R* CMathSrand(0xDEAD);
& D t+ E n$ S' O6 c, greturn(INIT_SUCCEEDED); R& A9 q) Y: T( Q
}
# w1 c# I8 j8 w/ G//--- Since we set a timer, we need to destroy it in OnDeInit().& N9 K/ w- q. Q
void OnDeinit(const int reason)9 T5 G9 ?0 L( q5 y4 w% R/ H% N
{; H9 S' Q3 Q4 |0 x4 Z
EventKillTimer();% P! l2 d& L, G9 M& M! n& e
}
2 @ g5 \( M1 t- E" j+ y$ C7 V: x//--- The OnTick function only informs us that we have a new deal
1 o" R- f4 Z" z/ u# Gvoid OnTick()
! L% ?4 b6 X8 ~4 j% g8 n+ f4 B{
1 Y5 u, o( W1 ^4 _9 N6 d8 I! f# ltem_tick = true;
/ E0 S6 I( }" R. {& O}
5 e/ n5 l+ D) ?/ L2 B6 W9 X9 [//+------------------------------------------------------------------+
C5 Z) D6 c8 ^9 g% u; p/ a( \//| Expert Advisor main function |
% Z+ d) w+ W2 @ v4 K) y//+------------------------------------------------------------------+/ u# g: t7 Q3 ]# N: F
void OnTimer()
1 O" \! u: ^: F" E2 q6 F{
" m1 d: i" y' p3 T8 AMqlRates cotacao[];" E; k6 o: P# |7 L3 w! g/ X' @
return ;
3 ~6 E) M8 X6 P1 K5 I- fif (negocios_autorizados == false) // are we outside the trading window?
1 j7 H" ?) [) \4 Z* M0 mreturn ;4 P8 v3 h' z! ~
//--- We are in the trading window, try to open a new position!
, I. o0 o) [1 F, J; ~3 e8 sint sorteio = MathRand();
; P" G- d0 E/ W0 q//--- Entry rule 1.16 w" x9 Y6 k3 S/ l
if(sorteio == 0 || sorteio == 32767)
, q' x( h0 V0 h. l% ?- ~return ;( z8 L9 q) e- I9 G5 R: f: K
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
9 g( ]8 v! A# o K! T' k{9 a- \0 p# U; K3 a7 F
negocios.Buy(info.LotsMin(), _Symbol);
, I; [ ^3 u7 `0 G* w& E}
5 ^5 V, m# M) l4 U' S! R. y" i/ S' Kelse // Draw rule 1.3 -- odd number - Sell1 }( V9 A A( O4 ~* t+ R
{: o% i0 B9 e, N, N( s
negocios.Sell(info.LotsMin(), _Symbol);
1 I+ q2 v+ S" i1 @+ f) g}
$ T8 F# O6 @8 B( ]: @}
8 N! ?/ V. ]$ V4 y//--- Check if we have a new candlestick...7 b# E; T5 O! m; A& y6 S
bool tem_vela_nova(const MqlRates &rate)
( q* C3 Z3 p4 Y{( `# X! \: c& x' F4 ?4 D
{6 R" l P$ R/ \2 ]: v7 _$ I1 B
ret = true;
! K& y: o& t5 g) L6 x5 ~close_positions = false;$ J9 n3 v7 r2 s9 ?& X
}* [# J! `: G, e! d/ j% U7 F# B
else
0 R# b1 Y; w0 g1 ?{( o$ A! {) l1 {- Q0 y
if(mdt.hour == 16)( H! E/ l& n" V2 h9 n9 L( \
close_positions = (mdt.min >= 30);. M* d( p4 T5 Z" K) N( @
}1 ^% L" A3 A: a; ?
}& W1 r2 w3 j) D, _
return ret;0 S6 K w9 _! I
}
4 ?2 n3 R2 c' Z9 z9 y1 a//---/ I- Y& z( O( I( L# R* j3 B3 t a: u1 d+ U
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ h% d/ N# _% P: a7 Z
{
. X5 G3 Q, B1 s, h. E5 [4 l* k1 Uif(PositionsTotal()) // Is there a position?. ~4 Q* v2 X+ ?3 D9 y) u" u
{
) k: T1 H% i1 u$ O0 N. N3 n% pdouble offset[1] = { 0 };
. Q0 q9 ~7 M1 T8 Z8 J/ Oif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?) y5 }# X9 b$ s9 ?
&& PositionSelect(_Symbol)) // Select the existing position!9 U$ t$ f: h7 _& ]- u w7 v/ s
{
2 `( U* i2 T/ e9 V! P a' TENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);, n$ _* X) b: N% x% \6 G3 {& q3 u
double SL = PositionGetDouble(POSITION_SL);! x" ]) H8 \" x5 ^# b7 @. y1 e& ?
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));5 {8 F0 L$ _+ K3 B6 ?/ _
if(tipo == POSITION_TYPE_BUY)
* H/ [. i$ G& ]. l" r{
* `! D" \2 [$ F0 I+ H; A) L' J sif (cotacoes[1].high > cotacoes[0].high)
) }. i C W% u4 d# j! k/ X! P{" m: G# a* S; \9 B: \* a
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
# ?8 j! }+ Z0 W! H) @: n0 G9 V5 l7 Cinfo.NormalizePrice(sl);0 \7 V& o) g4 z3 h8 L# X* I1 s% Y3 F
if (sl > SL)
% Z% I' X: N' {- @{5 x8 ^! d6 A3 w: H& P. R8 d" K
negocios.PositionModify(_Symbol, sl, TP);9 D7 h, K; T3 |) Z5 @0 `: z
}
/ b: {9 @1 M* o. h2 z- \- `# \}2 |$ q1 c) k3 C) [2 r
}# `* w$ ]. a& }; B5 \
else // tipo == POSITION_TYPE_SELL' G e& u8 D$ u7 b2 o
{9 }6 j/ Y1 ? r, H! t2 n s* d5 t
if (cotacoes[1].low < cotacoes[0].low): ^# b0 r- ^$ `
{
8 k( T* P, b/ n3 f) P4 j, t" mreturn true;
; @. ^) k2 H0 Y; j/ x: _}4 e( f N4 V" v0 s: I' X# H
// there was no position
3 Z x5 f& ?) y$ nreturn false;
; Z7 c) E9 O p4 {( o5 q9 @}. b! v) i" C' V" e/ u
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。3 J9 W4 ] M& h5 ?7 q. ~
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |