启动交易模型,并构建 EA$ K0 y: x& Y- w, [7 A3 c$ q
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。- V- ^0 E9 U! ^0 d/ e1 W* W; [- Y
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。* W* q" Z2 B3 C" m
以下是制定这些规则的代码。
8 z3 I9 w; y$ i- ?//--- Indicator ATR(1) with EMA(8) used for the stop level...( B3 _: U) C7 A _7 u+ w* {4 |& ~
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
9 X) `( M% _! V0 n- o6 wint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);( n* x- C) W4 H# G
//--- Define a variable that indicates that we have a deal...: a; F6 ^1 k- K- S' y0 \( f
bool tem_tick = false;
( R8 f+ _+ e, }' B, w//--- An auxiliary variable for opening a position
0 R, H) q8 Z. e$ v( o/ |#include<Trade/Trade.mqh>- E% x, e* P" t3 b& u2 d
#include<Trade/SymbolInfo.mqh>
7 h0 [" L0 [" {CTrade negocios;
4 t) I$ I3 U3 [3 {CSymbolInfo info;
5 s7 v F8 O: q v//--- Define in OnInit() the use of the timer every second6 Y9 y5 J7 X5 p Z7 U0 m! ^
//--- and start CTrade
" _4 H2 q2 n' S0 P3 Nint OnInit(): p$ o1 L0 W& P
{
2 x- D" G% u1 P% g# U//--- Set the fill type to keep a pending order
9 Q; O: S* J7 b2 b9 H8 a% B//--- until it is fully filled
' p# F% d' s2 ^% F9 nnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
) g- u% f }0 @ X% X//--- Leave the fixed deviation at it is not used on B3 exchange
m9 s. c7 s w' f2 e3 l4 Gnegocios.SetDeviationInPoints(5);8 P/ |/ D' U- G P! s1 r2 Q
//--- Define the symbol in CSymbolInfo...
+ J* f! h7 A" j' u( ninfo.Name(_Symbol);' o5 y' ^8 [0 y% B
//--- Set the timer...
+ c7 l& | u4 }2 j4 o! S9 b1 eEventSetTimer(1);
6 x# i4 m' c8 A+ `/ t//--- Set the base of the random number to have equal tests...
" g# ^9 o+ X' w& g- }4 SMathSrand(0xDEAD);( Y4 @0 x5 E' H
return(INIT_SUCCEEDED);6 D) Y3 c6 C/ Q
}+ G: S8 b# q7 l5 g4 T- y' L6 T
//--- Since we set a timer, we need to destroy it in OnDeInit().
# w0 @# y* e+ I" s- ^! A: c: {void OnDeinit(const int reason)
* |0 Z/ |3 y9 u0 W% ~ h{/ N4 }: m8 D" I3 U0 o3 {
EventKillTimer();3 }! {' N# J4 W q: \& i# v8 s) M; u
}
- X& S _! d. A( S//--- The OnTick function only informs us that we have a new deal& |' N: Y8 v: \) B- {4 H! }$ c1 X( `8 ]
void OnTick()
& B# H# O% i8 b8 ]{6 u. j: e7 t! g7 ~
tem_tick = true;+ _; {9 i' O2 U! M) A B" V
}
( f3 R y4 y1 Z3 ?8 B; M. M* u& F//+------------------------------------------------------------------+
3 y* ]' m- _% y/ ?3 f/ e//| Expert Advisor main function |
* @- Q# I' U1 l: I//+------------------------------------------------------------------+* K! H/ J! ]+ v) K' n# d2 G1 b) {8 Y- q
void OnTimer()
; @# t3 J4 C. M3 s+ n/ n{3 R" y/ h; H4 x; f& T, y
MqlRates cotacao[];
# T; O! r1 t O2 k2 Y& F, X7 O. I( P Vreturn ;$ w0 |& C. H. y0 }2 r/ q' x. W
if (negocios_autorizados == false) // are we outside the trading window?3 ]& k0 n" G4 A5 ?
return ;; b0 y, h+ ]' X" s
//--- We are in the trading window, try to open a new position! w- Q. N2 U1 u/ Q& M1 n
int sorteio = MathRand();! w' q u, c6 e+ W! F" m% s
//--- Entry rule 1.10 Y; Q, q7 J1 t/ [" f
if(sorteio == 0 || sorteio == 32767)
9 {3 d! d. s0 L) P6 S; M0 mreturn ;5 P9 g% s) w: r I/ r
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
5 T7 `! r( \6 [( D7 v6 } _{
) `0 O, z- F! ^! |; _4 j ~negocios.Buy(info.LotsMin(), _Symbol);) X, c- m( ^9 V% T( g, L+ r4 p/ Y* p
}+ o$ Y1 A5 Q/ [2 `7 |8 P
else // Draw rule 1.3 -- odd number - Sell- H3 q0 L$ T0 D# ]
{
& k' ~' K7 S+ G% s' k, j/ Znegocios.Sell(info.LotsMin(), _Symbol);6 d# v! V7 R _. E- D5 B
}' N8 H6 }& s& M* _" N/ H6 f1 m
}7 C4 {+ F, m; f
//--- Check if we have a new candlestick...
+ i. g7 F* c+ d: M0 `bool tem_vela_nova(const MqlRates &rate)5 i- s+ D" x: p
{
- I* E, }5 k' X! p+ p! q' P{* O- e+ }4 l1 L, r
ret = true;% Q) T( N5 R) j% v
close_positions = false;
- o% X2 O7 a+ s; b" C4 A0 b0 m$ b3 w7 D}
8 ]+ H$ N+ E( R' l4 ^else) O) _; I }" t g; k
{
3 s! d* o; s. ?+ T8 j/ ~$ ?' U" Vif(mdt.hour == 16)6 h" F, k. T9 E
close_positions = (mdt.min >= 30);7 D6 }; C8 x4 c+ P
}/ ?! ~& `0 F& s2 F1 q& e
}6 X8 T6 A% ^ l& k( {# R
return ret;" w: N/ d3 Y; {5 Z4 {
}
! s# D/ `7 D1 a( }//---
) P ]% c; t0 _9 r# e5 T2 Cbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
" X6 Q" E0 n) |9 J m" e{8 }/ g! @8 P- X K) c% y$ y3 j& _% D
if(PositionsTotal()) // Is there a position?
- {9 M6 I# y8 A1 Z: @& ?- e2 e{
: {( F* T+ o3 ^) Fdouble offset[1] = { 0 };; s2 M7 o- O$ l1 H2 I' O! v
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
4 J. J c* ]+ w. F0 X, A2 U [&& PositionSelect(_Symbol)) // Select the existing position!
/ P1 X/ X1 w4 a: H% n{
1 I$ ]8 Z. B; r" C8 hENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);6 Y- V' {4 B- L: b- k% i. @
double SL = PositionGetDouble(POSITION_SL);
$ F" _& a3 q( O( P0 ], e9 ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));4 K/ V. G3 T4 m) h" c/ L6 ?
if(tipo == POSITION_TYPE_BUY)9 P" N- `# Q- [
{. A% h% B- u* y. E" e' |
if (cotacoes[1].high > cotacoes[0].high)" g$ U' K: @. F3 A& T# }" Q
{/ I) d$ T6 p9 o# D: a9 N& u
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; N0 }" a& z% K1 w* [* q) M8 b% f
info.NormalizePrice(sl);
% W( j! k( Q% p1 _if (sl > SL), Q% F: x( I& m# S! D& W$ Y( {
{' `+ D f0 W' x2 U" s; O4 z4 t
negocios.PositionModify(_Symbol, sl, TP);1 l3 S$ H X2 N' l; K! m
}0 ], Y( G* z' M6 c n/ {+ c5 O4 S
}
* w4 N/ }4 K- G}
8 g' R& g0 \- ?* i! celse // tipo == POSITION_TYPE_SELL( r: I! s7 ?3 Z
{, }5 ?. W4 W4 J% q- V
if (cotacoes[1].low < cotacoes[0].low)
% a$ x" v1 ^. N/ U+ O{' C; P5 p% }& R5 I- _6 k
return true;
" ]. j) Z7 Q& F4 U} \; _- u; O0 i# G7 P! V2 v; F* Z
// there was no position; P# o {6 o1 g* t; g0 m
return false;9 t+ r- z. o% o; E6 g; x6 h
}3 C* H* l. S. y0 w) B
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; `& W2 b1 y( e* X" O: |
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |