启动交易模型,并构建 EA
! Q q" Z& L2 d- n/ Z在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
V4 B3 f. p2 _为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 a ^* V; I6 l$ D1 d! ~以下是制定这些规则的代码。6 ?' X8 A `$ F$ z# l( ~
//--- Indicator ATR(1) with EMA(8) used for the stop level...
3 J4 u+ g' u; {' Vint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
3 O2 G! f* v8 Vint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 C; \, l+ I- G/ u5 E# l" I8 t5 z//--- Define a variable that indicates that we have a deal...
/ F/ _4 ~9 b& H5 qbool tem_tick = false;
2 n$ R( f8 [: j) S2 y//--- An auxiliary variable for opening a position
/ |5 C7 `1 f. C2 S3 K: p. {#include<Trade/Trade.mqh>
$ w4 D5 |! e* p* l3 v7 O w#include<Trade/SymbolInfo.mqh>
! F! q3 H" e# `9 g$ W4 @* ?4 P: k! GCTrade negocios;9 M5 X- l! O6 A2 o0 M
CSymbolInfo info;0 k: m' a7 `7 l) G
//--- Define in OnInit() the use of the timer every second. d* K; h: }8 T' R7 t( ~/ R
//--- and start CTrade; ~7 \' E& C, W6 R
int OnInit()
8 s; D' |9 w/ _- ?. H- v{
' D9 R9 q- N+ y6 G6 p3 I//--- Set the fill type to keep a pending order
, e7 H+ v" m) L& P& Y, R$ n! {//--- until it is fully filled
* j3 s( K+ y" S* p3 Fnegocios.SetTypeFilling(ORDER_FILLING_RETURN);# j% n9 A! X+ r' F/ E$ U: }
//--- Leave the fixed deviation at it is not used on B3 exchange" |/ Q0 E+ I: }( C- u
negocios.SetDeviationInPoints(5);
0 M7 h$ |) P; `3 Y8 U$ z) K//--- Define the symbol in CSymbolInfo...6 d0 V! |, r1 N. Z
info.Name(_Symbol);' Q5 a! U1 g$ f+ C
//--- Set the timer...8 A m, W6 G7 C$ t2 S# d
EventSetTimer(1);
- `# V/ r |* V6 Q: @7 B//--- Set the base of the random number to have equal tests... _( R! x2 _4 U0 [% b/ z4 s- U) ^
MathSrand(0xDEAD);9 x+ _0 I' e0 H# \4 o( x i* d
return(INIT_SUCCEEDED); _, n: X/ x9 I6 [
}
1 c& I' V: R0 }: _! M4 d//--- Since we set a timer, we need to destroy it in OnDeInit().
. T$ J4 [, h+ }# I' a+ E$ Lvoid OnDeinit(const int reason)" W' u" l' t8 W W8 u: w
{
- ]: g/ S k/ ]) d. \+ xEventKillTimer();9 ] J9 q/ y5 K
}' N/ {- x9 x; m! x, Y6 ^- ]
//--- The OnTick function only informs us that we have a new deal, ^$ W4 [1 J* U1 J) w% G+ s
void OnTick()
+ O9 ^/ K3 e2 G T{+ ~7 w9 N. |* K1 r
tem_tick = true;: o- S" b+ X1 Z ~; V, m# H, Z
}% a) h E3 s5 P8 l+ \! r& h
//+------------------------------------------------------------------+! T* \% ^: o; v: _: e( _6 m5 q7 y
//| Expert Advisor main function |3 V+ q$ f* V, n+ Z* r
//+------------------------------------------------------------------+
5 b0 z! F: h* }5 k1 {3 s+ ~void OnTimer()- N9 Q: t+ l# @, @! D5 J9 \2 a5 s
{% Q2 }( |6 l5 h$ I# M
MqlRates cotacao[];6 A! ^5 U4 `9 D( o1 _# u
return ;0 P; w( \3 _) `. }2 j. b
if (negocios_autorizados == false) // are we outside the trading window?
, D$ A4 w8 [# I+ n- [* x6 [. Lreturn ;
, J: Q# X1 e, w8 B! K8 w//--- We are in the trading window, try to open a new position!+ s$ f4 Z, H3 G4 `4 }
int sorteio = MathRand();+ H2 X* L, B, O8 t, s6 j
//--- Entry rule 1.14 r F0 U* @& r
if(sorteio == 0 || sorteio == 32767)
2 E/ p+ n( `( }& Wreturn ;
; X j& K$ N4 Gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy* s8 t2 G* z6 J* W$ D/ ?
{
; j4 W- y, ? A9 xnegocios.Buy(info.LotsMin(), _Symbol);
+ \4 {. R l1 u# N0 F}2 i4 x% R2 C: N8 s! d# l/ g* P
else // Draw rule 1.3 -- odd number - Sell% H& h2 }6 v# Z# D
{
. `8 ~ c& { b' V5 Qnegocios.Sell(info.LotsMin(), _Symbol);
* @$ k) z: N% x! j}
7 l3 l' R f( N6 x+ ^}
% h' |- O/ ?- X2 B. c//--- Check if we have a new candlestick..., ^7 Y; f, U' p9 [9 G
bool tem_vela_nova(const MqlRates &rate)
" d, y. w% N2 [3 O. e5 m{9 f y$ p2 L) D% v4 |
{) a% @, c! ], g4 l- p) p
ret = true;
6 {* P$ s1 T( z2 J$ _7 D6 X# _3 `close_positions = false;
: R8 l$ S% C5 d( z$ n- a}
0 d2 o- ]1 k6 b7 `8 [else! U7 f( {# c$ r9 s6 u
{
. k% l! B |2 X/ @# o; J2 E% h6 tif(mdt.hour == 16)$ n% a+ C" r6 p9 r# N
close_positions = (mdt.min >= 30);
+ P! G8 g. z& ~6 a+ y% |}
& X: i; t' A2 z1 ?6 _}
$ ^" J1 |" S* a5 D& Hreturn ret;
9 M/ h1 k. R4 l; {, Z}% m8 n/ f. {2 ~
//---
: F; U' b4 g$ i, n% B, _bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
. j# f6 h, X2 Y2 y1 s8 l{
4 F* R3 v% U* Z! d/ {8 G' K' iif(PositionsTotal()) // Is there a position?& H# b2 N* q2 g3 L
{+ T) s5 P% U( Q% i4 ]# C" a7 \
double offset[1] = { 0 };. z P) A6 ?6 A/ h2 G, d/ P m
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
G; e s9 ^2 H4 m5 P&& PositionSelect(_Symbol)) // Select the existing position!
3 L2 j- I% D1 a+ E! o% Z{) X/ \1 Q% s4 d# V% D% v& v# H
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);# i% U8 H I# v, Z# R6 R* _7 M
double SL = PositionGetDouble(POSITION_SL);
! v9 s4 M; ^1 N1 d# Udouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* z0 E& n3 c3 aif(tipo == POSITION_TYPE_BUY)
* U9 {2 w5 X) n6 F% H0 {. S{3 d! E( U& v: A' m5 E8 H% ?
if (cotacoes[1].high > cotacoes[0].high)% V! e1 A& o! S' S
{
$ Z# `# ?) i$ d7 ]3 n* @double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
+ L9 l. v* G. o, k) @: G$ @. Oinfo.NormalizePrice(sl);
9 ^# I+ o( o1 V' i8 b/ l x' ?0 Qif (sl > SL)
/ N6 X0 U) t: K) `( n. P{# J4 C5 Y6 `- \; v0 E& r: d% a
negocios.PositionModify(_Symbol, sl, TP);
/ c! K$ I0 W( k' u2 ^! w6 G0 B}
5 m6 N, ^% R0 \* S P4 ?}6 |+ z. T0 ^2 X+ {
}) X+ n$ d& o6 f# u* x7 Q
else // tipo == POSITION_TYPE_SELL
; m" k8 L0 e0 ?% a, a5 f{
2 A9 @2 v" f; `0 eif (cotacoes[1].low < cotacoes[0].low); J2 _& {+ ^# N; p) _3 y/ \
{
; V( i" H: g" R! m" l0 z! K1 s! xreturn true;) T/ y* ]; Q7 @. F S! K$ L" G9 x6 k
}/ @+ W/ R# b+ I- V
// there was no position" k, r0 j; t! p$ `# k
return false;; C( Q9 B* m/ B) d A/ K
}
$ Y# g+ P8 X! u我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
" H0 b+ Y+ m4 N* ]( U到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |