启动交易模型,并构建 EA0 y, n3 Z# L0 m) p. x- B
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
D5 u" I5 F( j7 g6 S8 D8 U为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
9 K3 b4 ~8 C0 z$ \以下是制定这些规则的代码。4 H% K- X5 [6 J1 e6 {
//--- Indicator ATR(1) with EMA(8) used for the stop level...3 {# T7 h$ u0 ~$ F2 F8 r7 D5 X
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
6 t) }: A5 X! ]* j- \: {( @0 [9 vint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);& _* C- M" h9 u6 n
//--- Define a variable that indicates that we have a deal...: _0 k1 ^! s3 ?7 W2 C- U2 K2 P
bool tem_tick = false; b Y" z3 [- r7 B
//--- An auxiliary variable for opening a position
& h7 z8 j" b, X& {/ `#include<Trade/Trade.mqh># r; Q* z [5 f/ z9 S
#include<Trade/SymbolInfo.mqh>
5 Z0 J: {; ?1 m& h \* ~. [* hCTrade negocios;
; p- | r" X+ ~3 u) kCSymbolInfo info;
9 B8 Q. y+ t( F5 V//--- Define in OnInit() the use of the timer every second
3 P; a; P! t1 W1 K E$ M0 p//--- and start CTrade
: V2 K, l( b4 n) [ aint OnInit()2 y; S! q! x7 O2 z5 ~
{
- E2 A0 G9 m2 L8 Q! o* L//--- Set the fill type to keep a pending order) R" {5 c o! k* e* H5 @
//--- until it is fully filled
D4 k7 g! L* D& M* B3 znegocios.SetTypeFilling(ORDER_FILLING_RETURN);, s) }8 e+ k3 _ g
//--- Leave the fixed deviation at it is not used on B3 exchange f7 r* P- P6 [! e# s
negocios.SetDeviationInPoints(5);
4 @' n! p/ [; p |" ?5 `8 f* r9 d//--- Define the symbol in CSymbolInfo...
) f6 |% H7 K! m& sinfo.Name(_Symbol);
7 ^+ W8 J/ t+ B6 D8 k3 i//--- Set the timer...
I, H7 z8 O) E4 r- E& q' P: REventSetTimer(1);
?5 r2 Q$ a) C1 w/ ]% j) A//--- Set the base of the random number to have equal tests...
* r+ i( W" d/ q! u& m: g$ qMathSrand(0xDEAD);
4 T# U. K1 U" Qreturn(INIT_SUCCEEDED);
: b" \) s, T( Z$ L/ p' A1 O}( i2 p! i; j- f" J( _ ?" R
//--- Since we set a timer, we need to destroy it in OnDeInit()./ B1 u; _1 s9 A# v, i
void OnDeinit(const int reason)! n3 `6 t \; o& O
{# w' e3 D1 _$ v7 [7 e
EventKillTimer();' X5 k2 j& P- p8 ?$ d4 ?( I
}* [0 A4 V& q" A7 ?. b S: h9 [' O1 p
//--- The OnTick function only informs us that we have a new deal
/ s: Y/ Q4 c; W3 Dvoid OnTick(). M* Z1 f0 t Y& B+ v+ G: Q
{2 T, F! y* f% u. G
tem_tick = true;
0 @# T: q( E9 r) p0 V}
K0 x9 K/ x+ a9 a//+------------------------------------------------------------------+5 [6 _$ h) l& \ j
//| Expert Advisor main function |$ o9 c# i2 A6 X3 f
//+------------------------------------------------------------------+* f6 m7 b* R0 G' i6 }8 \
void OnTimer()
& m& t; q( p7 m- Y{
5 Y8 b/ g% N% k, OMqlRates cotacao[];
) W% f0 K* b6 s4 m8 {- X3 Yreturn ;
3 g% e6 ?# t* E- |5 tif (negocios_autorizados == false) // are we outside the trading window?# Y* p" y4 y! T$ m2 A/ J1 r
return ;
3 j+ X: U8 Z$ Z& E% Y0 T//--- We are in the trading window, try to open a new position!: k/ t- ?8 l9 D0 Y2 L3 w
int sorteio = MathRand();
$ V- z% a8 l6 P H4 C//--- Entry rule 1.1
$ q9 R" E/ m9 \+ u2 ]if(sorteio == 0 || sorteio == 32767)
7 G9 M( K1 U! E! f$ z+ Yreturn ;
; B1 b/ a, i9 v8 R. _' Aif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy- i# n; a( [( h
{
- c; D+ ^/ u% N2 e5 Q1 T) nnegocios.Buy(info.LotsMin(), _Symbol);( v/ P; M G& R/ {2 R. w5 B, E- B
}" m X! _& I ^" p6 v3 ^+ F
else // Draw rule 1.3 -- odd number - Sell
, M/ G _5 m9 r9 A* T{( ~/ e- w+ Q9 ^8 m9 F) y
negocios.Sell(info.LotsMin(), _Symbol);
" [# N! t' ^( u. g8 X}( w4 L6 G1 s2 J, _7 e, i
}/ h. i# O" `8 h7 y- E3 M
//--- Check if we have a new candlestick...
4 @. r; i* x: `4 T! c5 ebool tem_vela_nova(const MqlRates &rate)& E: X* r! i6 l
{
: |6 b2 U6 W: ]5 ~ P{
1 M. B7 Y& f: j% \ret = true;
& R* s% f/ G* h1 o/ y4 D3 T/ Lclose_positions = false;
& {/ E2 {% e! |4 {! k, |} d' Q" f6 j0 Y" ` {: S1 {0 M- t
else
! j _$ i0 x7 X; f5 P{. P3 B' @5 Q H [$ O) u5 t Y+ S
if(mdt.hour == 16)1 ^' r+ G& j) q6 K' }
close_positions = (mdt.min >= 30);
' d* D( g# m2 H}4 e) p- W$ I# I0 Y
}1 c* h1 A2 n! g. c8 p4 I6 Z
return ret;+ ?; C& Z9 r" s+ J8 M9 n
}
7 j8 q0 z4 F" x5 H* m; Z' W//---8 X( d/ G: r" _' ]1 c
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])$ C9 r; k4 d2 \
{3 t4 Q5 Y" n. J1 N
if(PositionsTotal()) // Is there a position?
( L2 |" o/ y1 D" y1 T{9 Q; p, O9 _9 W
double offset[1] = { 0 };* i2 F0 W: r3 N4 G
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?. S5 p% F0 y9 m- g6 H6 a
&& PositionSelect(_Symbol)) // Select the existing position!2 }. `" m4 s/ I
{
1 s4 O/ g N. s* [# N+ O5 iENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
0 g" l' Z! W( f. Y0 Ldouble SL = PositionGetDouble(POSITION_SL);. ~$ V. K3 B0 w6 _$ e+ S+ c
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));% `- K; A; b! z. y( m1 ]
if(tipo == POSITION_TYPE_BUY)! z5 Z( Z3 a' z! J" C' l
{
- k# `8 Q; t- J0 [7 Nif (cotacoes[1].high > cotacoes[0].high)6 k: x ~% \9 ]& ~
{% ]8 C8 `: J: l8 H
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];& M& c7 y# ~. Y/ ]" Y2 E/ }
info.NormalizePrice(sl);! R. _( I. v% O
if (sl > SL): ~4 T4 Q9 ?3 z" p' x
{# q% U) f |) e5 y7 _( L/ n3 |
negocios.PositionModify(_Symbol, sl, TP);* {% U( Z. ^" r" L0 }8 o% g
}
- O0 N% C& n, M+ Z}
& a1 A' }$ | U u* h4 H}5 i% ?9 W4 X% M+ T
else // tipo == POSITION_TYPE_SELL
- b% N' V! c' a! L* U+ t{9 R- @$ D, g3 F9 W
if (cotacoes[1].low < cotacoes[0].low)
% q% y! N/ y, y: h3 }{
) J; Y: Y& y% K; J& f# Z9 Nreturn true;
7 Z% w: C9 v) r! [" z3 Q1 @}
" Y' f+ U: r P' L// there was no position7 V. {, `& S( K
return false;, i# A* v, @! k, K% R! i6 O% X6 u# u2 v
}
, F1 g# w( ]3 v; ^我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。4 [2 o% t* _9 i& e3 `
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |