启动交易模型,并构建 EA
/ p% o6 \3 s+ d6 Y& Z9 F/ H8 N在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。- S- K2 U, P7 n3 B, x
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。4 j6 U: H5 F3 _" H+ T
以下是制定这些规则的代码。
5 A# n1 S+ O! r$ j/ h7 i2 [- n//--- Indicator ATR(1) with EMA(8) used for the stop level...4 o: F% o5 H! N4 D D: s
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
+ f, t q/ Q7 v9 Q: X' ^7 Gint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
# R9 h; x, S9 P. t- q//--- Define a variable that indicates that we have a deal...
' S9 M4 p% j4 `bool tem_tick = false;
* j/ l) _* ~/ I//--- An auxiliary variable for opening a position k) U* p1 C5 T9 D4 O" @ k; C+ N
#include<Trade/Trade.mqh>, i( F, l! X3 N4 I9 [) w8 A/ t
#include<Trade/SymbolInfo.mqh>
& g: m+ x) V) ICTrade negocios; o2 h! f, ^& `0 d4 b2 z
CSymbolInfo info;
) f( N" t0 X# u4 j/ ?4 b& i//--- Define in OnInit() the use of the timer every second
P {5 Q, N$ k//--- and start CTrade7 X5 Q0 e9 S& h3 [6 U* A5 ?8 V
int OnInit()0 @0 h" j7 F$ y! z$ b
{
$ o, f; S- F6 `% r7 C) \- S' u//--- Set the fill type to keep a pending order- _. `" }& M @* c; o
//--- until it is fully filled; ~" m' e" V7 f
negocios.SetTypeFilling(ORDER_FILLING_RETURN);% B! z5 d3 c- o q, Y# a( w; Q; H. i) w
//--- Leave the fixed deviation at it is not used on B3 exchange( s7 F J+ g3 }% E
negocios.SetDeviationInPoints(5);
7 S7 B' F/ C6 h* E+ ]6 e4 ^//--- Define the symbol in CSymbolInfo.... }4 a# S* L& ]) r
info.Name(_Symbol);( @9 [( X9 V) T$ \6 Y9 O
//--- Set the timer...
5 ]# m, [. m) T! _6 J& [EventSetTimer(1);
! P& f& n9 {! C( G* \//--- Set the base of the random number to have equal tests...
% w X0 t% Q3 i4 z, eMathSrand(0xDEAD);
8 u! L3 N' n {- N2 [! L! M8 \3 t7 mreturn(INIT_SUCCEEDED);
) i T1 r v% ~. D! Y9 X}
# \/ l" H8 b# y! L4 l9 l: s//--- Since we set a timer, we need to destroy it in OnDeInit().
% H9 x7 J% G/ h) Y$ ?: O2 t, o6 Lvoid OnDeinit(const int reason)9 f+ C8 L* t& [- W
{1 z, W* S w8 {
EventKillTimer();/ Y% h% P* o. A0 D
}
0 [. D: M9 c8 ~//--- The OnTick function only informs us that we have a new deal
/ w r8 Y- I! D6 h6 j& H0 u# fvoid OnTick()2 V8 C* E* O( A4 o% @
{
0 F1 W% C' M; { h4 s% n# ttem_tick = true;
. F9 N8 _# Z s}
L3 D: Q0 F2 O1 W+ J//+------------------------------------------------------------------+' F4 c8 R/ e4 h6 A
//| Expert Advisor main function |
- ]- Z m4 z1 ]) P `$ T: h+ T0 \//+------------------------------------------------------------------+$ i; z0 U. g3 ], S1 ?; E6 K
void OnTimer()
, a( q+ ^5 U9 F/ T: D( K{4 l' R0 ^4 M: D+ R: b: r( R
MqlRates cotacao[];# I1 i* z/ A7 Q
return ;4 n$ _* w, p4 A. n) f
if (negocios_autorizados == false) // are we outside the trading window?2 z5 s6 `% C: y. s
return ;+ Q; i, t/ H2 @
//--- We are in the trading window, try to open a new position!
5 L8 D4 {: k- C" H( F3 o6 I! c" mint sorteio = MathRand();
3 y0 S9 {( A. M4 v//--- Entry rule 1.1* V) G2 k1 x6 L- z9 d+ z
if(sorteio == 0 || sorteio == 32767)5 @5 B8 w; v, U- v( {, J
return ;
* L/ A8 N% M' S0 ]9 J- xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
2 P5 L: x5 d, H% h5 d8 K/ g0 _! c{/ m( y& D: W& L' p$ X( B8 @' s: B
negocios.Buy(info.LotsMin(), _Symbol);
! H/ H1 O% s! X* Q5 A: k}5 A# e: b( O0 j% u6 V
else // Draw rule 1.3 -- odd number - Sell
; |& E: G9 Y3 k( x2 Z{8 P! G2 m( m3 W8 T
negocios.Sell(info.LotsMin(), _Symbol);! q8 x* I" y+ @! {- I# n3 F& e6 q
}
5 H9 Q- _! X4 m}
) [# ^# }. I5 t+ ~5 q//--- Check if we have a new candlestick...
* b% Y7 J3 j6 H/ obool tem_vela_nova(const MqlRates &rate)
& ?' C) [- V: o X% x+ w{
* t4 _8 q. o; T9 R, ^{
* w! x/ X" M: _1 N1 S& b2 yret = true;% v; s- V- p( b+ N/ @" r
close_positions = false;6 M0 w7 g, i9 ~3 w
}
+ ?( i/ p: s, E/ L1 felse
: j% u, ]* [0 z2 K: e g{
0 h. B$ w) E9 T* G |5 ? [if(mdt.hour == 16)
" H& M; A7 ?) B2 ]7 b/ r# ?' jclose_positions = (mdt.min >= 30);
' Z4 ^ T& {, F7 G% u$ g& T}6 N8 W5 X- f3 n. B% K3 ?
}
$ q2 m0 _' C# z* sreturn ret;
' x2 F% J: d2 W9 Z7 s9 x2 b2 L}
$ B8 \" L/ _7 k) i//---
. _& D2 u9 C( xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
1 ]- L. N: n X8 R7 d{+ P% X, {! E& f% F
if(PositionsTotal()) // Is there a position?
}* |4 G! W2 R3 ^3 g+ Q# O/ M# U{
! G8 j: k; }7 Rdouble offset[1] = { 0 };
" q( U0 m$ u! m" G# ?9 I% m' Xif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?1 N* s* _! B! V O z' R6 u
&& PositionSelect(_Symbol)) // Select the existing position!1 g- P& _/ g$ I4 C y
{
* w N6 S" R4 w7 K, t, ZENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);5 ~* p( D7 Q& h2 a8 j
double SL = PositionGetDouble(POSITION_SL);0 Y U7 ?2 w7 [
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
2 @3 C6 z: X9 iif(tipo == POSITION_TYPE_BUY)
s( [& z |/ ^{3 [. m3 s4 Q8 N* s
if (cotacoes[1].high > cotacoes[0].high)
" e( A1 s! l$ f6 e* S. L{0 n5 c8 U0 B9 `
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
0 B! J3 a; y6 s& b) H* b& C$ {info.NormalizePrice(sl);+ P2 J! c9 Z; N. t
if (sl > SL), K6 X; X! Q9 [# E7 B6 D4 Y
{% ~4 j6 h; a; @: g3 w
negocios.PositionModify(_Symbol, sl, TP);
7 n+ Z& }2 Q! z. |4 I, ~! H& i}
j2 l( S* C: c7 |/ c}
$ V- J4 z3 V9 p% t6 l) V" ~, n9 v* Y}/ v1 S5 C" _/ @2 P
else // tipo == POSITION_TYPE_SELL5 S3 T9 g1 ? T8 e8 k
{- s5 N& M: J2 U, {: Z
if (cotacoes[1].low < cotacoes[0].low)( K" f: F5 l7 W% r% M) g" M
{
$ ]! `4 @ j0 J6 x6 n _ w/ nreturn true;
3 v$ H' C& F1 P: n}, k+ W& P; k7 M' W9 }4 V K
// there was no position
# _. o( g5 v7 M& M$ R& S ?# qreturn false;
1 U8 \; v B/ i" `: i}
! w/ c5 x+ w5 w; c* J6 h1 p我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。' ^: G: t3 k4 w+ F- `
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |