启动交易模型,并构建 EA
' j* Y8 Q; z, f* S+ _9 S$ }在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。( ]; l4 i7 n' R$ y& h$ C
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
* w* j! h/ S; Z& v1 h3 i3 z% m" p$ g以下是制定这些规则的代码。2 y" B' a1 f: I! |0 H, _9 A& X
//--- Indicator ATR(1) with EMA(8) used for the stop level...
+ e7 O/ }7 \) F" d3 oint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
- k4 i: e* B5 k. e. Fint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
) ^- A) H2 N8 m+ X# N" v//--- Define a variable that indicates that we have a deal...
, P/ Y0 G; n A' xbool tem_tick = false;) _1 `6 B* j& M& \; ^8 {
//--- An auxiliary variable for opening a position
$ V1 b+ n- d% M#include<Trade/Trade.mqh>1 ^9 b5 g0 w3 i( {! {( K
#include<Trade/SymbolInfo.mqh>' ^% W: L, z# S6 I6 _ u( k' X
CTrade negocios;
( ?+ b- a6 E: A1 _! [3 c" [CSymbolInfo info;5 e' W& i; R% W ^
//--- Define in OnInit() the use of the timer every second1 w( ~/ Y! B: @2 _8 [5 \6 M0 ~- v
//--- and start CTrade
a P4 g2 X7 S$ m, E- `int OnInit()3 Q9 Y1 Z Q& k9 M* R- r/ f3 r
{% [3 j* P" |; n2 p9 i3 D' C' o
//--- Set the fill type to keep a pending order
( H) J% P( w' x& Q* x//--- until it is fully filled
& u+ r; A4 @6 ~4 Z& y2 Onegocios.SetTypeFilling(ORDER_FILLING_RETURN);
; m! z; E- T1 Z. r( q9 |//--- Leave the fixed deviation at it is not used on B3 exchange& ]* m# B9 t. X7 _( P& v7 v
negocios.SetDeviationInPoints(5);
% ^5 W8 \ \. _//--- Define the symbol in CSymbolInfo...
7 _0 g, g G+ D/ M& \! Xinfo.Name(_Symbol);/ \, K% s" z3 b* d4 q
//--- Set the timer...
k% i1 j" P$ a. lEventSetTimer(1);
9 u! Z; e" e% m1 ?2 J8 N8 f5 q//--- Set the base of the random number to have equal tests...( c7 B8 t- Q' ?& s+ x( R/ p
MathSrand(0xDEAD);
6 d. D/ X6 E8 S* U: s" Preturn(INIT_SUCCEEDED);! T/ \( @5 I: O! t# ~' K. B9 Q! ^
}
+ u& R% L. a ^' P4 ]; { H3 Q//--- Since we set a timer, we need to destroy it in OnDeInit().
. N, t) E9 [9 w0 d0 xvoid OnDeinit(const int reason)1 z* ^; f% G6 I0 o8 f
{! W. J" S3 t( S+ J" ]+ u
EventKillTimer();
" ~% S0 Y2 D. E+ X5 v. y}- o4 C0 i% a* T0 l4 l9 z
//--- The OnTick function only informs us that we have a new deal/ N) @* I# q/ B2 s, }0 k
void OnTick()& |. ]2 s' ?0 W5 L5 T* s
{- w9 j: `6 _7 d+ t+ V7 L" r
tem_tick = true;; z2 T6 }5 i$ W" p ? I& z
}
; S" D8 [* [+ s* }0 x+ v' |% R9 @//+------------------------------------------------------------------+
" T# `* J5 c9 n- E# v//| Expert Advisor main function |
$ G+ Z8 W$ C, s( E//+------------------------------------------------------------------+! F! d% p1 v, G
void OnTimer()
' \+ F2 a* |8 T, R1 f8 ]6 O{
; t1 H* {1 l! h+ [MqlRates cotacao[];
& d+ l0 E/ ]$ O$ S l/ ereturn ;
- k- R' a! A. oif (negocios_autorizados == false) // are we outside the trading window?
# i3 y9 O" l- V. \' `- xreturn ;1 t+ G2 r' ^: h
//--- We are in the trading window, try to open a new position!" b$ F8 ?- @$ Z4 t
int sorteio = MathRand();
2 Q; B# G% t7 a" |8 @//--- Entry rule 1.1
- X( {" e; g" }3 M; Mif(sorteio == 0 || sorteio == 32767)$ X. W9 Z, E' r5 G" N+ i
return ;
- p: i! z5 B! vif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- A9 Q% X. c' F+ A4 ^{0 Z7 ^! m& \- P- w: x0 S
negocios.Buy(info.LotsMin(), _Symbol);* p2 N5 F2 y$ s% k4 d
}9 Y% k0 I( ^. e b3 c
else // Draw rule 1.3 -- odd number - Sell- J3 I5 e, d& [
{, _4 {# _, P! a- `3 W
negocios.Sell(info.LotsMin(), _Symbol);
- ?; Z, a0 d1 p, Y4 w7 l# m+ e}( r+ H9 ]6 Q9 u8 C
}
/ z S. V5 {, F& j+ r; Z//--- Check if we have a new candlestick...* |# F. j) h+ {, G
bool tem_vela_nova(const MqlRates &rate)
' C( z+ G. u1 `3 e{1 B( N( C$ _% N- L/ k( {/ N
{2 q- d1 r1 W- x J
ret = true;
6 T: W! d- w( D! q9 o, D4 j+ hclose_positions = false;* s( n2 {! {% ~3 c% F5 j% {
}0 a9 S) s7 ^% q
else
$ z% M: A4 d" }) U) [) F" i{
% G0 {8 J- J1 d" o! P) Y: Z! d. Bif(mdt.hour == 16)
2 U; j0 d4 K- B4 }$ |: l- sclose_positions = (mdt.min >= 30);7 [. J1 F: c& v' u
}
4 V' u! p* e- p}% Z" D' C* F4 n. a2 g$ p) b
return ret;
' D; [3 K. j3 I. B' @; J}, Z& L- Z' I- _( R! ?2 T
//---6 }: H ?5 L- } k4 k% m
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
9 U, E4 `7 G7 ]: K+ @{
% R1 u- l' e; T$ a- eif(PositionsTotal()) // Is there a position?
* A/ g O; |3 o# P{0 [5 M/ w- |' b! Z! \% D z$ N( s
double offset[1] = { 0 };
( ]$ N2 v d& c, Q. Vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?/ S# `+ X! m. I; l1 Z8 l h
&& PositionSelect(_Symbol)) // Select the existing position! S) Z, E% `7 i1 P8 p* _7 x
{
( b' y% f5 [% ?$ m3 c* V+ jENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
, `2 L+ j" h1 M* x* y2 W1 Q- A: Sdouble SL = PositionGetDouble(POSITION_SL);
" |( F! [* I% m0 p5 v7 o8 j5 [double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
, Q/ E8 e* C/ p! _/ W6 rif(tipo == POSITION_TYPE_BUY)/ ]0 z( l8 n7 I0 h
{
: B: _$ S. a" J! Iif (cotacoes[1].high > cotacoes[0].high)& h0 c8 L& H `$ a$ ^8 I
{+ M# _, o4 o4 |* {0 \; v3 J. {
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 w% {& W6 r; }( H( uinfo.NormalizePrice(sl);% ^1 `: n, a5 m! V0 U- m
if (sl > SL), C& B6 J; m, d4 X5 o
{
2 u% m( J( @- ]) o2 Gnegocios.PositionModify(_Symbol, sl, TP);) e0 e( o4 D2 `& j. {) X1 g
}
1 ~) u' i$ H* e8 y# ^}
3 G( E' c& \; J5 z}
* F4 q- q( F9 Kelse // tipo == POSITION_TYPE_SELL
h( p$ F8 }2 }* @ Y{
2 {8 y$ M6 V$ fif (cotacoes[1].low < cotacoes[0].low)
9 L; g2 z; }" Y3 f{
( c" A- I) _- ?2 h% f$ ^return true;
: H* X2 g, I( p2 F- L" ?}
' V3 f- R5 g& _' H1 u// there was no position
# P u4 M# W4 z* I" P. j% b7 ^return false;% g. r8 c0 l$ p; m
}& G$ Q" \$ d' b* ]" T/ b" ]
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
; n+ Z5 ~. b f9 _& z; j T到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |