启动交易模型,并构建 EA5 O% Y# Y7 {' d- D: P! g
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。+ q) n0 Q( Q6 z0 l
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。4 D' h4 O' k! l- w2 [
以下是制定这些规则的代码。
+ |* x$ ?. `% o! H* r//--- Indicator ATR(1) with EMA(8) used for the stop level...7 _. k% t% ` Y. R* @1 T
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
2 [$ B0 E; H$ P) h% e1 qint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
2 I# I2 m% x2 r: |* K//--- Define a variable that indicates that we have a deal...
0 F" z8 Q" e5 f$ g$ Fbool tem_tick = false;# v/ A4 F" ^- k- `
//--- An auxiliary variable for opening a position. \0 s" e$ O" I7 V1 w
#include<Trade/Trade.mqh>0 `: L3 K u$ L: _
#include<Trade/SymbolInfo.mqh>0 p% U# b* ~! h$ P
CTrade negocios;+ F' B( j ~9 F5 m
CSymbolInfo info;
& F/ ]8 z3 ^0 R! `//--- Define in OnInit() the use of the timer every second4 B0 ?) G- ~ z6 z1 H! g
//--- and start CTrade
: W3 R& ^* ^3 o; A3 L2 m% Mint OnInit()! U) v# A. K+ o( t4 w5 M" g& }
{
, O' D" g+ p C& H+ x$ y. _4 N- B9 X//--- Set the fill type to keep a pending order
9 c y8 k% E) L* t//--- until it is fully filled. D. k7 n' b( }9 R6 r' `; e2 U
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
+ H% {3 U" [2 B7 L n//--- Leave the fixed deviation at it is not used on B3 exchange/ E3 w0 s2 E8 x# ~- M" \+ b
negocios.SetDeviationInPoints(5);
; [4 v% w- c7 ?- H2 c' l//--- Define the symbol in CSymbolInfo..., @. |0 p( ~( \4 Z
info.Name(_Symbol);8 G( x% j+ Y: L. e
//--- Set the timer...$ ]7 _8 W# v! ~/ L t
EventSetTimer(1);
+ f4 A+ E, I3 v2 z( v- D//--- Set the base of the random number to have equal tests...- d3 P6 ^) R+ n" `# e
MathSrand(0xDEAD);
5 P3 _: o: L9 K# Yreturn(INIT_SUCCEEDED);
1 u( O' h/ }. S$ G/ c}
7 Q7 O+ c8 ]) x0 T//--- Since we set a timer, we need to destroy it in OnDeInit().
/ D x4 ~& i3 h, e! Avoid OnDeinit(const int reason)( z u# W9 E( ]: R' d8 `$ P- [
{
7 B! ^: H5 ]: J1 {EventKillTimer();7 ~9 w' t$ q5 O$ F) x" X
}6 S& k; M9 ~1 [! W. v4 _. M
//--- The OnTick function only informs us that we have a new deal6 M( W; n% i0 ~) Z+ }5 K
void OnTick()
; [9 G1 p7 H# O8 ?{
- k; V, b. W, E5 s( M, C* f; xtem_tick = true;
; o, K9 V% r& J0 d}' {( E b# X8 X& y3 P. ^/ |1 ?7 e
//+------------------------------------------------------------------+; }+ @! L! E8 W5 K; v/ X2 c$ A
//| Expert Advisor main function |9 B% K& V; h% P
//+------------------------------------------------------------------+
, p3 k4 x# H1 Q! N7 s' ~void OnTimer()
. t$ }! H9 z; G/ Y; y9 x{; h2 j7 ~. E% X. M7 {
MqlRates cotacao[];
! p* |! Z: X) W/ L4 H4 Greturn ;& E7 q( E: K$ _" f
if (negocios_autorizados == false) // are we outside the trading window?2 e8 v% ?% G7 d
return ;
' j5 K4 U, P( Y- K. t1 e//--- We are in the trading window, try to open a new position!
4 @! Z6 i) D" S, nint sorteio = MathRand();
1 }) R% j4 h9 E" E$ X7 }( l k+ k//--- Entry rule 1.1
& t: [+ V) G+ c+ N! \3 f; R6 eif(sorteio == 0 || sorteio == 32767)! F* ^3 j* `1 T9 c: ]3 _, A0 p
return ;8 G! K- M j8 I( p% e
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
x( d3 Z* Y0 U% G D2 `0 k{. Q- `4 O' n( q/ T
negocios.Buy(info.LotsMin(), _Symbol);4 m; U1 A* m. |
}
} Q2 d. a% W& p5 @else // Draw rule 1.3 -- odd number - Sell: f0 z( ^0 r# w) A$ A/ q
{
- q" D `& ~: \negocios.Sell(info.LotsMin(), _Symbol);
" Z, f6 m" p) T4 Q}5 `6 K% o6 s( j
}
# O! v" u+ o+ ]5 O" x//--- Check if we have a new candlestick...
G- v; z% W; H% N& M. a6 N/ lbool tem_vela_nova(const MqlRates &rate)
; ]2 t0 r3 i* E$ Z{2 T7 t1 @; Y( E$ q* R) _8 \4 A; S9 v6 I
{
z5 z- b/ v4 o. Lret = true;7 _" g- h6 h- s
close_positions = false;
2 z# b; k, _' c; j}
+ N$ I& M( T9 ]; U) ^/ Relse
: c5 D8 k4 e8 H$ e* }; x{
( T' s0 t5 c1 Q0 J/ bif(mdt.hour == 16)
: d& y7 S5 p+ g j/ _4 ~close_positions = (mdt.min >= 30);
' C5 L5 g {1 @' K, ]' ?}
% s7 o% n ?* f6 G/ w}
+ ]$ R8 l% p4 i6 F p2 C% Kreturn ret;& X5 f' A8 m' T" _' r6 }, V
}
) ^/ p1 v k# ~//---
6 _' l ^" y) l) P8 \3 `' k2 Jbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
" n) L1 w. I Y. O9 w$ I1 s{
1 ]$ w5 Y) W. N. Uif(PositionsTotal()) // Is there a position?* C1 X, W+ p- N
{
1 Q; O7 @" L- `: h Qdouble offset[1] = { 0 };8 O. g. l; c2 B! R4 f
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?5 b8 P8 n; e7 H* M! |
&& PositionSelect(_Symbol)) // Select the existing position!- h( H' f- Z1 f; V6 I) x6 e1 C g* M% P
{
* f. {4 W: g7 L* }5 E. J% \' f0 xENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);" }$ [5 C; z5 O1 @4 g! L' V2 N& P
double SL = PositionGetDouble(POSITION_SL);7 l- B1 W4 J9 e6 f
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));& ~+ w" a! F- p0 z- W; e- v; ~- l
if(tipo == POSITION_TYPE_BUY)
/ c8 ^. [( s! U* Q: P4 J. F{
r1 k+ V) P Tif (cotacoes[1].high > cotacoes[0].high)
) p% W; d( |; S{# K6 u1 t* z; |% O4 K
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
& t# i" W$ `, x' Z/ oinfo.NormalizePrice(sl);, }- s& m( y, g& a$ V, y* e; y3 a: ^5 L6 w
if (sl > SL)3 S' |$ x& | j# A* r
{
- s2 R4 U4 ]8 U5 {7 m3 Onegocios.PositionModify(_Symbol, sl, TP);/ T- n" Z9 M* `* Q$ U" Y: S: y
}
9 o" K4 g; N9 Y9 s}
0 i9 @" S* i/ q" u; Y}6 d5 @2 J2 j- u$ j& Y! Q+ g
else // tipo == POSITION_TYPE_SELL
3 K$ q8 p6 ^! O% f8 p{
$ F5 K/ c* z$ l1 g% lif (cotacoes[1].low < cotacoes[0].low)7 \7 A1 G" d! T; Y# ^; x: c
{2 k! D1 e I1 A; ^4 B. {
return true;1 z: H8 Q( a6 s
}: K: y$ c! K. W u; i& y: A
// there was no position
, D2 ]& g" n" t1 E4 f3 h- ]* H; Dreturn false;
. ?# J0 B) V9 t}& r! b; u( ?% F. } h, o
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 b; u! D/ e- P( @4 Z% G( e1 x
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |