启动交易模型,并构建 EA
8 s; \7 j w K, d& y7 A在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
' S" ]: a! p3 U0 T/ o9 G为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) E7 B: }5 m4 d: j( M以下是制定这些规则的代码。! p" @% ^8 F' }- R4 Y5 g2 m5 L. {
//--- Indicator ATR(1) with EMA(8) used for the stop level...1 U* K: f0 q: W1 e+ o" S
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
/ _' ?, c% W1 G! E; A6 t2 Bint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);% T4 W& R( N% w/ M& t( F8 q
//--- Define a variable that indicates that we have a deal...
! I. J( [+ c" k T9 q4 p' w$ Nbool tem_tick = false;
/ k: K# h- }8 ?$ T% B' U//--- An auxiliary variable for opening a position Y- J/ @9 K8 r4 H7 C
#include<Trade/Trade.mqh>' T" A* O! j4 f2 q# g
#include<Trade/SymbolInfo.mqh>
! l5 `( Y& s: x7 NCTrade negocios;1 |+ J! ?. U# n8 V
CSymbolInfo info;9 u& P" t9 R) }' E( I. y
//--- Define in OnInit() the use of the timer every second
: e" N3 g0 V" M2 c6 r6 r//--- and start CTrade
+ c5 C* f* x/ O& t* Y& c% Rint OnInit()2 w0 D0 p+ U0 J) X
{ s6 p: Z4 O* V! Z( ?
//--- Set the fill type to keep a pending order
8 d0 I1 M: R7 y//--- until it is fully filled/ X3 V Z* d5 o/ }% Z* |0 T+ m* W
negocios.SetTypeFilling(ORDER_FILLING_RETURN);8 R' z5 E, Y, R- r; O" D
//--- Leave the fixed deviation at it is not used on B3 exchange
. U$ c" {) _1 f4 ]2 ^1 c/ Unegocios.SetDeviationInPoints(5);' O% E4 h! L& m0 W+ Q
//--- Define the symbol in CSymbolInfo...
# x. R7 P2 j4 D- Zinfo.Name(_Symbol);
- i, H0 _# C7 R4 Q' L//--- Set the timer...
: W4 T" X2 J. g& F5 }& X$ x: rEventSetTimer(1);3 J; O9 n3 A: d# k$ `
//--- Set the base of the random number to have equal tests...( G' x+ ^' ^9 `& R2 l& ^- M
MathSrand(0xDEAD);; V* {: U. A4 N' Z. x
return(INIT_SUCCEEDED);
& w/ P- ^, ^# E& R; H) S( F}
8 A+ w# ^# G' Y//--- Since we set a timer, we need to destroy it in OnDeInit().
- X7 p1 ^' y/ a1 w" rvoid OnDeinit(const int reason)
! T, U5 x+ z2 r{
8 B- O+ J a( X9 R0 v9 gEventKillTimer();
9 ~- O: t R* T& Z7 ]" y}7 q' P; C; Y% S }/ h
//--- The OnTick function only informs us that we have a new deal0 V0 ?7 K3 j2 m: x
void OnTick()
; g5 [- {* F- A7 B{3 P; W I( \, M/ y, s( r
tem_tick = true;8 @+ t7 {. [8 d3 d4 t
}8 g: _' L* s8 D6 g) ]( e) q8 j1 h
//+------------------------------------------------------------------+3 W( @) ]0 ~) @
//| Expert Advisor main function |
' z" A6 s K! o, I1 q2 d7 C//+------------------------------------------------------------------+
) p4 l2 R& C9 k, I0 d& j5 K0 P% x5 cvoid OnTimer()
+ Y6 F) G D z5 k9 g( E# d{6 p7 x' h( T; _
MqlRates cotacao[];
3 B) A7 l; \& kreturn ;
5 a4 h8 Y$ a. b) pif (negocios_autorizados == false) // are we outside the trading window?
& _7 J! I3 J! i" |return ;
% }) p" b% z8 T7 e8 K( r4 D( L9 q//--- We are in the trading window, try to open a new position!
+ Z& e/ r% p& Y4 a% r) ^8 ]) _' Lint sorteio = MathRand();
. Y7 U: n& t- u" w% P; {//--- Entry rule 1.1! f/ L5 ?1 j* p% e1 Z
if(sorteio == 0 || sorteio == 32767)
* n( g+ F: T, R' Preturn ;+ V' F8 A9 t# V5 ?
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy) O" T5 W1 `6 @1 L" s
{
8 N, p- S# ]& }$ @negocios.Buy(info.LotsMin(), _Symbol);
3 P3 Q- Q/ M2 z! ?: Q4 x3 G}# y- h/ x& a: i2 U, u; n8 q
else // Draw rule 1.3 -- odd number - Sell+ o. F A. o4 ~2 ?$ n& Y# T
{
, U5 b3 B8 ~3 U" W X( Nnegocios.Sell(info.LotsMin(), _Symbol);6 Y9 v: r U1 x
}
. f& p; I8 I# E* E& t}% V/ s/ H# F, c v" H1 C& I: u
//--- Check if we have a new candlestick...
; P' O9 a8 {& U* H, Q1 |bool tem_vela_nova(const MqlRates &rate)
# v6 h& m( V- c ~* B* Z' ?1 m{1 A7 m- A2 ^& m6 y" k
{
0 a$ @9 }! ?/ m' u' m. o6 dret = true;6 Y4 _8 K, | L) D# L
close_positions = false;9 I8 f6 k3 C; c+ T) s" _8 ?
}
5 w9 {: Y7 T$ Celse
5 K. \2 T+ x5 d. B% O5 A7 ~7 T{
( M* e9 q( |' h* ?+ pif(mdt.hour == 16)6 M/ J0 ~: ?3 s( z
close_positions = (mdt.min >= 30);$ L: i0 _$ j) q4 r
}
1 A( A& ^/ P9 z* s* v}
4 F" h! U1 c: j; r) e" [" l6 v# Kreturn ret;
+ y- e) k6 e% E8 d6 r}0 ~9 A2 @, K3 T, y" y+ J
//---
' z* S" z0 P7 A# f3 i3 Abool arruma_stop_em_posicoes(const MqlRates &cotacoes[])* {) n9 i2 T8 R/ y2 G, H
{9 J: W4 ?. @7 K0 Z/ }5 ]
if(PositionsTotal()) // Is there a position?
9 X+ o |0 u" l6 A7 z$ w{' b8 a: j* f9 |- Z
double offset[1] = { 0 };
1 B. s* R7 _$ E. t$ n, ]if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?3 D3 {. k( ~; {4 \2 z' R) v
&& PositionSelect(_Symbol)) // Select the existing position!* l1 D6 x% E( y
{
) W9 ?3 j, \; eENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
+ a, w' ]( J. W3 Y! D' [0 Sdouble SL = PositionGetDouble(POSITION_SL);
; _) N) c2 G& L1 K& U4 _4 Xdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));* `( W, l/ `- Y
if(tipo == POSITION_TYPE_BUY). l |! w6 D0 r9 C7 @6 y
{
9 Q1 T/ S5 T7 |) dif (cotacoes[1].high > cotacoes[0].high)
" R5 l9 f& r( L t/ u! T{6 M2 W) j2 Z/ ]3 n* K& R7 ]
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
2 o0 T7 u- M* {( pinfo.NormalizePrice(sl);
# c# k5 E) }4 z# l x3 B3 X1 r x$ iif (sl > SL)1 U9 W2 g0 D; g
{
1 B8 w9 \; B7 }( ~$ P1 \2 pnegocios.PositionModify(_Symbol, sl, TP);
/ ]3 h: E" q) ]6 u# d. G2 f) E! ]}& I. ~% j' `3 h* Z
}# i5 t3 v) h: ]
}
1 ], w ]: c% Velse // tipo == POSITION_TYPE_SELL0 @+ H i/ @* a4 F5 |' j' k
{
1 r4 S2 q! b" m6 N5 nif (cotacoes[1].low < cotacoes[0].low)
: @' x6 ]; v/ T+ U) U- k5 Q{
& S1 H5 z* V5 K# zreturn true;+ M8 o, Z4 ^- C5 M
}" ^$ d5 g% R' Z
// there was no position7 x- I. v1 S0 l( K% r" D3 `( X" ^0 _
return false;
7 S& U4 C7 l, a8 Y}
; X4 ~$ |! u5 H& ]; Q* K我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。2 I6 P+ R2 Q3 r8 c6 ?: D
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |