启动交易模型,并构建 EA: M% p4 D: R1 ], Z
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。9 `& F+ s& {. w$ J
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
% U+ K& [7 K7 r- ?4 b: m: D1 L$ K以下是制定这些规则的代码。! q0 h! d! l( o: d
//--- Indicator ATR(1) with EMA(8) used for the stop level...
( a7 b e! e- q0 r& J7 Aint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);+ o' ]. l- }. L7 c- }; b: l
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);8 a7 H4 i6 `& R' D
//--- Define a variable that indicates that we have a deal...
G4 u7 w+ a) Z# Lbool tem_tick = false;
6 F& P9 s0 l! h' u( u, h% v0 w//--- An auxiliary variable for opening a position9 ^" U+ J1 f8 K& \0 g
#include<Trade/Trade.mqh>0 g; p, W2 q2 M' H9 s5 I7 p+ {' [
#include<Trade/SymbolInfo.mqh>: F/ d; I$ f$ k" P3 o
CTrade negocios;
& [$ W; q! Y$ W S! lCSymbolInfo info;
+ h6 ~# u$ G; Z0 w' G u3 p//--- Define in OnInit() the use of the timer every second
1 ~. Y; f) U0 h' U" ^& k//--- and start CTrade& J3 k" v( z, C7 s- K" ^7 C# o+ _
int OnInit(); ?) j6 o/ y" G% [6 `- f
{2 i; A7 D, J9 t; T7 r' L8 d0 A$ q( |; u
//--- Set the fill type to keep a pending order
' c6 H7 e5 \( c6 `//--- until it is fully filled
7 P$ N7 g+ H( m5 Y/ \; s" g7 Dnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
4 L( l* f* w9 T1 X8 s" ^//--- Leave the fixed deviation at it is not used on B3 exchange, _* g: e) {) m( j- M
negocios.SetDeviationInPoints(5);
R; h. E! l) M//--- Define the symbol in CSymbolInfo...; Y: ?5 D1 x0 n# i; p. i
info.Name(_Symbol);
6 c8 K) |; y8 C+ ^1 j1 `//--- Set the timer...
' [" Y) B2 X! QEventSetTimer(1);$ W2 T2 w7 z$ N
//--- Set the base of the random number to have equal tests...
: ?( j" n& k" T% XMathSrand(0xDEAD);1 T6 q+ t/ x+ X. A6 c
return(INIT_SUCCEEDED);* E! L/ Z$ H" ^ _
}
8 P" k3 {) k) @, S//--- Since we set a timer, we need to destroy it in OnDeInit().3 n1 p- M$ X* f$ B
void OnDeinit(const int reason)7 T' t {: E/ u4 s8 z; A; O
{$ O' p- `/ ^% \" b
EventKillTimer();
/ U7 B5 b" G7 [- w# ]# ~# Q) [" ]- M}; J6 J* _$ c1 H$ Y3 h# c
//--- The OnTick function only informs us that we have a new deal
7 U4 s" ^ {- e5 |: F xvoid OnTick()$ C- v3 o2 i0 c+ g1 o
{* z! p+ Q9 ]1 c* Q( _
tem_tick = true;3 Z5 ^5 N% s3 J; _, n$ V
}
, O- }5 e5 A) B//+------------------------------------------------------------------+
5 L7 o' `0 A6 c; D& p//| Expert Advisor main function |7 J1 T6 Q' i- X+ f1 e8 p& |
//+------------------------------------------------------------------+
7 K# Q! C9 }1 q8 g; g) zvoid OnTimer()* s; Q5 L) z- [9 H! U' y( m2 I" o
{
4 T8 ]! O8 L( w6 t5 E/ gMqlRates cotacao[];7 G% c' g3 v6 S" U3 R- k
return ;0 h/ H w1 G: w! O5 X4 G, t
if (negocios_autorizados == false) // are we outside the trading window?4 b. J8 @, b5 ?
return ;
+ L; _" g8 n7 t3 z2 t, n//--- We are in the trading window, try to open a new position!6 T: D! e, F* {3 n% p( N5 q: c( Y
int sorteio = MathRand(); ?/ h3 E6 c6 `3 g. J* r6 f V2 U/ z
//--- Entry rule 1.1, O$ `3 l4 i* @% M/ c
if(sorteio == 0 || sorteio == 32767)5 Q1 W7 G- q' N' \, W( R; ?9 ~% C
return ;, A0 s5 N7 r7 g
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy9 @" x6 U& S' o6 ~, p% Q# n. D$ |
{; R* E! v- s! c! u5 t( b
negocios.Buy(info.LotsMin(), _Symbol);; P+ V% b4 y+ d
}
4 e1 F# }7 r" Q1 B: J& t5 Felse // Draw rule 1.3 -- odd number - Sell
4 v4 h$ j$ v2 G- U/ T- t# s5 m{( v! b4 Z# f3 ?8 S) O# c: m
negocios.Sell(info.LotsMin(), _Symbol);- m) W: @! B \" J" t
}% E+ A! q E8 K+ p3 G% n* w t
}% a) g( e0 r8 s0 @! Q) q
//--- Check if we have a new candlestick...; h3 S. ]" ~% |, i$ R' m2 [
bool tem_vela_nova(const MqlRates &rate)$ [# C, c# b4 l7 D
{
7 }+ q1 w% W6 Z) [{& s! R# y4 I. K- y! G3 h, O, q$ l* q
ret = true;( z1 s5 I, q. j
close_positions = false;
& C4 _0 Y( H. a}
, r; P1 @( o/ j$ selse2 Y' O3 {% Y: n0 o6 [
{
3 G! e! e2 {) q, ^/ H: Gif(mdt.hour == 16)
G6 J) {, ?$ K) b/ iclose_positions = (mdt.min >= 30);3 Q" N- }1 f6 `. d" L/ _ x
}
8 L# w$ u F0 z* @}
# x7 n7 }7 c2 s! T- i: K0 Lreturn ret;; T8 H* z9 i8 v5 A2 T. t5 M/ p
}( ?" w7 r. H7 D/ L5 p
//---; x8 \* N7 L0 w* G% J
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
& D& u9 _0 r$ o/ s. m{
* W' r0 N: j6 t& o9 Yif(PositionsTotal()) // Is there a position?% k4 O+ a" M; ^1 K3 L- w9 y- N
{
. O) l) }3 I$ C$ ]1 Ddouble offset[1] = { 0 };
q: L: I/ `* S! N/ qif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?( J, Q% Z" v, B. X. k! o+ P( C. ^
&& PositionSelect(_Symbol)) // Select the existing position!# T2 p( Y2 G( O! d6 m
{
$ ]* P" u: @# r8 fENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
: W$ [2 `% ^( b/ gdouble SL = PositionGetDouble(POSITION_SL);
! l+ G3 t/ H4 q: O; Zdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
$ U% J4 E8 S3 O7 Vif(tipo == POSITION_TYPE_BUY)- @0 D2 P5 Q' }0 R. T, \, L
{
/ G j% [: P; W! H) v9 Wif (cotacoes[1].high > cotacoes[0].high)- _3 E& v$ L2 ^) W/ {# G
{8 U) v, K: @5 u8 j$ K+ M
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];7 G2 X( b! X3 @: ^% z2 E$ Z
info.NormalizePrice(sl);
" Z6 g# F# P- d1 f8 N) x1 cif (sl > SL)
^" d* `+ n! G, B7 k{
4 x t2 T; Q; |3 l+ `7 b3 _/ y8 Z$ F0 _negocios.PositionModify(_Symbol, sl, TP); O4 [, H S9 M4 ^/ l. g6 o
}
" t) F0 u4 Y- F0 Z8 g/ {1 O}- @4 V3 Y( B4 j! q8 O/ Z' Q
}1 K: p, C7 m _& O. g; c
else // tipo == POSITION_TYPE_SELL
' A" F) G$ D6 F8 ^& y{
; `' m" d7 c0 W2 d1 j. oif (cotacoes[1].low < cotacoes[0].low)
6 e; |" W2 I2 ]& @! ?{
" O$ T5 ?1 U7 Z: Z q* treturn true;+ y4 X; x# A9 m' h/ Z
}
5 N H$ r8 ^) X- U// there was no position
- a. Y+ c+ o+ ?/ `! O/ l5 F: z q7 }return false;- X2 R3 z I) G3 d4 F
}
& _" W/ I- H: X) U# V. I8 y, E/ n0 {我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
# N- ]0 z6 R5 v) M) H% w到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |