启动交易模型,并构建 EA
, p& ]1 o5 u. C8 Q ~" z5 Z在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
2 Z- L' v9 d- x; _# Q( z- ~, s为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
# n& ~5 P7 }8 O& \以下是制定这些规则的代码。
. @0 I2 L5 d+ t7 P1 H//--- Indicator ATR(1) with EMA(8) used for the stop level...# Z( m4 E! f! ~" A; U3 x9 t
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);9 ?; r y" P2 |0 |% k( D) b
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
; F% ?; ^8 _5 z+ \6 o( h4 J J//--- Define a variable that indicates that we have a deal...
6 q9 W$ P& d9 V/ I5 R! q7 H3 hbool tem_tick = false;. n4 L4 E7 R( A8 Z* ]2 I
//--- An auxiliary variable for opening a position6 d3 I2 ~7 l. u" k2 I! v
#include<Trade/Trade.mqh>% z2 a5 Q1 C) l& P! ~& ] y) q
#include<Trade/SymbolInfo.mqh>
+ }) [' c6 n VCTrade negocios;
q4 j. h: G/ K( aCSymbolInfo info;
" V+ U0 i8 k; K//--- Define in OnInit() the use of the timer every second, ]8 P5 Z7 d, U3 @1 P
//--- and start CTrade# j3 I' }4 x. b
int OnInit()
3 I9 c# q0 w" X6 z' I6 e6 A{ s$ r5 q5 w" h
//--- Set the fill type to keep a pending order w9 K8 W. J0 M- t _$ B3 {; c; S# X
//--- until it is fully filled
E. y/ ? z& r* Unegocios.SetTypeFilling(ORDER_FILLING_RETURN);
( e, a+ N+ c. @+ @# e2 M% P' m//--- Leave the fixed deviation at it is not used on B3 exchange3 K2 l- g. T# G: F
negocios.SetDeviationInPoints(5);
0 ~2 y: R: o0 @& M5 n//--- Define the symbol in CSymbolInfo...
7 Z- X$ q$ X4 P- x) n+ r! rinfo.Name(_Symbol);2 ]2 P5 ~7 t8 q
//--- Set the timer...
- O! R2 }: e, O. |( O, g% EEventSetTimer(1);
' V( B; `8 y9 U% i: o//--- Set the base of the random number to have equal tests...& o7 Y1 Z. }+ I" j; o
MathSrand(0xDEAD);
% C) g3 @" w7 u1 _0 Mreturn(INIT_SUCCEEDED);
; ?7 P# _, u6 X' L! {- e; {}
+ m) k8 O. n/ U' e5 `$ V N! g2 P//--- Since we set a timer, we need to destroy it in OnDeInit().# `$ j) e" ?% U0 ]
void OnDeinit(const int reason)
* U6 u, [" {# q" {; d5 E) e{
, W2 ~: l+ ?1 T, X4 w; t. QEventKillTimer(); Z4 ^/ _' J' O- r k. _
}/ ]- k% n+ V( N7 G; {/ K. |
//--- The OnTick function only informs us that we have a new deal
+ P2 B+ j! j8 j( @ A: q& lvoid OnTick()$ ^4 [$ A! g9 d8 o, f/ g+ D( Y5 Y
{1 u" b( K$ }8 Z5 l) b
tem_tick = true;
, Q0 [( X" n) N. F, y}
( t m& h! c0 d3 D//+------------------------------------------------------------------+& m/ z) B7 u1 E/ h; k6 r
//| Expert Advisor main function |
* E0 B# l" D$ z//+------------------------------------------------------------------+8 W1 j7 K" ^, c4 O" C
void OnTimer()9 S; O0 w- _8 k
{1 C: F0 w& ]4 ~. O
MqlRates cotacao[];
3 f, W' H6 @8 M! r zreturn ;7 o/ t: h1 J4 D" a9 @2 U
if (negocios_autorizados == false) // are we outside the trading window?- K, _3 |: @0 u }6 e$ s# l
return ;& q0 @; i+ J$ s8 s' V5 v* J+ u
//--- We are in the trading window, try to open a new position!9 p- v7 A5 M$ p: ^
int sorteio = MathRand();8 x# E% U6 j5 i, T: y
//--- Entry rule 1.1& c1 ~4 T/ l6 H0 ]! w r7 N
if(sorteio == 0 || sorteio == 32767)
, r, g3 ^* Q0 R/ h0 Q3 j' E7 Zreturn ;
- C2 R4 n n, F, p* yif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
' g0 ^6 i: Y3 M5 ?: v6 j{
4 t" X, g3 p9 a2 s) e+ x$ Mnegocios.Buy(info.LotsMin(), _Symbol);
2 P! x; o' y- o# R7 x}
7 }) A% I9 G; t$ ^5 K+ b! Q5 Z1 velse // Draw rule 1.3 -- odd number - Sell
2 M0 A; x: n3 Q% q C{) F/ u0 B& } @) w, r
negocios.Sell(info.LotsMin(), _Symbol);* z' D* o3 n' b _* V3 g% c* ]
}
. S# S7 w: i: w3 ^, W}
! e) X+ @- L$ M3 e: Q7 U. k//--- Check if we have a new candlestick..., L* d; p; F! b: J) w5 G6 u- `1 O& a
bool tem_vela_nova(const MqlRates &rate)7 S# n% g% y- v
{0 m; Q: v3 [5 Q7 c1 ^
{
. z! `- g' T$ O# i# qret = true;
* t3 q; e( P, `" Q' o+ Q9 Y& ~close_positions = false;8 C& R1 m0 I1 g/ m* y% [/ d$ v
}- z. E0 F. }9 J2 b/ ~% m, |3 M
else
" B$ m$ _8 W) ]/ e1 ~# ]6 T1 S+ I/ ]{
$ R' W& O3 k c7 K* s) W% Y! |' Y" tif(mdt.hour == 16)
- j% Z1 W: m, X# @5 F+ Q: eclose_positions = (mdt.min >= 30);
8 S9 Z2 } p1 l( P2 I3 v$ K6 @}0 ?( r9 `9 P u7 u" |8 D) ?: i
}6 M+ g# M2 L- n" R/ E% o0 }
return ret;
9 k8 [/ `- s. m1 `}
# |% K5 J. e8 ?6 h+ ^//---
. d, K0 g, Y. y6 w0 ?' qbool arruma_stop_em_posicoes(const MqlRates &cotacoes[]); ^% \# y3 [$ i! ^/ }* t* D6 O6 F3 _
{% B/ k& ] }' l
if(PositionsTotal()) // Is there a position?
0 ^. r6 Y; \ k{
! m( Y; d' y& h" b Jdouble offset[1] = { 0 };
0 c- b& k7 Z, I; _! F$ Kif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
1 J1 I0 p% ?+ w' y; Y&& PositionSelect(_Symbol)) // Select the existing position! d' `$ D/ G" l. G! @
{7 D) G: X& T$ |" d7 {6 L% m
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
, [8 F2 X5 |+ X' X1 Rdouble SL = PositionGetDouble(POSITION_SL);
; z0 A+ V/ h; n3 Ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));# w# T% x! b% v, V- }
if(tipo == POSITION_TYPE_BUY)( |0 j7 e/ P$ X
{
: p0 ^! I5 w" s' l; Mif (cotacoes[1].high > cotacoes[0].high)0 B+ T( Q) ~3 F
{" [4 q, `9 k9 u W
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
& l c5 B, |( U& n0 H8 S. einfo.NormalizePrice(sl);/ ?1 r$ u/ ~ ~# l
if (sl > SL)
7 ~% _) X& O. N: N8 m5 @( c{0 C4 \: ~5 D0 D
negocios.PositionModify(_Symbol, sl, TP);$ i- |, p0 G, N( ^: d3 Y. R
}
7 W/ ]+ K, N x. [5 ^}* S3 c& ^! |3 b% E! [" O% n
}+ Y/ r0 o: u0 j, ?; R$ [: Q% n5 f
else // tipo == POSITION_TYPE_SELL1 B( A) b" g+ R8 ^
{; b) Q: m3 q, N2 `! E2 _) \& c7 ~
if (cotacoes[1].low < cotacoes[0].low)
3 m, b# x0 I2 O' _2 v3 z) T+ Z5 V{
3 ^* o8 Z& Z; j8 j! v: f4 `return true;
' Y+ z: [6 K2 u# y n}
' A3 `* Z% S/ o, c' V// there was no position
( p- n: R7 t b& G- xreturn false;2 x* B9 j8 ~3 Q. k+ r& e5 L7 v
}
! y6 w0 f1 i' W) K3 a) `我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。1 p0 l: w \0 Y; p1 u
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |