启动交易模型,并构建 EA
7 l. D$ z, K& e在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
: ?/ Y4 x9 s) y为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。# T) C" Y1 [5 Q% P/ L
以下是制定这些规则的代码。
2 Y5 u- R3 o! F1 X- ]: n//--- Indicator ATR(1) with EMA(8) used for the stop level...0 L. H. ~7 Q& _' f( J8 i
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);9 g* [0 \4 Z% m9 O" F: ~+ B
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
2 K- |8 E% c* ^5 w+ d) j! }9 k+ X$ }//--- Define a variable that indicates that we have a deal...9 }$ `4 R; S1 f: w( X
bool tem_tick = false; q! U, ~8 K# p2 m
//--- An auxiliary variable for opening a position
, Q8 e1 a9 O L#include<Trade/Trade.mqh>
0 ~7 {& D1 z: G" w' X$ f$ U$ W0 J#include<Trade/SymbolInfo.mqh>
4 s2 A* [* }. I9 p2 n3 PCTrade negocios;- ?" [; k, ]( W. y9 {$ I3 `
CSymbolInfo info;% V6 }4 I: C$ R5 S
//--- Define in OnInit() the use of the timer every second
& n- W( N' }, \0 O0 e. ]. u2 f//--- and start CTrade, ^6 W0 c, ^. F
int OnInit()& J7 A) k4 }* V+ o" k
{
7 F; Y& }% A" z2 b. ?& ?& i0 f3 d//--- Set the fill type to keep a pending order
E& c" d" C$ ]0 P4 d! x: z//--- until it is fully filled+ Z8 i8 j" O0 N
negocios.SetTypeFilling(ORDER_FILLING_RETURN);8 Q! S9 }# I+ i" u* Y1 V1 a
//--- Leave the fixed deviation at it is not used on B3 exchange* y" ~7 \+ ^5 Y
negocios.SetDeviationInPoints(5);/ [! g0 u# B: u; O" M. h8 A6 b
//--- Define the symbol in CSymbolInfo... r! {3 \ ~8 l! h
info.Name(_Symbol);7 @+ }& [9 q9 k, Y% D+ x! t) r
//--- Set the timer..., [. z8 J, [6 {- f! S
EventSetTimer(1);3 X: M# ]- [3 y+ {/ `
//--- Set the base of the random number to have equal tests...
1 I/ B- }. @: ~, z/ Q% }& k( XMathSrand(0xDEAD);
% |" \6 B; I7 ~return(INIT_SUCCEEDED);
) I( @* ] ~$ m& t. g6 H}0 `2 f+ J0 ` [5 O; k6 a! ~* O
//--- Since we set a timer, we need to destroy it in OnDeInit()." J0 ~; Z9 |) O3 L4 O
void OnDeinit(const int reason)
/ E& ?1 t4 |7 b4 z& Q8 N# b{
# Q! M; c: Y) [# o7 x" zEventKillTimer();
2 B8 b' j- k$ m) L8 b; r}
0 I5 N s) e# v: x, [8 N//--- The OnTick function only informs us that we have a new deal- k! V: \# H# H' L' S' k/ Z. ~5 i
void OnTick()
) b' R5 L* i% ^. C/ a{8 ^/ W0 ~4 d" t& p; H# S
tem_tick = true;
j3 ?+ y* N3 d. ^}
+ G, t; F+ v: ]) _) u//+------------------------------------------------------------------+2 O, M1 I( i$ P6 H
//| Expert Advisor main function |
: |6 m6 r; P k( i) v//+------------------------------------------------------------------+
: m/ |) ~0 _0 P/ |7 }9 ]void OnTimer()
# g# h2 m' O! b8 {' T0 D{
( d$ p) s" }& R5 MMqlRates cotacao[];
3 k8 m) G# y8 \2 B' S6 _: ~& mreturn ;
; O% l0 J' i. l3 Eif (negocios_autorizados == false) // are we outside the trading window?1 @/ T: P, X) |1 q7 X0 g: L4 `
return ;
4 q j5 b6 M" r! |! K2 N8 U6 q//--- We are in the trading window, try to open a new position!
6 A" }2 d6 u0 z- ?- m# |7 cint sorteio = MathRand();% f4 \7 z, e4 P9 a: m
//--- Entry rule 1.1
# s. Y4 x, `2 b4 A5 l' n" O. ^if(sorteio == 0 || sorteio == 32767)+ k, T9 t* @+ _5 @) K6 Z6 R% N3 i* V8 w
return ;. A3 R, ?! j+ G+ R( X
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy1 ?6 H8 Y# t- o E- S
{
9 v8 ?" F+ ?, }' x6 o, A, q& C- xnegocios.Buy(info.LotsMin(), _Symbol);( Q1 ~) o" z4 m8 C) m3 a
}
" n/ _ X. H: V% H: x0 ~0 H9 qelse // Draw rule 1.3 -- odd number - Sell% w b% y1 w1 T
{* R4 k& F1 {( P4 C& u( }% N+ j
negocios.Sell(info.LotsMin(), _Symbol);' n" P+ G3 y5 v7 i+ ?
}8 R; d3 |: S7 D, Q
}4 c: [* x6 h- Q2 q
//--- Check if we have a new candlestick...% F( v) l0 n. ^" s
bool tem_vela_nova(const MqlRates &rate)- P0 l9 V& h6 G( c3 u/ E9 k) s
{- O4 m/ h( K% y3 y
{/ N( ^: Z% ^7 }+ |! S) G/ F" e
ret = true;9 A9 w3 o) I( r3 @" O
close_positions = false;" J5 X/ R7 b+ p; Y8 o
}- a, V: o0 A5 w; X2 N) }, d
else
6 H' U; \. }8 w0 ?8 u% L( ^( W{
" W6 l8 Z }( @1 hif(mdt.hour == 16) @; m, I+ ^) l
close_positions = (mdt.min >= 30);( \: }$ `% ^8 x. p
}
+ A! ^1 n+ w8 w6 e9 R) C0 f/ ^}, A- u3 u6 c& Q. i! X/ q1 d
return ret;2 R& V! T6 v5 c5 P
}
) p, w; q/ P' k$ U4 k- }1 H//---" }5 n5 K) n( [0 Y/ [" B( m
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
( I4 L0 K* S: k2 r4 E8 J{
, j1 |7 N* S5 vif(PositionsTotal()) // Is there a position?
$ e" @ q- F& x3 l1 W/ N{; g5 e8 Q# ~! p2 q5 s
double offset[1] = { 0 };
1 S; f7 y; o; M* q0 T9 Nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
3 A; j9 r* J) |$ G. L( z&& PositionSelect(_Symbol)) // Select the existing position!0 y. e/ v/ ~- Q
{
( q; F- Q' {2 W" y% E* o7 IENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);; L8 j' g) [1 Q$ M: K9 k
double SL = PositionGetDouble(POSITION_SL);" U5 m. R8 U& n; z& u1 M
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
9 Z- p( O; x3 K+ mif(tipo == POSITION_TYPE_BUY). p$ U7 x8 I, ]
{
* `: j3 h- n5 L# q% C9 uif (cotacoes[1].high > cotacoes[0].high)' ^0 E6 I0 @' k+ h7 \$ o, ^4 x
{
& V' w9 J; ^ vdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 c/ h+ |6 Y+ \* w+ e# {8 iinfo.NormalizePrice(sl);
$ D+ F5 X$ ~# l ~$ Y1 H* @. kif (sl > SL)
4 q+ A& G, ]% Z# S1 T4 _+ J- M5 {/ ^{
2 k2 a4 N* t5 m+ |; {negocios.PositionModify(_Symbol, sl, TP); Y' Q+ Y& G) R: P
}: E6 m& T y2 b$ Y: ^2 `
}& _3 k/ O# M- g8 @- @) o
}! z, N4 h+ D, y `" y* z+ i3 n6 U
else // tipo == POSITION_TYPE_SELL
9 ]9 n4 C \6 H4 b{
: Z& O4 b8 L/ `if (cotacoes[1].low < cotacoes[0].low)
1 a6 N: v5 r4 X6 O6 x{
) h- Q/ ]7 {5 } B3 q! N4 \8 Ireturn true;
; K7 V& p) |* r}9 x7 b& s' f* u/ `3 I1 B- e
// there was no position: L3 C3 l9 Y2 @1 N! E( W
return false;1 e5 v) G0 v& y% z
}% G$ J' f. M& u" g7 q- O& {5 Q
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
+ f5 [$ f8 w0 V( Z- i到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |