启动交易模型,并构建 EA: K: a, |. E9 w3 A+ f- u/ `; J
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
7 P( T9 {2 c5 l: c! j( `6 X为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
; j/ O: H8 R, g& V/ }6 T以下是制定这些规则的代码。2 J1 j1 e/ B2 o3 B5 x
//--- Indicator ATR(1) with EMA(8) used for the stop level...
/ l1 ~. d* ~! }% Cint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
8 r0 L7 }+ H: z, fint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);9 i/ x1 l# j9 {- A
//--- Define a variable that indicates that we have a deal...
' y) z( r* {( l5 m4 ?bool tem_tick = false;$ C' D! D$ D9 N2 ^7 y* [" ~& w
//--- An auxiliary variable for opening a position# o/ E% u& ~4 j/ l+ F6 N
#include<Trade/Trade.mqh>
2 }7 v3 G! o; M9 d* u#include<Trade/SymbolInfo.mqh>9 e% A" L0 I1 F; T6 ?" f# ~
CTrade negocios;
M' T3 A4 x l4 {1 P, H# z/ dCSymbolInfo info;7 c, e, u! H! P. X, w: |2 R& [
//--- Define in OnInit() the use of the timer every second
T( [- Y$ M! G5 N b/ }//--- and start CTrade
. K8 C" a$ g' H" x1 r" qint OnInit()
9 h6 i9 y/ E0 [. y5 x6 A$ i{
) B* i3 ?; c7 M; z! d4 P//--- Set the fill type to keep a pending order
" y) B( Q) G/ k% R6 D) j7 R//--- until it is fully filled
" f- O$ ^" P) E2 T! pnegocios.SetTypeFilling(ORDER_FILLING_RETURN);. U* b% _7 G8 S0 s
//--- Leave the fixed deviation at it is not used on B3 exchange
9 T* r. a+ x! A% Y5 {; t* B J+ jnegocios.SetDeviationInPoints(5);/ W5 k& D! w$ k6 ?
//--- Define the symbol in CSymbolInfo...0 b( d4 o: e+ l% n7 L6 Y% g' y
info.Name(_Symbol);
' {3 f }# R4 z8 j% c//--- Set the timer...# n- r2 T" w- c& P9 u
EventSetTimer(1);
' {0 C0 i; l& V# N$ T6 t n//--- Set the base of the random number to have equal tests...! W. K2 X% x4 M# d2 T9 s
MathSrand(0xDEAD);
9 M I# X6 h+ B% T* Z" Vreturn(INIT_SUCCEEDED);
( Q/ q( k* r) H}
: P- m# S% s0 B$ f$ Y1 [) O//--- Since we set a timer, we need to destroy it in OnDeInit().
+ c* ?' q5 v( }/ f+ A |void OnDeinit(const int reason)9 Q7 Y9 ~5 [- ~2 j/ B8 ^
{- Z4 x$ N# ^( X* E8 H$ k. G
EventKillTimer();
6 G+ V. S8 N' Q% e}2 c8 N8 f9 i+ q' S6 k3 K% a* l9 [* t
//--- The OnTick function only informs us that we have a new deal
4 M w& ~6 p' r0 b+ x6 avoid OnTick() }' N9 M, n& `% O
{1 j- n! W4 f) n2 ^
tem_tick = true;+ G- ?' ~0 w8 `) U+ f
}& t: T7 X1 J& C* A' ]/ L8 B& \
//+------------------------------------------------------------------+
* x' f. j" O# h. l8 `+ p# D//| Expert Advisor main function |
: I! `$ c" e) s3 P0 n0 T//+------------------------------------------------------------------+
; @( X+ Z1 i3 G; y% lvoid OnTimer()9 j! }, ], `4 G3 v
{
2 m$ ~) @1 z p/ R& k- u0 ?MqlRates cotacao[];/ u" ~9 F/ o2 y% S' x4 y
return ;* O2 L0 Z* n$ v" R$ S+ l7 Q
if (negocios_autorizados == false) // are we outside the trading window?% v6 n5 h# f& d- f9 h
return ;
2 X: d5 J: [( s4 {& _* @//--- We are in the trading window, try to open a new position!) }3 E+ d3 B% C+ p0 J% ^
int sorteio = MathRand();
6 ?8 }: I3 v/ ]! v//--- Entry rule 1.1
$ t3 I- B* G- y- }. x% T2 @, Vif(sorteio == 0 || sorteio == 32767)
. W$ x# D9 ~5 d) h9 b, ireturn ;
; [# h ]! {4 U% |0 ]if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
- I0 G' U# X0 D e9 S{5 Q [7 G0 w+ j" P5 T
negocios.Buy(info.LotsMin(), _Symbol);
$ r6 m7 B( v& n3 U}7 a7 ^" q5 w# I6 P5 ?* c) m4 _6 @
else // Draw rule 1.3 -- odd number - Sell$ `# A1 ^4 v7 [0 D6 {
{2 ]% b8 J$ `0 G& b7 {3 _2 c3 m
negocios.Sell(info.LotsMin(), _Symbol);& I( ]* [9 z( C5 j- f
}
* T5 I4 `, ?% k9 w9 v! d" l}7 g" x4 j( v3 d/ [; a; @
//--- Check if we have a new candlestick...
, c* S9 S& m* J4 W# V) m6 t1 _& B: [bool tem_vela_nova(const MqlRates &rate)' c+ s! i2 ?2 g4 E
{) [! I% I' g# R6 R' R- w" k! k
{
) {3 b$ }& ~4 Y( C9 ?ret = true;; y. X3 C! M$ c$ f, |
close_positions = false;5 W5 v" [, B/ Y8 Y5 E; N
}
( a1 g I& A T8 e8 \+ c- M/ u0 helse0 m4 x4 F& g3 p) z0 y9 P6 I& z
{1 @$ q& q$ T6 ^+ R- F4 C1 j7 G% P e
if(mdt.hour == 16)6 _4 N" M* E6 ?+ y) |
close_positions = (mdt.min >= 30);
' R- k/ s9 r, S# b7 `+ X}
3 ? ?& t# Q" ?* L- h}6 n+ Z8 E9 \! O3 d3 x
return ret;
% A1 G6 u- U2 C}. H# A) \& V. ^5 q1 ~# V$ d3 ^
//---2 Q% m& ^# F8 G7 P# j, ^
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
# P8 D+ }9 _0 i{# T4 x! Y& i* @! h
if(PositionsTotal()) // Is there a position? [2 p2 S! _+ _ k y- f4 I/ R
{
/ p; r) b* j" f( Wdouble offset[1] = { 0 };3 r( j1 Y& T5 \6 R9 d
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?- K0 K2 `3 I6 Q A+ w
&& PositionSelect(_Symbol)) // Select the existing position!- s6 b+ \1 V- i( q. a: d) Y
{& Q9 j) U8 [% e) N2 E' z6 [
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);' @6 L4 ?, n6 ]3 u' y7 `2 @$ L
double SL = PositionGetDouble(POSITION_SL);
) s! j3 `; L% H4 Z m* g Wdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
! J6 b6 Z) Q- a+ r' o5 Q) pif(tipo == POSITION_TYPE_BUY)
3 X/ n2 F l% Q: Y6 Y* @ h: x5 ~{; Z0 q) z' [9 n4 t& h
if (cotacoes[1].high > cotacoes[0].high)$ J6 f' O2 I; d& ?6 K4 p) Y$ b
{" B: o1 g0 G" S) n; P% Y% p+ F
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
, ~2 G- A$ ?8 I4 d ^- E ?info.NormalizePrice(sl);
) |& G% l; _# ], x, g( I; Kif (sl > SL)
( \" z1 \1 U; I% X: ?) ^{- Q& k; t& Y9 p$ h# }3 C
negocios.PositionModify(_Symbol, sl, TP);2 H% H1 k7 O* ^; P& H6 c" d7 d2 t
}
8 x8 q* M' [7 [* \}0 ? z: t! g3 B
}4 ^1 }) O3 u9 d5 z$ T# k; d
else // tipo == POSITION_TYPE_SELL4 h: N$ K* W6 v& w! ~8 d. k
{# i$ ?0 j; K6 P& N7 W% m
if (cotacoes[1].low < cotacoes[0].low)) Y) {6 s# e2 l2 \
{
/ A9 d6 P, C! f' \. t/ o' ]! T3 ereturn true;2 ?( o5 G& V5 S9 t7 j
}
9 [' ?" d; L. E) }// there was no position
4 @0 V" Z0 P5 J% ^5 ]6 ?& D2 Yreturn false;; Y% m- ^& Q# X( L" `
}2 _9 \; ^9 k6 L% r2 ]* l6 ]
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。# d7 P) C3 \5 p Y' F0 H
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |