启动交易模型,并构建 EA
4 E' `! m( I" x, u" t/ `( `在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
5 T9 N9 X. i2 W' ~" z$ I- W4 o+ `为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
J, O" E% B: ^+ b/ N( w# y以下是制定这些规则的代码。$ H# N1 }, Q, T" r. P$ E
//--- Indicator ATR(1) with EMA(8) used for the stop level...) G8 `+ f. `. H K2 @4 q
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
9 `- L8 o1 O l) ^int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);/ D3 b7 a! u2 j9 P9 O0 J
//--- Define a variable that indicates that we have a deal...
* A: F" I* G8 G$ b, f. Ebool tem_tick = false;7 Z0 g1 I' p# l1 [( k7 W
//--- An auxiliary variable for opening a position5 o8 O1 s4 [5 N1 L
#include<Trade/Trade.mqh>
7 O8 ]$ l$ I' I, J R#include<Trade/SymbolInfo.mqh>3 j Z, ?3 Y; C+ ~2 ?
CTrade negocios;
7 H$ W0 @( I! [; {8 fCSymbolInfo info;. H) U2 z; `& Z* s8 N
//--- Define in OnInit() the use of the timer every second
; Z. J. a1 @0 W//--- and start CTrade ]- d/ s$ a0 w8 [' n* `
int OnInit(); C8 c+ o3 E' M% V
{
I1 P3 M" O% u. ]$ N& N8 f//--- Set the fill type to keep a pending order
# \6 Q2 ]1 z' N//--- until it is fully filled
$ M; T9 e% Y3 anegocios.SetTypeFilling(ORDER_FILLING_RETURN);
- e' A) U) y+ F4 J o8 y//--- Leave the fixed deviation at it is not used on B3 exchange! N' p: _+ A0 V6 B" C
negocios.SetDeviationInPoints(5);4 F8 w6 y# u; {" A
//--- Define the symbol in CSymbolInfo...
: W* h1 F1 S& ?; Qinfo.Name(_Symbol);
7 j4 X; |0 X+ a8 e3 I//--- Set the timer...
' i" b+ P. C6 T9 qEventSetTimer(1); h. Y: F# R7 t! j1 P& Q
//--- Set the base of the random number to have equal tests...5 G0 A( e/ D, n" x/ u3 p
MathSrand(0xDEAD);
3 ]! P* J1 h n7 w- S" Treturn(INIT_SUCCEEDED);
$ ~4 N1 x# {- A0 @}
& S5 c1 {7 D" r; \1 @//--- Since we set a timer, we need to destroy it in OnDeInit().$ N) O5 {2 l/ R3 _
void OnDeinit(const int reason)9 j6 t& P' {6 j
{
5 v" y; K8 r# c/ C2 x4 |/ w5 CEventKillTimer();
9 p/ S3 `9 D! ^. ?3 ^; O% W6 T}
" d" y! L0 I9 W# ]( r6 [& e//--- The OnTick function only informs us that we have a new deal
5 A3 G; s& a; S# R9 {0 Uvoid OnTick()
, Y9 V. ~& o" x" U) J3 c{8 E0 u; i! B; `. }5 z- `1 b
tem_tick = true;
. a0 e6 z \3 z# D4 W}
% E4 v% W6 i* {$ ^4 ~//+------------------------------------------------------------------+
! ^! x! ]5 N0 T& {7 o" U//| Expert Advisor main function |
3 ?4 v# ^: [+ s0 K+ k3 C//+------------------------------------------------------------------+- K+ k: j+ Z) Y8 R$ r* J
void OnTimer()! S/ _/ @9 k! X/ ?
{
: R9 A9 O: v0 m3 ?) M- t$ Y. w! Q: l5 ]MqlRates cotacao[];
, \9 {6 I9 W0 \" B5 u# n: m5 wreturn ;
8 j+ o7 Y; M, S. {7 p5 cif (negocios_autorizados == false) // are we outside the trading window?
1 M# Z" X6 |, k: [2 P# greturn ;
+ |" G+ Q" _0 ^//--- We are in the trading window, try to open a new position!
9 w, `" P+ W# F! w6 Wint sorteio = MathRand();/ L- Q. M0 g' f
//--- Entry rule 1.1
" q J) _6 n* D, Kif(sorteio == 0 || sorteio == 32767)
' P1 ?! g$ Q8 v) ]. ^8 |% kreturn ;
% M* |. ~% Y) T2 H0 Oif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy) O! o; U$ T+ |6 p9 Z
{2 g, z' M4 f) Z0 T% U( x
negocios.Buy(info.LotsMin(), _Symbol);
% r, w' w! V- A}! e) D) c0 J( n2 p8 ?0 S
else // Draw rule 1.3 -- odd number - Sell2 n! p7 A8 B% e* @8 h2 l0 N( V! _
{, B* w' j' u; p0 H3 l9 o
negocios.Sell(info.LotsMin(), _Symbol);
; l8 S% B* _" `5 u: N, w5 x}% b$ T5 Q& _/ J y5 z2 Q2 E: M4 K
}8 s* R# i6 O" [- ?* R0 h
//--- Check if we have a new candlestick...
3 k: g* t2 u+ U' j, ibool tem_vela_nova(const MqlRates &rate)) A9 c5 s# f0 W% X; j" Q4 d
{
* \9 L R7 W( ^+ w M( _{
& m/ C3 V- w; S' W" p: `* X2 a1 uret = true;$ }* `- {3 f! } J% e) G7 P6 S
close_positions = false;0 ^4 w7 e0 t) R' h$ x ]
}0 B' U6 l7 E3 I4 `3 Z
else" D z6 d! |$ h$ f1 _# g1 H5 X. [
{
1 B' f* X: m( D, y; N1 B# E+ Yif(mdt.hour == 16): {/ O, x# A, k1 r7 }6 l
close_positions = (mdt.min >= 30);
" e9 j5 Z; W5 O' ^' T$ \) d}
5 F+ d3 ^# j) E. S( d}- D* B% X# O/ G
return ret;( ~) ]" ]6 q* m, ~. |. ~: A) H
}
' ~6 ~' c" k7 r9 h3 b8 R+ v//---
5 ^, N7 R, c" C5 G/ D. a+ xbool arruma_stop_em_posicoes(const MqlRates &cotacoes[]), U c9 l' o! H. S$ n3 | i
{9 q/ h% P9 v0 A, y6 W4 l- R
if(PositionsTotal()) // Is there a position?* Y- U. m$ f q
{
+ G! V, R' u' _; [: udouble offset[1] = { 0 };
% _7 y" C9 Y# V& p& ?; P+ {! vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
8 o! O3 E% w n, g0 x, Q&& PositionSelect(_Symbol)) // Select the existing position!
+ g2 e% F' x! X; q( P{
* s- V5 d& `7 EENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; m. Q* e8 g# A- @
double SL = PositionGetDouble(POSITION_SL);1 w' J8 {: k. M! c; z, h" {4 {( r
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));, B: ^* A. v) B" q6 A
if(tipo == POSITION_TYPE_BUY)
\# R2 n! D- I% A4 z% Y{& i) {; @2 A9 U: N1 B% H) k
if (cotacoes[1].high > cotacoes[0].high)
; V. d1 F! H3 G0 x{
3 t. h& g$ w7 W7 @' Rdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
9 |# F$ g. R8 t! } U- {" oinfo.NormalizePrice(sl);
/ M( g/ J2 \2 S$ P' d- oif (sl > SL)
' X- j, t; }/ `, p: e. b{. \' J- i& T. A) N/ i- r* q
negocios.PositionModify(_Symbol, sl, TP);
. z" z) ^7 H, V+ k6 Z: A# _) d L}3 u. @' {( ]4 m* ^5 |
}
% V5 i6 Z6 Z8 W1 Y5 w) g w( ~}5 y# ?/ P; V2 N+ Q; u B" n
else // tipo == POSITION_TYPE_SELL
4 ?2 k4 F7 q, F# ]& Q% g3 n1 A{
, u% X* |% ~5 B% |if (cotacoes[1].low < cotacoes[0].low)
! `2 F. D3 ^1 d$ `. m{
3 d; Q |+ C! X. T) Mreturn true;4 A5 T7 p ?3 u& s8 Y+ i* k2 {
}
8 u, }5 a1 X+ m1 J// there was no position
, h' a' z" v; a8 H6 S% ~/ Treturn false;( }/ T- W" Y( K$ A
}
8 m5 m; c( M+ I# ?" p1 Z- G我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
. |) E( o8 I* k: T% W( U到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |