启动交易模型,并构建 EA
* r7 c7 e0 ` x4 N. J* }在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ X) b) p6 j% P3 f/ `% p; F
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 C$ x- [5 Y) X# h" X$ F, g
以下是制定这些规则的代码。
3 X& p) q7 r. {$ k//--- Indicator ATR(1) with EMA(8) used for the stop level...
6 l1 b4 q' B4 T$ Qint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
; Q, O; y7 a+ k" R( U5 T/ ?int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
" B# H" @9 x- |/ ^& U//--- Define a variable that indicates that we have a deal...- K4 p9 c% p' Y
bool tem_tick = false;6 h2 ]5 M+ O$ k* n. t+ y8 K: g, L
//--- An auxiliary variable for opening a position
: C5 N7 w& P, ~3 F#include<Trade/Trade.mqh>3 z/ j! W: X2 ~6 W
#include<Trade/SymbolInfo.mqh>7 ], y& t7 U- q* @
CTrade negocios; U9 k. V" ]6 _1 ^4 h+ E; i6 T
CSymbolInfo info;/ b e+ P$ M! S& v5 m+ [) d1 N
//--- Define in OnInit() the use of the timer every second
5 B, {8 C8 K* D//--- and start CTrade
$ p1 b3 a4 W/ }9 K* g4 ?int OnInit(): T* B2 R5 l) w
{
+ E" h7 e# e* \) k//--- Set the fill type to keep a pending order3 s8 T$ H! N. e# M F8 N
//--- until it is fully filled
( N- e* ]! P/ ?* Onegocios.SetTypeFilling(ORDER_FILLING_RETURN);1 h3 w6 p+ J5 T$ ~$ A$ n
//--- Leave the fixed deviation at it is not used on B3 exchange# b2 O% N8 j! m8 {+ j' j
negocios.SetDeviationInPoints(5);$ v4 L/ s0 z1 k( t
//--- Define the symbol in CSymbolInfo...% ^% C1 }9 \9 ?
info.Name(_Symbol);) A+ A- E) |8 s; |; S
//--- Set the timer...
; u$ M! c: T8 p- hEventSetTimer(1);1 Z/ t$ e' \8 A$ J6 i4 H
//--- Set the base of the random number to have equal tests...
% G9 [. t0 j3 o1 K# `MathSrand(0xDEAD);9 G: s4 _! G8 [! i- R3 @
return(INIT_SUCCEEDED);
& C' t9 e+ W8 h, g5 a/ e) x J}4 U1 x, L( n9 Q
//--- Since we set a timer, we need to destroy it in OnDeInit().: g/ a3 G; D; X' d% ^. h
void OnDeinit(const int reason)
6 \( Z+ f C& \. K4 N) {{
( Z, i8 m# X6 JEventKillTimer();9 I5 p2 ?* ^. |" w, H. U s( A
}! y( P9 J6 S: C5 }& O: A0 ^, u
//--- The OnTick function only informs us that we have a new deal
- R0 r/ K& z# Vvoid OnTick()
0 `' M5 f# g; r# I. l) o/ I( z{& J5 D- }- F; f- o/ ~: P) z4 N2 {
tem_tick = true;# R3 V7 {, [ P1 g9 m& l9 v5 @4 d6 Q
}7 B9 f, Z1 X |+ y' T$ n( l
//+------------------------------------------------------------------+) y3 B; R( O8 U5 z0 j
//| Expert Advisor main function |- Z+ u( S% v. Q1 A
//+------------------------------------------------------------------+, [9 g0 B% V3 N! ~ c# l! I
void OnTimer()5 }) v; {2 y, [; ]5 u \8 w- E) p
{
5 W; K4 W! h) D$ s) ~MqlRates cotacao[];7 _3 E9 |9 W) n% E( j9 V$ w, D
return ;
/ i) z4 c3 f! c# q6 _if (negocios_autorizados == false) // are we outside the trading window?) R7 W4 {! f, Q* [
return ;4 R2 ~5 J, B$ s5 m
//--- We are in the trading window, try to open a new position!
; L! z! m3 O1 mint sorteio = MathRand();
# w, {4 V+ H, `5 R+ `% c//--- Entry rule 1.1
5 s9 ~: E. ^, y' Hif(sorteio == 0 || sorteio == 32767); I; R" V! p. q+ V/ O
return ;
- ?' {8 j; z- L1 @4 P% w9 e$ a5 fif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy8 _" x" I0 |: Q4 x4 r. I
{
3 m9 [$ Q F. U" S1 \+ V+ Cnegocios.Buy(info.LotsMin(), _Symbol);
& Q& q3 i/ ?8 }8 l' _* u8 m}
I3 @$ M* M( o8 D% i. xelse // Draw rule 1.3 -- odd number - Sell
0 p: x7 U Q5 I/ Q{
; d' O; P7 b, m# Y* \: a: Xnegocios.Sell(info.LotsMin(), _Symbol);
$ Y H' A+ d$ c}) }0 n) B: T/ n! m Z& G
}
& C; ^4 U2 B n- \//--- Check if we have a new candlestick...- j, G, Q! Z/ S" G
bool tem_vela_nova(const MqlRates &rate)
" O- z/ T. B3 Q6 h }{7 Y p5 K" C. @7 [$ _9 |; ^
{
5 P) w4 u8 c# s- C2 y# ^6 w0 Vret = true;
, w5 o1 E# `' @$ j8 E# nclose_positions = false;3 t, S7 \6 `: v" Y5 l+ B( S# I
}3 p* G- D. l8 u; {0 N
else/ r+ g; Q g# L7 O3 f
{
7 F! F0 S! r0 U; zif(mdt.hour == 16)
# I: @) P/ n* V6 ?: z- x; jclose_positions = (mdt.min >= 30);
' F3 B1 M, h6 `: G; M7 j: S! T8 D}
; n+ @1 V& t% z" N}/ O9 ~% e" M$ v3 \
return ret;/ T! x! b: _6 F; y
}
5 N; r5 Y8 W! \//---( o9 Q& s) g# H& v
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])0 P5 D: _- E0 b0 @$ `( r
{
6 S4 l9 q9 E& m* xif(PositionsTotal()) // Is there a position?
9 I8 p5 h. x4 R$ o7 H2 M' D$ a: v{
% c8 o: y, P3 G0 V4 n' {double offset[1] = { 0 };
5 H& W( W+ w7 X. q1 I. iif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?) G8 l% ^! H( z
&& PositionSelect(_Symbol)) // Select the existing position!4 k1 p3 N6 o8 i# {7 H
{2 w' F ], w r; Z+ e
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);$ T W0 h9 q, q D/ W
double SL = PositionGetDouble(POSITION_SL);; a% m* C; O9 Q0 _4 N
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
' d9 D' ]: p0 b: G. Z0 s8 D5 `if(tipo == POSITION_TYPE_BUY). `4 M* r; Z$ A
{6 l( ]) N Z1 Y. y, [ F' U5 w& j
if (cotacoes[1].high > cotacoes[0].high)
; e Y, i) }/ P7 z( {+ r! u{* k! m3 ?0 L; K3 a
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- D. s/ S7 i/ N. C8 V# x6 G: ~
info.NormalizePrice(sl);
9 O; N# h$ d" O% W% w! wif (sl > SL) x6 [# ~: _0 L9 x% ]4 U
{
/ a; B! x4 i. rnegocios.PositionModify(_Symbol, sl, TP);) z7 y( U$ S) g6 P/ P4 c3 b5 Y
}
% m8 }# L0 J- a4 I4 w/ a7 i}
9 }3 t3 _* A; s4 e: v- U+ P}
. ?( z% e2 o; L6 ~& l6 ^) ?else // tipo == POSITION_TYPE_SELL9 g4 l* e8 F* i( `3 g! k: [& ^
{4 P9 C/ v' Y! c, t2 n1 o
if (cotacoes[1].low < cotacoes[0].low)
" P; U: R% A: d v' K9 `{
2 R9 K d+ S) K# k4 Yreturn true;9 S# z" z0 P2 r1 K- }
}
3 c9 N/ ~2 g/ S" B9 j1 ?// there was no position, Y6 a* M* W* v5 j
return false;3 Q! H% |3 T& D( _7 c& I1 k1 l3 v
}3 q3 A' X: R# d2 Q# \
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
. }0 } m- U9 D" O到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |