启动交易模型,并构建 EA6 ^" J: Y# \6 q
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
) r* W! w* a/ L* `7 x) h为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。/ ?% T& \/ T1 ?+ k5 K9 B( h T7 a# J2 T
以下是制定这些规则的代码。+ _ k" }7 O! u3 O
//--- Indicator ATR(1) with EMA(8) used for the stop level...
6 q! x5 I6 d8 }int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);: R; H }: m- {/ j0 |) ]
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);/ ~; G$ \! I5 k4 [, c5 K
//--- Define a variable that indicates that we have a deal...
* L9 i6 W4 S5 R) ubool tem_tick = false;
3 D; `( ^" @' D+ b! o7 Q: \+ K3 }//--- An auxiliary variable for opening a position
`6 E+ Q1 l) }3 i" R0 ^#include<Trade/Trade.mqh>% ]; T7 A, ]/ L9 Y5 u$ d
#include<Trade/SymbolInfo.mqh>
. |% |0 O9 c( Z1 U. `- sCTrade negocios;) V) q" z; o4 o( |3 [
CSymbolInfo info;5 \1 i* A1 ]0 y% ?
//--- Define in OnInit() the use of the timer every second
$ M9 O) x% C/ O0 \* D0 y8 y0 H//--- and start CTrade
& G5 c5 O7 h8 x+ X- gint OnInit()
+ u+ U/ h! g" D! Z{" B) w! ?% e, {/ w( u
//--- Set the fill type to keep a pending order; l7 o M+ \6 z# s: E
//--- until it is fully filled
% o& r+ b" ?# H+ unegocios.SetTypeFilling(ORDER_FILLING_RETURN);4 t: Y- I* `8 H& D" I9 w2 X( {
//--- Leave the fixed deviation at it is not used on B3 exchange
# J) V6 Z. F; u2 W) \! |' Lnegocios.SetDeviationInPoints(5);
4 K7 c$ }+ | Z8 Z//--- Define the symbol in CSymbolInfo..., S9 P9 i; _' E& m5 t6 d* A
info.Name(_Symbol);0 h1 X& ~6 x$ O
//--- Set the timer...# p& B% ~$ z1 S/ A8 I1 a% I4 b
EventSetTimer(1);
( [! d/ a1 z7 y+ Z. s4 K$ f% G//--- Set the base of the random number to have equal tests...
( H6 H) Z9 q' j8 G6 X+ KMathSrand(0xDEAD);+ E- G9 n5 M1 a$ b7 y( o4 b/ z
return(INIT_SUCCEEDED);& M7 {9 w3 F% S. M! N
}/ W+ O( P5 Y! U6 w8 ?
//--- Since we set a timer, we need to destroy it in OnDeInit().3 a$ W% G* Q" R, q' L6 L2 o9 K* |
void OnDeinit(const int reason)
6 ~6 J5 E) I# g- r1 ~; `{
" p* U3 x1 X5 I) [- }4 @3 BEventKillTimer();! ?9 J. p& o" S8 @6 ^8 A
}
+ ^, ?1 a- f2 m/ }$ p1 ]//--- The OnTick function only informs us that we have a new deal
% h. Y# B b0 pvoid OnTick()
# m7 H3 ?: F! m4 r! r7 d{
: i# q# g! j2 x* N' p! J5 {tem_tick = true;
8 _; ~* k: { }/ _6 D5 ~# e}/ t X$ m+ Z1 e" q5 S3 ~3 G) E
//+------------------------------------------------------------------+, P; t2 ]& t! r% B) V! T+ ?
//| Expert Advisor main function |
7 u9 j3 B3 ?8 x; w: s# V2 }//+------------------------------------------------------------------+" |7 L; S# v' M: a! {) w
void OnTimer()$ x( |/ N# M0 ]0 w' X6 g% h
{ g% k" R; D% L( P7 h
MqlRates cotacao[];
; Q( G7 _* i$ T& \; _return ;
' B$ E. `! z- Z8 A4 kif (negocios_autorizados == false) // are we outside the trading window?
5 T) f; q4 T& R' l* freturn ;: j+ p# c1 F1 D: N" q
//--- We are in the trading window, try to open a new position!
7 o! f4 S7 D+ s+ {8 Zint sorteio = MathRand();
- F4 }8 K" y" x4 c! @% r//--- Entry rule 1.1( g4 H9 |, d* j& d% O
if(sorteio == 0 || sorteio == 32767)
* u9 q' ^2 ~+ {. @8 ^; Y( M+ j' wreturn ;
" i* u4 n% x A9 ~# @' Mif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy8 A( p, M; K) u/ N
{
. D5 S+ I# L: l3 g: wnegocios.Buy(info.LotsMin(), _Symbol);
+ a, h/ N9 g: ~: B( O}
. H9 p/ Z+ }* { U* v; f* {else // Draw rule 1.3 -- odd number - Sell
6 h" o+ I# @( G: q{) Q8 _2 v) K" [6 E7 [' W# q, {
negocios.Sell(info.LotsMin(), _Symbol);9 k a: |8 w9 [1 I" q5 D1 d
}0 u6 ]3 b$ j, [% a+ W6 Q
}6 v! K1 H1 I% e. E
//--- Check if we have a new candlestick...5 L' M- d% b' U- f3 U: ^
bool tem_vela_nova(const MqlRates &rate)) O: N+ ]4 d. t; R
{
$ Q6 H, o6 n0 ^7 y( ^, ~& \4 t{$ z" {. G. o/ V3 u" o
ret = true;
8 [* L/ r/ v* e3 s4 X3 L7 {0 gclose_positions = false;- ^% s+ C' C+ M( t/ A4 ^5 g
}
- O3 N# F4 {( |else
- ~, N. u: D5 W& c& I{
4 P1 R E2 Y- K% F1 B9 vif(mdt.hour == 16)# o# i$ J! c! @8 H/ o, y7 X1 U: B
close_positions = (mdt.min >= 30);5 Y4 p6 y& U, X2 @. ^( P; F4 ?
}
& y- {! V# B8 H$ U q# |8 o8 `}
3 W3 V$ C/ x6 N) Oreturn ret;, H* A" m& m: m* H# \( [' W5 {6 f
}
: U$ U' F ]2 ]% s% @! A2 @//---
) q4 S. i5 _7 ^4 L" ~6 [) g$ p! Q5 Abool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
7 M% O( g& F/ E: ^{7 N' ~7 U- i4 [3 B
if(PositionsTotal()) // Is there a position?
2 a& z& _, W* J{ S6 G3 `, m) |. w0 M2 a
double offset[1] = { 0 };: Q& H1 S$ ~) ~
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?9 h1 I& \% R$ ~
&& PositionSelect(_Symbol)) // Select the existing position!* G4 P$ a3 ?! j$ F4 b5 u
{$ F: C! U. y# y: ?4 c3 u2 Y
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);: E; g O, Z$ {/ q/ G
double SL = PositionGetDouble(POSITION_SL);# T7 d6 T# p) _
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP)); A3 G7 T6 F. a/ M9 p
if(tipo == POSITION_TYPE_BUY)" x+ y9 j g- x% Z8 M$ n" _
{
" {. V% S9 K( Vif (cotacoes[1].high > cotacoes[0].high)
0 h% o" G) k2 r2 y% {; x{ W7 q: ~! d' X& M4 g% n
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
% B3 {' e5 Q$ ~5 h: @! k iinfo.NormalizePrice(sl);. @) X P8 M$ p5 |) ~2 Q
if (sl > SL)3 C6 K$ i; q; J8 f7 x
{
- |: z* [* l8 A. Qnegocios.PositionModify(_Symbol, sl, TP);1 Z& o P4 E+ p, J2 G% m1 g
}; S: v0 r( q3 P3 f
}
7 K$ ]/ X& f5 c( _: \! |}
/ I& G/ E. }- x( |- delse // tipo == POSITION_TYPE_SELL& }4 i5 C! d5 q3 b$ k
{+ C5 ]- s1 U2 B' @! Q
if (cotacoes[1].low < cotacoes[0].low)% T9 S$ i3 l* }: d! {. k! l. [& z
{2 r, ~& G5 c1 k9 l2 d
return true;
, @/ l( f7 @6 `' `}$ q7 o: S& \) w1 j: f3 p5 ^
// there was no position
) S- m# q( t( {% R7 A/ Areturn false;2 P- E$ \1 L j- t
}
+ L: D. b7 T% c/ r: Y我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 i! W& w6 q, D U2 S( B
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |