启动交易模型,并构建 EA
! q- D3 F. v! f* O' @在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。( }, f* e8 I& g# @. v% f
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
1 R$ |+ ^" g8 a5 ]6 n以下是制定这些规则的代码。, M6 h$ Z5 @9 {- W& C1 A
//--- Indicator ATR(1) with EMA(8) used for the stop level...
9 N2 R5 Z4 z$ W5 [ Fint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);, ~. L7 `8 q* _- L N
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
L/ a% k) ]' J: q//--- Define a variable that indicates that we have a deal...
1 }- `! S- X% ]bool tem_tick = false;
# j( h q0 o. h* K8 v6 X6 b4 m//--- An auxiliary variable for opening a position3 ]* P! V& A* Y# \
#include<Trade/Trade.mqh>. a6 H) G. y" F: n/ s# }) ?
#include<Trade/SymbolInfo.mqh>
5 \/ Z* O' Q& @. T% S' FCTrade negocios;
+ T" G" m8 G% l. ^% QCSymbolInfo info;
6 z g; h% `: X0 o//--- Define in OnInit() the use of the timer every second3 v- p: j6 j: S6 Y
//--- and start CTrade
. m( y: H8 X* J9 s, T( }; W: s4 |int OnInit()7 P/ W o& n6 p1 B2 \
{
0 U6 ]4 u/ ~3 F; ~% F1 B. z//--- Set the fill type to keep a pending order9 e0 O: I9 |& [: L1 z0 }) _
//--- until it is fully filled
( ] `: R* ~( w1 Ynegocios.SetTypeFilling(ORDER_FILLING_RETURN);% m% Y9 K% K# K) Y! Z
//--- Leave the fixed deviation at it is not used on B3 exchange! z3 h1 N0 j& J! ]) \# C
negocios.SetDeviationInPoints(5);
7 |- A& [0 }; K( S//--- Define the symbol in CSymbolInfo...6 M9 ~" }; T8 e3 D, @/ W- m3 \9 h
info.Name(_Symbol);
) f3 L2 F8 r% t//--- Set the timer...5 }/ X( x* s% Y: K ~ {9 p* C
EventSetTimer(1);
K; R$ b# f/ e- O$ c- C7 q* L' Y//--- Set the base of the random number to have equal tests...
0 Y* R& }$ B5 A8 wMathSrand(0xDEAD);
6 v( d2 w/ X% _0 Lreturn(INIT_SUCCEEDED);% f6 _0 `' i2 T4 H
}
* w8 q9 [# n+ T//--- Since we set a timer, we need to destroy it in OnDeInit().
8 n: e* Y8 }# q# e, u# G2 Ivoid OnDeinit(const int reason)9 q' ~/ g% n+ z4 }. R
{7 D7 h# E) ~1 r0 O0 Q% k" n P/ T
EventKillTimer();
6 `: I* C, W6 T; I% T& D; V2 C8 m; B. r}
8 W. K' a- ^) A. c/ a5 B* |' O//--- The OnTick function only informs us that we have a new deal" B) `5 \1 a1 {5 f
void OnTick() E6 T* O$ F& e# C" j+ v
{
8 W4 F; U9 E! M% J) Otem_tick = true;
, i6 J2 H- B" g6 ~5 M0 s4 [}
- L# z. w/ r4 ^3 D) I$ I//+------------------------------------------------------------------+7 b# W; }) f* i+ f i6 Y# X
//| Expert Advisor main function |: F4 i9 R: t5 j* I# j2 B( h5 w# P
//+------------------------------------------------------------------+
+ o) M. {# r3 nvoid OnTimer()- l, t( Y* d0 R2 d
{; H7 w* I( |$ m1 h
MqlRates cotacao[];
$ U+ g$ W! G2 Q' Y! `return ;
# {+ T3 X- {7 R5 G4 Dif (negocios_autorizados == false) // are we outside the trading window?2 k( W/ S. C0 t. T# P
return ;. W: @. L& E5 E& f6 M! {
//--- We are in the trading window, try to open a new position!- X% @% D3 s D+ ]; ]; Y
int sorteio = MathRand();
) K+ C, O4 y' `/ @//--- Entry rule 1.1, d5 ~; ]1 Q3 x
if(sorteio == 0 || sorteio == 32767)
6 K5 Q: [! A7 Zreturn ;0 G- k$ ~$ a7 @# z
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy9 V* k7 n! V+ d1 {0 D
{, h# T% [. n9 F, x! E" ]
negocios.Buy(info.LotsMin(), _Symbol);
3 J" k0 H- O$ ]' w/ R9 D! a' i& j}
& V! W: P# R" C. A! Jelse // Draw rule 1.3 -- odd number - Sell& i5 a/ v" y, V# s8 b7 K
{
! t2 g6 @$ ^* bnegocios.Sell(info.LotsMin(), _Symbol);
0 b/ `3 ~# O! l: K! _& A0 L}
9 C" V0 s* \: E$ n' j1 N} ]$ O& c" r( `4 r: l7 w9 Y
//--- Check if we have a new candlestick...
- z2 @$ j7 K% Z! Q* H& y% Lbool tem_vela_nova(const MqlRates &rate)
( C/ T7 T' m. m0 }+ ?& ?{
' l6 D1 Y: V6 z: @{! Z$ G& _4 t) L9 y; F
ret = true; g& F) J0 D# G/ L) B$ N
close_positions = false;( A+ m2 w4 F+ I ]
}! F0 S' S1 _5 u1 B1 F6 S
else9 ~4 n+ t$ {$ z: O8 O4 a0 }1 S* x
{
8 w9 q" H8 O3 e- i Gif(mdt.hour == 16)% @2 S# J' R8 q& J
close_positions = (mdt.min >= 30);6 k1 q8 A/ C* i; H/ w s
}; v3 n9 C* d/ G
}0 h# N V( w, u: o0 `1 u. J: @( ]$ g
return ret;6 u l& F$ i* e
}7 @2 C6 q; ]8 K
//---. Q8 }% m7 e! q9 F- `4 y' E
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])! D1 F9 r( I% c, W+ X0 C0 H
{
* A5 X9 E% x/ f( Q# @+ [. |if(PositionsTotal()) // Is there a position?. ?' o" A5 V! K/ M) e* H
{
9 T0 _7 V0 t z. ^" n. Fdouble offset[1] = { 0 };
* z0 E) u/ [) z# N5 V( W- s. vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?* q4 ]9 _5 l( y3 e: N# E4 y( Z
&& PositionSelect(_Symbol)) // Select the existing position!
1 u/ L+ T% C! V# ?6 H0 v# m{
2 o7 h+ u- b9 m1 R8 IENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; w$ n# o# R! ]$ s0 A& E+ s
double SL = PositionGetDouble(POSITION_SL);
) F* P, \ X4 _5 Kdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));5 b- q( x) i) s8 R
if(tipo == POSITION_TYPE_BUY)
9 C" _ Z! L M+ `7 b0 m{
) f( p N9 Y' [" W9 M/ R$ {" m" C- Qif (cotacoes[1].high > cotacoes[0].high)$ T5 D6 s( B+ n$ d" _$ p/ x |
{
$ n0 M9 ]9 g9 u. y8 ^0 [double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];: f5 M9 X; t9 \5 T" K: x" u
info.NormalizePrice(sl);
0 W8 `& q& _/ U& Hif (sl > SL)
6 i* A( {7 D9 \, h- h{
1 [7 v; y5 Q- v; N9 a+ o2 hnegocios.PositionModify(_Symbol, sl, TP);1 `! U) |9 h* {) H1 I, |
}
8 ]" c8 v# t6 W9 k5 g5 u R- E% j}
/ n5 w3 g, x6 U9 h! J* ]}% s2 E3 `' g4 V4 a% J- I
else // tipo == POSITION_TYPE_SELL
m( E# V- h3 S. @8 S{" c4 S T7 M1 [( P
if (cotacoes[1].low < cotacoes[0].low)) @# g/ c [; ?, `% ~
{
% [' S$ o/ w9 b! v$ M) V8 t) Kreturn true;- u4 ~2 q2 T# Z* g
}
) v( k. p& E9 \) V9 C6 Z// there was no position" _0 _0 e. y3 b: M
return false;
% c( B3 n1 H. e9 f}
; w' J( N0 w6 Q9 q& z我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。9 T, o9 C Z& |9 g3 G; z; g
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |