启动交易模型,并构建 EA
@& \% P, q2 r" x在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
! Q y% a" v' p+ }$ d2 t为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
+ y9 }0 r/ n) B以下是制定这些规则的代码。
/ Y% a+ V q. T6 r//--- Indicator ATR(1) with EMA(8) used for the stop level...
# Y: N# P8 `5 I, q1 P0 ]int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);5 q9 ?; d c) `& Y r/ z+ _) [
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);8 n) [6 S3 {: q$ s/ b
//--- Define a variable that indicates that we have a deal...
6 ^, N+ g X/ B! l% jbool tem_tick = false;8 T: [7 r' r5 F9 u. v
//--- An auxiliary variable for opening a position
8 M! Y, ]4 j y4 o#include<Trade/Trade.mqh>
+ S5 ?2 J. x1 H6 v8 {#include<Trade/SymbolInfo.mqh>
( |& r L1 A6 [* t$ YCTrade negocios;
7 q& H* t) D) X) W8 F4 ?' r5 U* B, eCSymbolInfo info;
& M$ L8 N" u8 _; u4 d//--- Define in OnInit() the use of the timer every second
/ z s; w4 n) o) A9 u0 q//--- and start CTrade* @% v1 `2 I. |+ |" Q
int OnInit()
( u; E3 ?9 I2 N{
% W/ `$ O* M H* W//--- Set the fill type to keep a pending order* r' r1 E n3 l3 W
//--- until it is fully filled
5 ]6 M, N0 q" |4 H, [: d! vnegocios.SetTypeFilling(ORDER_FILLING_RETURN);" W9 _+ n2 a% `/ | r( N2 y# W
//--- Leave the fixed deviation at it is not used on B3 exchange
) f6 U9 H3 i2 ~( u% nnegocios.SetDeviationInPoints(5);
8 P% i- l. G2 f) G# U//--- Define the symbol in CSymbolInfo...
$ D a1 C, A- J) N: ?3 [8 m2 }6 oinfo.Name(_Symbol);
0 o% L9 I4 B4 y% W ?; C% h//--- Set the timer...) B$ x4 d& G; C M( O1 d3 z
EventSetTimer(1);
4 D' N6 y+ e8 S" E* m% @//--- Set the base of the random number to have equal tests.../ Q2 G8 L5 Z. w0 x
MathSrand(0xDEAD);: ^# S4 u+ q( h
return(INIT_SUCCEEDED);+ ^% H# ^( [- K
}/ f: O- \6 t4 z# K5 P, t! d( A
//--- Since we set a timer, we need to destroy it in OnDeInit().
9 d, c: F* R( [) i O# vvoid OnDeinit(const int reason)
! [; V7 Y1 B6 o( f{
; X9 y. \) @, x" k* OEventKillTimer();
/ o( v% x/ @3 x0 n( ]) [7 C/ [% }8 F}2 \+ T5 ?3 D6 {+ U0 L! L6 F
//--- The OnTick function only informs us that we have a new deal) o7 v3 E( L' H5 ^
void OnTick()
: u9 A9 I* e7 @8 P{: P' n9 D. y3 d
tem_tick = true;$ ~( P. n: P$ o O2 W
}* `& {5 ~: @8 [) V% p
//+------------------------------------------------------------------+) l5 ~ O* g4 e d9 q3 ^1 C
//| Expert Advisor main function | S6 x( V& j/ r6 n5 c% f
//+------------------------------------------------------------------+
i4 j9 B# k" @# ?- V# ~' x& gvoid OnTimer()" c5 C Q( w0 L: p; v: Q
{# q4 _+ S- f+ N! {2 L- X
MqlRates cotacao[];0 D+ u0 \, Q6 \
return ;
7 U0 r, O: j9 l6 _4 S# `' Vif (negocios_autorizados == false) // are we outside the trading window?, Q, |, _5 `( _9 [
return ;- J2 X8 ^' T5 h. s' s/ m$ i
//--- We are in the trading window, try to open a new position!
: M% ^9 F3 V! Q$ k1 mint sorteio = MathRand();" H: E" k6 q% U" }" o9 v3 V( X" v
//--- Entry rule 1.1
3 l3 [2 w/ N- v* k4 X) Y+ Vif(sorteio == 0 || sorteio == 32767)% i4 A6 o9 J- w6 z$ I9 e
return ;3 E" {# j3 y n; ]$ a+ x) ^; n
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
1 U/ m! M- p/ t) d0 c; u* H! u( a{9 B4 F b; M4 S2 R( k L. e6 y' P
negocios.Buy(info.LotsMin(), _Symbol);% A$ C, O) K* ~! z
}" d% @& Q# Q8 q4 l# b) |2 C
else // Draw rule 1.3 -- odd number - Sell7 ~9 X) z \0 x8 H3 p# V
{* V+ B0 q R9 t$ W% K
negocios.Sell(info.LotsMin(), _Symbol);
. [ Y" \6 m& i( i2 k$ z}
0 m) L+ D5 f. E: d1 v' ~& M}8 N+ m5 J& u" u: V# i- Q& T/ l
//--- Check if we have a new candlestick...' l3 D' C) u4 u" k7 B& A
bool tem_vela_nova(const MqlRates &rate)
0 t* T6 V4 C2 T4 L1 R{# K2 N4 H9 c5 G; b
{
8 ~* `& q8 h, V0 ` \" s1 c3 `9 G1 Fret = true;
; A% w+ X: t1 |) P. P! f, W% P/ Lclose_positions = false;
1 H( G) K: `, e* o" p}4 E# g) B# _/ n
else
5 u: G% {+ p/ |! w/ _% ?# w( E7 V{
5 t; w6 c( H" `7 D) Sif(mdt.hour == 16)* g3 O5 i0 I+ X z! G# a6 Q3 H9 S! ^0 k
close_positions = (mdt.min >= 30);; l* E" h% ^6 [6 B) d- W: m
}" `, L& x c4 i; t' E# D
}
1 B8 e( w) @& R3 ]1 Breturn ret;( y: z* _/ X( q1 H# |
}; W& V, O* Y: Y" u7 p
//---
+ _+ A& E7 T% M" n, hbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
' G: `* L( S" T8 I% N5 ^# T9 |{" Q2 Y$ S2 j! h; x( `2 O; m
if(PositionsTotal()) // Is there a position?7 ~- y% D2 p5 q4 ^8 l
{
- X7 Y6 [" H8 adouble offset[1] = { 0 };+ a: H# {& w; w3 S
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
) ?) E: @2 @+ l6 S2 U&& PositionSelect(_Symbol)) // Select the existing position!! R) @ b3 E" i7 R o5 H) ^1 i
{
0 W/ f0 | y$ s% B) jENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 m! P7 `8 T5 f* I. s, n
double SL = PositionGetDouble(POSITION_SL);
' ?+ z R. o% ldouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
4 o$ j0 ^ x4 y4 hif(tipo == POSITION_TYPE_BUY)
" Z$ M& [( U9 D* ^/ U{$ K9 f7 w5 R. d( n" }- U6 \
if (cotacoes[1].high > cotacoes[0].high)4 B! Q( |8 ]+ C* D
{! D S$ l' x* ]. f9 k4 E( F/ u
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
$ A) {6 w$ t) U: ~3 y3 i( `info.NormalizePrice(sl);9 Q1 l6 [0 T5 a2 g9 D0 m
if (sl > SL)
7 K& p% s( Q: ^7 H: m4 a# x6 A{- b# K/ X8 m1 J
negocios.PositionModify(_Symbol, sl, TP);+ s5 ?; E# c6 l+ `! @9 ^# ?
}5 Q. e- K! y3 q' Y% }4 V
}6 F( R- ~, ^9 j( Y- u) e$ w
}! W" G; G( i) C
else // tipo == POSITION_TYPE_SELL
C. D- k8 q) |. r4 o h' q2 ^% Y2 E{, g: [ q' k& t9 z* B
if (cotacoes[1].low < cotacoes[0].low)9 y- w- |" l3 Q& Z
{
. P! V0 i8 k- c3 c/ H5 H- h; freturn true;
; x3 _8 M! O, q) ^}( O3 G, F I7 N1 U/ j8 ^! l( ]! k
// there was no position
8 U4 Q# B2 z% L/ \. R8 ereturn false;
! @: V' }: g/ ?. D}$ ? B5 W, z W' ?- z
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
8 `; \4 l* s' R" G$ M到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |