启动交易模型,并构建 EA
1 `9 F* T, b( C' Y/ r( e在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。' [, F4 H) h2 @
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。1 B0 U. m) V* \% U& i* z( @
以下是制定这些规则的代码。# R6 k2 O% h# |0 r
//--- Indicator ATR(1) with EMA(8) used for the stop level...
( |: W5 s+ q) mint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
; q8 x( v) M" n0 hint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
! y3 S' c5 X" a* H1 L//--- Define a variable that indicates that we have a deal...
7 H2 p( E, p: n% f5 _7 [bool tem_tick = false;4 A) a$ J6 f9 m* O; j
//--- An auxiliary variable for opening a position
% b3 o0 c3 u' b, ~+ u" `#include<Trade/Trade.mqh>
6 p3 m9 c$ x! B% e% _! h6 M#include<Trade/SymbolInfo.mqh>
+ ]6 v* e9 u, OCTrade negocios;2 \1 a g, ~* Q1 \. t
CSymbolInfo info;3 a8 `/ e8 J5 j0 P0 l* B$ q6 A: y
//--- Define in OnInit() the use of the timer every second4 x% T; t4 }4 s! J! T2 R3 k
//--- and start CTrade
5 |. A/ G- _# H1 q$ D1 n- dint OnInit()6 q8 r! B6 K, \5 U; ?
{
) M( @& n! \) e! c8 N//--- Set the fill type to keep a pending order
9 K: _4 l! A- C* ~; r; i//--- until it is fully filled
) y. P1 y: m$ }5 O( p1 pnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
, n6 v; b8 E: m) w! K1 x, Z2 ~//--- Leave the fixed deviation at it is not used on B3 exchange
, S8 {5 H t0 d' n# V, Unegocios.SetDeviationInPoints(5); s9 F/ S5 I# E2 i
//--- Define the symbol in CSymbolInfo...; P! H& ~, p$ ?
info.Name(_Symbol);
2 c" x; M4 T! g$ |//--- Set the timer...
/ k- a2 T0 X% k, J1 BEventSetTimer(1);5 ~ I: \% l' J o% l! C$ J# A
//--- Set the base of the random number to have equal tests...
& a3 L, q& {9 \" M% G0 _MathSrand(0xDEAD);0 M$ I6 e# H6 b; Z2 Q. |2 V& p
return(INIT_SUCCEEDED);/ i/ @6 K" L* S' a
}) \6 a9 f3 `! R% V5 V" M
//--- Since we set a timer, we need to destroy it in OnDeInit().
# X1 c+ Z! d, Cvoid OnDeinit(const int reason)3 O& N5 f1 O, Y/ {* p0 s9 [* F
{6 ?6 {" I% G: w
EventKillTimer();% A/ @9 I( V9 o# w
}) m! n( X+ H( E/ l5 K
//--- The OnTick function only informs us that we have a new deal4 ^+ z" e% z6 P# n
void OnTick()5 R; e) A2 b- a, k& f7 W; |) g
{, w \ X; Z" y% L* x
tem_tick = true;
- t5 b; k: {/ J7 G9 g* Q; c5 E: R}
1 ~+ ~& L6 q- l8 a//+------------------------------------------------------------------+- X) f( R; a2 H& S8 p8 @7 @, K* J. C
//| Expert Advisor main function |1 @1 U5 [1 s1 z' \
//+------------------------------------------------------------------+
- I n& G1 k! i+ ^1 d% ^2 nvoid OnTimer()& K2 J$ I2 v2 N
{
# S" r1 M5 C' W1 C8 |; B- D3 jMqlRates cotacao[];# p' G X) b- Y) K+ O+ x
return ;
% _0 u2 @; Y6 s" Mif (negocios_autorizados == false) // are we outside the trading window?9 L$ P& \; f1 |5 H3 k+ k
return ;
. T8 ?1 y5 s$ x, C1 N* C* C//--- We are in the trading window, try to open a new position!% q T- O) @+ M! X) D
int sorteio = MathRand();
/ e+ J$ e' U6 W/ C4 r, l, |; ]//--- Entry rule 1.19 A- J. O/ _' x0 U" h9 }
if(sorteio == 0 || sorteio == 32767)
) v; @" Q4 i9 nreturn ;
0 R( F7 Y* L8 J7 G8 gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
) e: x& X% Y( D{3 A2 x9 d1 K2 |9 C, E7 R5 a/ A7 K
negocios.Buy(info.LotsMin(), _Symbol);7 I: m0 J+ U+ x, S0 |) o' I6 N/ z7 q
}
# G( Y+ X3 J& delse // Draw rule 1.3 -- odd number - Sell2 o$ |* W: Z# C+ @
{
$ C' U# z6 ?6 x: Z5 anegocios.Sell(info.LotsMin(), _Symbol);
! C( ~ G. h' k5 p2 x9 f' B}( ^' l) S$ X0 e3 ]# ?" G' W) A
}
9 J0 u* N9 [7 y' [( O//--- Check if we have a new candlestick...1 t, y( ?+ \1 H4 w
bool tem_vela_nova(const MqlRates &rate)
) b" X2 P' `5 k+ l; _2 b{
' v3 r" ]+ F: p( R{
- @% K7 ?( c* r0 R Nret = true;
, A2 Y& E {* p pclose_positions = false;
4 e; F6 L. }3 d% L/ Y}. T/ v+ v: k! }$ k7 w$ x
else6 ]) H0 o. k0 k& M7 W" p7 W- T8 H
{
1 B6 E# Q) {; R; X; n/ H) X$ Uif(mdt.hour == 16) U' n4 o; n- L
close_positions = (mdt.min >= 30);
2 O3 {0 Y- @+ m z* }1 O: B}0 O1 a% p' u0 I, Z$ r9 T0 {9 b0 I
}+ ^+ _# c/ q0 T7 L z
return ret;+ @8 V. f" O; i" p
}- E" w6 {: `4 r4 d/ B/ q
//---
5 ]* `# ?9 a3 h4 Wbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
" Q' |: v2 c( v# u; _; _& G: R @{
: e) J) p l# Z9 F9 Zif(PositionsTotal()) // Is there a position?) x/ j; l7 h( R0 U
{
4 W3 w* p4 \$ X# K$ C* b' I1 Vdouble offset[1] = { 0 };7 d4 A P3 z8 d. K) u8 a! h
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
% b. [, a# n- O&& PositionSelect(_Symbol)) // Select the existing position!
1 B8 M3 x K6 e- @5 i$ t6 O& ?{3 c& U8 Q0 Q$ ^
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
* D+ i, u. Z8 C; ndouble SL = PositionGetDouble(POSITION_SL);
5 J( D) ]4 e: r. h$ Ldouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));4 O8 `9 p5 T- n; [ A0 H
if(tipo == POSITION_TYPE_BUY)8 x7 H U( p% |
{! K7 @% H0 h4 p7 Q8 q
if (cotacoes[1].high > cotacoes[0].high)
; D9 T* Z7 M0 R9 x5 x. B{
3 K+ M1 [4 w+ t0 d9 }/ u' N2 Vdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];: a T6 j9 G7 l$ q5 e4 I
info.NormalizePrice(sl);- |" E4 g6 O( H5 Y6 F/ Y" [/ I) Z
if (sl > SL)% [* C! |' V- h1 D0 ]# A
{
: s% W. {' N% I. lnegocios.PositionModify(_Symbol, sl, TP);
# ]5 K; H9 s: @. c+ o0 n}9 L( j8 I# B6 I T* A4 H
}
# N6 ]& r: E/ X3 y- i- z) e}
6 c9 D6 g' m2 B y" y6 o5 j5 \5 Nelse // tipo == POSITION_TYPE_SELL
8 M% W- U, y% L. B{
: J8 h+ c7 H' Pif (cotacoes[1].low < cotacoes[0].low)! U" g! ?1 y& w0 p# v) j
{
7 g! E. r0 d1 @return true; y$ ]9 m p7 }1 q1 G& u
}
" J0 t. A* B1 g" p5 g8 E8 p g% M// there was no position1 n* \+ T2 x& ?, s
return false;
9 H& Z5 R$ P6 ]: u& x}1 _* `! T" t7 J: Y1 F9 l
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- u8 a- s! [+ }( c0 T
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |