启动交易模型,并构建 EA
3 W& o) y0 q) G; W: h在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
& ]: j3 Q& s- @* R4 \为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
" d0 s' X6 \9 E7 H' w- i以下是制定这些规则的代码。2 e/ T9 V& a% o& n$ z6 L
//--- Indicator ATR(1) with EMA(8) used for the stop level...
c- E+ f' i- Qint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
3 P/ v# t, i. Oint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);, a a3 c+ e7 q' ^
//--- Define a variable that indicates that we have a deal..." u0 m% p7 P: v# F! K# P/ B1 u
bool tem_tick = false;
3 p. U& v$ e# e. E$ U( Z0 y( z2 ~//--- An auxiliary variable for opening a position6 m; ]9 X6 ^4 y( |: _
#include<Trade/Trade.mqh>
6 a X# _! N: q/ v#include<Trade/SymbolInfo.mqh>
) P) h6 J ~ G" c. C8 i0 O) ICTrade negocios;
6 C, D$ _0 m' s$ J- mCSymbolInfo info;
( h$ i/ [9 z b7 l; b2 k//--- Define in OnInit() the use of the timer every second3 U8 n) E4 |' P) r
//--- and start CTrade
4 l8 ? O$ b- j5 Y; gint OnInit()) H7 X* u \+ s4 S5 q& ^
{
) w/ F& |3 v5 d5 f//--- Set the fill type to keep a pending order/ o9 `4 e3 v7 w O7 _1 k
//--- until it is fully filled
/ }4 w1 O6 m& Snegocios.SetTypeFilling(ORDER_FILLING_RETURN);
4 {% L- c8 o$ Z8 T! o//--- Leave the fixed deviation at it is not used on B3 exchange
' r* ^; f# r: _! Unegocios.SetDeviationInPoints(5);! F8 ^7 [ R$ S" Q
//--- Define the symbol in CSymbolInfo...) M" m6 f/ y+ E
info.Name(_Symbol);
" Q, o' f- a+ D7 O5 P4 X9 Y/ N8 q9 c//--- Set the timer...' x6 ?- ]3 t# |7 d- I- B9 I8 I/ \
EventSetTimer(1);4 o5 ^. l1 ~/ v/ M$ z. [
//--- Set the base of the random number to have equal tests...2 b1 Y) L, @' O, U- b( a
MathSrand(0xDEAD);! B& }0 ~/ V. y# P+ n
return(INIT_SUCCEEDED);3 X7 ]+ q' r( t6 e4 D6 C
}
+ N) P* g* R3 K* Q0 p$ Y! l//--- Since we set a timer, we need to destroy it in OnDeInit().
, Q: U( ?: U& @) | L8 rvoid OnDeinit(const int reason)
" @1 F/ f! {( P1 Q9 r, D' T{
5 n" v& U5 n2 {0 q- l( JEventKillTimer();2 _0 v K+ f7 d* f' Z& [
}
$ w# u# _) e* r//--- The OnTick function only informs us that we have a new deal
@0 L& `) l$ B5 J" \6 }8 ]void OnTick()" v0 W8 m; Q6 D
{
$ q9 M9 A" f2 etem_tick = true;
# ^( W6 B7 @' D* C$ W}
* ^! T5 C( n- r' \4 s//+------------------------------------------------------------------+
/ a$ t+ n) ^% i; ~6 r B0 _//| Expert Advisor main function |
, ~( K: i: e3 a//+------------------------------------------------------------------+( p7 B3 v; q; g" R3 g
void OnTimer()
1 ]# U* _2 z4 f' x{
j" {2 }$ @: @: nMqlRates cotacao[];
' V- \ {1 k1 v1 B. f! ?return ;/ p! |. j" X; M/ I. d! K" V' G
if (negocios_autorizados == false) // are we outside the trading window?
) Y1 S, m6 m3 i0 z8 g# ]/ G( [return ;3 A& z2 b1 y1 u/ S9 w' D
//--- We are in the trading window, try to open a new position!
" n* B1 K8 d8 U& Z9 W8 w' t: Z" Mint sorteio = MathRand();! c: J4 G* R. n; |
//--- Entry rule 1.1. ^4 F4 _% Y0 e. Q
if(sorteio == 0 || sorteio == 32767)5 _- o: O6 i) P& @6 t
return ;
f L$ j2 A* Rif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy6 T2 k* x* [& |3 C3 H F
{2 Z- ]; I% M! h0 c
negocios.Buy(info.LotsMin(), _Symbol);3 \3 W7 e9 F, n& k
}; C0 W- ]* r7 d- J+ K- e; Y* ^/ L
else // Draw rule 1.3 -- odd number - Sell
4 I; _! t' {# C+ V4 d: o4 a{
* Z; T: P6 a" ]& ?negocios.Sell(info.LotsMin(), _Symbol);
, O, [3 U/ t F8 J, J}3 ~4 D$ }& l' u' X
}
% w$ u1 M/ b3 ~//--- Check if we have a new candlestick...9 `5 U2 ]) ?& t6 T2 \
bool tem_vela_nova(const MqlRates &rate)
& g! [* I' {; G3 q/ f, L{4 s1 u5 Z6 A6 k/ r* x
{
$ d9 k, y/ X' `& U, Rret = true;7 E p: \' m% {' |% Y& V
close_positions = false;
0 Y. g* a# J4 A q4 d; k}8 C8 _7 Q. K1 l2 i
else
' z% G+ b3 o G( o! m{
) P, W: ^9 g4 m# u; _- pif(mdt.hour == 16)8 o: m+ q: v( s. D8 E9 I
close_positions = (mdt.min >= 30);
$ f5 f, }0 i$ f P& M}) y. V1 o- z8 `2 d- r' ]3 p
}2 {$ `% u* S' G5 R$ S
return ret;
% I `. T4 M. D5 g}6 p. w0 I2 S' Z' o5 i+ y( c
//---# u" r" M& J" K! A# P, e0 U% h% T
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])' Q1 w" v$ _, U5 w
{
/ }; `' y- L$ ]8 Oif(PositionsTotal()) // Is there a position?
8 v# _+ a8 g4 {1 `$ g2 d' `{
- Q3 e0 u& |( l5 k2 Sdouble offset[1] = { 0 };
9 M5 P, c/ d: H9 Gif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
. H5 E8 H( A& d) P' `% u% E&& PositionSelect(_Symbol)) // Select the existing position!
T( P1 c% u3 M& \& p- K{
; n T8 P* Y/ TENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 s% S1 L% n' {# E$ i: Q" o- S2 A
double SL = PositionGetDouble(POSITION_SL);2 g O9 V( Z8 K5 K1 j
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* p) }0 g l, n' Z5 E9 B0 @if(tipo == POSITION_TYPE_BUY)1 T! |6 q5 G) z% U* C
{/ r/ Y" j6 f/ u% m, C( L. p9 |6 ?# Z
if (cotacoes[1].high > cotacoes[0].high)$ t8 ?1 C( L2 S! C
{( h/ Z* ]8 w% H
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];' L9 P$ d7 ]1 Z# ?$ J6 ~0 P" C
info.NormalizePrice(sl);
+ S0 L: R; \. T7 f/ U% D; i: _. {if (sl > SL)
: O1 N+ P, y$ W{
8 {, T. N9 c! ynegocios.PositionModify(_Symbol, sl, TP);
# ~/ d2 j C: i9 p! r/ G! [}
/ a. U, j2 D8 ^! c4 Y% ^}
0 ?/ \- _# N0 O& \6 D8 v W8 a% t% @}
' C: t" a- F( m; M9 F" pelse // tipo == POSITION_TYPE_SELL, p/ h5 |* R( E0 |( Y. j
{4 y2 F1 M7 y& B! d# Y% V
if (cotacoes[1].low < cotacoes[0].low)7 T3 P# ]& c& k
{
3 T6 v6 l. B1 j; Breturn true;# f+ x) t5 x* y
}
" \; {9 k. H9 K& S( p) |' M- M0 k// there was no position9 h+ L+ U, S, G; U& R5 \# i0 h
return false;
# m3 D1 e+ ]" D( |! F2 F5 ]}
2 l, |2 h0 Y* x+ d我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。5 `: W5 S" u+ c) r3 Z
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |