启动交易模型,并构建 EA
- }+ c5 g9 P2 c; u" `在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。 x; W5 i5 p1 _/ V
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。' L0 R! p, x3 y A' O3 k7 ]) K6 v
以下是制定这些规则的代码。2 O* j5 Q* q5 T+ ?
//--- Indicator ATR(1) with EMA(8) used for the stop level...
. u0 z! [$ Z4 n# Q) Y/ eint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
/ g) [7 J: m2 \6 f: y" R( Iint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
4 P g) d7 b r* G8 x8 Z/ V, B//--- Define a variable that indicates that we have a deal...1 w! C Q7 @% X) r- p0 ^
bool tem_tick = false;
( ^. I0 b# n" l# Q% v% K; C# Y//--- An auxiliary variable for opening a position) j5 [1 Y8 W6 u0 Z2 G8 d% v
#include<Trade/Trade.mqh>) ?( x$ _. w/ b& D0 j% F! p) O' o
#include<Trade/SymbolInfo.mqh>
" \: G8 w E# n1 ?5 U" a+ fCTrade negocios;
, G% L# a1 Y1 n' d2 mCSymbolInfo info;( @* Z* w- k7 ~( Y8 J# V: N: Z
//--- Define in OnInit() the use of the timer every second" q# T$ w" t1 E$ K# z) U, R
//--- and start CTrade
0 W3 B+ x$ S6 X) x3 `3 [int OnInit(); a; v4 q# q3 s8 `1 e5 u6 w
{
( G4 f! d+ N: z8 @6 u8 m+ j6 q- m//--- Set the fill type to keep a pending order" D7 _$ B% |1 Q$ T1 v2 u
//--- until it is fully filled
% w( z( @% d6 V" D9 r0 O+ Dnegocios.SetTypeFilling(ORDER_FILLING_RETURN);, r* d% g+ J! E5 c8 P
//--- Leave the fixed deviation at it is not used on B3 exchange
6 o) C2 y( m5 j. V+ j2 X/ q/ Unegocios.SetDeviationInPoints(5);
. O+ @- T7 O- u# x//--- Define the symbol in CSymbolInfo...
: u9 x* }/ O; Q, h& P' @- zinfo.Name(_Symbol);; B; ]+ m1 D- D5 E
//--- Set the timer...
& [3 _) |/ j: T, \3 UEventSetTimer(1);: F0 X; o* L; l* n+ s
//--- Set the base of the random number to have equal tests...& Y- P- _) K" e" T" Q
MathSrand(0xDEAD);
% d R: t9 |3 ^) o) }return(INIT_SUCCEEDED);
7 G5 j7 W6 j! u& U8 S}
, I9 V4 i4 Y8 a4 N; R6 d! t//--- Since we set a timer, we need to destroy it in OnDeInit().! }' H5 V( O8 W; X; a1 ?3 |3 }& g5 V
void OnDeinit(const int reason)
( }$ t1 x+ X6 L( v! i{ c) i1 @& Q: A$ A/ P( a
EventKillTimer();
?9 }3 U) z( j}) T0 @) l$ p9 {" Q+ w
//--- The OnTick function only informs us that we have a new deal
% E) c( H2 ] y) q1 V, E$ H6 Uvoid OnTick()' R2 Z) s" R' l9 D
{
( N2 G5 x: x* m* n" [tem_tick = true;
. l$ v" T/ C% z1 O/ V9 I" Z}! n3 u- X3 ~ L3 Q
//+------------------------------------------------------------------+
6 E3 ]" o9 ]- G! B//| Expert Advisor main function |
; ^- C- ?, g% m//+------------------------------------------------------------------++ V" j+ O5 i8 M8 r. y
void OnTimer()) w0 D& l0 |6 n/ [) R, N, l
{
; S& z+ h% L L8 N9 H8 K0 ~MqlRates cotacao[];
~9 X% b+ B, \/ H$ O2 w5 w {return ;
I9 G6 f/ U) Z. M. @+ |, i; Kif (negocios_autorizados == false) // are we outside the trading window?1 A% v3 g; q$ p; }
return ;$ ^& @" |( w- f! O
//--- We are in the trading window, try to open a new position!
. J* H" e n6 o( y k. vint sorteio = MathRand();# |$ h- U/ a |- Y3 d/ ^. ]
//--- Entry rule 1.1
+ R/ n" t D$ s3 V% v4 F# Zif(sorteio == 0 || sorteio == 32767)7 o3 L' P, v: A: |/ u
return ;
+ f! w5 [+ J( E& ?5 z7 wif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy1 O/ H& }5 q5 U1 k
{& @* k" J/ J& K- d. c( i m
negocios.Buy(info.LotsMin(), _Symbol);: J8 z2 A8 n4 y% S: J1 @+ D
}
0 @' h7 ]$ v6 Z. h* a( \+ Jelse // Draw rule 1.3 -- odd number - Sell
2 k8 c' O! y; w{
0 o* Q Y- O T; W( V- wnegocios.Sell(info.LotsMin(), _Symbol);5 M" ^/ h- [4 q2 t( e( O1 Z1 _
}0 m# u9 `: g$ H* z( j! Q
}
5 e4 Z2 X2 N0 A" |4 X//--- Check if we have a new candlestick...
$ r: }# _9 M" x6 e' w) L O1 dbool tem_vela_nova(const MqlRates &rate)0 r2 X& G! d* C6 u( e) m9 P
{1 b3 Q: i' {: j; O0 l# ?
{
. g" P8 j" w N# C. \3 Sret = true;, U2 C7 g: O3 P3 D
close_positions = false;' v1 w9 m# U. F5 \& Z
}
. ^! L$ V: C& E# q5 T8 i% B% yelse: ?) `7 I4 [5 b: m% h# }5 O( P- _
{
4 K- I) `. _. Z, h; Sif(mdt.hour == 16)
! I# r0 g4 ^9 `* j# W/ Eclose_positions = (mdt.min >= 30);+ S. U' }; j+ A: k1 k
}
! q) c" ?1 y! [. F2 N/ l}
, s, ?# c. i% x: C; T/ z& T Ureturn ret;! A1 t/ G. I+ @$ P4 g' F, C
}% a: R8 Y7 |3 A, J
//---
' H$ A8 f/ N0 O( B. Obool arruma_stop_em_posicoes(const MqlRates &cotacoes[])8 W2 g; R3 O6 \2 M4 |& ~0 N
{' d6 b5 S5 P3 k9 j
if(PositionsTotal()) // Is there a position?6 }) b7 y) m, j! m: J J& ?! I
{5 d9 I; m. R M% O: W& _/ b) o
double offset[1] = { 0 };" Z$ E8 o" g4 \4 E, e- m
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?, Q# }0 W; O3 g
&& PositionSelect(_Symbol)) // Select the existing position!
( z W. p( d4 h# C2 n7 g, y' l{
& e/ ]6 r! _% ]- BENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 j+ E o; W& J0 H
double SL = PositionGetDouble(POSITION_SL);
- e3 b( C4 W) g# ?double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));# {4 n5 g' A8 N4 ~) {$ X# R' s
if(tipo == POSITION_TYPE_BUY)- w# |% O9 P1 G+ {
{8 V1 W+ E% q! J% c* U4 U- S; j" k
if (cotacoes[1].high > cotacoes[0].high), {8 Y& Q f- a! ?$ t* B
{5 L9 Y- Q- P7 Z3 y4 Q5 e- B
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];6 R# K8 c. j% U3 J
info.NormalizePrice(sl);: V% x: r7 L; b$ Y% }! _' ?
if (sl > SL)2 S# c$ k9 T: B7 s/ j
{
$ E" }& Q, n, L2 G, T. e% Unegocios.PositionModify(_Symbol, sl, TP);" y7 S1 ^/ ^# ]; V
}
" \, k9 A# g2 R}( L+ [" X/ u# D0 X! z
}# ~: p# K* Y6 E1 `4 S
else // tipo == POSITION_TYPE_SELL* Q4 Z- @3 y5 `8 e" E
{
' ?( y- r2 _' Dif (cotacoes[1].low < cotacoes[0].low)
0 ~% l8 F6 `% o4 `, G8 I{1 `- o" `9 B$ `; p) a* e
return true;
) R3 g' x- O$ O" N9 f}
, ] i, @' z& H' [$ h" Y( \- a// there was no position
( q; t1 {" K- H) I* Z% xreturn false;
7 ?" o9 V, A2 D}" M4 Z4 k8 V Z9 g3 J5 @; M ^
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
* ~$ Y; Q- z/ O) Z, t+ b到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |