启动交易模型,并构建 EA
: y: U: F! c5 d; _5 I; b在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。% F% g+ a5 d6 J
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。- a) L+ |- F/ p" P( F, V
以下是制定这些规则的代码。
% l5 Y0 d/ |6 S4 U2 `8 a+ i# W' p//--- Indicator ATR(1) with EMA(8) used for the stop level...3 L2 A) g/ |; I9 X0 _7 a9 {+ t
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);4 ~: {9 c$ S: m, h4 \: C3 v ?9 G: ~
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);7 G" ~0 R5 c* M8 Z
//--- Define a variable that indicates that we have a deal...
+ d8 p* m- N5 ]! O" N5 b g! }) Kbool tem_tick = false;
+ F. f- e s; @+ f# H8 m//--- An auxiliary variable for opening a position$ @7 g1 o: X6 D6 o6 M6 l: _1 z% ?
#include<Trade/Trade.mqh>! U7 v+ V; q8 L* N# k2 m; e7 h
#include<Trade/SymbolInfo.mqh>! [( x( r9 x$ B. a1 ?( I
CTrade negocios;
# }( e/ L f2 f# M7 d BCSymbolInfo info;* y) i3 u; l7 Q
//--- Define in OnInit() the use of the timer every second p- H: M2 h0 u6 p$ ^% W: ^
//--- and start CTrade
* R4 f: I6 O" P6 ~int OnInit()
2 |6 Q; R8 i ?0 i# @{
3 ? ?: B4 H: }//--- Set the fill type to keep a pending order
2 w2 z. l6 P7 I. f8 i//--- until it is fully filled
0 ?0 X1 M0 R5 {% rnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
6 p1 D$ p/ X: U//--- Leave the fixed deviation at it is not used on B3 exchange, ^2 N7 A& Z4 X3 g! x
negocios.SetDeviationInPoints(5); Z* Y" e9 z4 s: C! f7 x/ m2 M
//--- Define the symbol in CSymbolInfo...; N. \# @+ r3 s; {. n
info.Name(_Symbol);
+ \1 a5 ^8 e p. N//--- Set the timer...$ h5 j2 v) v/ ^
EventSetTimer(1);2 ^. w9 r! p0 f, [
//--- Set the base of the random number to have equal tests...; m9 ~/ i" K: d: d1 ^" J
MathSrand(0xDEAD);4 V3 m8 X% g/ }# b0 ]
return(INIT_SUCCEEDED);
/ E/ t/ O9 V" z3 r}
3 q$ M) X- P9 ~) w8 G: `5 x//--- Since we set a timer, we need to destroy it in OnDeInit().
" T7 r* Y/ ^6 evoid OnDeinit(const int reason)/ r4 i" m# g* g* P) i$ u, _
{3 X) G# _. ?8 M4 ?8 e% J' e8 I
EventKillTimer();; W3 H' Y8 y. l% ~
}
' \2 C; ~! P4 @2 m% z; y//--- The OnTick function only informs us that we have a new deal
# x, F% b0 T2 E0 [- o' S. zvoid OnTick()5 o* i# q' ~+ Q$ L8 \) U7 Y
{
5 L8 ^7 v, s; r v. Qtem_tick = true;
4 v& _+ f/ }0 j}
3 y1 ?4 u+ _# q* h6 R, F1 L7 {( r//+------------------------------------------------------------------+
5 A; M9 n6 X7 z5 c//| Expert Advisor main function |
. s& R. _6 h$ ~& ^* O+ N# e4 E& h. B//+------------------------------------------------------------------+" z9 L0 }, P7 ]
void OnTimer()
- Z. ]& |! ^( D0 T{* H& A! i9 n6 A, K# C2 {
MqlRates cotacao[];- L$ |" S) u& K# }
return ;: z, `4 o+ t& ]% K6 @
if (negocios_autorizados == false) // are we outside the trading window?
+ Q5 D7 l7 o7 x* treturn ;8 `$ @7 a, Q" V
//--- We are in the trading window, try to open a new position!
0 m" U% _1 Z5 {7 H2 iint sorteio = MathRand();
2 h8 i W* _/ F$ d+ p: a//--- Entry rule 1.1 Z+ l1 q3 I" S' P
if(sorteio == 0 || sorteio == 32767)
4 k$ y; u2 _5 Freturn ;
/ L4 A$ Z& I# x' u% t: ?if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
) p2 i9 J0 M: D9 }7 d% j2 t{
5 c9 }* x' T* I. j8 z" Z! k2 @- inegocios.Buy(info.LotsMin(), _Symbol);. |( ]; p5 G N4 C: Y. K
}& L; [% ~9 Q2 s# W
else // Draw rule 1.3 -- odd number - Sell" w6 s, A: z& x9 K m: v
{
' R5 q; K. F8 f8 P" @$ h% ]negocios.Sell(info.LotsMin(), _Symbol);9 M7 u1 W7 V6 } s- @1 j
}
+ b4 _- `$ I( `) v3 L) P3 C}0 q5 _+ ?. P9 Z5 ?; [" X0 |
//--- Check if we have a new candlestick.... l. G3 y$ k! X
bool tem_vela_nova(const MqlRates &rate)
$ O8 }. O1 M- O8 _# o, ?{
/ p2 w+ @( J" M+ Z2 j% k{
) n! O5 S$ P kret = true;+ T5 x/ V* r1 Q, h/ n2 h
close_positions = false;- _# F) R- F8 {* ]# d& k0 t
}
, D% w) Q/ c3 [. e6 K; Ielse
, K; m( B/ I9 t& l- `) {2 k6 r{5 `! E' L2 P' x; \. M* ]7 O
if(mdt.hour == 16)* I# P" f. ?# Y8 g/ I7 B
close_positions = (mdt.min >= 30);
( {% ]: x v1 L- @' t}* C% Y! \5 `- q' |% ~/ l9 a
}; g! ?5 X9 N8 b, `
return ret;. Z+ |! {( ?2 c& v2 N
}
; r4 T% w- d" f1 V& ~7 y//--- _6 H7 |7 B" ^6 S+ X$ C
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
7 e3 |9 a5 S) `0 V+ G0 }{
2 g* P4 z; m5 A5 Aif(PositionsTotal()) // Is there a position?1 Y. ]9 }3 j: e0 Y
{
- ^, \( m' ~# z4 g9 l) c4 Vdouble offset[1] = { 0 };
5 o* X3 F2 ^/ D% Y. m* v kif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
8 z) b( M3 K- p, u5 E- V; w&& PositionSelect(_Symbol)) // Select the existing position!
# O- ]- Z1 m. i+ ^{* b! _, @+ {, [3 M3 u) T) I
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
& {) B- `; l; V. m _: X( O9 cdouble SL = PositionGetDouble(POSITION_SL);3 R) L! p$ y/ T! R# J: X: I/ Y
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));8 y4 {8 C2 K) ]2 R1 |) f
if(tipo == POSITION_TYPE_BUY)
& ?) ~( R: F# I5 f{
4 B( h, ?2 j! |6 a( J' h8 {if (cotacoes[1].high > cotacoes[0].high); {$ d* \; Y$ J* K% q( l* a
{& W* z- |# r& f8 {/ p4 N+ A
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
( |0 M0 W9 F S4 winfo.NormalizePrice(sl);8 j! w) o- _& }6 ]
if (sl > SL)' ^) y0 G+ H# k, B8 y" U. ]
{- s( i/ g' f& {; d
negocios.PositionModify(_Symbol, sl, TP);
+ `$ _, j& B8 a& v) q}8 R( v: H' U& V4 f
}
" c m$ C1 ^# F7 x2 a& f) B! |}
1 _5 W6 ~$ t5 n2 Q% aelse // tipo == POSITION_TYPE_SELL
" {2 N6 P2 y1 T# ~1 O1 X& @{
+ Z g1 C3 A4 C; {if (cotacoes[1].low < cotacoes[0].low)% j- v" m$ H9 b/ r) F
{
0 y8 A0 C% a9 r8 q# Preturn true;
; v% N" ~: h1 w1 K, Y% x3 Z7 N}4 N( K9 U5 T& W$ |7 k3 H
// there was no position; V" Q( J' y3 O
return false; w4 S4 L% V) j) @$ S, F( ^
}
: r. b. C9 r* Q4 d( ^' i我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
$ s6 T0 d7 i) l6 \" L% i7 r5 S. ?到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |