启动交易模型,并构建 EA! v: j* ~5 L: l) V
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。9 J9 K3 u# u# @$ P. k
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
0 G% @/ ]7 w( M# v# V以下是制定这些规则的代码。
: z& [; w* Y4 G- I5 c+ @; K) N//--- Indicator ATR(1) with EMA(8) used for the stop level...( j8 f7 t! e% Q k3 e" C. B
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);, @, I: o/ o) B* u. n7 g
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);7 x9 j* q0 E2 `& h' T& n
//--- Define a variable that indicates that we have a deal...
" k- X. @, k. }# V' A, dbool tem_tick = false;
/ |. D& O0 g8 q0 ~- q6 W7 U//--- An auxiliary variable for opening a position
, B( W0 X6 d; U' t) }#include<Trade/Trade.mqh>
8 }& Q5 V8 m8 g& [% v) l; Z9 Q#include<Trade/SymbolInfo.mqh>
+ T O2 f0 t* o4 d4 HCTrade negocios;
. C5 }' j0 i. iCSymbolInfo info;/ Q8 Z5 }% t6 c9 f# D6 R+ X
//--- Define in OnInit() the use of the timer every second1 u0 M: h$ k" d* u# p5 v# j
//--- and start CTrade$ Q+ O5 G5 R. [0 D2 h/ v
int OnInit()
" v! R, r6 B, k% ^; d7 V* w{
5 u% q) Z6 `$ E* U1 @//--- Set the fill type to keep a pending order# K2 R% J5 }+ d# b+ b
//--- until it is fully filled
* z, |. L' X$ Y, K. y9 Knegocios.SetTypeFilling(ORDER_FILLING_RETURN);3 j( ]7 ^- M0 V @+ d
//--- Leave the fixed deviation at it is not used on B3 exchange
/ r" Q8 x' p h& c9 Wnegocios.SetDeviationInPoints(5);
. O- G7 c4 H, b( l+ | Q0 p6 U//--- Define the symbol in CSymbolInfo...- M0 {) i- e2 [( @- B
info.Name(_Symbol);
" O& L6 J7 ?4 j//--- Set the timer...
% H" b7 Q0 r; P3 S( F; w( jEventSetTimer(1);1 L0 |0 _9 E4 R: x0 P
//--- Set the base of the random number to have equal tests...$ V V5 J" D) G2 q2 A1 A
MathSrand(0xDEAD); h% }! W) M: r0 Q1 L K
return(INIT_SUCCEEDED);
: i% F& G. N9 _" C; J}( w0 ^* p% z5 ]! u' a$ n
//--- Since we set a timer, we need to destroy it in OnDeInit().
6 g9 Z& q9 ~* `& mvoid OnDeinit(const int reason)
# K9 I0 k1 w- F2 b; U{
% W! L' V/ i7 bEventKillTimer();+ g# R6 C' N! _# A$ f! i/ K3 v
} ~' X6 X0 d% Z X/ }" d
//--- The OnTick function only informs us that we have a new deal) o+ a1 u# ^7 \/ h& L0 s
void OnTick()
0 e9 }/ [# A& |) O; `( D{# @6 R8 u4 q; Z
tem_tick = true;
/ V/ P# Q9 H) B8 Y}
* a: M9 W0 @* W//+------------------------------------------------------------------+" _7 \0 K7 D; N7 ~) q0 E- Y( D( i, b! }9 p
//| Expert Advisor main function |
6 x6 `- R0 @/ N* P# s4 `( \//+------------------------------------------------------------------+
4 z% Y) m& }" w! x5 A% z! F7 jvoid OnTimer(), C4 d& ^ M" t& P3 m$ b
{, {/ q2 [: h* x& @ \3 r6 }7 [
MqlRates cotacao[];
7 v3 I/ k9 F, Z( W1 Oreturn ;
+ A( z% R; h4 ?( jif (negocios_autorizados == false) // are we outside the trading window?
: l9 k3 w* v0 W/ \. Freturn ;
; X% ~2 g! W% a" a' b//--- We are in the trading window, try to open a new position!
8 \' \7 y; v/ j( T. W1 Uint sorteio = MathRand();
+ w7 I; c; A/ x$ S1 Z5 [//--- Entry rule 1.1" \9 H n& c: [* X
if(sorteio == 0 || sorteio == 32767)
+ [$ s- u5 c$ {9 K& G! Dreturn ;8 `! a4 x7 H$ y
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
; e( j+ ]* i5 H1 `) S4 @{
, w _- s& y1 ]% d( {% vnegocios.Buy(info.LotsMin(), _Symbol);) A1 {# _' ]4 V/ R. R
}
6 n& M/ V6 j6 }& ?( o) Uelse // Draw rule 1.3 -- odd number - Sell8 h* ~ L( q9 e2 k% r
{8 ^# L/ }/ `8 G2 d! o) A! O
negocios.Sell(info.LotsMin(), _Symbol);$ Z2 p! ?, t# ^5 R' f
}
) n3 e0 O" B3 D2 e+ h5 X}
7 R. C" J2 T: ]+ S3 \; o//--- Check if we have a new candlestick... H& z0 o* A) @+ I
bool tem_vela_nova(const MqlRates &rate)
. {6 \5 o$ F+ [6 e3 m{
) }4 v9 [7 j1 ?( {' m& {9 E7 s. `7 t{
. Z7 o0 d; X2 g* a! Sret = true;
/ m- Q" D1 E2 K0 o7 C2 pclose_positions = false;
1 C% H |: Z9 I2 c7 t}- ~2 E2 @7 c4 E5 T: G+ j& g
else. `& Z( ?2 W3 j7 H
{
+ I+ `! h ^" [5 \- Uif(mdt.hour == 16)$ [- M( P' P5 P5 m% P; E
close_positions = (mdt.min >= 30);, R! e1 H9 x$ E2 @2 q8 U- [
}
- z: \7 y9 A5 e8 Q3 Q' Z2 z}
) _3 D% b8 e0 |# oreturn ret;
( S4 W" Y( b0 I# z- M2 G( E8 }}/ n' @0 o6 M3 x+ W. v" r
//---
5 s% ]: S: T" D+ Z: F( bbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
1 D9 L7 p) J& K' T; s7 V' A( z. J4 e{
$ O' R5 }0 u6 F1 mif(PositionsTotal()) // Is there a position?
6 {& k5 ?8 s/ h* E& x{
( q' m' Y& I5 Q2 ~' k6 n/ D Q% u8 edouble offset[1] = { 0 };. U9 u3 [0 O4 D
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
4 n8 A- Y D2 l( m4 A&& PositionSelect(_Symbol)) // Select the existing position!) N6 I# c- m* R) f: |
{
9 T I/ x& k; N! r; v& |ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE); u% B" ~- { v+ x/ p# Z) Y2 u" u6 M* [0 W
double SL = PositionGetDouble(POSITION_SL);
* | [1 L# J5 \7 a( ^double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));4 R7 u6 c5 ?5 V) U' Q: W- C6 i/ v: J
if(tipo == POSITION_TYPE_BUY)
0 Z+ O4 @5 j4 {, B9 K7 [4 Q{" i: t4 L+ r* R/ k
if (cotacoes[1].high > cotacoes[0].high)
" H' [) S: J' k$ o. Q% X. v{; g" Z5 I, j; c: o7 [
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];! B4 |) v- z& a9 K9 \
info.NormalizePrice(sl);
& T, p/ S1 I; Y4 Kif (sl > SL)
# g" R2 e2 c4 q* x$ S. ]* A9 N{2 ^/ t8 h" H5 T5 j7 k
negocios.PositionModify(_Symbol, sl, TP);6 H6 T# g9 ^. y3 Y- R4 r# n% N
}
" K" F- K7 H) p$ d}9 E3 Y h. h& B, b8 G% D/ y+ b$ [
}
' f0 M O$ l1 Q' xelse // tipo == POSITION_TYPE_SELL
% ]$ r+ [4 K/ M8 B3 I |# A{2 f! O: L* O# \0 S$ \! e' W
if (cotacoes[1].low < cotacoes[0].low)5 r/ k0 z2 G2 L4 I3 E. m+ d
{! J! F8 v- q1 }
return true;3 c% b+ q+ M, \ U9 S
}
: s. W% o4 K+ d9 r// there was no position
' m+ L7 C e3 F. l) q. a. breturn false;/ d# K9 G# \) N
}
. a$ J9 r7 e, d9 A+ X9 b我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
( @, |* t1 D. f( A到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |