启动交易模型,并构建 EA
; _' C* C# L9 I( v9 V. h* w, i在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
' Z0 ?+ U" \, w/ k9 h7 x' ~8 x; @% k为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
: U1 R% T: q6 `- Q9 d以下是制定这些规则的代码。; e' r* t) B8 a6 G2 B
//--- Indicator ATR(1) with EMA(8) used for the stop level...
' d! I6 b# D" X7 V, j8 ~int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);) K; Z* l1 N% Z+ E5 S3 I, c! ]) `
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);' o' ]7 U+ P2 y& k( @+ M# r- ?4 t
//--- Define a variable that indicates that we have a deal...
; J) Q' K& {2 K8 H- ~bool tem_tick = false;
( H$ a6 Y4 r( Z# b+ a# j9 Q% P9 ^% m//--- An auxiliary variable for opening a position
6 X& c! Y7 Z/ R; M' C2 ?#include<Trade/Trade.mqh>! }1 Q8 Q1 f6 L9 y
#include<Trade/SymbolInfo.mqh>& q+ J5 d8 [6 u2 K
CTrade negocios;5 `( j( R0 S; p# g
CSymbolInfo info;
; E( r# x$ t4 l- x! U2 |' Y//--- Define in OnInit() the use of the timer every second2 M4 L6 n! Z- R. C% f9 i U' d( j
//--- and start CTrade
3 J" q: o' w# \" V9 F0 W, Pint OnInit()
0 e4 ~0 ?: B+ W6 J{5 v) k( u$ _* c* i }2 f
//--- Set the fill type to keep a pending order
5 ?! H, H" e) ?" R" u8 \! ?//--- until it is fully filled
* G9 S" c+ w7 U5 enegocios.SetTypeFilling(ORDER_FILLING_RETURN);
1 g; B- R& b6 E' M6 I: F//--- Leave the fixed deviation at it is not used on B3 exchange6 X! p% \& [ v9 m- @
negocios.SetDeviationInPoints(5);
) P `, i/ T2 y4 B3 e//--- Define the symbol in CSymbolInfo..., m* S4 _6 V/ {7 j- H8 L
info.Name(_Symbol);7 @* w. F3 G4 Q) B# m" K6 i
//--- Set the timer...
* I5 S" X' B2 E& o& q( U5 cEventSetTimer(1);, `6 {: a/ @5 H g9 W9 K2 k1 ^
//--- Set the base of the random number to have equal tests...
- g' `# R3 z. FMathSrand(0xDEAD);; `( n1 l- C5 E0 R6 |: S
return(INIT_SUCCEEDED);
, \* h: z$ r( D}9 `0 B9 ~% M# k2 b( v) ?
//--- Since we set a timer, we need to destroy it in OnDeInit().7 e* r5 Y1 E* A O* H
void OnDeinit(const int reason)0 w$ K# s4 j0 W! J( X
{
' y: }( O0 k( p) a7 n$ EEventKillTimer(); y5 Y0 g5 }! H7 A- }& Q+ B" U
}5 R" s+ Z% r3 g' W0 R, d
//--- The OnTick function only informs us that we have a new deal
# U5 S' t) V. X4 ~- q# n7 ivoid OnTick()
3 Q0 B5 _. a+ h) j( t# S* S% R( C{' {, T- w/ p- ?) p& ~
tem_tick = true;
; `2 B5 g7 ^: C8 n5 a}6 I' N7 ?1 f% u$ i; |% z! G
//+------------------------------------------------------------------+
* W0 ?; X F* b: @, T//| Expert Advisor main function |$ N- r! U: d( c4 i2 q, N1 \0 Z6 A
//+------------------------------------------------------------------+
* k/ ]- _4 M, p: Mvoid OnTimer() Q3 q N( d, O1 N) b1 n
{
* I! W& T' G7 n1 H. [MqlRates cotacao[];; Y- X S8 h) l f7 @7 I7 N
return ;
; G" l+ q1 Q3 _$ I Tif (negocios_autorizados == false) // are we outside the trading window?" Z1 }8 d! t# w7 i
return ;& G+ A. A$ ^3 d8 L3 W7 }
//--- We are in the trading window, try to open a new position!
7 d& W. _4 m! S7 Oint sorteio = MathRand();
& Z& u% t- t! z+ ~, x' V/ f" v//--- Entry rule 1.1
4 R2 @$ P) h( g) O* I1 Q2 w/ eif(sorteio == 0 || sorteio == 32767)2 J1 M% Z$ N% B! Q4 S# z0 B9 A
return ;( a9 @; P( z J+ P# |# A
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
; S$ Q0 a8 g, A- l" k3 a{
2 k. `' ^6 q7 d4 g' Nnegocios.Buy(info.LotsMin(), _Symbol);5 k9 _9 }- j; M9 o: q' J6 }4 o; S
}0 w/ b+ \. s8 C" u
else // Draw rule 1.3 -- odd number - Sell
' A0 X; B/ ^' ]{
- q p/ c( d; a Z2 L6 onegocios.Sell(info.LotsMin(), _Symbol);
- u; P* `0 K" T% q: ^ H7 F7 r$ q}6 k, v" n) S5 m9 ^
}" N% ]/ T; \* m
//--- Check if we have a new candlestick...6 D' e k1 f! m& T: |, I
bool tem_vela_nova(const MqlRates &rate)
# U' |- B: ]# g: ?3 J{
* d' z8 r4 k8 K- V) e/ `{- n& A+ q3 Q0 T6 U2 i1 c7 m/ V
ret = true;
& o4 Z; B' z4 ~4 Bclose_positions = false;
8 y1 @( @& a7 r# M+ M}
2 Z- z" I; X9 v! q. u1 ^4 R8 xelse
0 v+ a# S) z3 r* Q6 Y{0 \9 F) n; {& i' n4 f+ o
if(mdt.hour == 16)
2 k1 O8 J( A- i( d" _close_positions = (mdt.min >= 30);
% Z. }9 b& i) }7 T1 F4 P0 y}
. d% B2 I1 u4 F}
! n5 H% O) ?* X3 p/ p$ Breturn ret;; S ] P i5 A" }9 e4 Q; U4 q
}
& G' M' F/ D& c//---8 J' ^1 E# P3 _& b$ T2 p3 N
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])$ [4 s8 z* J4 U% @! x
{
: ^; x+ a8 Z& S' l9 Xif(PositionsTotal()) // Is there a position?9 j& p4 f" s# }& z6 U
{
8 Y k/ b& u9 U# ~+ E y+ U6 udouble offset[1] = { 0 };
! {4 f( V0 Y" s1 W5 b0 b* pif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?6 }: r: n. q' i# o
&& PositionSelect(_Symbol)) // Select the existing position!& P8 q- R! c. T' ?2 E1 m! z: k# p2 b
{( d" N- ^: D1 `3 {. w
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
; S6 z. g7 {4 J1 hdouble SL = PositionGetDouble(POSITION_SL);" p8 B" l2 x# s! e- z
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
& n. w1 s! I/ y+ j2 u; |2 f2 Mif(tipo == POSITION_TYPE_BUY)' r6 ] f$ ]' y
{
* `9 B8 ^. Q- q$ T5 {if (cotacoes[1].high > cotacoes[0].high)8 R0 `! k `2 ?# E0 t$ {
{7 ?4 m3 Y& _: p. i4 [* O o
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];% e' c) e! I- o3 n: B" L; {
info.NormalizePrice(sl);
7 G& _# P6 [) D8 I) U$ b+ zif (sl > SL)
+ r2 l) d# m" V{' @1 D' B0 ]" W
negocios.PositionModify(_Symbol, sl, TP);6 A7 ^! h! y& g/ N$ Y! a, b2 D! Y
}
/ D* R" t- L* t}1 U% _ n+ E. f
}
* B4 [2 ]- b! E: lelse // tipo == POSITION_TYPE_SELL. W, O4 i0 F0 I9 R$ ~) `
{
4 ?8 j5 n [" r% yif (cotacoes[1].low < cotacoes[0].low)! s Q0 x8 z; x& x3 V$ [8 @& L
{
) s3 t( R z& e+ Y3 d& Areturn true;( n& J% `0 z& o m1 K) Z
}
7 `% _& x$ d2 E$ `/ s' P& e' L3 b// there was no position
/ U, a/ G( ^, t" ]return false;
) E" u" Z0 l7 k. c3 j1 P}" E2 a$ ]" `2 i9 N2 H
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。( \' B1 k- C! r
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |