启动交易模型,并构建 EA
/ _8 m( `3 ?; X* g3 U7 c" w在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
+ U: ^) y; r6 P; e2 M为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。) k! _& I0 u' l# Q( Z# Q
以下是制定这些规则的代码。9 b t+ u! l. w- `, n, U8 q- q# p0 H
//--- Indicator ATR(1) with EMA(8) used for the stop level.... g% O4 s) S4 _0 `" P2 f
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
% p7 a' b" C5 Tint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
]: U* L* y) W" i6 U% d//--- Define a variable that indicates that we have a deal...
1 v k9 ~/ p6 b6 A7 lbool tem_tick = false;! b) d+ T5 J' I2 j; P7 S& g& ?0 q
//--- An auxiliary variable for opening a position" Q5 n; y% a* J( T+ X- w" X3 u8 t
#include<Trade/Trade.mqh># V; O; D2 ~& |
#include<Trade/SymbolInfo.mqh>0 |" |+ K8 I4 I" G" r: r
CTrade negocios;& n, M! _. ~# G4 X/ O$ `
CSymbolInfo info;. f* J; g! D3 U, U: \: n9 m
//--- Define in OnInit() the use of the timer every second
5 K/ ^/ m- O# h3 q6 G//--- and start CTrade
, t9 O; S; _4 i0 s/ \' Nint OnInit()
% z& _1 B/ T2 m- B9 m{
* n ^/ F- k" P f6 d' P//--- Set the fill type to keep a pending order
# o# @3 U9 J' n6 }% D//--- until it is fully filled0 Y+ o& X8 A: f4 T: y G# I9 `2 R
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
/ s! }8 z* l% Q: t, q//--- Leave the fixed deviation at it is not used on B3 exchange0 g) l9 C) C# P5 A
negocios.SetDeviationInPoints(5);
1 H8 U$ t( y6 P; N9 t//--- Define the symbol in CSymbolInfo...! w$ `3 o, f# Y, R: z
info.Name(_Symbol);
+ ]8 _1 T, C s, t//--- Set the timer...
7 J- l6 ~& C1 y8 _" M$ J; G# O5 hEventSetTimer(1);6 v- m( k0 S( ~. y6 [, Z$ s
//--- Set the base of the random number to have equal tests...
; {3 [$ W B+ x: vMathSrand(0xDEAD);3 O/ c1 h/ v: R* {) j* q* F
return(INIT_SUCCEEDED);$ J7 i, |) j; u: C7 s
}
5 d$ q' r6 s; j! v//--- Since we set a timer, we need to destroy it in OnDeInit().
. o; g% S# ~8 W# X( j0 Z( nvoid OnDeinit(const int reason)7 h* Y Z1 B. s1 }* X
{
- ^, X/ t9 n( ~: O9 H4 gEventKillTimer();1 Y. O2 `( D% i, u/ \3 X1 h; ]- G' H' U
}
: I; l( O9 k( r: y3 e//--- The OnTick function only informs us that we have a new deal
, p' `) b6 i/ u/ Z* Evoid OnTick()
" M. o% @2 ?- E+ v{: Z4 o9 @! e* e% ]) |# P5 ^
tem_tick = true;
3 {$ K7 J# D: t! v}
( o, s" J8 `) w7 X+ J k//+------------------------------------------------------------------+
' i5 ]% j+ I2 ^# g: Z( H; m//| Expert Advisor main function |# b7 B9 ?( P7 U% j3 \+ `& H
//+------------------------------------------------------------------++ Y# Z2 a; h, w1 T" { ^/ U
void OnTimer()
4 }# A; y" N- v+ y8 i8 F1 _- [{) X, X$ y4 ~0 n9 z: w6 g: R, I1 s e
MqlRates cotacao[];* |' O8 E+ B1 E4 u: f
return ;9 a' S+ s) V" J+ A
if (negocios_autorizados == false) // are we outside the trading window?" P, T- ` P0 _+ v8 b
return ;2 C* s. h. o6 D- c
//--- We are in the trading window, try to open a new position!
0 ]* J, @( w' u: r3 f Gint sorteio = MathRand();
! b* |( h2 ?$ y! u! j$ f//--- Entry rule 1.1* |& z& O" _( z3 g' g9 n: [
if(sorteio == 0 || sorteio == 32767)
# |( P, w: @ Y9 y8 r" F! Ereturn ;
( C" Q. ?1 ~; H7 l! Uif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy8 s! ?' M6 I" a
{
: D. n, I9 t4 M1 n! u8 x( J5 a3 A% hnegocios.Buy(info.LotsMin(), _Symbol);; r) x1 V$ ]2 F" ~" D* d2 w
}. @- g- F. q6 c% Y
else // Draw rule 1.3 -- odd number - Sell( h8 D7 ]6 e0 ^7 j* ~
{6 B2 w$ K* g7 \+ r% k" ~( f; j
negocios.Sell(info.LotsMin(), _Symbol);
! C1 N8 y: H; n* Y; F: Q7 l: G}1 I- I- P9 x& s2 } ~- j
}
' ^6 o& z: Y4 a9 q7 q* b//--- Check if we have a new candlestick...
5 y( C6 _ N/ m" {3 w# wbool tem_vela_nova(const MqlRates &rate)+ }# j* A0 B9 o
{2 p) ^ k1 K+ e! A q
{
6 H; E; {% O. e; x k( [0 [ret = true;, s+ v! `: ~. Y2 L/ J
close_positions = false;
' T; K! L3 e& i( J}
3 t% U/ q; y. x5 i0 q4 o' Helse0 q9 }& ]; X7 s. n: N4 p7 o( g4 C
{
4 ]8 y! v- P% M% W, u: xif(mdt.hour == 16)4 ^& t8 p3 i! e, V6 ^: p
close_positions = (mdt.min >= 30);4 S+ ]. Q' F u7 P: `
}. K8 c- t) D% r- i3 z& c. s
}2 A2 a) d# j4 o+ A
return ret;
0 v% c- s. n3 ^7 r* Q}4 Q8 M- k3 _ J3 y T- |
//---) s4 {! x; B' D
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 Z0 f1 _ ?( C
{: O1 ?, y' D, q1 R5 @
if(PositionsTotal()) // Is there a position?
5 n3 P( `% M6 `7 G{8 z9 s& u1 z9 i f* {
double offset[1] = { 0 };) K$ `0 |* u7 H5 A, R9 I
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?; _. E$ z5 x' G, K7 r ]5 f
&& PositionSelect(_Symbol)) // Select the existing position!
& t' }3 V) r, Y; u, v8 m{
' k% I$ l9 {. @( [. A8 |ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);( v! U: b- ]5 p6 ~1 g
double SL = PositionGetDouble(POSITION_SL);
6 h0 b7 o+ R- p* P8 R; `6 x/ ]3 Vdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
8 k1 q- @9 [# e: c# l* Oif(tipo == POSITION_TYPE_BUY)
' v1 C9 {3 J" Q; t2 A6 W4 a{& ~& W: X% q' z
if (cotacoes[1].high > cotacoes[0].high)
7 I; T8 L( Q: x) C! K{
; r4 F% \0 W% R: @0 V! W" ^- Udouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];2 S3 y) l& J/ |, F6 w
info.NormalizePrice(sl);
; E+ W/ `& M" @; m) x8 G, s9 y6 o2 k- Fif (sl > SL)
* a3 F4 z1 U5 ?# R{
) {. Y5 |/ m% [' cnegocios.PositionModify(_Symbol, sl, TP);6 ?4 e6 l Y2 b
}) s X3 C! y [; G/ S
}$ ]9 h$ \: W( q# S, @# F
}" Z5 t; e: y e$ S9 y6 Z: y
else // tipo == POSITION_TYPE_SELL* f9 [+ f8 c: V4 f/ i
{
+ Y* `" C2 x, Q+ Uif (cotacoes[1].low < cotacoes[0].low)& R% \1 N& R( }$ E$ k
{0 V R* t s7 N' V. \. @9 X. ]% g
return true;
" \" I/ K x$ J4 N}
0 q; n0 i+ R5 P3 d, ?) a* S// there was no position& Y! P1 R' ]. y7 K
return false;% y, @+ E6 ]( f9 v) I5 D8 ]
} `1 |4 ?$ w$ ^2 r" r2 w( i
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
6 t/ B% b! ]( J到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |