启动交易模型,并构建 EA
5 f$ J# J0 r% Y在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。) ?! e4 g% i3 x0 ` \9 [- [/ m7 J
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。9 ~6 a4 d2 x1 a3 U& ]2 a
以下是制定这些规则的代码。
1 [* _1 c E3 f `; W! _( ^//--- Indicator ATR(1) with EMA(8) used for the stop level...
! U4 X) v8 H/ c1 gint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
+ n) p0 U. V% h- F6 f3 u! E6 `int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);1 e; i* m& j- t
//--- Define a variable that indicates that we have a deal...1 p: B% K- ]- d: _/ t( E
bool tem_tick = false;7 ?1 U% u7 g" j* {4 j. j; b' L
//--- An auxiliary variable for opening a position. A4 y# y/ V; T3 I6 W0 y0 v
#include<Trade/Trade.mqh>
; P/ c+ f+ U' }; |; f+ L5 w#include<Trade/SymbolInfo.mqh>5 l5 G) j9 i0 j" \5 z! Q$ u# g
CTrade negocios;# Z. m) t6 l1 }8 q* H. z1 [
CSymbolInfo info;
4 B- M9 F$ D1 f5 x4 W9 h* ?) B1 l//--- Define in OnInit() the use of the timer every second
' Z$ [1 d7 _! K2 I- d* t//--- and start CTrade& i9 R, l; M" o X7 C
int OnInit()
& u1 S3 S/ O3 o# q P2 {{
# V- J5 y) Z' O: X: x4 x//--- Set the fill type to keep a pending order
3 Q$ ?: F6 k9 x& E) n8 V1 Q8 S//--- until it is fully filled3 L2 B+ S1 w/ V5 v- {2 J8 s7 w
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
7 W" a: A/ _& t; D! J9 f( i" {1 q//--- Leave the fixed deviation at it is not used on B3 exchange
, m: y0 L6 [5 c6 h- X4 k5 Cnegocios.SetDeviationInPoints(5);
1 J0 q7 { N* o/ \1 e//--- Define the symbol in CSymbolInfo...9 l, b, v. ?7 Y: g6 r1 |- K
info.Name(_Symbol);
$ K2 L0 p9 [3 R' D3 ?//--- Set the timer...
$ f8 Z, a1 A& y8 }7 HEventSetTimer(1);
+ a9 y/ v1 `4 d. @//--- Set the base of the random number to have equal tests...& b2 z0 V+ v) {/ U' d( b
MathSrand(0xDEAD);" a: Y/ o, R' h8 G# i- v
return(INIT_SUCCEEDED);& V/ G" H& D* Z0 q) t' ?0 o. ^
}
; x$ I: B# ], j/ j//--- Since we set a timer, we need to destroy it in OnDeInit(). q6 E) b. t O x2 d7 K$ N- A
void OnDeinit(const int reason)1 \' Z5 z8 C* Y A W4 ~2 ^3 V
{( K9 | w6 }3 t) D. _" c9 T8 C; L- N9 m" b
EventKillTimer();
$ Q9 v Q4 m3 W( c. u}) C' N9 S4 m6 Z
//--- The OnTick function only informs us that we have a new deal
! a2 ^* z; \3 M y& {. Yvoid OnTick()
" @! b# a7 y( D{
& v7 X# v: u: `0 ntem_tick = true;% Z+ Q! p1 d; G! {3 U
}
: p& l. j4 a7 H' K+ u//+------------------------------------------------------------------+- D# K& }/ e, L) X2 O/ K5 ^! _
//| Expert Advisor main function |
( @( @: _) Y# w( x8 w, J6 M//+------------------------------------------------------------------+
: `8 t4 J0 K8 L! V2 ivoid OnTimer()
7 b7 m* f; B5 ?+ k' g3 h{: @' z/ Z: K+ b% U* Y& [ v \
MqlRates cotacao[];. c& O/ T- D4 R$ J" |
return ;
1 G/ U; {) \7 [* Zif (negocios_autorizados == false) // are we outside the trading window?
' ?0 L' b% q( e% y9 p9 treturn ;
" z, H& o% ~% r& h. b//--- We are in the trading window, try to open a new position!
% M$ q/ U* Y$ K' K, jint sorteio = MathRand();/ f y6 m1 l" O! L
//--- Entry rule 1.1/ M& L3 R% p- n2 m
if(sorteio == 0 || sorteio == 32767)
- u" [ z& u ?, breturn ;
6 W: E4 A: Z8 n! a# O4 Qif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy& h6 g) Q( f( }8 f& C
{3 \! _' ?% H0 z% N, a( j& }
negocios.Buy(info.LotsMin(), _Symbol); h6 B, h8 A2 a1 t" q7 ?, M4 H0 D
}$ `: R# U t/ d7 B8 f, p
else // Draw rule 1.3 -- odd number - Sell
3 x5 |9 L! G7 R3 g" T{
7 T. u1 m8 \: j, bnegocios.Sell(info.LotsMin(), _Symbol);& K8 c: P8 w1 @, f8 k7 J
}$ P t" C% Y& w( C" Q7 v7 f
}
; @" ]% I7 W. p4 A//--- Check if we have a new candlestick...
e7 X4 T& c+ ^bool tem_vela_nova(const MqlRates &rate) ]- P1 c) ]2 G0 m6 a
{
6 x1 ]5 i# t0 p2 P" P0 V# I{
! O4 e4 k! n2 r2 xret = true;# T/ j1 }4 Y/ }" k
close_positions = false;( D" C j* }7 ~% h) z
}
h/ m. T/ N- {* jelse! i2 Z/ G8 ]! j; _3 ]7 y" x, d$ [
{
$ S. o7 m7 a3 S+ T- J+ w3 Hif(mdt.hour == 16)
, B" {. P; M5 s0 g. w6 R, q/ f% R0 Jclose_positions = (mdt.min >= 30);- [5 D2 w7 w& s4 Z) u
}) r2 w* { T; k* K' P- P a. v
}- s3 K+ z$ r/ d. ?- y/ A+ n: W. G
return ret;
. w' t' y' J& @7 N- o# ] d}
4 s6 _3 \3 n* S" ^5 s9 O# E//---% D' t2 D- `0 Q, h0 R4 h+ a& }8 h
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])# K. L! Q4 t. _2 @2 k
{& w I8 m) G6 g% t
if(PositionsTotal()) // Is there a position?
3 m3 x; o) Z$ o{% e2 E( ]: a' g- l5 @- c9 y
double offset[1] = { 0 };: Z8 O$ k3 S+ ]1 h+ c6 e0 _9 n
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
, d# F/ K1 Z9 T( @% O2 u# {&& PositionSelect(_Symbol)) // Select the existing position!
" c0 t) f+ D+ |. @; G{
$ M$ Q/ D. e! v8 O& p8 A7 `0 xENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
$ A/ d3 A3 K; Y0 ^. b0 pdouble SL = PositionGetDouble(POSITION_SL);3 C+ h+ d$ N& |
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
3 J; y6 x7 O! V: t( ^' M. @9 Cif(tipo == POSITION_TYPE_BUY)
C# _2 b5 a+ P% u) [1 L1 M c{
9 J% T) I" J8 t. c p$ u' J* |- {if (cotacoes[1].high > cotacoes[0].high)
4 P7 S8 I) S+ R, n4 b1 n{
* `% P1 o, _% R5 ~- j( ]double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 @( @. n* P1 N: Y4 Q0 Rinfo.NormalizePrice(sl);
) ]# d6 W s2 kif (sl > SL)
2 J0 u& d5 t, P: O2 |( H8 E{1 Q0 C" W" M5 c
negocios.PositionModify(_Symbol, sl, TP);3 w0 d7 a/ m4 p9 s
}
7 ~* \) j9 n7 u' L! D. Y# o& y}1 r, O% H9 P' A4 ^4 }
}
3 C5 R. j D0 O1 e4 M* z0 gelse // tipo == POSITION_TYPE_SELL) s9 I3 @# R7 N W
{
/ n5 x- q/ ^' a# h4 wif (cotacoes[1].low < cotacoes[0].low)
9 V s4 c( ~, `* w) u' e1 X3 c$ p{
9 F5 ^& Z4 [+ S6 H8 Freturn true;! d. [& T# f4 Z
}% l4 V$ y. H! o0 \0 x+ B. b
// there was no position4 `. W% p, O! [& Q6 S' S- ]% k; [' T4 }
return false;
. M3 @4 [ v- J) X% b* D" e% l}7 P5 n h l X7 v
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。1 G1 ]" M$ h5 P/ j
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |