启动交易模型,并构建 EA1 q7 ^* v( Y0 `8 M5 @2 H% M# }
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。* G( t) c3 F7 T5 @- e
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。2 B' z# S( ]6 P0 F- b! l
以下是制定这些规则的代码。
! P( t- Z& p G3 m, q" J" H//--- Indicator ATR(1) with EMA(8) used for the stop level...
- }9 Y* a, g2 I( hint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);: M; E" ~! w: @) g3 E$ o
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr); T0 q$ G3 {1 \' o+ d
//--- Define a variable that indicates that we have a deal...; K4 }% t0 I* k$ ~
bool tem_tick = false;+ a% s3 J7 d8 n" l9 D; M. a7 t
//--- An auxiliary variable for opening a position
& J) A( F1 K( ^' D' ~+ W7 D#include<Trade/Trade.mqh> H# N: u5 {5 ?5 d2 ]
#include<Trade/SymbolInfo.mqh># {+ X% w, B0 H2 V" j( M# D' E
CTrade negocios;8 E% V" ^7 a- V# |0 F; o- X4 l
CSymbolInfo info;
& w' K8 i, y4 `//--- Define in OnInit() the use of the timer every second
% ?$ y+ A: L4 J7 {8 s+ ?//--- and start CTrade! ]. @5 B" Q9 g
int OnInit()! v" n& U- h: Q( V
{
8 T9 m" P r& s% P//--- Set the fill type to keep a pending order
8 H7 `8 G. w- P5 V1 L+ N2 `//--- until it is fully filled
" W6 k9 l- V0 Y6 g* Tnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
8 _" a3 n2 i9 ~//--- Leave the fixed deviation at it is not used on B3 exchange7 W" X) d2 g$ Z: O
negocios.SetDeviationInPoints(5);
! O' R( `; Y6 O//--- Define the symbol in CSymbolInfo...
+ S+ S# S6 c( N7 w6 H2 Finfo.Name(_Symbol);* L- [1 d7 ^0 ^
//--- Set the timer...; ~0 j, [' M6 E, o/ f& p' I
EventSetTimer(1);' ~6 `2 E P6 y* _( J0 ^7 l
//--- Set the base of the random number to have equal tests...8 O" D3 i* E0 x4 R/ U. `
MathSrand(0xDEAD);7 G2 G% k/ s1 k8 W( G
return(INIT_SUCCEEDED);
3 P& `3 X6 C" R; F. L7 d}) m" p* `( t- L# [$ z/ k" G
//--- Since we set a timer, we need to destroy it in OnDeInit().
7 \) }, M h' `2 A: D% jvoid OnDeinit(const int reason)
) Q' \/ G' ~) V4 y2 @1 `. m* k{7 E& a; T! O& n/ @3 \. m; Z3 r
EventKillTimer();
; p. n* D1 D4 L& Q* d2 A- w& F}* i% {# n$ E* w
//--- The OnTick function only informs us that we have a new deal
; T- b$ ~. I) f9 t) D0 W* Ivoid OnTick()
5 r# {8 H h! b/ Y& C; B{& V: x0 L$ a, a: C# B
tem_tick = true;
2 d3 C. A8 J- J* {( U4 W+ K ?0 c}
& }/ K* u% E. g. e: O//+------------------------------------------------------------------+
@5 g. v* P1 S5 Z( [ L//| Expert Advisor main function |" N8 e) l8 d, t0 t' D% f
//+------------------------------------------------------------------+3 {- V+ W2 K0 G, g/ U
void OnTimer()/ E& f, Y7 ?. z0 o6 v% P
{
5 w- `" C- Q: Z2 p0 d5 [4 h9 `MqlRates cotacao[];
) k( r8 T# {1 s8 U, l* dreturn ;
; E$ P# y( Z* l7 M6 n% T8 V. ~$ _if (negocios_autorizados == false) // are we outside the trading window?
* b- w7 F, c& V& d8 p- l! preturn ;' K2 @5 T e+ n1 w/ r, X
//--- We are in the trading window, try to open a new position!
% r/ g6 X* V6 d1 X' d hint sorteio = MathRand();
, R# J* w9 p0 q/ F//--- Entry rule 1.1
3 }& [4 R/ a4 _; Q9 K, O7 a4 A }if(sorteio == 0 || sorteio == 32767)7 g" y% {7 O7 v; b% k; ^0 L% p
return ;( F; [: ^1 A7 Y# I# ^) V
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy/ }+ N6 V D" w- p7 U
{
- c4 q8 m$ J8 r: y: X4 W/ Wnegocios.Buy(info.LotsMin(), _Symbol);$ L' ^% M1 D) U4 t$ B: p
}
! b; b( W+ n4 l3 o- Felse // Draw rule 1.3 -- odd number - Sell- ?' e5 w. x: _8 ]( c3 d _# I8 b
{6 ?5 g9 |. P+ V4 N
negocios.Sell(info.LotsMin(), _Symbol);& K$ u3 O# u# l
}
3 t7 _: J* z7 ]4 `}
2 K* F7 c8 f. K$ t//--- Check if we have a new candlestick...
1 t7 J! u# E- o& m, q6 [8 c* Obool tem_vela_nova(const MqlRates &rate)
: d# b3 d/ f+ R- j{& E# q$ g2 N) {9 j; E. x# U& [
{
7 n1 {1 l5 I" A$ o \; [; Dret = true;
2 d( C6 i# h! Z K* {- lclose_positions = false;# X0 r* ^2 b5 \8 ]2 y$ q: w
}
/ e. J4 P# H1 c( [" Belse* P7 ?, x4 Y1 \2 u6 Y0 m0 [
{
2 t" z3 J" h9 Xif(mdt.hour == 16)* B, X! n: O0 E: A
close_positions = (mdt.min >= 30);
( u, V: E" M$ [) F# S7 {9 m}* ]) W, ~* W: l: E/ m
}) B5 M. Q$ t5 N! K
return ret;. s% M: K2 j+ F
}
0 K( P: |2 E P$ ?7 @9 O! n//---$ E( \! c" z4 N" _* d: m
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ q4 h. ^* D4 m3 a5 |4 Q- o0 F0 [
{
+ S' ~/ }( a8 ? l, K/ Q" Sif(PositionsTotal()) // Is there a position?
. w' Q U1 m% z0 R8 R7 z7 U{) l+ m% G, m. a; O2 Y; [
double offset[1] = { 0 };( u8 n" @- c X5 x8 E _! M1 J
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
: T. Q+ t7 E) z U+ W9 M&& PositionSelect(_Symbol)) // Select the existing position!
6 u! D6 j: R! z% k: h- Z" k' L{
! H3 i2 _8 J$ i, P1 ~9 i$ I; y4 G5 KENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
! t/ y6 M* {4 r7 z% z# ]' ndouble SL = PositionGetDouble(POSITION_SL);
! |# Q' d1 K t m! {) ^1 Idouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
6 g" n2 N8 B m" f7 M, w$ Wif(tipo == POSITION_TYPE_BUY)
/ \7 e! c5 t& l+ W{! T2 V6 h: E1 P; C3 x
if (cotacoes[1].high > cotacoes[0].high), d& Q! [5 ?. y9 I
{% d& p7 }3 A+ O# E: k1 W7 ?
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];' }9 X3 G' N( g1 l3 c
info.NormalizePrice(sl);
8 p% H8 U8 ?/ e3 V& rif (sl > SL)
( `3 e4 A( i9 h& l! S4 h{
1 h6 k8 p' s5 W0 L' _9 S0 |( K2 `negocios.PositionModify(_Symbol, sl, TP);* A! ~* ]1 n/ N
}% P1 U1 R5 l' O9 ~$ ~ _
}
1 R" o$ ?2 t+ m4 @5 N- q; V }}% b% @; R) s7 m" M) S0 X! u
else // tipo == POSITION_TYPE_SELL
3 W& Z. y; q" w) j2 q% C* ]{
" L3 [6 Z1 ]. e8 y/ A) f& n* K( vif (cotacoes[1].low < cotacoes[0].low)
: p0 @2 j$ m, h, q{0 k- D% ^3 z# k! `# m6 i
return true;; o0 Y0 {7 M Q/ R* N
}
) D0 h1 @0 [3 u8 L8 _9 l# i// there was no position
{' @! o7 |# s/ kreturn false;0 }6 n; f# I8 ]0 M
}4 Q/ s# W( B: }' |* q
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。" c6 B( b( Q) Z
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |