启动交易模型,并构建 EA' m" Z. }+ J9 d# n4 ]3 | m
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。8 H3 _7 {5 i6 I* t! U' `" c, S& T# k
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* x9 Q" `$ }* C! Z
以下是制定这些规则的代码。
" N4 y5 R, B, o) ~6 v+ S! z0 I//--- Indicator ATR(1) with EMA(8) used for the stop level...
; j# E% T% j% S; A# U. s1 lint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);: ^ T ?3 r( t) y
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
0 c0 N1 Y" J! I. I3 i. q/ Q//--- Define a variable that indicates that we have a deal...
- r4 |$ R( C/ t& k* N! A, m7 _8 Pbool tem_tick = false;* N1 E+ B- z+ ]. a! I
//--- An auxiliary variable for opening a position' d' [3 G# E3 V9 Z3 E
#include<Trade/Trade.mqh>
4 U* N7 K6 [' I4 w" x8 g#include<Trade/SymbolInfo.mqh>
* ?4 R2 K2 b; U Q# fCTrade negocios;
6 v& x' H7 h8 D u7 bCSymbolInfo info;
& R$ ?+ _+ y4 W: q5 q//--- Define in OnInit() the use of the timer every second
* d6 T% L1 L0 \; d5 Y7 u2 [//--- and start CTrade
' L) F1 w: y. [; m) \1 s2 y1 Hint OnInit()& }- `& D! W( i" v; R! M8 E# t+ ]: D4 N
{
3 R# s5 W, o/ g5 [7 ^- O//--- Set the fill type to keep a pending order
, y( p4 w. A0 a' |, A+ P K0 E. b//--- until it is fully filled! R$ `- W4 N' D& e$ i$ |
negocios.SetTypeFilling(ORDER_FILLING_RETURN);5 l. I. W d4 {4 }' Q$ A9 k% e
//--- Leave the fixed deviation at it is not used on B3 exchange
+ V: i; l+ r9 W) jnegocios.SetDeviationInPoints(5);$ u: k4 M# J3 I+ |: k/ \
//--- Define the symbol in CSymbolInfo...8 f; g/ E' v. `* q
info.Name(_Symbol);
% }( ]7 n! l9 X% G+ z7 a//--- Set the timer...
6 X2 h. F9 I6 p' U* K2 d% M3 a) ~EventSetTimer(1);
, H: E; t. G3 d j d# p: v//--- Set the base of the random number to have equal tests...) w8 F% C0 \1 i3 B! P' F
MathSrand(0xDEAD);8 N) T/ V3 Y# ]" }& O( L! `
return(INIT_SUCCEEDED);
! a. D. V% j$ Q3 @; Y}
/ }: K3 k g& r/ L7 n$ r/ L2 j0 E//--- Since we set a timer, we need to destroy it in OnDeInit().; s8 j3 h- z$ |
void OnDeinit(const int reason)/ }* n4 t! p. B+ Y; W
{7 f! u+ m1 p; b3 u/ D1 q
EventKillTimer();6 r" q; K: f# q6 s1 {# j! j+ h3 C0 e
}2 d8 n5 @7 q* U/ c3 N) H9 O( u# G t
//--- The OnTick function only informs us that we have a new deal
/ d7 X: F& H- I! O( yvoid OnTick()& M& ?, A' e# i6 ~: A. G8 M f
{
% J- p8 l. S% N, {tem_tick = true;+ T; c: M6 M3 u- @ Z/ O
}+ i- ]$ j0 r8 k3 X$ G
//+------------------------------------------------------------------+
: J! w/ L9 m. D- y6 p) z9 [//| Expert Advisor main function |6 V k! L: C! X4 W% f2 E! _
//+------------------------------------------------------------------+& w: w# H! H t2 `
void OnTimer()
# j$ ]! j2 f) e3 l7 W) ]) m. \{' l3 Y6 N% I. O: S5 X
MqlRates cotacao[];
' P8 @, |" C6 w; w& |return ;- y0 l* z, f; d8 q) v
if (negocios_autorizados == false) // are we outside the trading window?
# B2 U" A4 h; F9 r: W- Q9 Ureturn ;
' P) M5 d3 H+ u4 x7 e: }+ o//--- We are in the trading window, try to open a new position!
9 K9 o- a* s$ e/ K# j% `int sorteio = MathRand();
0 U4 j/ W& L& G4 c3 T) B//--- Entry rule 1.1. x7 Y# _* S) S1 n" y) i/ q {( S) W
if(sorteio == 0 || sorteio == 32767): z* s6 @& a N. L5 l
return ;5 l d8 E# h! C. u1 F$ \! e2 Y. |5 j
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
( y( H+ V. P$ X5 i4 t# k{
/ I! `3 @$ [0 nnegocios.Buy(info.LotsMin(), _Symbol);; ?0 f" ?6 a7 P6 z+ ^# @8 A
}
$ ?, ^+ e* Q( lelse // Draw rule 1.3 -- odd number - Sell; K# V% v5 d Q# D$ Q$ Z' d' v
{
3 Z( T( ^' S/ L0 `negocios.Sell(info.LotsMin(), _Symbol);0 h, g6 l6 @3 U: k% D
}/ K/ W4 c* r3 j1 {7 ^/ c" L
}
7 f* \ [6 V9 Q/ b! M//--- Check if we have a new candlestick...! z2 J5 t/ c- t8 I; o
bool tem_vela_nova(const MqlRates &rate)& q# h( K; R( H( D2 c
{
# |/ C# z v0 S5 X, u8 _" r{
$ z! ~, L, z+ q- h) ~( jret = true;
5 ?! b8 }2 q3 G4 r0 o* O+ k$ aclose_positions = false;2 u6 ~+ f( u& b
}
+ n& b. {8 E7 G4 @else
$ J8 z. i5 A0 d' W) ]3 w- c7 S0 J/ @{/ J* v8 X" F0 U6 c' z7 i! F) x
if(mdt.hour == 16)
$ i0 u% x$ W) u+ }5 s# ^close_positions = (mdt.min >= 30);
5 j) M2 P: G! T$ t$ e: ]}
2 d$ L' N9 m. F* D; Z! P}
6 p9 K; C& C+ m: d9 x% F; t' v4 Ureturn ret;( P" e+ f0 y' g0 S0 F, f
}
% M* v' U! y/ p2 g8 H- v//---+ z" w! J8 W, y+ a% J; X# v
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 M2 {) k/ u9 V0 V9 | A# i! i
{
3 _& ~+ d* @- ]if(PositionsTotal()) // Is there a position?$ ^% t- i( B1 [ Y5 c
{
. { K6 J; {2 G# z7 Jdouble offset[1] = { 0 };
! R# K% B$ {0 q/ y& I- Rif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
- J" H- `, a7 G&& PositionSelect(_Symbol)) // Select the existing position!3 f' m) I; a, {! d9 i1 v5 e9 Q
{4 ?/ w0 D( R* \' }7 b
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);# a2 d+ \" H7 e0 A- W6 l
double SL = PositionGetDouble(POSITION_SL);
1 \8 _& M$ R/ x& ?double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
y. ~; a$ M* P( Y' Lif(tipo == POSITION_TYPE_BUY)7 A+ d. Z c; Z R2 ~0 N4 H
{
+ r$ K8 T5 w( h C7 j' Gif (cotacoes[1].high > cotacoes[0].high)" U5 `' ]2 o' d
{) `, S: V2 F% t. \9 u* U
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];3 j0 o( F H/ n5 x8 Q5 K
info.NormalizePrice(sl);8 i* X8 R. Z3 o4 l# V
if (sl > SL)
* M( h3 m' J" j1 m" C" @{3 t2 U$ ^9 `7 e4 O
negocios.PositionModify(_Symbol, sl, TP);
4 \- a5 ]6 j) ^5 x}
B* g) f/ v# T1 n}2 t, U% }) M4 j4 R9 U
}- f, w! F) `0 D
else // tipo == POSITION_TYPE_SELL, m; p/ O/ W5 H1 y
{
/ f3 G1 y7 R6 x. \0 dif (cotacoes[1].low < cotacoes[0].low): v/ s, v8 e5 S
{$ I1 t% k+ M: T1 k
return true;
+ ^1 I& h5 l- c3 v/ u( A}
/ [& t. p1 U! m4 T3 d2 L// there was no position3 g. ]5 o8 u! _) [: s/ `: T
return false;
* R- Q0 V) H/ ^( P* O1 W7 m2 m6 [}
) [- r B7 c* ^2 o我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。, P3 J5 k8 T y$ X3 B* B, X" ^7 P6 R
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |