启动交易模型,并构建 EA( N8 E) p6 ~6 ]; m% ]* M
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。, z& U8 i$ N% y/ O* k8 f/ b4 j3 D
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
' _) F6 K, k7 M以下是制定这些规则的代码。
* z0 B% S( T. B//--- Indicator ATR(1) with EMA(8) used for the stop level...
: u& V; F9 o; u; l Q. dint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);+ C4 F7 D, N8 G5 W3 e A
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);' u1 _/ U& b9 \7 {! y& Z1 m
//--- Define a variable that indicates that we have a deal...0 Z+ y, _7 a9 c. h
bool tem_tick = false;
, B. e. H+ Q: b3 K5 Q8 J% u//--- An auxiliary variable for opening a position, i7 I$ S3 |8 _4 Y6 {$ H F
#include<Trade/Trade.mqh>' D7 u6 U& ?# p% b" w
#include<Trade/SymbolInfo.mqh>. p2 N4 X. j: G1 t6 s: }" o
CTrade negocios;) }+ S! C, r! c, o. r) b
CSymbolInfo info;
& |) K/ B% z' n0 |' M//--- Define in OnInit() the use of the timer every second# z/ V0 g E6 t5 p3 b
//--- and start CTrade! t+ d7 S; E5 n; A1 t
int OnInit()
; O4 k# `; P% _2 f4 {{
( p! Y- A5 F0 t8 G: ~//--- Set the fill type to keep a pending order/ X0 D2 o( P1 j2 ^6 ^7 a' t
//--- until it is fully filled
9 W% ] A* D# u3 k4 Znegocios.SetTypeFilling(ORDER_FILLING_RETURN);5 @/ b* E. K0 ]
//--- Leave the fixed deviation at it is not used on B3 exchange( |0 L9 `" ?8 s6 z
negocios.SetDeviationInPoints(5);
( o7 q* w, f; w//--- Define the symbol in CSymbolInfo...
& i9 N1 l9 O% }info.Name(_Symbol);
: W* E( W* j! \. L/ \* X//--- Set the timer...% X7 Y9 Y# Z: [9 o$ m7 \
EventSetTimer(1);
" m i' ^) C/ M' h//--- Set the base of the random number to have equal tests...
& R* b2 H* d$ t- U/ w1 mMathSrand(0xDEAD);7 v& W$ S! {' n% ~! z, i3 C
return(INIT_SUCCEEDED);$ C3 v# D1 ]0 ^* V8 s r4 O$ q- T
}' @+ {. ^* X C8 z. f8 {8 x* x" N
//--- Since we set a timer, we need to destroy it in OnDeInit().
; [/ g2 X' H5 @1 z" rvoid OnDeinit(const int reason)4 k" L2 \ p3 _5 _
{ a" ]; S L& K9 d* l
EventKillTimer();8 L* ], ?( {. P0 S# s0 L
}
, k8 g8 L" ]# O- c' t//--- The OnTick function only informs us that we have a new deal
, I$ P3 A* x5 \! |void OnTick()/ L6 ^5 Z! b2 K2 V/ r" `
{9 p% K+ p! R$ e& L- t. T
tem_tick = true;
) `& \' g$ T+ h- t1 K}* r1 d* A& H. w0 R, {: H: U
//+------------------------------------------------------------------+: B: c/ g% ^; ^. g3 d3 b
//| Expert Advisor main function |- N* d, G8 y" X" L7 w0 m% [
//+------------------------------------------------------------------+; f& k6 C8 b' j' U
void OnTimer()( ~6 l- k; s& C% N$ }/ X9 h2 ^1 V
{2 w* u; o. {! v
MqlRates cotacao[];
% Z/ F9 j) O* Mreturn ;. d2 l# W/ X& T t A
if (negocios_autorizados == false) // are we outside the trading window?) S( [* |2 i( \" @( ^2 U( O, A
return ;
8 z7 K: K+ [+ f x6 _//--- We are in the trading window, try to open a new position!
a% `3 G; E, | N: t# yint sorteio = MathRand();
$ N5 Z$ ^; h) F! C6 I$ ^3 G; b, L//--- Entry rule 1.18 m; Z" v: Q6 R
if(sorteio == 0 || sorteio == 32767)
6 s0 c+ J+ F; @3 Q( treturn ;3 W! e8 r8 A' _ N9 y
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy; \" L, Y; @) C1 W* h
{6 ]$ W3 r: b+ u: O; g
negocios.Buy(info.LotsMin(), _Symbol);& m8 k' C( s1 X" |5 R& f
}
) p% u5 C. ] Kelse // Draw rule 1.3 -- odd number - Sell- V, L! |3 F+ k! q0 U- Q
{/ w q7 ]. ?% d! f1 l& `
negocios.Sell(info.LotsMin(), _Symbol);& }- {+ T f" A# q; n2 t# x0 z0 t4 Z
}
$ a$ b+ O4 }4 ]0 Y. ^+ i}3 }% V7 Z0 e6 o( F& }1 L9 _
//--- Check if we have a new candlestick...
! X- C' u/ G& J+ O8 b1 l; I. sbool tem_vela_nova(const MqlRates &rate)
' B% {7 m* n/ _: p{+ s/ q. d3 t% _( L/ Q% ^! J
{, Z# r9 Y2 w9 p# X* T
ret = true;2 J9 t2 T" S U6 j4 Q5 e
close_positions = false;8 {' \0 T. ^4 D) K% U
}
6 {& o Q. ?' q) \/ felse
* X/ m, K7 m X" l{
. l3 a/ \0 J3 B! P7 pif(mdt.hour == 16)
k9 C; e, `% Y* N, Cclose_positions = (mdt.min >= 30);
3 `. Y9 W" P1 E) O7 o7 U} R* Q1 \. g, U9 i7 ]0 s
}- B Y4 g5 l1 f5 j! m# b% t9 R
return ret;* G2 }; [+ v/ j9 B6 `" ~0 \# T
}9 H: m: U) j/ X4 B+ u+ g% x" O! f
//---
) O; C9 s) @5 p- L. D5 y+ D' ^bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])' `: V# k. L$ D7 u0 v
{% d5 w+ y# r: `, H4 Z
if(PositionsTotal()) // Is there a position?# h! }& b7 e& O$ q
{; V0 T8 v- _/ p8 Q4 ]6 f
double offset[1] = { 0 };
3 i/ N- X& P, N* e( S: E0 ~% mif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
5 o- G a& k! P&& PositionSelect(_Symbol)) // Select the existing position!& o* {5 H4 A2 [) \' j3 C6 ~
{
. { C! U9 _; t6 KENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
4 R$ E1 [8 c5 L+ I" c% Z' Xdouble SL = PositionGetDouble(POSITION_SL);/ X7 T" M" s! n" V- d4 E% N3 Z
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));, ~2 K1 y& n& m; Y# X7 N8 ^# v
if(tipo == POSITION_TYPE_BUY)
2 }8 Z% B- R+ S- f! Z/ L/ q{4 J7 t" q5 x2 B. H% d
if (cotacoes[1].high > cotacoes[0].high)3 V3 n4 a' D0 i- E! Z
{
; [+ p9 \/ W- K) ], g) ndouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];. V+ N: b; S! u/ b+ `- i3 j
info.NormalizePrice(sl);
. \& ?; j' C% T) H; C5 \2 vif (sl > SL)! x+ \$ f; X. d1 c" }8 _7 t" V2 v
{
! S1 H% u/ ]5 i" f+ vnegocios.PositionModify(_Symbol, sl, TP);
+ q; P0 }% ?3 m- n: c# X}# b( r8 X1 b, w
}
: L1 b$ P% Z4 r; i+ D% U4 j}
6 |/ G' k8 }( d$ ^% i* R belse // tipo == POSITION_TYPE_SELL
! e# h& e G9 o4 d" R{0 C3 b3 R: \% A- U: t0 C
if (cotacoes[1].low < cotacoes[0].low)7 @1 O0 K4 i4 Y
{+ ~; B: C3 S7 K3 P/ F3 r$ r
return true;# T2 T% o5 W+ |. [7 U- `
}
$ I, e+ V3 w5 ^, O3 b2 m" n// there was no position2 |2 \, M' _3 I @) a; W+ f; Z
return false;& c- E( X: j9 N9 d
}! n5 D8 _1 m9 M; J5 U# v( v" z3 T
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
- {- w9 }9 O* a% g; X3 b7 F# v到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |