启动交易模型,并构建 EA
+ _, o8 p4 g" N在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。8 h4 {: q9 Q+ l: U* \7 `6 B( _5 \
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) ^7 T6 b: L+ c/ v以下是制定这些规则的代码。4 ^7 v; k% S$ O; q+ o$ w
//--- Indicator ATR(1) with EMA(8) used for the stop level...
4 i; n/ i0 ~$ m' K' rint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
% }* V( m: _" Y0 W" k( Z0 j# mint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);& d* i. ?1 n9 B+ l
//--- Define a variable that indicates that we have a deal...
+ W: b6 K* S& D1 |* \2 s6 X( |bool tem_tick = false;" j3 l& ~+ v1 i* z W R" ?6 z
//--- An auxiliary variable for opening a position
- h6 r1 I( D! b0 |% W0 r4 Y#include<Trade/Trade.mqh>
/ u2 j/ m5 ?9 v0 [: O% T9 k#include<Trade/SymbolInfo.mqh>9 _ ]9 @7 S3 |9 m8 F# V. J
CTrade negocios;
4 }. D. J, ~; s% ^CSymbolInfo info;1 }7 p$ m! y1 W
//--- Define in OnInit() the use of the timer every second
5 T5 X8 A) l$ m//--- and start CTrade# v" P. G+ h7 Q
int OnInit()& E4 R0 X4 B# r- \: [& `2 r2 o$ I
{
8 T, `: \& X* o//--- Set the fill type to keep a pending order9 O& Z% E o" F) O j' j
//--- until it is fully filled
6 P1 b( F X: m1 J" m" O6 O: H' Xnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
9 F9 b/ r5 v% U//--- Leave the fixed deviation at it is not used on B3 exchange
/ M' r' m6 O9 i8 U6 y( ynegocios.SetDeviationInPoints(5);$ M& j/ N+ L+ @$ l6 l5 W
//--- Define the symbol in CSymbolInfo...
& W4 @: S1 R: [# L% ^info.Name(_Symbol);
, u- u! D5 d# y. n5 F" n5 {2 o//--- Set the timer...6 A1 X2 `2 E1 m7 j5 H& ]
EventSetTimer(1);
& F0 Z* a. ]3 G3 W* f3 F//--- Set the base of the random number to have equal tests...# d" d9 L# W! E t2 t
MathSrand(0xDEAD);
: Q2 C, s/ K9 N4 xreturn(INIT_SUCCEEDED);* ]% p0 q) B! c' E% f/ A, D$ `
}* c9 b2 m' u5 q
//--- Since we set a timer, we need to destroy it in OnDeInit().2 j( m1 t$ c3 [# H' a% V
void OnDeinit(const int reason)- @: c$ p, o' w, g6 B+ C h, r
{
% a1 ^9 x) }# v8 f N: FEventKillTimer();
* ^+ n3 _* P" a2 L( I1 [}
/ l. `6 K8 w3 |' C6 J//--- The OnTick function only informs us that we have a new deal t; ^7 R% U) Y2 q$ W
void OnTick()/ C, E: j- }" Z, m' ^& l
{
2 U: Q, X! p0 N" S# U5 [tem_tick = true;4 V2 i8 L8 ^2 F t* k9 w1 X: x
}2 F$ F+ q5 y" W+ ?
//+------------------------------------------------------------------+! T! K% D Z% n, |& l
//| Expert Advisor main function |- n8 b2 F0 o, D
//+------------------------------------------------------------------+; y8 i5 T' l6 [% x: o& {
void OnTimer()
7 v( L( p! i$ h! A2 N" ^{9 [7 q4 \: ?7 `. y# Z k4 k/ a$ a
MqlRates cotacao[];- _4 m% j, u5 {) T, x& U2 x- C
return ;% j! v- o0 m3 u, U+ Y7 {
if (negocios_autorizados == false) // are we outside the trading window?
2 v9 \+ \. L6 z4 d8 mreturn ;
! B& t9 K. p4 T7 e4 c* ^* [//--- We are in the trading window, try to open a new position!
1 ?5 e& S: {) ?+ ~( ^int sorteio = MathRand();5 | D- C$ f5 a6 y K
//--- Entry rule 1.1
: [9 `8 e& e2 p- a" [9 Wif(sorteio == 0 || sorteio == 32767)1 |+ x; ^8 |# A/ c$ K2 E
return ;
* `. ?5 \% t% q+ E0 {$ |if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy. v7 B" h6 }( [% ?' w" x
{+ C8 F& G6 w% L" R, L }+ H
negocios.Buy(info.LotsMin(), _Symbol);$ [! p" ^/ T: o* I' q! T
}5 n) Y s# k. A! D8 L
else // Draw rule 1.3 -- odd number - Sell
8 b( W3 A2 R) ?5 F" s; R5 w+ t{
0 V4 d2 _% T8 c; U% S1 rnegocios.Sell(info.LotsMin(), _Symbol);. T1 [2 o& q3 x# g% ?
}
; \2 |, J$ D( u* V5 y- ~6 m0 t7 g}
1 c* L2 ?* p- t& P+ o//--- Check if we have a new candlestick...% O, J% |7 u. ]) C
bool tem_vela_nova(const MqlRates &rate)
F5 i# _/ n) ~, `{' [+ ?5 v7 R) `
{
4 b* ^3 j! n- d1 m5 Dret = true;2 N1 c N( s$ i; ], {' h/ Y1 |
close_positions = false;
4 }0 y+ k8 P6 s# _/ ]}
& c4 k9 B& f' z- Nelse
2 `- }$ R7 [- x1 j{' |. ]$ B' @1 y
if(mdt.hour == 16)
B L$ w3 L. J7 S5 n$ A4 I0 z) }close_positions = (mdt.min >= 30);. I! Y* [" N& T
}3 \' v4 @+ L6 c: x
}, ?/ o: W5 X i/ k/ f1 b: z1 u% h
return ret;
6 ~; r7 R4 p8 [6 \}8 `' Y+ p2 e: u4 ~. a
//---
6 c! o2 [) A% L8 n% V) w" Xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
9 {7 _+ `! e# S" o' I+ [{# T. J" [& Q9 u
if(PositionsTotal()) // Is there a position?& g; ~0 t5 o2 D0 @ r; N9 o+ J
{
* Q- v! G4 @& r! Rdouble offset[1] = { 0 };
|1 w3 ~7 e- B6 \1 Yif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
9 O6 g7 a4 j% u0 s' H3 r&& PositionSelect(_Symbol)) // Select the existing position!
: T1 F! `2 b9 f& M{ J" X+ n' B+ l L, D! \2 d
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
* C# z7 |# f* A+ Q! h# k8 N1 mdouble SL = PositionGetDouble(POSITION_SL);& {; Q6 I9 ^6 N- @
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
& r+ s+ D1 I' W" E1 j: z6 X6 qif(tipo == POSITION_TYPE_BUY)
( ?9 C, |) L5 o* `8 @{+ U+ U7 {& q$ s( \- l, i. s5 e' n9 ]
if (cotacoes[1].high > cotacoes[0].high)
' @: ~" S% t9 i5 o k{9 P+ h5 H; A* ^3 i% @3 U; m+ m
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
) d6 s( b+ ?9 Y: O5 [, Cinfo.NormalizePrice(sl);) c- N# ~- `* s' ~ g# m ]! l
if (sl > SL)- F8 Q4 `0 K; w, X h, m
{8 E% B9 r% a0 R8 t4 W5 c
negocios.PositionModify(_Symbol, sl, TP);( n) C5 }+ G1 F# p9 ^
}$ |. D2 |9 N! D w1 r
}, N9 y- I# c1 \) O& P9 l0 U: N# G6 \
}- V7 q, `; T5 M0 t8 `0 \! A# _" a
else // tipo == POSITION_TYPE_SELL
2 y* J5 _1 n/ z# |{
: N! x4 y( X% \8 U8 w. |' O3 gif (cotacoes[1].low < cotacoes[0].low) q3 V. G- x, B! y& P: ]9 y
{
3 u7 _' I7 |3 a, m9 o- s7 s3 P/ Jreturn true;
6 l+ |' A" }; h2 V2 t+ q) M}( W- m. r J' \* h0 n& j/ a/ h- e
// there was no position" h. f- j6 B" P& H9 L9 I" Y* ~
return false;4 L# B. Y7 h: i; U; [5 k
}; p' _, p2 _! [
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。% A3 t* c9 w+ o$ a& U( V
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |