启动交易模型,并构建 EA1 N/ K3 k( O/ O8 ]" k2 J
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 } l! x6 I9 E9 n$ a. I3 O2 }为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。 g- N6 E4 z( j* ^8 @0 e
以下是制定这些规则的代码。
0 ^% U5 |$ Z% ^7 d2 T, K2 \& e% j//--- Indicator ATR(1) with EMA(8) used for the stop level...
% j& j4 m" s# u/ Aint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);$ u( u& I# H4 l
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
/ O5 B! V6 N4 t* }6 u X9 S//--- Define a variable that indicates that we have a deal...
$ s8 W+ y% E# {9 O6 Kbool tem_tick = false;
) M( ?; b4 [3 w2 @! ~4 Y, Z//--- An auxiliary variable for opening a position
% m$ x0 A9 G0 P; Y#include<Trade/Trade.mqh>3 v4 {' q' u* n) {9 @. k
#include<Trade/SymbolInfo.mqh>
A% n, L0 w/ v0 Q* e% r# K- V pCTrade negocios;' {( c* H% E5 v8 A( E0 G3 J% p
CSymbolInfo info;- Z7 v7 O, B- V- `' Z
//--- Define in OnInit() the use of the timer every second7 E4 G+ ` y. X
//--- and start CTrade/ V" s! E u4 K+ J( j0 C- ~( }
int OnInit()* y! A2 W6 N, x2 G4 k0 d. W
{
3 c' h# P) C/ _' t1 T//--- Set the fill type to keep a pending order x) O$ ^7 Z" `6 W- A
//--- until it is fully filled
1 g- d. u, K; l1 R# Z- U+ Hnegocios.SetTypeFilling(ORDER_FILLING_RETURN);, j: j6 t! {6 E2 U7 h6 t; x0 a
//--- Leave the fixed deviation at it is not used on B3 exchange
$ c; X1 z3 \! T7 D$ D2 ^negocios.SetDeviationInPoints(5);
( ~* ^) E" ^* }! V! x; l; a s1 u//--- Define the symbol in CSymbolInfo...
7 I; P. a0 v/ [2 p0 ?. p) V8 Yinfo.Name(_Symbol);& ], J7 _ a% G+ E) N$ Z
//--- Set the timer...
& a$ B* e+ @( \0 A3 `4 FEventSetTimer(1);; y7 L4 Y5 ~) J+ o ~
//--- Set the base of the random number to have equal tests...
0 W* T3 a5 J3 a* h7 n; PMathSrand(0xDEAD);
% K7 r6 U$ j n- g% F4 e5 hreturn(INIT_SUCCEEDED);
" f- ~8 Q# f- }: ~3 O. j8 M}' |+ `3 n( N q# C
//--- Since we set a timer, we need to destroy it in OnDeInit().
O0 \9 Z6 e5 _' |; Bvoid OnDeinit(const int reason)
' g+ r. W& ?. [ V2 a2 x& Z. T# t{7 K- Z1 H( V2 ]8 s
EventKillTimer();
. ]8 c7 [% l/ \/ M+ U}
" s A; m# e1 l7 s* w* Q//--- The OnTick function only informs us that we have a new deal$ j* D$ B. z- N/ j/ V9 K
void OnTick()6 h; h* C9 ?, i+ s; j& `
{! N/ P% t" \' x5 G
tem_tick = true;2 N* W- f3 b$ m, G
}- K6 K! J* R2 {2 F* R0 ?/ d
//+------------------------------------------------------------------+
) f) b$ w! o8 v- i; }* U//| Expert Advisor main function |8 E9 O o) v' `2 W, ~3 M
//+------------------------------------------------------------------++ a; g {+ q- q. I7 _7 F' C
void OnTimer()
7 f' m5 i Y+ ?# [9 y4 y& C{
) l" w6 b! k( {+ \! M/ TMqlRates cotacao[]; p0 j' f/ I6 _$ `; n; s. R- H$ i
return ;
: C! K* _) L. g8 D. M' Uif (negocios_autorizados == false) // are we outside the trading window?
( U& O% C4 `2 qreturn ;
! T, _( @7 K7 ^5 [//--- We are in the trading window, try to open a new position!
2 X X. | x: c5 O- k7 ]int sorteio = MathRand();0 t$ l5 x1 V' F! x
//--- Entry rule 1.13 c* }3 w0 N$ I# s) U' Z
if(sorteio == 0 || sorteio == 32767)
% k* w# G6 P5 P) Mreturn ;. @- V+ |8 u1 Y" i) S
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy; d5 x- m5 a8 }: w" {
{0 W$ R+ u$ k c7 }$ _ x
negocios.Buy(info.LotsMin(), _Symbol);
0 |; V- O: ]* z7 b& \- o% R}
# N% K" I/ e: H: l7 f+ Eelse // Draw rule 1.3 -- odd number - Sell
6 ~ v0 p0 E Y) u. S Z' |! l{
) O7 g" W* g$ A qnegocios.Sell(info.LotsMin(), _Symbol);
7 _6 e0 t" q7 }3 n5 f}9 H) K% H/ T4 m6 X9 q
}' |. y: z: {$ N( @! L
//--- Check if we have a new candlestick...
6 {' h- Y. y; S7 Jbool tem_vela_nova(const MqlRates &rate)" r4 S% r. G. h( [
{) i- A& {% s1 z p: ?# G9 b$ S0 c
{6 V; @" p; g8 k: S6 K) u
ret = true;
' t: A- y$ S( Iclose_positions = false;
5 @- Y& {, K( X* k5 [2 g}
7 ?0 p% Y& g" g4 B) Eelse8 U! B; ~- w* M, f! s
{5 K; J) {; O0 W- ^$ i- P) ]
if(mdt.hour == 16)0 \" o6 c3 c- [, U+ g- @
close_positions = (mdt.min >= 30);
( d' Q- V A7 V5 ^}. Q* @7 p+ X) x; u# z8 U) q
}
. M7 g9 v" r, {* y5 B6 }return ret;: y! J I% h8 K& Q
}
) z: ]% M4 H* C, ]//---# w/ I Z/ P! v
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
! j3 E1 C g+ R{
5 W$ ~1 ~: f* Lif(PositionsTotal()) // Is there a position?4 S5 R6 o8 H m9 M9 K
{
+ m% E: p" D) I( W! G' C K, p! p# {* Ydouble offset[1] = { 0 };! ~) D4 T' o" W$ G; [! }9 I8 G! B
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
E6 A( s) j0 g* h) r0 u4 A&& PositionSelect(_Symbol)) // Select the existing position!
5 z( o( c" z( p" I{
' ]/ E" w$ i6 dENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
% o9 Z: R# r3 y3 q7 ^- Fdouble SL = PositionGetDouble(POSITION_SL);
o- s4 u4 H2 E2 ?- ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
9 ^* `/ K2 {9 n( `/ D3 fif(tipo == POSITION_TYPE_BUY)( w! ^0 I) {% t3 B
{
% d" h& e+ M% h- Xif (cotacoes[1].high > cotacoes[0].high)
! m+ J; Y' _0 S% z{
# N# k/ r9 s) |+ S$ P. i1 edouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];% E' C- V! C1 Z6 Y. |+ x8 T% A, B
info.NormalizePrice(sl);+ ?" s) [8 Q% ^7 a2 o, L9 o
if (sl > SL)
& X" ]) b% M! a- S- `8 t. o& z7 u{ X' [. X7 m2 _& i/ \7 _
negocios.PositionModify(_Symbol, sl, TP);% ?9 |' R3 |0 X, f& @
}$ R P% g# B8 g9 {% L* r5 P: a
}# }. U) I7 J4 R9 B. S+ ]- J7 I) d: T+ |3 h
}
$ q, t. F' n+ belse // tipo == POSITION_TYPE_SELL# c4 b- s& M* I/ @
{
8 x6 h5 r+ ^) X3 V! F( Wif (cotacoes[1].low < cotacoes[0].low)
7 h2 o6 {& r7 L{$ K* p/ c8 c0 J% Q: T) I
return true;
& N+ E3 d( q, w}
! a2 B) u4 \% L+ U" |. b// there was no position
5 ]2 ~+ E0 f2 W1 _8 lreturn false;
+ D! V [* I4 ?0 K+ N% Y}8 L' @1 F" u# e2 w2 o8 t
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。+ C; Q# |' O( @/ e! M
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |