启动交易模型,并构建 EA
% w( D4 w( s. C" D$ @在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
5 @: Y W1 V% j2 ^; ]为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。/ a# G; s- \ L% [/ P
以下是制定这些规则的代码。
5 V- d$ P# c" O3 ~* u//--- Indicator ATR(1) with EMA(8) used for the stop level.... z/ z% m8 n( G% Z+ _
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);- j% Z5 O2 ~" c9 H9 G9 P, o
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
8 N2 r4 J1 o3 S" p6 y, {9 n//--- Define a variable that indicates that we have a deal...; S R' U* p' K {( b
bool tem_tick = false;3 Z* r: } N4 ]2 O2 W: g3 E" L) Y
//--- An auxiliary variable for opening a position
4 L5 |; z2 ]4 E#include<Trade/Trade.mqh>) q: l4 W% [* n% L
#include<Trade/SymbolInfo.mqh>
; t. j7 r# v8 k$ \! n# H- M8 N% pCTrade negocios;1 @& S& }8 P* @5 \) d' g( M
CSymbolInfo info;
/ M1 |0 u% z5 B//--- Define in OnInit() the use of the timer every second- g# k0 ~! U1 i. P! Z
//--- and start CTrade
* v9 q* H- ^6 s! z! uint OnInit()1 ^8 n; ^9 W. v0 q. z
{; _4 f2 a y q6 g: A/ v9 n( b
//--- Set the fill type to keep a pending order* e7 s$ H2 P% A0 T
//--- until it is fully filled
1 Y( m. I, c* {, H& o/ V3 U @negocios.SetTypeFilling(ORDER_FILLING_RETURN);; z; b. ?3 z' m% Q/ o% x C+ P
//--- Leave the fixed deviation at it is not used on B3 exchange/ k- m' @$ |6 x9 }" q+ }
negocios.SetDeviationInPoints(5);
+ ^7 W' j/ ?' Q$ n/ x//--- Define the symbol in CSymbolInfo.../ G' _+ }! K1 t! N: o
info.Name(_Symbol);
, M2 E. q% b$ e3 }' d$ t//--- Set the timer...! B. o) o( H7 z
EventSetTimer(1);
- \4 U: k6 {* L0 b' d9 G4 x//--- Set the base of the random number to have equal tests...1 u2 O t6 c" ^ P+ }7 ]7 k
MathSrand(0xDEAD);4 C: @: _' ]) W3 t& v
return(INIT_SUCCEEDED);) m; P7 t3 S& G4 ^: b
}
2 n) ~) j( S* o1 N//--- Since we set a timer, we need to destroy it in OnDeInit().
% s v- R; P# v+ _" z9 B9 bvoid OnDeinit(const int reason)- ~( ^. u* y$ v- t8 F
{
/ ]8 ^! M) ]; P# |' l" ]EventKillTimer();
/ ] l: T5 J [9 R}) L8 i: [& ?0 ]4 H5 N
//--- The OnTick function only informs us that we have a new deal9 ~- V1 m7 B0 ]6 i9 S, L+ g
void OnTick()5 o1 p* I t: t# X% p0 L; b2 ^
{
( s5 q" c7 |; I( vtem_tick = true;
7 R$ m" g( @( q: G/ l}7 |# D* s3 n7 i, [3 e
//+------------------------------------------------------------------+
. }( C' s7 U5 W+ [( D' m+ F//| Expert Advisor main function |
: y9 h( L' D5 i; X( K8 o4 I//+------------------------------------------------------------------+; b1 N# X% d8 F4 e
void OnTimer()
: w* M, \; z( b- @! h/ \{* f, b) ?3 o, A% P
MqlRates cotacao[];
" s% M' A% d+ L1 { K! T- E# Preturn ;9 e. Q, H# `( K
if (negocios_autorizados == false) // are we outside the trading window?
. A6 o$ T8 L$ U) S2 o. R( xreturn ;
; p; ]: Z: C5 M//--- We are in the trading window, try to open a new position!
0 E1 y1 k2 U. m, Nint sorteio = MathRand();' \ o5 D$ y* r+ k `* ~
//--- Entry rule 1.1& O# e+ L) X3 U( N; X
if(sorteio == 0 || sorteio == 32767)
# G0 Y7 \6 q2 W+ P; _8 ~! Z mreturn ;
3 A/ I$ g+ F, xif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy+ q w' I k4 _7 W( f$ T& u
{1 [0 O+ e3 H# F5 b; Y
negocios.Buy(info.LotsMin(), _Symbol);
* A7 W# o4 d; F0 Q}* C! H. L( f# J7 P/ h. t( Y: C
else // Draw rule 1.3 -- odd number - Sell4 v/ P5 v% w9 }( z4 l8 p$ Y ~
{
2 ~- u; p5 F+ _) Q; E wnegocios.Sell(info.LotsMin(), _Symbol);
6 U" U" ?+ B1 h3 c! s4 Q7 z& S* g}2 S; \" R1 F; F+ `4 ]5 {1 F; `
}2 `# i$ u! K3 b3 S, S, B+ ~
//--- Check if we have a new candlestick...
6 u! ~3 V1 w. a! c2 M, b, m& U( |bool tem_vela_nova(const MqlRates &rate)/ Z7 f( {! m6 u" M [; d) C# m
{
" D8 J* N% ]7 R- g, e s/ N0 D{+ i2 S& |# v @, M5 W# N
ret = true;$ K( O: r0 O1 e! I2 a, v
close_positions = false;; y3 H" g& h/ r8 I/ @2 B
}( i# S" _2 Z& `0 {
else) y2 V* p0 }. l9 C$ ?. C: A
{9 k' W p) h* t0 w: l
if(mdt.hour == 16)# X* }$ I( `6 b' \) G
close_positions = (mdt.min >= 30);6 Y8 I( I1 Y4 g
}( X$ ^6 h# ?4 A: l- p7 ^- @
}4 P# q8 F4 q7 _( l, C' v
return ret;# b$ l" @0 l/ v
}% c D3 g: _0 X0 f* T" C
//---
& Y% L/ z9 s( p9 t. n; sbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])2 O8 s7 m3 c: w+ \% C5 O* Z
{
; y0 ?& D# Z: i0 e3 \if(PositionsTotal()) // Is there a position?* X9 e8 r" K8 A4 F% X
{' J' H& @& l# {/ e
double offset[1] = { 0 };
9 G2 I4 F0 ?* a9 `if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
+ U, y$ n* H( T1 F7 H&& PositionSelect(_Symbol)) // Select the existing position!
& W3 A, H( v- b( h/ x{) U& B* g, {4 t+ W5 W5 A2 Q+ o
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);: `/ v, M! c; @& } Z% c
double SL = PositionGetDouble(POSITION_SL);, i: ?5 \1 q+ L
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
6 {! e# \& b) X) [) @1 ~" E1 j( qif(tipo == POSITION_TYPE_BUY)
1 T9 q$ R$ X; `3 H# y{# C6 b$ |' ?/ D: \; n, c8 x
if (cotacoes[1].high > cotacoes[0].high)
) C+ ?& g( w* \! K+ K- _{. I/ f$ _4 n N
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
. I. w, V& Y( Z" m( D# Hinfo.NormalizePrice(sl);' Z% _9 C: L+ `! J/ f( k+ V' j
if (sl > SL)
0 K0 [( `3 M! n$ z: i Q2 J4 B+ f1 U{
5 ?) T3 f/ H+ p1 H3 ?negocios.PositionModify(_Symbol, sl, TP);
; D5 t( @* j4 i- i+ a+ U6 t. _, V7 g9 E0 }}
' l1 m8 F$ C0 J" l; V}# r3 _% ^/ _3 q' T$ y
}6 X) \7 Z) [. a" E
else // tipo == POSITION_TYPE_SELL
3 D/ V( ~0 s: j1 B1 u. @{
& O9 F% O, P9 ^) o1 fif (cotacoes[1].low < cotacoes[0].low)
* U+ H, l5 f- P! i& y{
. C& D* u5 L9 O L" R8 H- ?return true;' \# Q1 ~ f! x! c% I
}* l7 I( z+ ]$ n& p9 D: S l% H& c
// there was no position; x* ~+ y# A8 ? l+ G
return false;& r: a/ F5 l; |4 G+ e. P! e
}1 t- n% C! A2 Q
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。2 [3 D/ q7 a8 e9 H ` a
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |