启动交易模型,并构建 EA
' g5 j6 k# r/ w& _$ ~在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
' l4 j$ }5 Z4 B7 E F' f6 f3 ]% c8 ?为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。; h5 Q" x. A" B, |( W* j' u. L
以下是制定这些规则的代码。: H: e) ?+ V9 Z3 u
//--- Indicator ATR(1) with EMA(8) used for the stop level...6 V, H+ k! ]7 ?& @2 K
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);$ f# \5 p5 y" m" e0 M/ c
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 j2 P0 M2 d/ }+ f5 j//--- Define a variable that indicates that we have a deal...
, |* V% X- B u+ D' p' b( }- I5 m8 Tbool tem_tick = false;; b7 l' m+ j7 L+ R# N
//--- An auxiliary variable for opening a position
+ l5 \* z8 ^8 B4 w$ D. Q; w#include<Trade/Trade.mqh>4 |8 p- C) P! A
#include<Trade/SymbolInfo.mqh>
/ A& b$ q) g) t( Y cCTrade negocios;
# a. h7 I8 q5 O5 F0 c9 UCSymbolInfo info;6 S; d" A8 N3 i9 ^
//--- Define in OnInit() the use of the timer every second
) b7 ~# c. O: s; B//--- and start CTrade
! t5 W0 m5 b) Y& W$ u3 N, e$ H$ U; j2 {int OnInit()2 c8 ^" g. N+ L) W! i# _7 y
{7 U6 J% L" Y7 W( p7 i7 B' H; K4 X
//--- Set the fill type to keep a pending order
& g% Z+ |( M9 G8 V: L5 U//--- until it is fully filled
. B6 c4 j# y# L' S7 ]# W$ Fnegocios.SetTypeFilling(ORDER_FILLING_RETURN);" \' F8 X4 Y7 W3 k. z
//--- Leave the fixed deviation at it is not used on B3 exchange1 P6 u7 s+ t; L' a) ?2 J7 |" `
negocios.SetDeviationInPoints(5);- r, `) ~& C6 } Q! w. B% R+ v
//--- Define the symbol in CSymbolInfo...
. m# a8 S% b3 |info.Name(_Symbol);9 w; S$ f, G+ |, b$ l9 u/ z- T: u
//--- Set the timer...
2 k* r6 [" f* QEventSetTimer(1);
9 q Z# b( e, r* \; `; V//--- Set the base of the random number to have equal tests...
8 g1 J- N t: G c$ v7 w2 Y" jMathSrand(0xDEAD);4 X0 j) @1 j, X2 r1 [# @6 m0 W! j" g
return(INIT_SUCCEEDED);4 E2 x7 N! S$ M5 p7 a% X
}
) ^& E! V; X. _. \//--- Since we set a timer, we need to destroy it in OnDeInit().
- y. Q5 P& Z( Y1 Cvoid OnDeinit(const int reason)+ r1 \3 C# o/ e0 H/ W
{
5 d) q; \' T5 U% x- r1 REventKillTimer();6 m: H0 g+ N. F. @* i' h9 u7 h
}- i7 e8 J+ |* ]$ O: l
//--- The OnTick function only informs us that we have a new deal# C, [3 a3 _; s& q2 ?
void OnTick(), i0 v5 L! A4 _4 T
{
2 S8 c0 | S8 j( T4 ~$ m8 ntem_tick = true;
) O4 ?3 m$ g# E S0 {" r z}+ f6 P( Z8 r" d: F; o6 c& V1 h
//+------------------------------------------------------------------+4 t3 v. A) P/ B! N4 E. `
//| Expert Advisor main function |
( Q- k) b3 u3 G8 z//+------------------------------------------------------------------+
6 f5 y. e: m7 D. Nvoid OnTimer()
- B8 }1 k. b' P7 f8 K# E{
9 p: A+ ~! i0 fMqlRates cotacao[];
' s- I' B' } Qreturn ;* \& l2 L: F; ^* g+ y% Z/ \
if (negocios_autorizados == false) // are we outside the trading window?# w1 B- G B. r4 i0 a
return ;% l- z4 {0 X" m4 ^9 R( Z A- c
//--- We are in the trading window, try to open a new position!9 X3 f7 c& f$ g; p
int sorteio = MathRand();
* `/ ^" p8 W t# }( w//--- Entry rule 1.1
" b2 }9 m: L2 bif(sorteio == 0 || sorteio == 32767)+ h( }" l) J2 s7 r5 ~! G
return ;
8 U' ~- H( D9 c. j- Pif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy# p0 h" s z% o$ E& O; L9 G) ]
{
5 p5 n$ e, e5 k) W$ ?negocios.Buy(info.LotsMin(), _Symbol);* n& ?* B/ b- T g! t. z
}* T3 ^5 i, T$ }; r# h+ u2 x5 N
else // Draw rule 1.3 -- odd number - Sell$ S# \/ H3 S" k
{+ ~) C6 [- X) T+ t5 V
negocios.Sell(info.LotsMin(), _Symbol);
. n$ X* ~! o4 U1 K: I8 f}
( F$ T& ?3 E8 i8 H9 e9 C5 i. i}
: H/ x9 {# J! a+ D5 U" S//--- Check if we have a new candlestick...& Q/ _+ u6 E4 _& o! x; J5 x4 h
bool tem_vela_nova(const MqlRates &rate)
. m2 k3 ]/ Y0 K7 h{5 O& @1 t0 E% ^" n& T# T
{9 @1 N. c; h& z! X0 X/ u6 f
ret = true;
1 D: {+ N% x& V' d2 @close_positions = false;, l9 A/ Z. Z: _ L& s! T
}$ }% ^% f. j" Z2 \- n4 H( I
else5 h6 N, t0 D5 m! g' T" Y
{
+ O. S5 h3 S( K0 q2 U& t6 K# {if(mdt.hour == 16)6 A2 q$ U# m5 x n; p
close_positions = (mdt.min >= 30);
" Q; f# s( R6 ^9 ]}
6 ~- ~6 O; ?9 S0 O}
9 P" Q( x6 A& N2 dreturn ret;
; ]3 x$ |. e/ r$ {0 q# |8 Y- _}, q+ P# s; Z# t, u3 q% l5 ^% e
//---
% t: Z/ U" p2 f) i, a, R9 mbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])* n# ^% t, q0 N+ \( Q) c7 I2 F
{& w1 c5 v( M" f
if(PositionsTotal()) // Is there a position?
1 J A5 q/ P. p1 b! p# \{' m9 b5 e O2 X' ?
double offset[1] = { 0 };7 w1 I, ^! A! d* D/ [5 ?
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
; h H1 H7 |4 D# N3 F. k |. G$ i&& PositionSelect(_Symbol)) // Select the existing position!
3 b9 D& Y$ u5 y1 h$ j+ \* L{
! ~3 u8 |) U) e, O7 IENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
4 o3 D4 Q, Z8 T. h7 Ldouble SL = PositionGetDouble(POSITION_SL);
- H) Y; L8 \: q. q$ d; xdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
- F/ u. u6 d0 k/ `if(tipo == POSITION_TYPE_BUY)
# O+ m3 Z; X; z{
' r$ `5 S- J' k$ o, V7 a' I4 v' Mif (cotacoes[1].high > cotacoes[0].high)
( S3 Z# p! @- X) t7 `( I{
' p: w& w8 J- C# N5 k( Hdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
% t2 t$ }9 P0 p& Y! Oinfo.NormalizePrice(sl);
6 n' |9 I, W! s) ^* Sif (sl > SL)1 q. m$ s; \: C$ J( w
{
2 X' L' x2 f |4 snegocios.PositionModify(_Symbol, sl, TP);5 p k# ~7 E3 j+ o' @, Y
}/ G( G( V2 A, F1 w7 {0 ^
}
; v8 Q% k% ]3 G( t9 P7 R. R% H# C# a}
, O" y0 {. U( [, felse // tipo == POSITION_TYPE_SELL l3 B3 [. A+ |& V7 E" Y! O( ~
{, I5 A+ j. p6 ]* n- A p' u
if (cotacoes[1].low < cotacoes[0].low). t9 R0 T. ~( [& s& e& [( L
{# d. T3 y! J" T t8 M
return true;
( [2 z* b! L, ]6 y' C}8 L( s% Q, ?. Q
// there was no position7 l: F8 s; ?. e: A. b4 \ E o' I
return false;
0 V4 i# m1 U4 d! ~}; M& `8 d6 L+ f* b& @, w
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
4 S# z. F. L: L4 _7 U到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |