启动交易模型,并构建 EA
( j" {& @; D$ M* F j在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。3 G% Q: @" L& o. U$ o$ ~! C& |
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
% U$ q. F8 e+ {/ R. S# M2 K) q以下是制定这些规则的代码。
4 z; N" K! @# Y) S//--- Indicator ATR(1) with EMA(8) used for the stop level...
( t' H) G- Q0 b. |' Uint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);; y( D, Q* E- p& x2 H
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);6 m/ U; ^% Y7 `, N- e6 I# K) X
//--- Define a variable that indicates that we have a deal...# c! N# ^7 {( b
bool tem_tick = false;+ G/ O% H- z9 i* x
//--- An auxiliary variable for opening a position
# ]2 T" K( k' R! |8 j) R3 J$ |#include<Trade/Trade.mqh>
( c% ]. t* Z6 ^4 |) q% V: k9 U#include<Trade/SymbolInfo.mqh>3 g/ L" N! x6 W/ y9 f' k& W
CTrade negocios;
/ `6 i$ g" E9 Z9 ?CSymbolInfo info;! F( c/ Q& F; u H& T- F) r
//--- Define in OnInit() the use of the timer every second- r2 l$ N( E4 _" \0 D- a; N* u
//--- and start CTrade
0 w. L$ N8 o3 i G( Z( dint OnInit()4 I( S1 j- w }: ]; O- {
{
, _' D/ N( @2 p- D//--- Set the fill type to keep a pending order$ P: n0 v' z; j& T6 T$ q6 W
//--- until it is fully filled
( S+ ^ ?2 J$ i1 e: h% N3 i* wnegocios.SetTypeFilling(ORDER_FILLING_RETURN);* Q( {: d8 E- v% n9 b% s# {
//--- Leave the fixed deviation at it is not used on B3 exchange7 d R, j( x8 O6 X( Z0 e# V
negocios.SetDeviationInPoints(5);! {2 X9 x" [# N4 {, z4 ?0 j
//--- Define the symbol in CSymbolInfo...
" ] }) ^; t7 L! G+ linfo.Name(_Symbol);9 W6 a7 t; J2 k" F/ ]3 S
//--- Set the timer...
! _6 D8 u' v. MEventSetTimer(1);8 c8 d7 Z7 d6 b1 N, r X
//--- Set the base of the random number to have equal tests...- }: `/ S. @: k- E6 n8 d5 A l
MathSrand(0xDEAD);
8 z& q1 R; \3 K( Nreturn(INIT_SUCCEEDED);
# b5 S* G2 Y$ X}
: g" I0 N/ y9 N" H T//--- Since we set a timer, we need to destroy it in OnDeInit()./ C. U/ K0 P" a
void OnDeinit(const int reason)7 S) e9 P5 R! l) P& L3 A# ^
{1 t+ n- C7 K4 s
EventKillTimer();% R9 G0 S8 N+ {, J7 `' s) P
}- `' i1 ?4 u/ T7 c3 f! \
//--- The OnTick function only informs us that we have a new deal# D- `( b! _& `9 R% ?
void OnTick(): f2 S1 f& Z- J& \- c- b3 d
{ j! A' v( N& k- m& `
tem_tick = true;
+ R6 {2 v# C! @! u/ H7 Y% Y+ n}
) G- _8 l1 g9 \5 C% m8 W* B) ]//+------------------------------------------------------------------+; T6 a& v9 ^8 B* s
//| Expert Advisor main function |5 O1 r. w) @ V" Z0 X
//+------------------------------------------------------------------+
3 h" F; G: m+ }1 b; Bvoid OnTimer()
7 V9 l$ X9 |' u9 g1 B$ T: n3 T2 Q{* J0 v* U' n6 ?* p5 u
MqlRates cotacao[];& @' z5 z/ u9 ^# J: k$ A6 ~
return ;
) O7 n, L6 [+ J; w; u2 nif (negocios_autorizados == false) // are we outside the trading window?/ O2 a# |! P' z/ x2 \: I( p# {" S
return ;6 m$ J+ @0 p* } B
//--- We are in the trading window, try to open a new position!0 \8 S# K' e2 c$ T% i
int sorteio = MathRand();
; t8 a+ D6 W) L) C, K3 Y//--- Entry rule 1.1
% L& |& x! R2 `if(sorteio == 0 || sorteio == 32767)1 T9 ~7 L$ K$ Q, k: d% W6 n. y4 ^2 _& p9 ~
return ;
1 B+ X9 ^1 ]4 d2 X; Tif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy! C F G+ V0 m" x
{6 z5 i9 a9 G# b# ?9 k
negocios.Buy(info.LotsMin(), _Symbol);6 t8 _# q- d4 f4 `) z
}
+ ?1 H2 {3 f" j- [0 z# Qelse // Draw rule 1.3 -- odd number - Sell
+ W! o" y# e/ F{* }6 }+ N$ s$ {1 p& ?! c" j! q; I
negocios.Sell(info.LotsMin(), _Symbol);
3 q- e2 r* }3 ? |9 p}! k. f& r5 h ^4 `; i1 d% v
}
' T" q. J1 a& q9 V+ D3 m- ~# p//--- Check if we have a new candlestick...( Q3 W& B0 {4 v1 A
bool tem_vela_nova(const MqlRates &rate)% s" R% i+ x. M8 u( |8 j
{# a5 j4 Z% S% c$ p! a
{/ M5 P; ~6 Y6 K4 q9 U# Q
ret = true;
7 q1 T: U5 R4 i" d6 Lclose_positions = false;
n2 }0 w0 U# E T}- ~7 _5 v: U ?' u( Z* q+ I' O
else
: k. V# F$ d2 E1 [: ?! y4 Z1 w{: W0 n& J7 w0 ]7 f
if(mdt.hour == 16)
: U- J9 S) b1 R4 O/ {close_positions = (mdt.min >= 30);/ G& K8 L, v$ o- ?) C/ J
}
. |) O! q" i! m( Y( L( M2 Y* v/ j}
0 L/ |+ _% |% N7 ]: jreturn ret;
j# {3 W, Q' n, v* k}
1 W$ w# d! G& c! {8 J( l9 _//---
) z2 L/ E; o7 C5 ~; b% }3 Jbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])$ m) Q1 ^/ u: m
{
) F# _; r. R" N) A. Rif(PositionsTotal()) // Is there a position?* C! \$ S5 Y( t; v% E9 u
{8 t6 w4 ?; {+ a2 r0 q
double offset[1] = { 0 };
5 E: g8 ~5 }6 i0 l- ?6 z* @. z1 lif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" L# H/ D9 V1 n- z3 ~5 ~&& PositionSelect(_Symbol)) // Select the existing position!4 L B* d9 C+ P
{. F% z6 R7 G/ C% L
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);* ]6 Q2 U, Q7 e7 [; a5 `% f
double SL = PositionGetDouble(POSITION_SL);
# d- C+ C$ Z- Q1 I* M# Zdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));; }- ^; A C+ I
if(tipo == POSITION_TYPE_BUY); Y( N9 z( `3 r' U1 h0 [; w9 Y1 ]
{
$ e( l/ N/ d. b/ b) i- V- Zif (cotacoes[1].high > cotacoes[0].high)
" a7 J/ Q. b& N& Y: v# ?{
( n' a6 J' Z4 E7 Zdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
1 F6 Z& V0 C5 g M4 E: Yinfo.NormalizePrice(sl);( M8 d; v) z6 j( z8 @/ N/ ~8 K
if (sl > SL)* e e4 J% [7 z: O: L% p* P
{
9 Q0 a, j1 `4 ]. Unegocios.PositionModify(_Symbol, sl, TP);
) B( d) H9 C7 ]/ |}
# }) Y; a) E1 P/ l! l8 V: t$ h9 l}; }1 I4 m5 @0 P G# ~
}
( L4 S( g% e# b j' Aelse // tipo == POSITION_TYPE_SELL3 m( F0 w* ]6 A# x
{
8 s4 e( W6 V* Tif (cotacoes[1].low < cotacoes[0].low)
0 ]" I/ J1 z& Z) X# j* N/ r- W{
6 _5 g" H* k5 d! o2 ]return true;6 h+ Q4 V' Q% S" I5 s, |
}5 z$ P5 m x2 d$ q4 B
// there was no position
3 m% }6 H: B( zreturn false;+ |. |/ J( @& x
}
0 i9 `; u t$ I. g我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。 q3 d4 v; L. D& I$ K0 t, g; N
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |