启动交易模型,并构建 EA, I3 Y" M7 J9 s( v
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
5 D4 o+ r$ Y- S" V a9 i6 T# d3 H为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
. d# F9 c( o* J4 q3 U以下是制定这些规则的代码。1 C# E# V l+ c8 Z- ?
//--- Indicator ATR(1) with EMA(8) used for the stop level...
, }, f0 G$ O. ~9 p! I2 z; ~+ yint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);- T& @2 V* l P8 ?; v
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
" V; ~' e5 ?- t; Q. x3 M5 W* R//--- Define a variable that indicates that we have a deal...+ I! L" e* P# v, z+ I" X
bool tem_tick = false;5 w0 u" v& M: _% f) C
//--- An auxiliary variable for opening a position
' a' { W; K i. O. }#include<Trade/Trade.mqh>
0 s+ d \% p! B$ [5 u& n4 Q" s#include<Trade/SymbolInfo.mqh>
2 ^ L, F$ e2 E# h$ E6 t4 w' b, T5 MCTrade negocios;( Z$ w4 u0 T. c2 s Q0 A. E
CSymbolInfo info;* ?0 q# u- `$ v! u
//--- Define in OnInit() the use of the timer every second# v$ q3 S# A7 `/ _' U( p
//--- and start CTrade
( x3 V3 G: }( ^; m7 ]) d& Q" o; Wint OnInit()
: H8 Q1 U9 J- ~7 u, g. m{9 x& r5 S/ M, j4 r
//--- Set the fill type to keep a pending order0 `# ~# c# N' K1 f2 ~1 r
//--- until it is fully filled( d/ L3 L+ ]# X; p7 I$ V
negocios.SetTypeFilling(ORDER_FILLING_RETURN); T& x) H' X1 v: } F
//--- Leave the fixed deviation at it is not used on B3 exchange
4 v9 I# Q; E1 o4 ?* g2 k$ r _negocios.SetDeviationInPoints(5);. v' D' b/ ^# ^/ L6 z2 m
//--- Define the symbol in CSymbolInfo...
, w6 v$ V( i8 Y4 @info.Name(_Symbol);
' B: d C# t) V0 f: Q0 F//--- Set the timer...% L3 p0 x: G, C
EventSetTimer(1);) j- w6 ^7 W" O8 E3 Q8 k
//--- Set the base of the random number to have equal tests...
) A, n! f6 s# l# R D' o8 N9 tMathSrand(0xDEAD);0 _8 w$ x% t* ^3 g/ f! ~5 {
return(INIT_SUCCEEDED);
9 P# @2 a2 {; M$ Z- X}2 ~' ~1 j( } R# q7 O6 ^
//--- Since we set a timer, we need to destroy it in OnDeInit().
# Z/ D/ V: p1 K% L1 Vvoid OnDeinit(const int reason)
8 m$ a$ D+ F! H{! M1 E) ]4 ~; k$ U; _0 p- f
EventKillTimer();
& h# u' O( E! `7 ^}% D0 F/ a- M. f a
//--- The OnTick function only informs us that we have a new deal6 S" W! Q6 F* s, i9 ^. ? E( v
void OnTick()
4 H+ O' d( e; c4 c$ r A/ l( ~{
) {! j% N! \6 o' Ctem_tick = true;
[# f0 E% U$ L7 ~}
3 {- W1 j+ q9 } n8 D//+------------------------------------------------------------------+
" @ V/ ?! J3 E4 U4 R+ \8 c E7 W//| Expert Advisor main function |: B% D* b% I# r+ y4 r* O, ?0 F
//+------------------------------------------------------------------+2 m/ R5 g' ?6 f$ A! t: t
void OnTimer()3 q5 E; j0 y) a+ W/ x
{! ~. [. q5 @3 R
MqlRates cotacao[];
6 C( S# N. K2 M. F1 C! v2 N' xreturn ;
. _( o/ o1 |# j. W3 eif (negocios_autorizados == false) // are we outside the trading window?
# P/ ], E8 o ?+ Areturn ;# y" f# q) |0 E: q' }3 T
//--- We are in the trading window, try to open a new position!
8 V$ e8 ]9 [- [. ~$ lint sorteio = MathRand();2 m1 I5 |! g/ d N3 o8 S
//--- Entry rule 1.1! s* H& b' S5 Q5 [% t
if(sorteio == 0 || sorteio == 32767)* k, l5 N, K4 a( U$ p) J
return ;) O( y% u7 v- h3 b: g
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy5 y; p* A" `! I" q4 x9 u
{* u+ g/ z3 X7 B" l- E" S/ t- @
negocios.Buy(info.LotsMin(), _Symbol);
5 D1 K8 x' g/ ~* {# E! o) I, P}
' M7 g7 l. o9 i4 E6 x9 T5 delse // Draw rule 1.3 -- odd number - Sell
1 Z; u$ m& b9 x1 D, b% N& W{; o$ B5 E7 h/ v8 [9 h
negocios.Sell(info.LotsMin(), _Symbol);% |2 P# Y) U6 P2 T# \
}+ [) C5 \4 @9 y
}
6 Y- Z) D3 ?6 s, ]* o//--- Check if we have a new candlestick...$ W3 J @5 C7 k3 G/ }* U/ Q
bool tem_vela_nova(const MqlRates &rate)
8 B5 ~3 u. F$ \{
$ H3 {: |. e3 y3 w{
. ~9 z) B/ g3 Y1 Hret = true; [, I/ a$ v' _/ a/ T
close_positions = false;; B) n4 F/ c4 W" l2 @, j
}) A2 n& U1 { x: F. n) q
else
, x) U1 g- ]9 D; P8 R0 Z{3 y+ L9 B, k- M5 ^' W0 y
if(mdt.hour == 16)9 L! a( i) e/ u; y6 ]" T- y8 O9 N! L/ r
close_positions = (mdt.min >= 30);
* U. @+ y9 t" u) l! z}
+ L4 d& ^% ?; F# I) E2 @. x}
- O+ | u/ J+ ?return ret;/ J4 u8 e4 n, N" ]% y. x
}) K, @' l- U" k# T& Y& q% g
//---# R, o' c* A& r' f* `$ {
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])% j% a# W1 g' t7 [# a8 ^, V
{
1 |2 s% a! {/ W+ }* {+ u8 Y" Xif(PositionsTotal()) // Is there a position? ~3 {8 H7 ^$ }; k+ i6 ]5 \
{! d( j- d9 z- R( c
double offset[1] = { 0 };
! A7 Q& u% O& i$ n {0 G# l6 nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?( v+ r% }8 c: \# S {+ G* v
&& PositionSelect(_Symbol)) // Select the existing position!
; }7 ~6 A [* p& M+ M. p{' p i4 O! L: ^8 Y8 \. `; H
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
5 n0 w, l \$ ?: ], Ddouble SL = PositionGetDouble(POSITION_SL);
7 D, ]' [& G/ Ndouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
1 e( r/ ~. H2 Kif(tipo == POSITION_TYPE_BUY)
+ F; b) p2 y0 w* }, f{) Z3 v% W3 N# M+ N( X
if (cotacoes[1].high > cotacoes[0].high)2 C% Y. _+ p: m$ n$ ?/ P
{
$ p H$ I7 J' |7 C" k' l. Q9 |% xdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];$ J: u" k" D. L9 v" _9 w! h7 B. j
info.NormalizePrice(sl);. C0 Y5 ?1 W/ A% b$ z
if (sl > SL)
) |7 A3 p6 D8 Y. P2 ^2 Y{
- c3 X2 ]# ?( anegocios.PositionModify(_Symbol, sl, TP);
9 q! I- e6 v5 Y# ~ I6 z4 X}
! M. v! {, G7 W* |# H: b& s}7 w, Z( d* z4 w; [
}4 ^, e% O1 W( L' K
else // tipo == POSITION_TYPE_SELL; p+ H7 M, O1 y1 v1 v0 M
{
' c; w% w5 ]* a, C% g$ x! [& Tif (cotacoes[1].low < cotacoes[0].low)
7 ^0 { b8 u* ]; F& Q$ A7 P' t{% ? Y: t1 o1 v2 v; G$ \! J
return true;% j0 Z ]+ X6 Y4 i# B
}
8 p. d& j9 ?' W7 ?; h// there was no position
_; W8 U3 ?, ]9 P0 f! P! Creturn false;
; U+ o$ c6 L! _: o! o3 K" ]}
& p1 \1 o1 z; k: ]我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
0 G7 J* z) V6 u7 u到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |