启动交易模型,并构建 EA
B r! B {5 s- [& u: K1 z: M% g5 Q在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。! k- W4 J8 s9 f. G+ W. |( y
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
/ o0 W a/ U5 ]. P5 S以下是制定这些规则的代码。
1 J) H; H$ Q8 ]. k' d# I//--- Indicator ATR(1) with EMA(8) used for the stop level...! y E, G# z- @. P |+ w' r
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);2 X* x4 q$ k" d7 L
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' j! W" v5 G4 i' o//--- Define a variable that indicates that we have a deal...0 w/ S1 c( f; I! M( a6 t6 V% z0 E
bool tem_tick = false;, y0 f# T5 l7 H0 l) J# Q- D
//--- An auxiliary variable for opening a position+ U1 ^7 [1 F' P+ n8 `" k9 ?. D0 b/ ]+ P% C
#include<Trade/Trade.mqh>+ F( P8 u7 c F3 v9 o' v
#include<Trade/SymbolInfo.mqh>$ G) |6 n' L, w5 `% _9 y: }; F
CTrade negocios;& T; H2 u: R3 A' O) q7 O S5 ]% o
CSymbolInfo info;
1 ^" e# Z+ G) D' C' C7 b' H% [//--- Define in OnInit() the use of the timer every second
! \( H% [$ C6 ^7 m//--- and start CTrade8 ^2 ~6 J" L+ d$ T" R
int OnInit()+ T% C# M9 X$ J1 T* u/ S
{9 `; z! l; W+ Y7 Y) n' Y
//--- Set the fill type to keep a pending order* d# O( P: i. p) O
//--- until it is fully filled9 u# P+ X1 h H" D/ ^* r
negocios.SetTypeFilling(ORDER_FILLING_RETURN);; O6 }# N: R/ X% W, \
//--- Leave the fixed deviation at it is not used on B3 exchange9 w/ t' q: q. @
negocios.SetDeviationInPoints(5);
& Q' S* t2 ?$ o7 j//--- Define the symbol in CSymbolInfo...
: G) [# A6 f4 C" Q) `# b* X$ Iinfo.Name(_Symbol);
7 j; e( R- D' R- _//--- Set the timer...
( n# h: ]: b4 j9 v: Y6 {EventSetTimer(1);# W* A. [+ b- m: X6 K1 ]
//--- Set the base of the random number to have equal tests...
0 R% A$ N9 B1 q/ M" c1 j, y; yMathSrand(0xDEAD);$ }+ G* e: t: U2 Q0 A0 q8 r
return(INIT_SUCCEEDED);
! V, J0 r% O1 x, t4 w R- I}7 W, b4 j1 T, C6 p! s' m, F- C
//--- Since we set a timer, we need to destroy it in OnDeInit().8 P( g' N% I0 M: V
void OnDeinit(const int reason)! r# | k2 I/ I. X9 ?" v9 B, z
{3 m* G$ X I! D6 B
EventKillTimer();5 ^4 V% S. R3 _& N, ?
}
$ @1 B1 g; i7 d8 j! x( }* p5 b//--- The OnTick function only informs us that we have a new deal: C: K6 U6 h P; ?/ T E- t; p) L
void OnTick(): A9 x: f- n) R; y/ m; n
{- m& M8 V8 T) e& l" [
tem_tick = true;# M* @4 n: e# m) `/ B
}
% f' ?3 U. ^; [2 l//+------------------------------------------------------------------+! b8 F, ~" T9 b5 N& J5 W
//| Expert Advisor main function |0 l6 t7 \4 {" b0 K
//+------------------------------------------------------------------+1 q- u; z+ ]$ M8 f/ J! q g/ x
void OnTimer()' `' _0 n2 x- a( C, l* d
{
! @1 i$ m* p2 F# A3 aMqlRates cotacao[];, e7 X/ c" e( I+ e) l) q
return ;
- n+ P/ H% L3 V. m; ~if (negocios_autorizados == false) // are we outside the trading window?( w4 m! i) `8 a" D
return ;* s2 s0 t2 W' K, n
//--- We are in the trading window, try to open a new position!
' y- ?2 T4 \. L: W) w" _int sorteio = MathRand();
& K) x+ y; ~2 P//--- Entry rule 1.1
# Q, _5 E" v. t, u) |& m) Rif(sorteio == 0 || sorteio == 32767)
4 H4 q; Y0 c7 m; creturn ;4 p* I6 I" v5 H
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy6 |! Q8 B/ K$ J" U% `
{
; h- P7 o- p" bnegocios.Buy(info.LotsMin(), _Symbol);
- b0 d* U* W9 J+ Z/ ?}5 D9 }. f" _( q) g$ N5 t, u
else // Draw rule 1.3 -- odd number - Sell+ k! _/ L. D, ?0 `0 h4 _" c
{- ]' F2 U4 @1 h% C' }0 Y
negocios.Sell(info.LotsMin(), _Symbol);: S- a! m6 C) a( ~5 f2 t# J
}8 G3 P0 u3 K @+ o+ s/ p ~
}
# ?/ _* d# W7 |1 o//--- Check if we have a new candlestick...% r# p! U0 g) U, g( ]' {
bool tem_vela_nova(const MqlRates &rate)
& C- k3 d* E0 V% a, u, G{. H. r' G5 d) G3 n
{
6 x1 G3 e3 V$ t" l# N4 f3 _- \ret = true;
/ T9 |* m; x" E* U5 c& {close_positions = false;
3 V% l! l! n D$ }" M}2 n! ~) L) v+ k& O T
else( \5 l; U0 L* |7 U" y H( G
{; I; R: D' Z1 u5 `9 m ?
if(mdt.hour == 16)
2 G3 Y0 O; }6 C/ \1 Mclose_positions = (mdt.min >= 30);
, b% Z4 c* F2 c4 P}
9 Q3 C+ C0 F, |4 ]' G9 K}
7 v# d8 L9 N+ ireturn ret;1 u1 y5 |+ O: e* R5 P K" a
}: @) E( ]+ t+ R
//---
# e& E* Z9 Y/ h* q) Sbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])! H/ }8 @- q5 r* _
{" i' l1 m0 c6 ~$ W
if(PositionsTotal()) // Is there a position?
: ?( n" O$ q' n9 b5 y{
2 O y; B- u |. k3 Kdouble offset[1] = { 0 };
- ?* t. Q" k, H+ ^if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" O4 e+ M i3 V, {; I&& PositionSelect(_Symbol)) // Select the existing position!
# \0 J# H1 h/ k' I{
T. O( h5 Z5 r2 j f1 C7 K+ k( |ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
& O2 q0 q! B$ ? edouble SL = PositionGetDouble(POSITION_SL);
& s1 [4 I8 F4 u9 X7 Y. G% |: ]0 ^double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));( {$ Z; C' l- e# n
if(tipo == POSITION_TYPE_BUY)4 H. ]7 o/ w6 K! w$ h, f! W6 X
{
c) z( B& ]# [3 zif (cotacoes[1].high > cotacoes[0].high)
5 Y! V7 x2 v% Y7 p B{
2 g5 o! X3 C/ B$ l0 Y4 X adouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
$ M4 K4 E- }1 \ Q* S! I: c# sinfo.NormalizePrice(sl);1 h4 b1 @* m; @5 o
if (sl > SL)1 ]& \4 B [0 O' X! P/ i8 T
{2 i, x) k+ r; K6 `/ ?
negocios.PositionModify(_Symbol, sl, TP);
+ z# ]5 j3 B. z, j4 M}
+ v$ P5 T, L8 k! l8 q" l}
. Y; \- ~# f# a% Z. j# ^0 Z0 P}* H9 j% G8 j' p5 n
else // tipo == POSITION_TYPE_SELL
' F5 P: e4 h) q p% T/ e{ E2 N3 V4 m! N/ G; g( ^
if (cotacoes[1].low < cotacoes[0].low)
" a. C3 ], V, L{- b# v, k1 g# r* q0 Z
return true;
. D7 `; H0 c) R}! c3 [& c5 F* c2 D. u& B" t5 t
// there was no position% g) o0 Y6 n2 p! t6 ?) r
return false;' X- }5 {- b9 y I1 }( O7 i* l
}
" f# G' \. Q. e( r我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。' _2 C8 d! b) t. V2 `
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |