启动交易模型,并构建 EA
, k4 }1 o9 q/ n" o+ g* [' g2 u- P在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。) C0 f u- d. Y) B% Q% l" Y2 h# V
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。) |# u4 H( v; o/ `+ J% T
以下是制定这些规则的代码。
. T. p/ [! s1 B& _" t//--- Indicator ATR(1) with EMA(8) used for the stop level...
3 m! N$ e4 Y: I) b1 }( \ yint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);! y5 c5 s3 N( \8 p7 P$ l' G; \$ F
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);" E4 B2 s" K* K# X
//--- Define a variable that indicates that we have a deal...
9 O/ k5 N$ O& L% [: p5 j. Nbool tem_tick = false;
( o" t) Z6 f+ e! n Z( L8 l5 d( j//--- An auxiliary variable for opening a position
4 U$ e; \& J D) U5 U- \#include<Trade/Trade.mqh>" x' p% a" O% N7 v5 t, ]- @4 X; l
#include<Trade/SymbolInfo.mqh>
7 P/ `, L k3 w9 m, `CTrade negocios;
9 [& c7 Z) x7 k$ |: H. kCSymbolInfo info;' d2 s3 h( ~! h, n. b: o {
//--- Define in OnInit() the use of the timer every second4 I1 ]! r* I1 \5 r% j0 ^) q
//--- and start CTrade$ T. |5 {: F( h, m: [6 f: s+ W
int OnInit()( b E) K1 S! G2 M$ u7 R
{7 |; I% \3 J2 M- y- L
//--- Set the fill type to keep a pending order4 V# S0 c5 b0 b$ Q5 l4 O+ o6 G
//--- until it is fully filled
* Y8 M/ f! e- q3 w" Znegocios.SetTypeFilling(ORDER_FILLING_RETURN);; ~5 G9 w5 N! {" H; s7 I& S
//--- Leave the fixed deviation at it is not used on B3 exchange/ M: S6 s5 D$ w- J" W
negocios.SetDeviationInPoints(5);: Y4 t' |: e/ M: ^& [
//--- Define the symbol in CSymbolInfo...9 P) z. f6 }- c3 B" w2 u1 R- R/ g
info.Name(_Symbol);8 I2 t" z8 L9 m; ~* P
//--- Set the timer...' E1 W. v Z F
EventSetTimer(1);0 j" h ?% d5 r7 q) h
//--- Set the base of the random number to have equal tests...
5 ~, V# U/ K4 fMathSrand(0xDEAD);( a' H( [8 M8 k& W P% N% x
return(INIT_SUCCEEDED);/ v( w! s/ v5 I. @; C
}2 _" A: _; N5 D4 U0 ~! g
//--- Since we set a timer, we need to destroy it in OnDeInit().
( g0 H) @ w& Avoid OnDeinit(const int reason)
6 Z. x' u+ s4 A# V9 U3 q{3 F5 b8 |) }5 p
EventKillTimer();' I3 D4 c) x/ j5 X( l+ y4 A
}4 @- [0 B+ R; ]. ]
//--- The OnTick function only informs us that we have a new deal
# F; n0 I }, y9 g$ Bvoid OnTick()2 O; o# `7 N& b$ Q! X# e
{
- N( j/ A9 e9 y2 m) ~4 [' [! dtem_tick = true;' p8 C/ r5 P, q9 N7 |& N# L/ b! s
}
+ f9 I, O- S- g4 t& a//+------------------------------------------------------------------+
+ a* \0 n4 a0 I2 {2 w6 u( B//| Expert Advisor main function |
$ I1 B: @( C$ m# K% s. Q//+------------------------------------------------------------------+
9 n% b/ A! |9 N, n# X6 Svoid OnTimer()
8 W( l) S A2 C{
4 f# k+ @& G& u f: yMqlRates cotacao[];
; P, K8 d; X; _+ p) j& lreturn ;
) m; K; V( `! r2 kif (negocios_autorizados == false) // are we outside the trading window?
8 ?# o9 B" I, ^return ;
% S$ q/ ~8 E- F+ y, R7 p% M//--- We are in the trading window, try to open a new position!+ U% W2 c9 R' E( @
int sorteio = MathRand();+ }' x7 ^ u% K$ B
//--- Entry rule 1.1
/ }8 E2 P% J4 z6 f) r/ w" T Y. Lif(sorteio == 0 || sorteio == 32767)% H; f5 l2 r7 `. y) e
return ;
: a+ Q. O0 l! J/ r ^9 @: Fif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy* p9 L2 h: E1 {/ x1 |5 X+ Z
{2 k$ h+ S3 R* R- v* z) G1 x+ h
negocios.Buy(info.LotsMin(), _Symbol);8 w2 \3 c$ d* |* t+ ^; g
}8 a9 p. o- E6 M" [
else // Draw rule 1.3 -- odd number - Sell. M- J+ V. F5 E
{3 ^( V' n( H& `( z! }
negocios.Sell(info.LotsMin(), _Symbol);: ^" Z8 ?% S- v, e
}
! p+ P: T+ F9 |- _" N. ?, p F}# y: x K8 i. O8 {& ]* S
//--- Check if we have a new candlestick...0 ]4 p i9 f$ h( O* N) }
bool tem_vela_nova(const MqlRates &rate)( S& w! u1 u: I I! }
{
! t) l/ K9 s( d% M0 Y( }) ?{6 n2 ?1 ~9 G. a# a- F/ q! l
ret = true;
" z2 L4 ?/ [# I% eclose_positions = false;
: Q2 d) e0 I. m}
$ j, M6 p& H& Oelse
4 v8 u, O7 M2 `( K- ~{
0 s& h* E3 z# S& R7 L% cif(mdt.hour == 16)
/ H) L! f# \) O* |- u% eclose_positions = (mdt.min >= 30);
; S3 z. D" i0 k! N' R/ Z}& k7 g1 k1 m B& J1 |
}2 c. b' q% Z8 z( q( r. \+ B
return ret;- @" \$ m" [$ s/ K# r
}
6 ]6 h) [ v( z+ m0 w5 `//---* x9 d1 C' V) y3 ^* Y9 o1 T
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
0 ]" d! K4 f5 E+ {9 C{1 J9 @. N% O" _( z. H
if(PositionsTotal()) // Is there a position?
1 b0 q0 j, P& v/ ~2 A$ @{
8 S6 a2 t! s/ b4 z* m/ S" Udouble offset[1] = { 0 };
+ T* H: g( t- k k5 Iif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
6 G; p- w- N+ c- E! X8 ~, V/ F7 l8 k&& PositionSelect(_Symbol)) // Select the existing position!
& j# D7 X& t- p$ @9 `) w# l7 K{
& c) L+ Y* r; G3 [: y3 [, L lENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);: F* a! H- u5 A9 H) L% Y$ F- S
double SL = PositionGetDouble(POSITION_SL);! [' n7 _3 o' ]
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));2 G# k, g" s4 j+ G/ Q* k( F7 e& @
if(tipo == POSITION_TYPE_BUY)
5 v- N8 t( g- N) G{
+ X( [7 ~8 x" Z9 {8 D2 f Rif (cotacoes[1].high > cotacoes[0].high)8 Q8 @5 a! g3 ~5 }$ ^
{: B. V% S) w% x
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];4 Z( v( e7 c0 Y
info.NormalizePrice(sl);
. F9 f/ h4 {. [- U( g- fif (sl > SL)
3 h' V% s" r W( E" e, R* ^{* l9 ^; n8 w0 t: D1 P: E3 w! a) ^7 T
negocios.PositionModify(_Symbol, sl, TP);
" w/ B# u3 J# H3 y% @4 \ t0 }2 X}
4 G: ` X! h( v4 V/ y" h1 k}6 W, ]4 m9 d( a3 t! H2 n% u; [- ~
}
( X0 X( s2 w J. m8 jelse // tipo == POSITION_TYPE_SELL
3 q( U% h& K: s& q) p! z. H8 y{
4 C8 g8 s- a3 ]! `$ Pif (cotacoes[1].low < cotacoes[0].low)3 V( G' l2 \& E7 ^$ B. I" {
{
+ n5 D) v. Z4 B6 P2 g8 zreturn true;; T' }8 B7 Z' |
}
, L$ y. A7 T# _! H6 ~; p// there was no position& |; b [: k) `+ f
return false;
1 V: g* {( f8 R+ q} A# ?, ?: o/ v
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
5 y. o% Y+ J2 V到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |