启动交易模型,并构建 EA
1 {: W8 D8 b" Y! `在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 O0 x+ V5 e8 I: D5 O* u+ V$ A为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
6 \$ {# N' T1 C以下是制定这些规则的代码。
& v% M+ Q1 J' }/ u: {+ H//--- Indicator ATR(1) with EMA(8) used for the stop level...
. C# h5 z$ Q6 T' }8 hint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);) o4 y$ a2 C4 j: i/ l) x
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
/ Y% |5 A* I8 |//--- Define a variable that indicates that we have a deal...0 z" n" h+ f( j4 E6 x' t
bool tem_tick = false;1 }. R0 X3 M' W
//--- An auxiliary variable for opening a position' _5 \) [) r& A& a3 ?( R8 m( m8 w
#include<Trade/Trade.mqh>
/ U+ i# d+ u$ `# U#include<Trade/SymbolInfo.mqh>
0 `' U# T4 f, Y. k" y5 O8 vCTrade negocios;: F/ o( k5 T8 J8 n c
CSymbolInfo info;
% K5 `* v: @* A4 |//--- Define in OnInit() the use of the timer every second
7 B5 x9 A. H J! l//--- and start CTrade
3 O' r1 o2 J2 L2 Z6 aint OnInit()
. i2 J3 q, K6 g- }9 V, T{5 M: Z- F8 J' c6 U9 f0 \$ Y* m
//--- Set the fill type to keep a pending order7 n3 f7 s0 {9 @8 p0 D
//--- until it is fully filled: M2 {/ F" M4 C, u) d! }
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
& z- `% L1 \2 J//--- Leave the fixed deviation at it is not used on B3 exchange7 B9 G& _9 K2 I2 ?9 a
negocios.SetDeviationInPoints(5);
# A! K, X5 G% U+ c) T//--- Define the symbol in CSymbolInfo...2 h1 e3 z% d& z- \, I
info.Name(_Symbol);
6 L5 E2 X& s+ q9 A7 m//--- Set the timer...
0 r8 c* P l! ]2 kEventSetTimer(1);% Y: l* U: Z, Q- S$ [0 l
//--- Set the base of the random number to have equal tests...
. P7 g5 N7 d$ ~- F Z1 T' [0 J% rMathSrand(0xDEAD);
* b. s2 U$ U- r( U+ zreturn(INIT_SUCCEEDED);
6 v# ?9 Y0 Q( r$ p+ S8 S: ^5 Q}5 G$ R2 L0 _" ^4 m/ n7 b
//--- Since we set a timer, we need to destroy it in OnDeInit().
8 l5 z) D7 Y: ~- f2 a% Qvoid OnDeinit(const int reason) j& t# X$ L) {2 y7 J7 _
{
9 V( ^0 q ?' S0 d9 c& kEventKillTimer();4 A% @+ H. F2 j& W
}
0 h" Q9 K) _) o. ?7 w//--- The OnTick function only informs us that we have a new deal# C8 y% y/ ~6 i+ N' F
void OnTick()& o/ s; w9 ~! a3 n- s0 Z7 L' s
{
$ b2 |) k4 e, |tem_tick = true; N7 u. E: i! m7 {
}. [8 h9 _$ W' D; t
//+------------------------------------------------------------------+9 y% v8 k* ?) a; O8 O
//| Expert Advisor main function |
. f2 u1 F0 i1 b5 }//+------------------------------------------------------------------+6 ~. A9 e. D5 Y- N1 [; r2 J
void OnTimer()8 p' A8 W. ?7 N
{
. ~2 Z& I4 E8 I8 {MqlRates cotacao[];+ u, S( y- ` C4 ^* V8 ~
return ;
$ R9 C4 X t ^* y1 V% m* \4 N5 A7 Hif (negocios_autorizados == false) // are we outside the trading window?
1 _$ [) J: s* ireturn ;4 k8 B& [2 n& C8 V0 w4 Q: z: p5 }
//--- We are in the trading window, try to open a new position!
& r, Z, ?) n' U* pint sorteio = MathRand();
# @9 q: c& L* u" m//--- Entry rule 1.1& C$ |& C0 T" E- X k$ C
if(sorteio == 0 || sorteio == 32767)
" [9 o9 q- J- t% ireturn ;
* n0 W% ^, _, F* Z) e( d9 dif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
/ p+ Q/ @9 v, H/ u/ p4 h! d/ T{2 {' x) b; `+ l) x! o
negocios.Buy(info.LotsMin(), _Symbol);) h7 g* u: s6 ^* o* W/ M
}
$ d* L3 `; g9 W" d+ @+ Eelse // Draw rule 1.3 -- odd number - Sell
Y, q% K/ _4 i7 ~8 j{1 w$ n; X% W' l1 O
negocios.Sell(info.LotsMin(), _Symbol);) @9 s- L1 K$ [( U
}
3 g; i* f2 T0 o, q: l0 D}
/ x( g: c' \- J5 ^* Z//--- Check if we have a new candlestick...
8 r' [) d2 [: N6 q$ ?% Mbool tem_vela_nova(const MqlRates &rate)* U3 M2 ?( {; E. k1 r
{
' B9 S' T6 K0 L8 U, N0 E% x{
9 [4 m" W+ M# u! oret = true;1 g; T0 P" B' ^- V) S) C9 ~
close_positions = false;, v1 g" @# p8 r3 I/ x1 c
}
3 }% ?: ~3 ~# a+ Qelse
3 G E' Y, { l{
; f# r* V$ ~+ ~% k% k" h) Pif(mdt.hour == 16)# J5 Q8 s, h8 ]; K: j
close_positions = (mdt.min >= 30);# Y% Z9 t6 R1 U. r- C
}
" z0 W) d. K9 W, h}4 Z' `1 w: \; n$ j
return ret;
- U" {$ o# q" b% U; Z, x}
/ A+ g6 j% u6 D6 y, A9 M//---
( f+ M. K0 U- j' obool arruma_stop_em_posicoes(const MqlRates &cotacoes[]), e. W2 G9 M1 z. E/ @
{
6 H( G+ z! Y( z! P: f5 ]* @if(PositionsTotal()) // Is there a position?/ g( z2 A( G+ p& ]( X4 R5 t
{# X# l2 L9 _7 h+ s- h
double offset[1] = { 0 };3 C+ c" N/ Y1 ]' p
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
9 U! S/ a9 y" X5 x" f* g5 z&& PositionSelect(_Symbol)) // Select the existing position!/ y5 g4 |! {. E' y
{$ S( M7 T& x2 O* K. {3 u! H
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);( P2 J c6 O& e# @% u$ k
double SL = PositionGetDouble(POSITION_SL);
N, z2 e" m0 R D# Kdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));' |0 R- D* ]+ u Z0 L, i7 S! O6 x
if(tipo == POSITION_TYPE_BUY)
) j8 q5 C) k" \/ o, H$ d{: w: g, ^/ D( w6 l# E) t8 R/ {
if (cotacoes[1].high > cotacoes[0].high)
. {6 Y% Q, ]5 e{
" P, u+ f9 W& s9 pdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];- s, Q' }3 l* W$ s* b
info.NormalizePrice(sl);
* G' r( z3 J. a1 V( O+ cif (sl > SL)
# i; ?/ e+ N1 d3 t, m( `: J1 h{
8 c- h) L+ v; W( w# i. Knegocios.PositionModify(_Symbol, sl, TP);; X. E, U/ S8 z5 R: L
}3 y+ Y' X* g* l, n
}
! D/ W% H/ i3 N8 I}
" b, s/ u1 X; F2 ?: Ielse // tipo == POSITION_TYPE_SELL
; z9 ]* W/ F! d% s6 }{
$ G5 j/ _4 B4 R* I! Kif (cotacoes[1].low < cotacoes[0].low)( M6 o, o0 Q' f" P1 E8 U
{# e# l5 ]( o X- C
return true;9 \4 D+ B% n9 Z$ E7 D2 Q
}* ?; b: }* \, m [; @, y
// there was no position) {' \4 n; R: k9 B2 X
return false;
7 Q5 ~5 x0 a. k3 F# C}
+ q7 {; V$ b- D8 X% @6 Q* q我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
8 [/ Y4 d C# Z5 U" Z5 m1 e7 ?到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |