启动交易模型,并构建 EA
' P6 l. Z+ u3 r D在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。% A6 t* S7 y1 D7 E+ ?4 D$ n
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。 \* b* Z# h8 z4 @5 n
以下是制定这些规则的代码。# b" O" i' E: u6 ^: [+ R7 t8 o- k
//--- Indicator ATR(1) with EMA(8) used for the stop level.... w) I; n) R+ ?; i& n$ y7 ]
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 L# w6 ~- K' j6 C# p# b
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);) R2 N+ \" }2 L* K
//--- Define a variable that indicates that we have a deal...& {7 d5 M# d% b1 r; ^, w
bool tem_tick = false;
3 } |& O5 s: p5 r1 v" g//--- An auxiliary variable for opening a position
- H0 x5 Z( t' @5 y$ U5 Y#include<Trade/Trade.mqh>
$ Y4 C. K( `7 H3 ~#include<Trade/SymbolInfo.mqh>
8 v( m; y% M7 DCTrade negocios;
2 e; P' {% S2 p+ ~- w6 ^CSymbolInfo info;# O' B8 J$ K4 x, y& E7 ~
//--- Define in OnInit() the use of the timer every second
4 f3 L2 E; O! U- N* ^0 m2 l% y//--- and start CTrade; |* h4 j& A9 }- T+ G# J
int OnInit()# _& H& S( E/ P5 e5 y5 |
{6 ?9 t/ c# @ v
//--- Set the fill type to keep a pending order1 w- y/ n) a/ ^8 e6 u5 f* M
//--- until it is fully filled
5 T) E% `7 G% b- A& Mnegocios.SetTypeFilling(ORDER_FILLING_RETURN);. @1 p2 `6 {. ?& Z; x c- M
//--- Leave the fixed deviation at it is not used on B3 exchange- u1 U' B+ `; }$ C
negocios.SetDeviationInPoints(5);/ N9 ~( z% j' y5 Y
//--- Define the symbol in CSymbolInfo...
' z" f+ H9 c9 P% ?7 |4 U/ \, ]info.Name(_Symbol);
: g, a( ]. e: B. m# R! Z Z; d//--- Set the timer...
, Q( m* D8 k% H; t& a" C8 ?: }7 yEventSetTimer(1);8 C! c) I% n8 e0 `
//--- Set the base of the random number to have equal tests...& y/ O5 {4 {! _
MathSrand(0xDEAD);
) ~% C/ Q) j6 l1 C: Q' freturn(INIT_SUCCEEDED);7 I# S( W6 U* `' R! y# i' X- ~9 p
}
* m! k. T/ k7 \. {//--- Since we set a timer, we need to destroy it in OnDeInit().
, q5 R7 m' x, G/ |2 }' ]7 ivoid OnDeinit(const int reason)
0 r$ s8 W5 k; J& n4 |{
. o- ~: L, u! I, y. `7 T tEventKillTimer();
: n/ P Y+ l7 r" a( N% f s7 h" \}
) P+ S( D8 n* Q$ a3 T//--- The OnTick function only informs us that we have a new deal
, ^9 l/ w1 t/ x% a5 Mvoid OnTick()1 x% |/ ?. F( l; \1 u& N" `
{
7 t H+ J( k1 g7 V @0 \% U7 Ntem_tick = true;
$ O1 u# {; L( _, Q$ q}
. \, k D% [/ ]! H1 x//+------------------------------------------------------------------+' D a7 Q% M9 R+ Y
//| Expert Advisor main function |9 x( W6 D( i" N) \+ k$ Z
//+------------------------------------------------------------------+
4 h/ P- h5 K4 P6 E* ^' e* y8 b- Qvoid OnTimer()" F: O' y7 d. f* F9 e
{
) j7 Q$ C9 x7 {MqlRates cotacao[];9 p1 p) c$ O! Q7 Y- d4 b7 l
return ;) s5 o, v/ ^% n+ m+ S7 G7 \) g
if (negocios_autorizados == false) // are we outside the trading window?
: o* o$ ?( d l/ m oreturn ;4 W& L3 U, t& o% j( @3 M
//--- We are in the trading window, try to open a new position!9 h* ^$ i* C2 K8 i. j; G0 L
int sorteio = MathRand();/ _! Z0 P1 G0 Y8 x
//--- Entry rule 1.1& f! y K' z3 `3 ]$ ^
if(sorteio == 0 || sorteio == 32767)
( p; a3 j3 Z, U, X" w4 L3 d2 Breturn ;
& l/ \$ o" N! {$ G8 f4 ?+ gif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
: E1 T) h; m% `- E5 ]{" P0 B b9 o4 x) e1 D
negocios.Buy(info.LotsMin(), _Symbol);6 u2 S8 C, ?+ s$ `" \
}
" y/ c! @+ c# n( R- |else // Draw rule 1.3 -- odd number - Sell
2 f: n5 {& k6 ^( q: l$ n a{
$ o/ Q/ W9 [% x, pnegocios.Sell(info.LotsMin(), _Symbol);* x* i! R8 j) }. F( u _, E' k
}
4 M. @' v8 ]) k5 O}
3 `8 B" |1 _1 x2 k" H//--- Check if we have a new candlestick...- x3 B( d" h! W- K l6 M
bool tem_vela_nova(const MqlRates &rate)
p5 h- z# z$ W, \4 o3 Y' k* T{+ d. v) e7 x. b- m/ `$ G% d
{
( o- ?0 h1 W T& g5 @2 rret = true;
5 s x1 h/ l8 P% X( U nclose_positions = false;9 Y* B* b& _- d& h+ q
}
% E* r9 @1 E( l$ T* ~% velse# c4 e; E. ?! N4 k- V, A: z8 G
{
" U5 A- y9 m# w1 k+ k, E! h: bif(mdt.hour == 16)' J/ j! ^7 y s( [
close_positions = (mdt.min >= 30);
! B; x7 t$ S/ D* o* d}. |. y* P- _5 y: m
}/ ^& z9 K- i, a% |) Y
return ret;" D4 `, N0 ~& ?
}
* f$ \8 U. X3 M2 k$ {* z/ O [! ?0 A//---# f7 m0 r B5 I: q2 R
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[]): P. D0 T2 v# q0 ^
{
/ z9 W' p1 j: w1 R5 }; Rif(PositionsTotal()) // Is there a position?; _& S; I+ S4 v- w" `3 G! ]3 g, X
{& E2 Y, L: m1 u& b2 F2 f
double offset[1] = { 0 };# {0 P* h+ z( a: D: b6 U5 j, w: E
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
- F" m8 z. V5 o; r3 W2 W$ g+ P&& PositionSelect(_Symbol)) // Select the existing position!7 J. W; f" f' A b+ K
{$ m* ?) y9 b. [- e; t- J8 U
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);) P# O/ e8 o# {- v" y. S
double SL = PositionGetDouble(POSITION_SL);
1 N( J3 K7 @. i6 R fdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
! r2 J z! f! X- e' M( q. Eif(tipo == POSITION_TYPE_BUY) M( ^1 S" V/ O( L6 `9 ]
{
) Q3 _+ T4 i4 `1 |) Pif (cotacoes[1].high > cotacoes[0].high)
+ L) Y( D4 I& Y* m' O9 ^{
1 c% @# h7 I3 Kdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- ?" \/ U8 X5 O1 [
info.NormalizePrice(sl);
1 A: e! y2 p* V0 Y( d+ K& xif (sl > SL)- _3 I% J. d. v1 }4 z$ \
{
{7 F; `2 m% B0 Y' bnegocios.PositionModify(_Symbol, sl, TP);$ A U5 C1 U3 x1 D: N* V' w
}1 s' A8 w0 _2 D
}. O; @- p/ Y8 O
}% s# ]; v* N4 ?3 R2 q
else // tipo == POSITION_TYPE_SELL3 j+ Q1 Z( Q& S6 V
{9 ?- n9 s/ F1 b" W- ?& C3 C% |; G6 J
if (cotacoes[1].low < cotacoes[0].low)5 ~5 J5 M9 i' d! r# ?; b2 {
{
3 c6 z3 v3 M, mreturn true;3 ^( U- r% t E
}
- p7 q1 X/ f1 X/ e. }6 A$ W0 B// there was no position
# b% ~' [' m$ M( T. s3 s5 \return false;
) w2 @6 G, S. s* {2 ]: y, L6 O}
4 P- y5 Q2 M$ \7 O: _7 u我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- d2 O& r1 ?9 ]
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |