启动交易模型,并构建 EA
( e$ P2 ^2 s4 D3 y) t3 _1 k在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。9 V0 E" J+ i( Z* C
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。6 f8 s l t! c
以下是制定这些规则的代码。
2 G& k g1 k6 ^) @9 R) S4 W% n//--- Indicator ATR(1) with EMA(8) used for the stop level...
: T$ Z7 q& M3 e1 k! vint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
5 |, z; b( [4 E1 qint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
" K) N4 x- x6 r- Q, f+ e9 N4 G//--- Define a variable that indicates that we have a deal...
" A5 Z4 [1 c1 L" t y( }1 jbool tem_tick = false;
. X9 z# ^4 l6 L. L* A//--- An auxiliary variable for opening a position8 p7 f0 j9 J3 C3 \
#include<Trade/Trade.mqh>
# A' ?8 E: i8 h: B" s, I#include<Trade/SymbolInfo.mqh>
" N7 F' l) r% OCTrade negocios;" J6 M" N* `2 q F9 V
CSymbolInfo info;* I) `+ h' ^$ _' \2 i" y
//--- Define in OnInit() the use of the timer every second- H0 `9 {: R0 L$ Z8 b2 n
//--- and start CTrade
( c8 J, w5 U2 E" a) u( Cint OnInit()7 _% s; ]! M. n e
{
1 |' V9 M- H- w* C//--- Set the fill type to keep a pending order8 K; g/ V. E* A7 g
//--- until it is fully filled# n1 R$ B* c, K1 ?
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
9 g1 C6 I9 A- h) h& u//--- Leave the fixed deviation at it is not used on B3 exchange! f& f" N8 y# o$ ?5 G; Q$ E3 G3 C
negocios.SetDeviationInPoints(5);
# [7 v! p3 N5 Q; e, J//--- Define the symbol in CSymbolInfo...
( f! d N: S+ B7 oinfo.Name(_Symbol);" X0 [; P5 S4 }& R1 i- x+ m
//--- Set the timer..., c! P- s% k5 x& j* S% E
EventSetTimer(1);
0 K2 i! e; z/ K2 p0 Q8 ~//--- Set the base of the random number to have equal tests...
K: ^2 _/ X9 E# e( R* [! gMathSrand(0xDEAD);
& a f7 x5 Z' j6 f! t3 s# v" \; o+ breturn(INIT_SUCCEEDED);
8 i2 m2 r/ w& N' H3 {; H! Z- {1 m}
+ B# m* ?9 h8 W2 R. F* E& Y1 g//--- Since we set a timer, we need to destroy it in OnDeInit().! A0 q9 ]0 d) f4 \9 ]
void OnDeinit(const int reason)
6 S+ I# V3 h# x; n v{
; G$ j2 `9 t; s) g9 xEventKillTimer();, u# u- [ J ?/ ~& v- \
}
1 t6 E2 v8 b" g; J7 x( Z7 v//--- The OnTick function only informs us that we have a new deal
6 E! O$ J& P3 R/ v; c, T7 jvoid OnTick()6 U* Q I! v4 I& E
{
; d% c G1 s# }tem_tick = true;+ ?" k" ^' @7 `: J% S1 r
}
. M+ q( R ~0 w7 Z* k+ w$ o, J//+------------------------------------------------------------------+
5 g- s7 x; _! X6 `* }//| Expert Advisor main function |/ J- ^$ v9 W9 m7 x
//+------------------------------------------------------------------+- B* k8 t1 k& _" e7 {# A' ]5 g) {
void OnTimer()4 {6 _4 q1 P. L. Y* t- C- v) Q
{
! j C& x% p, B, ]8 ]1 u" lMqlRates cotacao[];
! n- R/ T& u k( m5 n3 j/ [return ;
- {7 |. @5 Z5 n+ y, q* mif (negocios_autorizados == false) // are we outside the trading window?
. o' V, _+ F7 G! F& G6 x, freturn ;
+ U* y1 k$ I1 F/ o; x7 k& H//--- We are in the trading window, try to open a new position!
4 s1 P( Y. S9 F% q+ lint sorteio = MathRand();
+ R7 ^0 s7 ]9 J/ C2 ?& C. @2 L//--- Entry rule 1.1' R" O/ @# t" E) b* }* f) n
if(sorteio == 0 || sorteio == 32767)
5 I1 b# l# l- L$ C. Ureturn ;( C3 @9 b5 T2 _. C7 |, n- `5 u# i* K
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
/ Y6 o; A1 f* P{. Q' [( X+ V! Q' Q
negocios.Buy(info.LotsMin(), _Symbol);) G3 }, K p3 \5 y, C
}
6 j2 O9 v6 q' F1 T+ gelse // Draw rule 1.3 -- odd number - Sell
" t Z( d& N; c{7 q8 g4 l4 @1 M, i6 W
negocios.Sell(info.LotsMin(), _Symbol);
2 X$ R5 u( ?0 y1 _}8 v! F3 s' b1 k& u6 }3 J
}4 z& a0 O7 |4 ]) D* g9 _
//--- Check if we have a new candlestick...
! q9 ^3 M& f' `* u$ d1 f' P: Pbool tem_vela_nova(const MqlRates &rate)
( L) _# n8 F) l/ U, B1 ~{1 a( {1 K, [) _5 R
{6 c. W! Q% B0 E4 x* x$ y
ret = true;& U; J: l( v& r# f, V( }
close_positions = false;
# I0 H- U/ p9 R}- x6 }& W6 T ?0 v2 K; B3 }1 z
else
4 K/ @) Y- \7 B- A* v4 ?{
- `2 g+ T1 Y8 O; J$ S% H/ \if(mdt.hour == 16)% Y& t7 e, T( |6 T4 A
close_positions = (mdt.min >= 30);
( N4 k5 v9 j) P9 _9 h* ~% M}
7 h; s# o1 x" }6 F( x. \7 q0 `}
$ I/ u; N' }2 m6 V/ k& w/ Mreturn ret;) {$ g/ A1 T$ r7 i }1 y
}
! N& O* {0 W& u) Z% P" [//---
7 k+ e! \" r2 {3 g5 M1 L+ ^bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])' ?/ ^* q7 {$ n
{. k' q7 c" E3 o+ N" c
if(PositionsTotal()) // Is there a position?
* k0 n( f9 P9 J7 M- c9 V{0 N* k+ u5 z% S$ Y1 ^
double offset[1] = { 0 };
% S. [/ J# a% G% Z" ]+ g. J4 iif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?2 d0 `7 @$ G' t
&& PositionSelect(_Symbol)) // Select the existing position!
7 c( X1 j/ g1 ~ r2 b{4 f6 N+ o; p8 `9 E4 B
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
) _7 h5 t- K7 i Y9 ^( ]' u; F1 ~double SL = PositionGetDouble(POSITION_SL);) A% s+ K$ a* \ N% N, u
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
! C: q, i( | K9 @& H* a, Nif(tipo == POSITION_TYPE_BUY)' f% u% Y& A! g) `7 |
{
, Y/ N3 f% _. J3 |if (cotacoes[1].high > cotacoes[0].high)# M; {5 J9 P. q, Y5 G
{# D/ a- G$ A5 Z3 F
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];+ e' A2 f C! i T+ y8 ^* n
info.NormalizePrice(sl);5 x' n. o* F/ l% J% P
if (sl > SL)
, K- H- ]8 y: {/ j; n: q+ ?. E{0 d/ I$ Y0 {- ~7 t5 G/ }6 t S
negocios.PositionModify(_Symbol, sl, TP);8 ]8 J4 E' D" N6 p% v r* N
}1 L" a' \" K, J f
}/ {1 I$ a- u5 k! e$ a+ d3 x. L
}
; S, T( b$ C, B4 m/ i" Ielse // tipo == POSITION_TYPE_SELL% k1 g; M$ E+ L1 ^5 R, P7 A8 D
{; A/ y; H2 w% R# R( T; w3 x2 R
if (cotacoes[1].low < cotacoes[0].low): ?" U- [) p: H; I# g8 x& T
{
) T( N2 C" [* ereturn true;
1 L+ g9 d! P$ @5 a( N8 H}
- e; N7 p! K" Q! i, p, l$ Y// there was no position/ ]/ Y0 u2 ^$ K+ Y- b8 M# h
return false;
6 ]- H( k- D" ^}: p% _5 }' X+ m( I
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。+ v2 w6 Y4 b! i3 z( D; W
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |