启动交易模型,并构建 EA
2 [7 F5 z0 D; J$ r在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
6 x' m1 U/ b# g1 |( Q) q为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。$ c4 S2 ~" U9 d9 F" b$ j
以下是制定这些规则的代码。
' Z' U" y6 m) |) P' m! I& W" ~//--- Indicator ATR(1) with EMA(8) used for the stop level...
! K, i1 ?+ S7 m/ ~int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);, L9 s8 m: K. ?, {; @' G
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
, J% P0 _5 x& d8 k1 a: u1 m//--- Define a variable that indicates that we have a deal.../ f' D8 k. t5 A
bool tem_tick = false;
0 ?/ _3 v9 K/ X) s* b//--- An auxiliary variable for opening a position4 U8 @" P: f$ ~- G4 a
#include<Trade/Trade.mqh>5 W& u" b. b% a7 O e$ @
#include<Trade/SymbolInfo.mqh>. N! e" y* y2 V5 Z( I
CTrade negocios;6 n. d4 U) Q o
CSymbolInfo info;
. X% {# d1 x: N# a//--- Define in OnInit() the use of the timer every second9 |9 l, r0 K: a2 x, V& P$ B
//--- and start CTrade. K% j u9 }! ?6 Q& V
int OnInit()
8 p" C. G& ^6 | b: b{
8 R0 U; I. R0 y: x( N, v//--- Set the fill type to keep a pending order- {* |2 G9 T+ f6 x& b J! h. P. Z z
//--- until it is fully filled
3 V. T0 q$ u/ w+ a8 G& H0 fnegocios.SetTypeFilling(ORDER_FILLING_RETURN);2 D: {( P3 L- R1 ^
//--- Leave the fixed deviation at it is not used on B3 exchange
7 V% B% p' `2 }2 {) U( Q$ y; q0 [. `0 Gnegocios.SetDeviationInPoints(5);5 \. K) {) G# R* U' z
//--- Define the symbol in CSymbolInfo...% @- t( u) j6 G, o9 j
info.Name(_Symbol);
5 @* j# l: b/ J$ ` ^* G//--- Set the timer...
4 M5 l7 G9 d; R& G5 gEventSetTimer(1);
/ `' s7 c4 n$ r. X) u6 X# [//--- Set the base of the random number to have equal tests...
* G, O( w, ~; ~6 q8 C, ?* ~/ p2 k% `MathSrand(0xDEAD);( F* B7 Z2 u0 D; Y1 E: H2 B
return(INIT_SUCCEEDED);0 G: k7 q- w, X! e5 m; |, C3 S2 T
}
1 W2 l% j( C, j' a, b% o9 U+ u& P//--- Since we set a timer, we need to destroy it in OnDeInit().2 y& K7 p9 c0 X$ @. Z
void OnDeinit(const int reason)
' g$ `: O, K: d+ }( ]5 Q6 x{) E) q; \" ?" S' y, R/ u
EventKillTimer();
7 i6 b* e# ]( ] r6 ?}6 V$ w& k7 T( i
//--- The OnTick function only informs us that we have a new deal4 B2 Z v4 f- S- {/ |, P% w5 R' z
void OnTick()
/ ^) i8 x) r# L, S( w: M8 {- q{0 C, r7 k% L$ B+ Q* u' c- X
tem_tick = true;: Z8 N) d3 g, p0 n
}: i( a* N; S; t5 u( V7 K3 |- H( @- E
//+------------------------------------------------------------------+
. k% X+ x- L. \' n& G0 u/ E//| Expert Advisor main function |+ ~1 v# ?" o$ w2 B) h
//+------------------------------------------------------------------+
1 Z/ t# x! x+ o' g6 {, B9 j( E- Hvoid OnTimer()
, X- Y' ?' t ?% B{: s3 z8 ?3 \4 d; r* ?2 \- z
MqlRates cotacao[];2 d, @# G$ W! d0 l- u$ r; B
return ;
( m2 Z- ?6 c6 [8 ?1 B) nif (negocios_autorizados == false) // are we outside the trading window?
& [4 o- R Z& ^, U/ G' _return ;1 V' x# x) L; n. F* }
//--- We are in the trading window, try to open a new position!
5 ~ J- P% U+ ~9 Cint sorteio = MathRand();
j% q3 `% r! ~# W/ y//--- Entry rule 1.1
. P4 U2 Z0 n; `if(sorteio == 0 || sorteio == 32767): P: N. q: N! x. J3 a2 w3 A
return ;9 |# {% s6 w2 j1 C1 o8 a
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy7 k% M' I: t' `; V
{
, I7 a4 E$ U7 W: A F) Bnegocios.Buy(info.LotsMin(), _Symbol);" f. c8 y! Y% q' u9 n! k9 ]3 ]) }
}
3 L& j$ ^. J- t2 s! [else // Draw rule 1.3 -- odd number - Sell4 J$ W) W+ k' m* p
{7 a9 H9 K+ t7 y
negocios.Sell(info.LotsMin(), _Symbol);/ D$ y# g! z" Y
}
# Q0 C% W# f1 O1 Q9 V/ V}# w0 S' C, }( ^# N( E) g e+ s
//--- Check if we have a new candlestick...) u2 {3 z* M+ C1 `
bool tem_vela_nova(const MqlRates &rate): l& `6 W5 r, u+ S" Q6 S
{
/ [9 y5 z4 v9 t{' c3 ^/ v: B: x5 M5 f/ P# C
ret = true;
& n6 r/ J8 j5 y: ]/ x2 X7 gclose_positions = false;1 N7 S" g6 T8 g; A* ^
}+ G- p% l! B5 G& ~ ~# O; Z
else
# W: G+ v% ^! v% N, f{0 n/ d3 H- S8 i' Y1 g; D/ y% N. ]
if(mdt.hour == 16)
/ r2 l6 x2 i. Bclose_positions = (mdt.min >= 30);$ [$ v' z) C1 Y' q+ _7 G @
}
L+ ?4 d* {5 D}" B" `5 u. k( q
return ret;) B7 `# i2 h" U& P9 A, ~( c
}2 p% M- V7 X) {! O9 N6 U8 w8 [
//---& j& d8 h* N# x# f3 s, f4 |8 f' q
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
$ [ l. @: _0 @- B. l' Y) K{
8 C# T' A5 h# Y6 q4 Eif(PositionsTotal()) // Is there a position?
: |' }) g+ w/ r& n{5 n0 i5 p5 F* u+ V3 j7 g
double offset[1] = { 0 };/ X5 d3 `0 {' J) m3 l
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
& M/ d) v: m: F5 F& m. s3 H+ l* T9 c&& PositionSelect(_Symbol)) // Select the existing position!, ?5 A! \: u# T
{/ Y$ ?0 t* k, |9 {. {
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; p. `1 B6 }' v3 l1 g9 R4 {4 N" |
double SL = PositionGetDouble(POSITION_SL);
) Q3 z1 D8 T' Tdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));. G" S8 U% V O( o7 ]6 w2 a- @* J
if(tipo == POSITION_TYPE_BUY), [' Y$ w9 [6 g1 n
{( [& ^0 P% C% M
if (cotacoes[1].high > cotacoes[0].high)3 h0 M; Q0 j5 S' U
{
" ~& \8 R5 }; T0 w1 ydouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
) A: C" E) G8 u* O/ Q& q w( D. ainfo.NormalizePrice(sl);( V1 W. @* W5 ]1 }, ]8 W& U- X! r4 I
if (sl > SL), m9 D: V9 d( g* y+ N2 s/ z
{* W- a% a8 ?* u3 l! y7 O
negocios.PositionModify(_Symbol, sl, TP);
* D2 K" O g, `4 }" Q; B}
# t" i- j9 M9 n}2 n2 A2 C2 R3 |$ M- G9 L
}
# {( r8 H2 `- Welse // tipo == POSITION_TYPE_SELL+ Q) B7 z, p* W- s n, [2 x- Q: i
{
, f2 }- o0 O" Z- B8 ]. p' \if (cotacoes[1].low < cotacoes[0].low)+ P9 T1 m; E, M9 E7 Y# F0 j* b
{
: S; u4 [4 F. F5 r( greturn true;4 Y# U; Y; j! w& d
}
: Y9 }7 k4 y: g// there was no position
7 R9 h1 l& W, ?return false;
' W9 c# G0 I8 x% _0 \1 X3 L: S}! h2 ?( X3 k. s7 E- K6 R3 d
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
9 ^$ c6 S$ g3 ?6 E到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |