启动交易模型,并构建 EA
# B# W n3 _9 |" E+ d1 Y在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。 U; ]9 e- `3 N
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
& u+ s' T; v }1 P% y以下是制定这些规则的代码。
0 N& |. o! Y4 c, D' E8 f//--- Indicator ATR(1) with EMA(8) used for the stop level.../ J& M6 j) y* c4 E5 ?, D
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);/ x$ ^# |; ~, q" q H. _
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);" i# Q' }2 h$ A
//--- Define a variable that indicates that we have a deal...
_* E, Z* U4 `bool tem_tick = false;
: u7 z" F, m- Q' y% p4 ?//--- An auxiliary variable for opening a position( j9 [) E) z9 z2 ?8 V7 Q3 }
#include<Trade/Trade.mqh>
; B- C& }9 [/ l3 u$ g. K#include<Trade/SymbolInfo.mqh>
( ^' P9 P& C& _; U/ `, ^' DCTrade negocios;5 X" Y7 r4 N4 N+ L
CSymbolInfo info;
, [3 m( I$ Q0 c1 Z//--- Define in OnInit() the use of the timer every second4 ~ x a9 e$ m' c: X8 D' n
//--- and start CTrade
, e" p) ~9 L( O& l! b- I9 eint OnInit()
8 P9 }8 G. ?& r7 q{7 h5 \) q, q& E
//--- Set the fill type to keep a pending order; a. S/ Y1 c! ?6 g" ^2 ?
//--- until it is fully filled$ u7 Z$ y/ U$ P% M
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
: U5 i+ d+ T. B& l# Z//--- Leave the fixed deviation at it is not used on B3 exchange
# `6 q# h# _" j# v8 s2 Y5 fnegocios.SetDeviationInPoints(5);
0 H4 J2 C. G; P0 H0 [2 }" H//--- Define the symbol in CSymbolInfo...
8 G$ |! N9 _4 i; i, p( Jinfo.Name(_Symbol);) l& s) `4 M7 i
//--- Set the timer..." v c/ r+ P" V& x
EventSetTimer(1);
: J' j& w+ k$ Z7 }" _8 l//--- Set the base of the random number to have equal tests...
0 I3 K5 ~3 g. M3 E- N- JMathSrand(0xDEAD);0 Q, ?4 _: ]) N; _
return(INIT_SUCCEEDED);
q- Y! k$ l+ {$ J" t7 u+ |% q0 K8 z}
2 `- v# j2 w& m" z/ s" ~. H//--- Since we set a timer, we need to destroy it in OnDeInit().
7 l6 a' Z3 m& t& G/ d3 V: Q/ {2 Lvoid OnDeinit(const int reason)
, q5 S- u5 x- x/ B2 Y, Y0 k. M4 ?{; L+ P; Z, P: \% f6 N
EventKillTimer();
3 p( M6 n4 P M( @5 `}
N. R! [. U& \3 L( o: T9 s//--- The OnTick function only informs us that we have a new deal
- ^" v: T4 A6 A! t& M# {void OnTick(); Z- J% S! y& z! u
{
: I: U* C' C4 N6 P/ U1 mtem_tick = true;# @; @* u' O1 [% C: f5 a( [
}, M0 D! ]( l; A" R- ~! H! _
//+------------------------------------------------------------------+9 a2 \$ u8 F0 s6 s
//| Expert Advisor main function |
2 L y, R7 ^8 G N8 L+ o//+------------------------------------------------------------------+
( x& j' b; i) S7 ?. avoid OnTimer()1 c* K/ N& p" ]2 |+ V- x) b! J, K
{
( r" h3 o+ ]& y& V9 `( L# H( p4 a D6 vMqlRates cotacao[];
5 w; u# i" d) N) d( H jreturn ;
+ R7 X: Q$ ^; [0 K9 k+ R% @if (negocios_autorizados == false) // are we outside the trading window?
- H# a% W7 N0 \6 nreturn ;7 F& k: F, U5 R v
//--- We are in the trading window, try to open a new position!8 F5 R* r5 v, [
int sorteio = MathRand();: b" P* V2 a) z! m: G9 j* P- i8 a7 C
//--- Entry rule 1.1, A+ M M2 E7 s- \, J( |
if(sorteio == 0 || sorteio == 32767): _# ^# L. W1 H P8 @! V
return ;& |+ A1 V( s& E3 F* o J
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy0 o; X {* K" v O
{
& {) \8 f0 H; S8 k* }/ \8 B: O/ Vnegocios.Buy(info.LotsMin(), _Symbol);8 v) ^9 d. B0 D7 E- x/ g
}+ L! `+ \0 x7 w' @. f3 K2 }
else // Draw rule 1.3 -- odd number - Sell& C# W9 l9 s& g( q( c) e! i: t1 {0 d
{/ i0 h Y: h! y' y$ R7 P* i' m
negocios.Sell(info.LotsMin(), _Symbol);! x6 }" ^2 l; ]5 W n- @
}2 |$ k2 K/ d4 L
}
5 Q" l6 T3 U1 _/ v8 m//--- Check if we have a new candlestick...: l1 z* l0 u4 i
bool tem_vela_nova(const MqlRates &rate)+ S4 {% K* ~7 M- @
{
7 w, {5 N9 z. |{. G' z0 d- j( c" O
ret = true;
3 p: q# V; W% g1 _ Yclose_positions = false;
( C' ` `- d. j3 n}! [- C. F& ~2 w7 `8 P
else2 q5 s7 E( s y% E1 y! m& j* C$ |
{2 b. B) V; x' R0 S; a* ^: Q/ e
if(mdt.hour == 16)3 q: ?9 ?! p% u5 _
close_positions = (mdt.min >= 30);
* s, X; k* B8 q y- d}' Z7 Q0 e. b9 ^' I# B
}
% J/ x: s4 I- Q: lreturn ret;/ h$ E0 M; x3 C! b& o4 ?$ }
}: z s0 A7 p9 J0 ?
//---
9 F* k) v" P; l$ e# Xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
8 r4 a+ p' C) ]! Z( R{! W; t0 ^* W% A" z$ u1 b
if(PositionsTotal()) // Is there a position?$ r1 N, _, |- F. h/ u* \
{4 I1 U; B, P/ d* C* k
double offset[1] = { 0 };. F5 l1 q- k* ?8 z7 f
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?. c6 [- X0 e6 v$ o _& _. d
&& PositionSelect(_Symbol)) // Select the existing position!
; T' A5 O# C5 u7 l{; _8 L9 T: q0 b2 y3 G! V
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);& a) e7 s) _2 k# j
double SL = PositionGetDouble(POSITION_SL);1 I5 \0 O7 H- b$ m2 _
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
& o e* ^7 E: Q; ~! o) J; i, \: V5 Yif(tipo == POSITION_TYPE_BUY)
$ K3 ]( x6 m+ {" N6 k1 `. N3 V- q" u{
: N$ Y8 |; H. Q' B; L! |6 X" iif (cotacoes[1].high > cotacoes[0].high)5 f* W- [: C; f9 p5 i5 d a
{# D Z7 K. C& W5 k! B1 b9 n
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];! k/ l# H* f( N3 @& q" O
info.NormalizePrice(sl);' \# H- V( X5 Z9 y" O) X' m; h
if (sl > SL)
9 o$ L& h1 e1 ?, @, ?4 I& \{
) K! ]* q( }( Y; h' ~negocios.PositionModify(_Symbol, sl, TP);
' {/ K8 ~ Y% l}
! e; B( P/ _8 c5 C0 l( ?! N}! s/ z3 K% W0 g+ k6 G# X( E2 d9 ?
}% ]. x" d; q: x$ Y. Q
else // tipo == POSITION_TYPE_SELL( h: R, H" ?/ M! E* ^& y
{6 x& k1 X' z e3 e
if (cotacoes[1].low < cotacoes[0].low)( p' B# z) r: V9 N& b3 y
{+ v; K& O. m, [/ M$ F& V* |" P
return true;; E$ e- h; G0 b* o1 H) i0 w) m* |, _1 g
}
; c1 o) d2 c4 i) @9 ^// there was no position. d5 t7 h6 l7 [6 a2 \( P' ~( h% F, U
return false;) J, k$ @- B! C$ ?9 R
}
/ R4 A4 f/ l/ _7 h( h我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
" J2 u9 x& H6 P5 t$ I到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |