启动交易模型,并构建 EA
6 b+ Z$ F! y- I! U- i# n9 y2 Q" O4 r在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
: R. V, V8 T2 }, A2 s/ e3 @' v8 H- c为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。& m' d' j+ U( e9 i
以下是制定这些规则的代码。& f3 |/ B D9 j
//--- Indicator ATR(1) with EMA(8) used for the stop level...- A* i9 U e3 a X
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
+ l6 D/ u( `0 @7 ]: Rint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);" S" f2 {# a( [3 M
//--- Define a variable that indicates that we have a deal...
: D$ J" i% v5 Z- I& G! bbool tem_tick = false;
$ p& C6 d" p9 f//--- An auxiliary variable for opening a position' K+ l8 T2 _) K8 g! U/ b0 P% ?& {, t
#include<Trade/Trade.mqh>- e$ T1 z; U+ {$ X, J
#include<Trade/SymbolInfo.mqh>
% m' M- ^$ C% Z. u+ a, Q0 k( ACTrade negocios;" F; i/ X {3 m5 @# Y; ]" D
CSymbolInfo info;/ ?0 }6 x* |! L _
//--- Define in OnInit() the use of the timer every second
. d( l i/ h2 X% G//--- and start CTrade
& m. L8 [8 \; h; G, R7 J0 Qint OnInit(). i9 D6 v) |; a
{2 J4 F* A1 t4 M" I7 H- S. e- U
//--- Set the fill type to keep a pending order
+ L! m2 \2 n3 f, c//--- until it is fully filled. W- P* c! m5 @) l0 G" q
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
9 w* w, w+ J. U' o//--- Leave the fixed deviation at it is not used on B3 exchange
4 y7 q9 W* L1 Unegocios.SetDeviationInPoints(5);
0 Y' r6 J" L9 T8 d# b! R//--- Define the symbol in CSymbolInfo...- O7 v! K9 U1 x. Q/ ^+ B
info.Name(_Symbol);( C" D; v5 U$ t4 z& T
//--- Set the timer...1 ~3 r$ o+ `9 \# X
EventSetTimer(1);
0 W; X5 D2 Y9 \. \9 N. [* v v( W. |//--- Set the base of the random number to have equal tests...1 g! i* j2 C9 C
MathSrand(0xDEAD);; ]- Y0 R( p; M* l+ m, q
return(INIT_SUCCEEDED);
- i/ j5 Z4 n8 D1 ?1 u1 o}$ ?' V2 v, i1 \ F$ @( k S
//--- Since we set a timer, we need to destroy it in OnDeInit().
: M, Z3 T# o) |( F. M. G) avoid OnDeinit(const int reason)
3 h6 d8 j) z$ {# W* H{7 z) P/ V; R( `: g3 Q$ \3 k7 _1 S
EventKillTimer();
! Q8 w2 y9 L& V9 B9 `6 @}
$ U( L2 f, U9 s+ r1 \! [//--- The OnTick function only informs us that we have a new deal
6 z. k% e; X% a6 G2 rvoid OnTick()! h4 D' D# L8 {9 F
{/ ]) e# }0 L$ f2 P, F
tem_tick = true;
# P' M9 k* |; C; h" s* z* D}- c8 p6 L. z5 [
//+------------------------------------------------------------------+0 h8 j- m- [' l8 t
//| Expert Advisor main function |' |* F9 v( j8 y2 A1 \7 Q& V
//+------------------------------------------------------------------+6 B, ^# u, g% R9 B3 z+ b4 n! _* u
void OnTimer()- _* d; b2 w1 ?* R7 D: `2 G
{
4 M1 d/ w% ]7 \MqlRates cotacao[];: x: p1 z. z* `$ t: C
return ;
z7 C j9 q% l B4 ~8 [" C3 l! M: h2 Tif (negocios_autorizados == false) // are we outside the trading window?
e# U) ]/ f( f' j% e8 L7 oreturn ;
6 x j2 {0 ?9 I6 C$ D. q//--- We are in the trading window, try to open a new position!' v% m6 s# q) ?* ]" j i
int sorteio = MathRand();
9 J" Z; |5 o" r& y; Y//--- Entry rule 1.1' B- b3 q c0 F) |5 q
if(sorteio == 0 || sorteio == 32767)
2 T( P1 h7 o0 Wreturn ;* }' L2 M9 W3 H
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy1 _- m3 o' P# ^ t+ a4 k- j( q
{$ ^' e2 i! {1 Q' ~ O+ O+ ]/ x
negocios.Buy(info.LotsMin(), _Symbol);# l* J1 S4 S5 u1 |, e. A& ^" B; V
}5 e% K% I& |( U' ?. K
else // Draw rule 1.3 -- odd number - Sell
( ]2 e% `5 Z# n" a! K, O{' I6 B. s$ B2 V) K7 l
negocios.Sell(info.LotsMin(), _Symbol);
! r* s/ |! [ v" R1 g6 R; K3 \5 Y4 c}
+ K% ~. Z6 r: H}. B5 W7 e G. x% r& \. `7 J
//--- Check if we have a new candlestick...# P+ L* n/ S1 Z) A
bool tem_vela_nova(const MqlRates &rate), v8 n& R( }. i3 x; o$ _: t) S- V
{( s8 T( ?5 i( ~/ _. d$ t4 g5 B- z
{, [( l3 |# F3 I5 ^% @* B
ret = true;$ k+ h0 g# y3 B% Q( \- [/ T
close_positions = false;" H2 X0 X9 v/ a% k3 T: Q
}
n5 _: J# o- g" a% |0 K0 X, Welse
' j, c# O' k: H9 M6 C7 ^" \{
6 ^& l/ d( r" M; _! q$ O7 G6 [( qif(mdt.hour == 16)
9 A; J4 t6 V$ m8 V2 z! n0 [close_positions = (mdt.min >= 30);0 f0 T6 Y% X8 P$ m% m1 w9 n
}. A8 j# ?" p- ^# d
}$ b4 b4 N! L1 h( c$ z. M1 P( c
return ret;) n9 A4 [1 h0 r3 _1 D
}
2 n1 o, k: U0 ?9 K//---
. E# D- X2 Y6 u6 e/ j/ Jbool arruma_stop_em_posicoes(const MqlRates &cotacoes[]) {& D. T" g) i- ^% h8 d3 o6 h
{
6 J3 P+ x a0 ^1 L9 q9 aif(PositionsTotal()) // Is there a position?
8 n( C4 p5 d N4 q/ O. D{
/ U, J* [& p6 L" rdouble offset[1] = { 0 };$ R H( e# v+ U( D1 K
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?- w/ W8 }1 Q8 k1 E$ a+ Q! R
&& PositionSelect(_Symbol)) // Select the existing position!8 Z& ^# n* j9 V. k6 ?/ } ?
{
! I5 P. P$ v9 wENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
7 l. P9 ?/ g" a" E! C- b" Y7 @% adouble SL = PositionGetDouble(POSITION_SL);
. _" _; d8 A) H' H; z; d+ Q. @0 ldouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
/ d* D7 K- ? r" ?if(tipo == POSITION_TYPE_BUY)8 y- T P4 ^0 X K4 B$ H/ x5 j9 i# a
{
' @3 W9 n. Q/ z& G) v# }if (cotacoes[1].high > cotacoes[0].high)- n- ~7 K. n- }8 l4 P9 z
{$ R' @( X5 b0 Z9 A( |& |
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];8 X# X5 v4 r2 f' L/ T9 r
info.NormalizePrice(sl);* t- f/ @" F& c. F4 H& [# ]/ \
if (sl > SL)' g) |3 D; L2 V. B
{
& s' V2 z# s' p1 knegocios.PositionModify(_Symbol, sl, TP);6 o3 q% k t. V. _' v
}
* k( x* f, d0 U( C}& Y: x9 P& o. T" w/ W
}' n4 W/ \6 j$ e- {6 u7 w- A
else // tipo == POSITION_TYPE_SELL
. h/ o3 y5 O* U) D3 M8 k{6 q( n4 t7 r, R- \) C9 l1 a$ V
if (cotacoes[1].low < cotacoes[0].low)* ]' D( u" f* M. x: T
{7 ]# j( I0 t$ s8 V5 u
return true;$ b2 E+ f% a) v% D
}4 v8 U* |9 W$ N* ?" r$ L( S
// there was no position
+ V9 C3 }: z8 H1 @0 Treturn false;
1 l" `8 q6 g9 C9 B0 l: R. q+ t}6 B" F! s2 f7 ^- ~/ m- b
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
; u1 [- p. z8 Q. E: _到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |