启动交易模型,并构建 EA9 y$ i$ X# ~; d# Z9 B
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。# P9 H% o" ?6 T# E# u& t
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。/ ?( b2 @; V% v1 j: K* y5 K
以下是制定这些规则的代码。
: F& _2 j; S6 U. ?& d//--- Indicator ATR(1) with EMA(8) used for the stop level...
q; e: M8 u0 i' wint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
/ A# I5 H' I: W( ?( A" Qint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
6 _- o( {( r! P2 w( k//--- Define a variable that indicates that we have a deal... [# \7 G# J+ f% E
bool tem_tick = false;
* [* v5 M; B2 q- H//--- An auxiliary variable for opening a position% f" q+ S/ f. ^1 U; Z3 [
#include<Trade/Trade.mqh>
2 N! F9 o: ~/ e" B$ v# w9 z#include<Trade/SymbolInfo.mqh>
) E/ b; F9 Y% o4 r+ cCTrade negocios;
1 L) V0 Z2 O# l& W8 w- u3 B+ k" Z) BCSymbolInfo info;- j7 @: [: |3 N$ _* _2 D
//--- Define in OnInit() the use of the timer every second1 R% E0 t0 r# b. }! N
//--- and start CTrade8 c' I G1 r" c8 u0 x5 L+ Q; X2 h
int OnInit()) e9 s( X/ G; c2 x5 ?( x" z
{
% | j! c- M* L& p( |% c//--- Set the fill type to keep a pending order# Z5 O/ }8 _. `# S% C/ X& g( w
//--- until it is fully filled$ V/ D: ^; X( H0 z( J
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
5 f2 X9 l4 g5 n+ A* G3 ~//--- Leave the fixed deviation at it is not used on B3 exchange
; M0 I& K+ H4 [: m! |1 s- bnegocios.SetDeviationInPoints(5);/ O7 r) b# [) D; u' J
//--- Define the symbol in CSymbolInfo...
& M# @$ [ @( d9 m H( yinfo.Name(_Symbol);
# k- K D! i( P0 B//--- Set the timer...
- L: m; e9 R) V5 |+ L# cEventSetTimer(1);
o* x2 K8 b8 e; E3 J6 N) M//--- Set the base of the random number to have equal tests...* r' C: E* ^1 p
MathSrand(0xDEAD);' E; Y) x& b9 l3 ]
return(INIT_SUCCEEDED);0 P1 c0 G. y0 }3 v
}* s/ z+ A f+ {; t+ k
//--- Since we set a timer, we need to destroy it in OnDeInit().( d: f: E4 j1 G' t2 b( D
void OnDeinit(const int reason)
! J1 [" Q, V1 Q; |{! o6 h5 _" c: W5 R# y$ }, n7 B4 }
EventKillTimer();& y/ m2 |6 Q5 I# E& u* u: h
}
, G- K. k' C- E, t+ F& ^//--- The OnTick function only informs us that we have a new deal9 B6 r, Z7 y" S- A7 O0 Z
void OnTick()
, s) F" F( k7 v; ^6 T{
3 x% X6 J4 d3 M A6 U0 gtem_tick = true;8 }+ Z- C6 [- q9 F8 E" x' Q3 z
}" i) b3 x+ O* ?
//+------------------------------------------------------------------+
" B! G1 e1 ^/ m0 S% [- h1 v. J" R! a4 x//| Expert Advisor main function |
' `5 J$ m5 j! ~//+------------------------------------------------------------------+% l: P5 d. O) v$ }
void OnTimer()
- q+ P4 O$ O/ A7 U: m' E{
7 V7 m/ k, J6 l7 T5 P5 KMqlRates cotacao[];
; r5 G' `1 b9 c$ J! a2 x' @return ;8 R. v3 H+ P; I5 H* w/ \% ^) [7 r( @
if (negocios_autorizados == false) // are we outside the trading window?2 z% Z, K7 J0 _5 U. |& \
return ;* E- v4 l' Q& y( M$ e/ X
//--- We are in the trading window, try to open a new position!
3 @1 C: J1 t7 ~, y i8 jint sorteio = MathRand();
- \. F" |% v0 V2 ?6 X//--- Entry rule 1.1& D- E! ?- V2 }, N6 U
if(sorteio == 0 || sorteio == 32767)
7 }# a: s L4 d5 Preturn ;
2 ^9 m! h# k& R' E# z% p0 iif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy* o: [- r& F: s8 x! d, {
{
8 a* d0 ~+ N$ G- r7 t% z. anegocios.Buy(info.LotsMin(), _Symbol);0 y e) E8 V, u% N
}/ O2 v( A: ~+ b. g, ~/ u+ O, g* ]
else // Draw rule 1.3 -- odd number - Sell9 k5 ~; g4 Z9 d
{ V1 ?3 s& S+ ?+ E0 E- a; P8 B
negocios.Sell(info.LotsMin(), _Symbol);
3 Q. D u% ~$ g `/ s$ w* D5 n}
' Y/ f* s2 y# k}& R8 J7 i; Y! p/ _ p1 W
//--- Check if we have a new candlestick...' m x) H7 q# q- n) ]" W
bool tem_vela_nova(const MqlRates &rate)6 W" x: T* N: h
{
/ o# ^, B* V2 ^6 L$ \9 q) x. t{8 `0 ^) @1 W: D% U |& {) @# D
ret = true;
4 x, K1 N) U) S1 q! }; j% Vclose_positions = false;
9 Q' f' `. j9 @' L7 Q}. r5 ^; T, [1 p( \
else% d9 H( I; [$ ]. Y
{
/ U9 j0 V" F# e/ d5 x8 X7 Nif(mdt.hour == 16)3 ]# ]# s1 |+ J$ f
close_positions = (mdt.min >= 30);
( H1 ^9 ~( b; N" Q}5 s3 R. q: m) D8 @% y
}
# W. o8 X$ ?) {: o6 o/ b/ w0 Dreturn ret;" @4 J0 N% \6 Y3 c; d+ l: S' c
}( Z% P& _' X+ U: P. z5 P5 ? g
//---: W4 \0 y3 ~; z0 U Q |5 L1 A
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])# s5 q5 E3 L0 i# \
{
. v3 }& z* j7 \% l' ~if(PositionsTotal()) // Is there a position?
{# c* Q- B. o* e{* O' T5 ]# b z- V5 _
double offset[1] = { 0 };, ]3 Y v3 h5 k l
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
8 W* c: V, k q1 h&& PositionSelect(_Symbol)) // Select the existing position!; E4 k: x8 f! q! d f3 E$ c/ J
{
' I1 P* ?. X. L& h% ~2 d) U$ sENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);( w0 Z/ s- L' w' p0 Q
double SL = PositionGetDouble(POSITION_SL);
) v3 z$ O; C% D" y' E* |+ M! cdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));) G; z% `/ J9 T# l5 b
if(tipo == POSITION_TYPE_BUY)
* r, ^1 A/ n, y" c8 s{5 F* g& S$ j: j& s0 x- @' p" f: @/ f7 [2 |
if (cotacoes[1].high > cotacoes[0].high)& [ P9 I" e3 m: d1 G4 J) g
{
V- ~0 ~# ~$ i! L2 cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
r. Z) j0 H9 x+ s" s# binfo.NormalizePrice(sl);
# ]1 ]4 d9 u- \- O7 Rif (sl > SL)
/ b% Q# a* b( r{* b! Y7 G& P$ b$ E( @6 q
negocios.PositionModify(_Symbol, sl, TP);# X# }) |! V3 X$ m* R' D3 N
}
( N0 J! t( ^* I/ I% q/ l+ }}
& h$ \" w; x6 j* N/ o. U}
4 B" e- X5 E8 E7 ]+ f m" p. `6 x9 [else // tipo == POSITION_TYPE_SELL
8 U5 N$ m# L N( |0 k{% G7 u4 U. E' ]4 @! o9 d$ j
if (cotacoes[1].low < cotacoes[0].low)1 C3 ?6 d* y0 l1 R
{3 S& J3 I o; J6 o
return true;
$ b+ X' @) F# b( W& S5 ^}. O' t, g* A# P# n6 B: v
// there was no position3 r7 n( F E9 A& `5 R8 `* N9 [+ y
return false;
6 _7 _8 n1 k9 E9 v U( J}' {5 X% N/ D J% M
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; h2 w! c- J' Z5 Y5 y/ i2 x
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |