启动交易模型,并构建 EA
7 \! `" D& T/ c6 t+ G: r在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ d$ [6 s2 \, e H J2 I" O0 a
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。8 S) j7 I% C% w1 J& h7 \
以下是制定这些规则的代码。1 C, c# ]: |: m9 T
//--- Indicator ATR(1) with EMA(8) used for the stop level...) @8 [' y1 U r: m
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
! E" z7 t3 ^* bint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
: N" g# j: [6 L- X//--- Define a variable that indicates that we have a deal...% c9 R6 \ H9 v4 h, y
bool tem_tick = false;; E: D6 p5 C/ _9 A% y) V
//--- An auxiliary variable for opening a position
) j* T6 {4 X8 N3 x5 ]#include<Trade/Trade.mqh>7 m4 m! e8 A! |4 h* o! U8 t; w
#include<Trade/SymbolInfo.mqh>
! i; b+ N3 I3 H( b" u, ACTrade negocios;- B2 {7 |0 k% A$ i3 M% X
CSymbolInfo info;6 X3 _) b4 |; u7 T0 Q* ]7 c
//--- Define in OnInit() the use of the timer every second
. L% P9 V4 \3 V) o9 a- @0 T//--- and start CTrade
; C' b5 W; o J7 Nint OnInit()
$ E& q9 T. w) ?- R{
( J& q) {8 C# A9 Q6 D: x//--- Set the fill type to keep a pending order
. Z# @8 w# C6 e* W- R Y2 e! w! F//--- until it is fully filled" x" z. k2 m9 L+ J6 v! R
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
; }# |1 T4 j# a; G//--- Leave the fixed deviation at it is not used on B3 exchange% y2 ]' `' n# N% z0 s
negocios.SetDeviationInPoints(5);
9 A# c/ s0 C3 D" n//--- Define the symbol in CSymbolInfo...
1 Y' D: _8 ~- V* Ninfo.Name(_Symbol);
" s/ D; A2 i/ M* ^3 f9 H/ H% X//--- Set the timer... }3 h% v+ e# I8 t1 _) w
EventSetTimer(1);$ `4 Y4 L; r6 G V
//--- Set the base of the random number to have equal tests...
7 `1 Y j( z7 u+ |5 u" |6 u1 B0 dMathSrand(0xDEAD);
. M f' A3 d: preturn(INIT_SUCCEEDED);8 p# j7 ?" m' B; ? y. ~0 j, {
}
8 S+ \% z- |" O9 x//--- Since we set a timer, we need to destroy it in OnDeInit().& }: ]$ c1 i7 `* X; x8 w/ u
void OnDeinit(const int reason)
' g2 h* B; {3 w: v{
* b9 N% L6 Y. H, h X4 q' q' DEventKillTimer();4 ?# t# |5 ?" f1 @9 U
}) O" C# J1 E; E- |, X+ |& ^
//--- The OnTick function only informs us that we have a new deal |. M7 c* n3 Y5 s# F0 S
void OnTick()
" ]" ?3 F- G& j" h9 z9 f2 S{' s R5 z2 P1 m% n* m f; E* f
tem_tick = true;1 h- }: M" l, z
}
6 r( w" R5 P- n9 A( C- [//+------------------------------------------------------------------+9 Y- G8 w. i7 _ q; l9 r9 C# V
//| Expert Advisor main function |
9 w! K) n! g3 N5 e//+------------------------------------------------------------------+
' d4 e! u6 P+ F& Q; j& I+ Uvoid OnTimer()
' ^* X# [2 T- F2 w% v{
, `( p$ l0 j( J2 JMqlRates cotacao[];9 n: D3 B' Z1 t0 m4 D
return ;
- ?! C/ g3 e" W9 g1 M: Q) C9 g4 fif (negocios_autorizados == false) // are we outside the trading window?
1 x# K/ u+ c) l1 {, Rreturn ;, k$ S: d) d5 g; p
//--- We are in the trading window, try to open a new position!) W+ ^% a" `. G3 }6 c3 I# d
int sorteio = MathRand();
9 K# `, [5 M7 G* w" x$ \* C: r* |//--- Entry rule 1.1
7 j5 g E' X% p( k" a8 ~/ X, Lif(sorteio == 0 || sorteio == 32767)
6 `5 r( ]# m% W7 ?# ?return ;9 k/ i% v1 ^# Z# u8 ^/ Z1 S# B7 @
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
, H N. I: {* [; e4 _{
# g9 p5 n0 h# r0 a8 Vnegocios.Buy(info.LotsMin(), _Symbol);
1 S- Y1 C# f }}. |6 m2 W9 I5 h/ m+ N" e
else // Draw rule 1.3 -- odd number - Sell
, `5 @' R7 C) k{& x1 ?9 D% U; B' C, O' X
negocios.Sell(info.LotsMin(), _Symbol);
. U% O; \* q$ j# I$ y8 F6 D, n}
/ q$ f" Y; P/ S3 V}0 O. r7 n6 M( G& f+ X. R9 G# d9 P
//--- Check if we have a new candlestick...7 g r0 M8 H$ x( k0 ~* `- J
bool tem_vela_nova(const MqlRates &rate)1 j9 T" q% b5 ~1 r7 n
{3 t( c. x$ f$ `, p7 T( d$ Z: ~
{% G' M( c* C$ V) I
ret = true;5 Y. `( D" S+ r( J, i- y
close_positions = false;8 r* I; L! g! ?6 A! _ } T
}' ^) G2 j& p) J' {
else
( s) z3 y+ c. M: b4 g: m5 v{
/ z7 B t* {& h$ F- {( @6 Oif(mdt.hour == 16)& d) e3 V/ `! u* k* n
close_positions = (mdt.min >= 30);
0 ]) m0 x1 i6 K) t# [# A1 |8 |0 @}
! B+ E% J6 O5 k3 o' Z}
% k9 q/ _; Z, H* ?! J8 o2 {return ret; |4 h, s/ y6 D5 p! J! x7 K+ Q7 ~
}5 w2 `# W' e! P) _' | m# s
//---$ g7 J0 _# {$ n1 B6 Q4 n' j; F
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
. }: X* ` c& d$ X$ D. R6 z! f{
7 P% E5 `1 P$ e( i* r& w$ J4 lif(PositionsTotal()) // Is there a position?4 u, ~ Q4 y5 u
{) F' A4 ~, j/ K: N) s* V
double offset[1] = { 0 };
, \! l4 ] }& F1 y; ~* t Mif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
' M" ^: d& ~5 ?1 ]8 R, v&& PositionSelect(_Symbol)) // Select the existing position!- G( j3 I% o9 a! |; Y
{( d5 O1 F/ Q0 K6 D3 _- y
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);+ a) j! I0 x, ?3 K' U9 Y6 Y
double SL = PositionGetDouble(POSITION_SL);
8 w) N' Z% d8 `! Udouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
/ h$ \/ o: U8 tif(tipo == POSITION_TYPE_BUY); N4 t9 |; N* v0 q
{4 D) {8 A* T9 {: c5 S. m
if (cotacoes[1].high > cotacoes[0].high)) f3 P* x- K [, \- l+ A& ^" K
{1 F4 o( l" i& j- I) o2 q+ E
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
0 e5 }* A7 W f# `2 z! _( Y5 A3 w1 v- yinfo.NormalizePrice(sl);
+ M6 _0 ^2 b- ~3 w3 oif (sl > SL)5 D" a+ g$ s" n) j( K1 h6 x
{
1 s- ?6 c5 j, ]negocios.PositionModify(_Symbol, sl, TP);
! R( z1 Y" z: X}5 ~* E, [/ [! e8 a
}4 w) q) U$ x" Q+ R" c4 t6 W: ]
}
7 V! g! F+ H" _6 Y, ~" gelse // tipo == POSITION_TYPE_SELL
( h' ]6 ?- f( s! {{
0 T# S9 P& r+ h1 I6 C3 T7 Z! ^if (cotacoes[1].low < cotacoes[0].low)
% C+ c3 F8 n0 w{
6 [) `) C- |! [6 Preturn true;
' d! l7 y" P' s: I}: ~4 @' N6 o8 ~* A
// there was no position
O W$ K9 r# \9 V' M6 breturn false;
3 m5 T3 V [- K( `( Z, |. P/ F}
8 `' V x4 Z8 }. Y& a& M我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- v3 v6 T5 v5 c4 F% c
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |