启动交易模型,并构建 EA" @4 T; e) K6 G3 Y( r. ^) E6 n
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。2 ~! Z+ _( @5 n0 A: e
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
5 k# \" j1 c3 Y' u9 v( b. P. n$ y以下是制定这些规则的代码。( F# g, H1 ^4 h/ j' ?% {/ R) t
//--- Indicator ATR(1) with EMA(8) used for the stop level...
' G5 }% t% E7 L" z8 q# a; hint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);* Y+ k# j" { r2 P- G7 A
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' p5 K& u3 ?9 h) }//--- Define a variable that indicates that we have a deal..." L/ |2 k- E3 a$ q6 x [5 r. \9 L* d! y2 s
bool tem_tick = false;! B. W3 u9 q0 u& n! P- H
//--- An auxiliary variable for opening a position
/ G- A* V" T; ~& \#include<Trade/Trade.mqh>4 g! ]9 c: q$ @1 Q- {
#include<Trade/SymbolInfo.mqh>
& u* J$ n& L, y" G2 j- v2 ^( T' OCTrade negocios;
+ g8 E* b1 i: V" N. u" bCSymbolInfo info;3 n! @( @& t; [2 C! ] j
//--- Define in OnInit() the use of the timer every second
! Q; Q! N v- s& }+ F//--- and start CTrade. y# m/ L; k T5 i: D. I
int OnInit()$ U7 N, K$ v# l1 n. v
{
+ u& R, f, `: U# X$ n/ @, y//--- Set the fill type to keep a pending order
8 A, f9 x; |, _//--- until it is fully filled3 f) n0 a6 `0 j
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
( c/ ~" }7 f. ~/ I2 d! M$ x//--- Leave the fixed deviation at it is not used on B3 exchange1 Z. \" {, X. w. ]. j
negocios.SetDeviationInPoints(5);
/ M/ W! Y3 O0 u5 C7 b4 y//--- Define the symbol in CSymbolInfo...: H' p4 [: u( F2 W
info.Name(_Symbol);
( O7 Z$ H; u! z* v3 D. ?//--- Set the timer...
" w, |- k# {" [0 j) XEventSetTimer(1);
- S# N2 C: u. G; W% }3 c) O//--- Set the base of the random number to have equal tests...6 D$ T7 b2 M5 f
MathSrand(0xDEAD);6 G4 F4 h8 u" _* T; u% O8 P8 n2 d. [
return(INIT_SUCCEEDED);4 \* P( J: J9 W4 y% a2 H$ h9 v: ^
}
! r9 w) Q5 Y, ^5 m' O//--- Since we set a timer, we need to destroy it in OnDeInit().& w, U/ Z8 u2 r9 Y0 D u
void OnDeinit(const int reason)
: [2 E! O1 [- ?. \: e{4 M" r+ `/ u$ q6 U k, n/ J9 ?
EventKillTimer();
9 s- d' R( K# t9 L. B: p# s; K) D}
' i* Y( Z" Z( R) G' |//--- The OnTick function only informs us that we have a new deal
/ J7 F! S1 k8 T! k* rvoid OnTick(); ~6 @! X' z: F
{1 S& J9 s" |# p
tem_tick = true;" h1 W: ?: P3 q! c5 J# S
}: K7 n+ Z1 S* r5 r' h- N* m+ A
//+------------------------------------------------------------------+
; _- G' Y2 ~* d- M6 z//| Expert Advisor main function |
( o% q8 ]0 M) P( R+ I//+------------------------------------------------------------------+% x: b2 P* e! {0 U( i4 Y
void OnTimer()
! Y6 V$ _0 W$ r- W1 K9 M( z{
2 a; E" M. }& Q! bMqlRates cotacao[];+ X% F1 K, e A: X% s+ w
return ;% b# ] h* X0 @* b
if (negocios_autorizados == false) // are we outside the trading window?4 x! P) \6 W, l9 z& J& O
return ;
' r* E) h( S$ o, i9 r$ b//--- We are in the trading window, try to open a new position!
: p1 o$ I7 U; M2 bint sorteio = MathRand();
0 n( C' Z! Q- c) J//--- Entry rule 1.1- i) v8 w; m/ h$ ?
if(sorteio == 0 || sorteio == 32767)7 A# A" z$ \, w+ T; F1 ^
return ;! L0 U; N" Q) T3 @5 s' z
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy/ P% x7 c- S$ Q
{0 H- H3 \) A9 T4 m
negocios.Buy(info.LotsMin(), _Symbol);
! q6 a& X& p! @/ ^" v( W. g}1 v5 P" O! K- T0 G
else // Draw rule 1.3 -- odd number - Sell
3 `% _/ E9 O6 b* d# D{: S6 u8 D9 F$ j3 @: x
negocios.Sell(info.LotsMin(), _Symbol);
8 y, b7 K1 G1 c9 Y$ H1 q7 a}
9 R [+ P% @9 u}
9 o' B& E6 _# |- T) V' [//--- Check if we have a new candlestick...! C- l8 r) K& b2 {0 Q- O% ~, I
bool tem_vela_nova(const MqlRates &rate)
+ ?5 Z* p e5 I7 z& H{
% T$ c1 f- P8 ?3 T% l{1 z/ o! Q* u8 j% O) D7 F( Z
ret = true;! B f1 w" E) ~. B
close_positions = false;9 F8 W) c( h$ D' _! c8 q
}$ s) R, r0 [( ~
else* V! }( u0 G V, `
{/ L+ B! t5 j* n$ p, o5 E
if(mdt.hour == 16)
g9 i' s+ P, D, g; \close_positions = (mdt.min >= 30);
% D" X, o/ G$ d5 s* j4 b}
! \; N1 f A# Y}2 |3 n- ?8 n4 N
return ret;
5 j5 ]# r+ e" r2 {1 R}5 u4 J1 S' L' U7 o$ F/ e
//---
% F0 x; z. c i) H! O# E& Ybool arruma_stop_em_posicoes(const MqlRates &cotacoes[])% ^3 b% l. I. X+ m& [
{% z2 B* D+ s% q+ y
if(PositionsTotal()) // Is there a position?
1 \( C" H1 m, u B; H. p{
2 ^ M G7 C. z* j' R' r/ l$ P Qdouble offset[1] = { 0 };7 E1 V7 \" X- r9 G' @ S
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
) v" c7 ?. X% s, p% L&& PositionSelect(_Symbol)) // Select the existing position!
# r, l8 b: C. \$ t{
# D$ \ P1 k5 y* D NENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);* p+ i, Z0 H) b2 Q0 M# [* ], U
double SL = PositionGetDouble(POSITION_SL);
9 m( q% {( k w0 Ddouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
3 _) }4 @+ m' F2 [/ E: @* |if(tipo == POSITION_TYPE_BUY)
5 n3 G8 e, O4 C$ T' S* x" D{! G- H( T$ z" _, W
if (cotacoes[1].high > cotacoes[0].high)
- P1 q& x8 V" l{" i6 k3 Q+ u: \; n' G# m
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];5 K+ u- g4 v. E B5 o+ @2 w
info.NormalizePrice(sl);
# d4 P5 X. k3 z! z3 ?if (sl > SL)0 O5 ~, I& v+ p* w+ j1 s5 S; q: ?
{0 b" C6 S5 [% M4 _
negocios.PositionModify(_Symbol, sl, TP);) S+ z E+ D+ B
}
" |" X W9 L0 p5 w2 w5 J; U}
1 L0 R9 Z, b% `8 O}
. ]( c4 U2 u& x/ D i) `else // tipo == POSITION_TYPE_SELL
( B/ e/ r0 V% q K3 t{& j$ r0 N. d# D
if (cotacoes[1].low < cotacoes[0].low)$ Q/ K2 n1 y. b* e/ n+ W# u. p; T
{
! K+ ^$ Y1 K" X: }' C9 C. Y, Y# ]# _return true;
: c" { O; E! L Z5 a' W}
* G9 c- X7 U5 {: e* z// there was no position
( U1 d9 }, @. v8 d" T( R+ t" l3 areturn false;
3 x) J& b0 a( I- z7 `8 s/ \}2 x# L# ~, x1 {- c [! h
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
$ \6 m1 m$ M' t r0 Y* A到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |