启动交易模型,并构建 EA" s7 Q( g+ e; ?% v' l) R
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
2 M; p$ _/ [/ _/ T* W! l' X为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
" P( P6 J4 n, r. K6 F以下是制定这些规则的代码。# K$ K, J H7 E
//--- Indicator ATR(1) with EMA(8) used for the stop level...+ r/ Z) \. v' ^+ @/ J0 A; r9 z
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 ^! C* F% k$ p1 i+ k2 M$ j
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
' W0 }3 J2 W4 r2 v//--- Define a variable that indicates that we have a deal...
' p" d4 T/ h8 p0 qbool tem_tick = false;, v2 v; ?6 {: x
//--- An auxiliary variable for opening a position
4 O2 M0 V& d3 p' j$ \ E" d! |#include<Trade/Trade.mqh>$ ~* w+ Z9 p9 g! p$ z& ]
#include<Trade/SymbolInfo.mqh>
9 `$ a; [& ^2 ?$ s$ x) w; t1 H* XCTrade negocios;7 D! I* v: ~. M9 p! a# n
CSymbolInfo info;0 `( t# C _9 j" ~8 ?3 Q
//--- Define in OnInit() the use of the timer every second
' `1 A3 D# ^* [+ o! o6 Q/ `//--- and start CTrade& y4 b2 t8 w. r
int OnInit()
4 C. W" |, i- x0 C0 x4 ]7 R0 Y, e{2 i; U1 \, Y' P* [2 Z' F0 C
//--- Set the fill type to keep a pending order
) i( V, n8 c, f( s% y//--- until it is fully filled5 {6 Q. z4 ~6 n
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
4 k1 q$ e% `) q- b, r: c" b- T% p//--- Leave the fixed deviation at it is not used on B3 exchange
3 r3 s- P8 c' r- Enegocios.SetDeviationInPoints(5);
. `' x% w, @5 X+ ? l" f//--- Define the symbol in CSymbolInfo...
$ ]. M% Q0 o$ Y- x4 L9 ninfo.Name(_Symbol);
, K( E, {( R9 U! q//--- Set the timer...; {6 ?2 P8 ^1 S o2 d+ O* e( H' u
EventSetTimer(1);
9 t) [. o! p5 K. g//--- Set the base of the random number to have equal tests...
2 `+ Q( X2 i2 F% ]% K9 L6 PMathSrand(0xDEAD);
7 O* C4 w7 R/ [ [1 I: n% rreturn(INIT_SUCCEEDED);
: n2 P! Z$ c7 |}
/ v C# I5 j+ e" R//--- Since we set a timer, we need to destroy it in OnDeInit().: s% h7 r9 r# V* M l
void OnDeinit(const int reason)
, L1 K/ W% ^ p& r7 A) l{ d/ v- A( K5 ~8 T- F( h
EventKillTimer();
# c4 ?1 r' ^ A6 _7 |" Z}0 U' ^5 q5 u* T7 u% C
//--- The OnTick function only informs us that we have a new deal
+ B: t+ S8 k& F. l' e4 E7 H+ Z( y3 dvoid OnTick()
9 A4 a8 Q/ y2 t$ n$ E{
% c, e/ x5 B1 f% c. mtem_tick = true;
1 T* l% N' I* w. V. t}
2 ?& i7 J2 ?* H$ r# T* h//+------------------------------------------------------------------+( X& x& Y0 T& I3 Z4 Q4 y+ ` j
//| Expert Advisor main function |, a& h8 k8 [, p3 v' y
//+------------------------------------------------------------------+3 A( ?; `! @3 z7 ^
void OnTimer()
V% a4 D- d/ {5 s{' P8 R+ H: R& x t; [
MqlRates cotacao[];: I5 x) e7 i1 z* u
return ;" O. j5 W: w* [, P' O% N! g
if (negocios_autorizados == false) // are we outside the trading window? q8 t4 G" X, O$ J
return ;$ d# C$ ~" Q- O; t
//--- We are in the trading window, try to open a new position!* [) o* M" w2 Y, l, [9 F' O
int sorteio = MathRand();! H: A; w# k# {3 E
//--- Entry rule 1.1
* S4 }/ U. l! ]$ }9 K+ g0 iif(sorteio == 0 || sorteio == 32767)
: _* M- b; e. }5 m9 F2 Oreturn ;
( d5 O5 ^$ ]( P0 p* L3 u) q1 g% cif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy6 b& p' b- {/ H/ p
{/ h& \: K8 p ~0 E1 m" `5 g
negocios.Buy(info.LotsMin(), _Symbol);
# q) J1 v9 F5 } n& m}4 N' {5 f: _3 b
else // Draw rule 1.3 -- odd number - Sell: r$ d" r- y' G4 O. Q0 i
{ a" _% x, O& S
negocios.Sell(info.LotsMin(), _Symbol);5 I. k# b6 x$ V% B6 ?
}1 z* C0 L. d3 x6 ^: T
}
0 i5 C3 v0 u( a# V# V//--- Check if we have a new candlestick...# E8 J7 O0 w% ^& P% e
bool tem_vela_nova(const MqlRates &rate)
2 J4 q8 L" H" N0 S8 ^% z{
$ a5 B; ~2 W( h- U3 G! ^{
% m5 [5 {+ T" |& rret = true;
4 S$ K6 E$ ~: u* d0 d- ]3 tclose_positions = false;
+ F, |! ?& d9 n: [& S, @4 T}
& ~0 {% |* {& L0 A, A& s, Felse2 n& ~! Q4 g( `# j# J' E$ A
{
$ D6 l$ k7 h7 N1 U0 ^; Yif(mdt.hour == 16)6 \0 G4 s2 Z9 t* O: E8 |) ?' _% q
close_positions = (mdt.min >= 30);% P# K& e" B) [/ J) r: X
}3 ~9 B% R6 P, q0 [2 J; U5 B
} }) t6 {: c9 V% g+ @* x" ? E
return ret;
3 c1 L, u8 x4 l: J! Z0 @}9 z: A C) C) _
//---
W) `! J8 l( W: @5 {- }bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])/ V6 d! {+ V3 A. D9 J4 {
{* v1 E* `, |' c: H$ M4 `
if(PositionsTotal()) // Is there a position?, t: S* u8 G, t
{
. L- L5 b5 V7 pdouble offset[1] = { 0 };
& L4 l" [$ Z: T" e% Wif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?3 A/ C$ i# W' R% S
&& PositionSelect(_Symbol)) // Select the existing position!
3 V* |+ i0 r [! k, F6 s0 ^/ b1 C{
$ u& d9 i/ s% qENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);. c7 c. f# Z1 ^9 d8 N/ M
double SL = PositionGetDouble(POSITION_SL);7 r X B6 d8 F( y: Y% q
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
2 W* Q/ b1 r% i% n$ `( xif(tipo == POSITION_TYPE_BUY)
: Z0 l5 `& |/ {3 c{, o* d9 N( T4 P+ }# t& K8 _/ N
if (cotacoes[1].high > cotacoes[0].high)
+ x: @" E: Y& g{
3 @' X% m/ E4 k, I F: u' }& c1 Udouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];$ S/ h7 F7 P$ A, L( i( \
info.NormalizePrice(sl);9 L5 b; @0 V7 Z
if (sl > SL)
4 S: @. Z0 G9 E6 C, k& G8 B' U4 a{
7 D Q+ o5 n2 ?9 E: Y; [& G) wnegocios.PositionModify(_Symbol, sl, TP);
+ N) Z, ]" @ Q5 u}
! S: S. c' B7 j9 n8 k}7 W+ p w# _7 i4 ^) ^
}' U/ L! ?2 v" F3 M
else // tipo == POSITION_TYPE_SELL
9 a% J- L/ H' u) i8 d7 O{3 T+ ]: d( Y4 W2 X. N; ?
if (cotacoes[1].low < cotacoes[0].low)
, r; y' O, ^1 M9 |! l' R{
( O" R& O4 y+ D* j# G7 `1 `return true;
: d6 E( I; y# k3 u$ j. X}9 c6 E! C/ H6 G) d+ v" K2 I
// there was no position
$ r8 Q( \7 A8 H3 ~return false;
7 T6 U1 Y5 l! B( v}
( R+ C2 K2 u# D* }我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。, B! m+ p' w8 {' ?1 L
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |