启动交易模型,并构建 EA
$ ~) E5 B1 H; y0 T: {6 W! f在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。+ o+ x. P; X( q
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。( x9 `, G- F& L- V5 S8 X
以下是制定这些规则的代码。
1 U. w; k* \( k( R//--- Indicator ATR(1) with EMA(8) used for the stop level...* }0 g* E$ m I s9 d
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);$ Y1 H5 ^. [* y# G( p
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
, i" g* `4 B) f5 m# }- {//--- Define a variable that indicates that we have a deal...
8 V% v( g8 @) I$ Y5 L* sbool tem_tick = false;: T* x) s" P$ ^ v( O
//--- An auxiliary variable for opening a position* {3 m* T9 U: ~' h% i- z! S
#include<Trade/Trade.mqh>( I A* d. u+ d, b
#include<Trade/SymbolInfo.mqh>1 b3 Q5 p: A9 [- ~
CTrade negocios;. @# {$ }2 W) O
CSymbolInfo info;; V: M/ {( ^6 t( w- X
//--- Define in OnInit() the use of the timer every second
7 u1 a7 i& A1 z4 _: s- Y//--- and start CTrade
& Y, l( @- ?1 o0 }int OnInit()' {; k# P! g; G0 }9 z6 `0 j
{
4 t8 h$ Q8 K6 V' t+ y//--- Set the fill type to keep a pending order
% E2 M& z4 i( H2 C5 D" _; o" L: _5 g//--- until it is fully filled
1 c; p& y7 [- y6 e, P: v4 g9 Jnegocios.SetTypeFilling(ORDER_FILLING_RETURN);( S# Y/ W. H( C0 \1 B' A" Z
//--- Leave the fixed deviation at it is not used on B3 exchange: b* r* _& [; V9 B
negocios.SetDeviationInPoints(5);( Z( A5 c, f$ s
//--- Define the symbol in CSymbolInfo.... w' N- j* |* H( e
info.Name(_Symbol);: N: c5 {2 f: [- T& g% y3 Z( N) B
//--- Set the timer...) _+ Y7 m$ x9 ^ L) X( ]2 [) o
EventSetTimer(1);
" j5 q7 H, x% Z2 m: V- A0 n7 I//--- Set the base of the random number to have equal tests...
) _0 W& t% j J) o8 X* PMathSrand(0xDEAD);5 ]7 e Y0 ~( [8 ~$ X
return(INIT_SUCCEEDED);
" j: B& \( ]: x- h0 q' [! D$ M}
* p- T) e! C$ o" Q8 ~; ^7 B//--- Since we set a timer, we need to destroy it in OnDeInit().. A) Q- ~% G8 o( d; z* r
void OnDeinit(const int reason)
2 G! V3 `% [1 L! l{2 C: ?: ]9 T8 c3 f: W3 y! a/ E" o1 T
EventKillTimer();
) j2 I* {7 m0 V' ?) K}/ g' U+ y& m: L- T- h7 Q W) H
//--- The OnTick function only informs us that we have a new deal5 s$ q. g3 e M' V
void OnTick(); y: S3 s, X% K7 A0 [; R% y
{
# Y7 y2 g' `# T, A) N) @. Atem_tick = true;$ O1 T. F3 }7 B
} p: S( i8 y8 t. q) y
//+------------------------------------------------------------------+
+ N3 M+ m2 z2 S+ W//| Expert Advisor main function |
8 I5 U. J9 g& L8 H% ^$ w8 a//+------------------------------------------------------------------+, N! y }$ n4 ~' r
void OnTimer()9 }- F& J4 Y0 l- [3 Y
{
# r: g4 w7 N% c7 Z+ O' FMqlRates cotacao[];/ g$ _3 n9 q! q1 Y( s& [: ^
return ;
9 n. {' e0 z/ `8 Fif (negocios_autorizados == false) // are we outside the trading window?
* k: T- I% B5 m( B) ~, `return ;3 ]0 x+ }# H8 E& p6 V, Y* X2 P) ~
//--- We are in the trading window, try to open a new position!
5 \% V5 P& y5 ~. {1 ?/ Qint sorteio = MathRand();
6 Z% V: ^8 c% c9 x3 S//--- Entry rule 1.1
0 _6 R( t N8 N. O- D9 ?if(sorteio == 0 || sorteio == 32767)
3 _/ |) ] G" Greturn ;$ f! u- t+ Z" I' t! E
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
2 Q& Y$ `, T% e{% k, A8 _$ m, R" v; \" ^- [$ W8 f
negocios.Buy(info.LotsMin(), _Symbol);
/ ~, }3 H- _" J2 F+ L* t}5 {; Q% N0 {2 ]9 p2 w& l' B5 {, V
else // Draw rule 1.3 -- odd number - Sell: ? g) Y5 Q- |" Z) e$ j- u
{; |3 {) [3 S. [
negocios.Sell(info.LotsMin(), _Symbol); L- S9 H7 U, o9 E4 v) b! ?
}
7 t/ h' U+ H7 b7 U1 t}$ l& a/ m* q# u( r2 j4 X# j" q6 z
//--- Check if we have a new candlestick...# a0 V% V2 m5 m' d8 Z5 Y1 t, C# W
bool tem_vela_nova(const MqlRates &rate)% e; v: A* \6 q
{
: y5 v: [ k8 d, V( ]' v* b" @{5 h* K; u- m4 j. T5 t+ \& o2 {. F) l
ret = true;
: ?& j0 M, y. o7 X$ Lclose_positions = false;
6 i4 r" y. d+ Y}
3 w5 n% X0 |' G! I$ belse$ N) R0 `5 ]6 k5 f6 t3 l" H
{; y0 S9 a- k) y( d
if(mdt.hour == 16)
7 v) f3 v" B* `* @/ p) ]* fclose_positions = (mdt.min >= 30);
9 c: v; _3 S/ O M* U, m8 d/ n}1 v& `/ o4 O0 T. _) @' T9 `
}( Y- m& E' S/ h' H' J
return ret;
$ z6 k8 t- ^$ R8 Z, K$ |2 [}6 x' r* C# I; r0 D" U
//---0 z7 {* N& u. V/ D0 ^0 W/ y
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
$ b' R3 r) _! P7 ~% f; [# S{
7 A- c( H. t! _2 yif(PositionsTotal()) // Is there a position?3 W' W: d7 ^. f$ `3 N
{
) z" l- x5 N* h1 K }, zdouble offset[1] = { 0 };
- Q! z7 p9 \( k" z) ^# Qif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
( C; q% A( }- s1 X( Z&& PositionSelect(_Symbol)) // Select the existing position!
7 r. ]5 @% \9 R+ O2 x{
% @( z! p& i" b8 z- F `ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
# }: M4 W) t) H. r& J" ndouble SL = PositionGetDouble(POSITION_SL);% e: w' o6 @5 R* {
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
, G7 r/ e# R/ G$ Eif(tipo == POSITION_TYPE_BUY)
! _/ ?) u0 u; S" K$ B5 `{
4 V+ U0 k5 H+ t5 X4 |* j4 _if (cotacoes[1].high > cotacoes[0].high)
0 A e7 q8 J( F/ G{
# \" b: b2 J" t7 t9 y% S% ?4 cdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
+ s ?& k: r# o' E4 Kinfo.NormalizePrice(sl);
& M* S# s" D; P1 o9 i& }0 `4 kif (sl > SL)
) @" |$ y h$ r7 Q{ t9 `2 P' B" z
negocios.PositionModify(_Symbol, sl, TP);
; s X$ \( {) b' a0 M# f9 h}
5 r6 k5 q }1 v: x- n4 f7 K% B}
8 R. l7 w! q$ V h! n. b} ]9 C! r2 O7 {9 @* S
else // tipo == POSITION_TYPE_SELL. c5 ?/ B& d/ j) D4 c0 d1 D( K8 D
{
+ T( y, [9 F4 ]( g1 W$ ]0 F, z0 [8 d. iif (cotacoes[1].low < cotacoes[0].low)
) N" g$ c1 x1 t{) }- c8 p) u6 Y G! X& L5 `# Z
return true;
; J9 h% g/ \# l) i}
! E( B( o; f. B$ Y4 O// there was no position
0 j1 O* P! z- w3 R& o. mreturn false;
9 U6 W- k5 {# P& r}- q! @/ C. f, M
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。, z& M) V: H3 l8 {# g; U
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |