启动交易模型,并构建 EA
; q- {7 X$ G6 a, m) G6 O在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
' ?" x1 j7 z% z( d6 P; F6 o% s: Y为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
8 L/ g% C) b( J7 M- K以下是制定这些规则的代码。
5 k" c1 b5 c7 o% ~3 B//--- Indicator ATR(1) with EMA(8) used for the stop level...$ B) Q( F) ?: E g
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1); Z: C6 P' c/ _
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);5 `& M0 K) y2 q
//--- Define a variable that indicates that we have a deal...
I1 b: Z/ p8 D' Ubool tem_tick = false;
* T- k) _1 Q- T4 J' P- l& x//--- An auxiliary variable for opening a position* z, M( ]# w5 Y3 J; H3 K
#include<Trade/Trade.mqh>1 ?1 Q7 C3 l! X4 A; _: H
#include<Trade/SymbolInfo.mqh>
; J$ i) K8 g V! T2 C3 kCTrade negocios;
, C+ g: @) r# ^$ a* j) n& p8 Y QCSymbolInfo info;
4 ?$ t6 O. ]7 I: O% g- Y+ i4 V//--- Define in OnInit() the use of the timer every second: ^: q9 ]2 @& x0 c' V6 R1 m
//--- and start CTrade* w. N" A4 w0 ^; F, s% a
int OnInit(): _; E, J/ g) N: K
{! C& N" b2 t9 J4 k* w$ v
//--- Set the fill type to keep a pending order, b: M' ], ~, S1 d% O
//--- until it is fully filled1 {8 a9 T; T; o1 W _/ w
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
. c3 K8 k, [) w9 d0 U//--- Leave the fixed deviation at it is not used on B3 exchange7 P8 H/ z: t4 f+ @3 Y' J
negocios.SetDeviationInPoints(5);$ X$ [' p0 B L1 K6 K% M
//--- Define the symbol in CSymbolInfo...
1 V; U3 `5 A3 S/ d8 V" Linfo.Name(_Symbol);* U6 f9 o" l* H
//--- Set the timer...
9 C0 T7 W% ~- ~; u/ iEventSetTimer(1);: k; \; p/ \: m+ d1 G/ v
//--- Set the base of the random number to have equal tests...# O# I+ J0 v3 @3 r9 d) b
MathSrand(0xDEAD);
0 ]1 z) r* a; N1 d3 p/ M8 oreturn(INIT_SUCCEEDED);
0 I, a, ]# }8 H}2 h6 Y. u# A5 w" K9 `+ G6 \
//--- Since we set a timer, we need to destroy it in OnDeInit().
1 T9 f: G8 x" @7 Z$ ~& } y. |void OnDeinit(const int reason)" t) |1 T$ `8 E- `
{3 z3 m5 [; g6 P
EventKillTimer();9 R4 }& Y7 O- p( g2 z0 A1 W% d5 [2 s# d
}
: q3 {+ E& a# k; s1 j- J- h//--- The OnTick function only informs us that we have a new deal3 c( t. x2 ^1 S0 C
void OnTick()
y( _0 |+ v- m0 N0 x9 @" ~4 e{ z, c5 k- G8 X7 P0 c! V; l6 [* q" j
tem_tick = true;
$ r e4 p' W+ F$ X) s) O! c; G}
' U8 Z8 p7 e; C. s9 ^ o//+------------------------------------------------------------------+4 ]' b( A* P% [) C" B" q
//| Expert Advisor main function |9 J' g8 i% U( P7 j+ h _* j% H
//+------------------------------------------------------------------+( J9 J# F5 v: Q( I6 j
void OnTimer()/ {' w- P! O% e+ J, x
{
7 c9 s3 f, e1 ^* _8 m: c3 c X6 \& NMqlRates cotacao[];
2 a# A o# B" p& K& u' breturn ;
6 z- H6 Y @9 y1 X2 m( G2 Jif (negocios_autorizados == false) // are we outside the trading window?
1 @! T( X- G( ?0 \) s: Greturn ; n m+ p/ Y& Z- G
//--- We are in the trading window, try to open a new position!
- z: \: ~/ U% x6 w/ v7 y& t3 I. r5 pint sorteio = MathRand();4 @' C9 G/ }3 I6 e h# G! N% o
//--- Entry rule 1.1! w. n1 J2 f0 |" N- q4 X' [
if(sorteio == 0 || sorteio == 32767)
+ Z" `4 a( @% Q4 v+ v! [/ K0 Lreturn ;
8 G' U. i- c8 i* d0 E% ?: ^) g4 |$ \if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
) ] Y& ^6 Q% |. x; f$ o; |) k2 g) G{
% a6 i$ O: @5 ]7 y) o8 i) y. Fnegocios.Buy(info.LotsMin(), _Symbol);5 \' e8 X6 E$ f- C S1 b
}
$ X# G3 r% S5 F! M/ Zelse // Draw rule 1.3 -- odd number - Sell
9 T0 H4 L7 l( I6 F" b{- r+ h5 m' w+ S5 a
negocios.Sell(info.LotsMin(), _Symbol);
+ M0 J1 }" C% n* N+ P}
- `% m0 \" Y' c8 b5 a}& Q2 i' \8 E4 h! ]1 k
//--- Check if we have a new candlestick...6 r; t M5 H+ c) V, f" F b6 t2 `) C
bool tem_vela_nova(const MqlRates &rate)$ p( b" \0 D& P% B Z4 v
{
C; j$ P4 o( ?+ w) c" @( S3 x{$ T9 @! ~3 ~; x' s- j6 D( H2 Q
ret = true;. a5 p) {* o( G% o
close_positions = false;
9 t% u4 u8 s% r6 E+ t}
8 a7 ]$ Z% q; J' n" |else
- @8 k3 F: T9 H8 k- Q4 L" v% |$ [7 @{
. M$ ]* o! W }- D- Lif(mdt.hour == 16)
0 S, H! S- K8 j R4 g( K3 bclose_positions = (mdt.min >= 30);. L2 g+ f! A" X/ ]1 Q6 D
}
5 q3 W1 l. e+ j, H" Y}
# c6 ?6 U. [: ?5 A$ ?- \return ret;
8 T7 f! O- W9 k, v7 f2 D( b4 `4 L}
0 r* s8 g! L6 \1 [ D//---8 \' v4 Z: ^" P/ A$ X& r" J
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])& |; F. P/ x; _5 J& a& f. }5 s6 y
{' U4 w2 t+ g0 a- l) h
if(PositionsTotal()) // Is there a position?6 j" J: X) i; g9 _
{$ I' ?+ Z- Q9 g i, K3 ?
double offset[1] = { 0 };
6 Z9 ^) e) ?( n3 U2 ~1 ~7 Nif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?2 U5 H, E1 A: S9 R# d3 g
&& PositionSelect(_Symbol)) // Select the existing position!
5 N( K' M- @7 n* M* _" @{
2 Q5 \8 S2 e' LENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
T+ `9 a2 K8 b, J% d" ~3 w1 idouble SL = PositionGetDouble(POSITION_SL);
; D, N& p S# T# ?9 A2 d) u+ gdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
0 }! L# W/ T0 @! a2 gif(tipo == POSITION_TYPE_BUY)
2 m* o" `( O, U% H: }: f8 j4 E{& @ D1 ^ A% j* X* ~
if (cotacoes[1].high > cotacoes[0].high)
% O$ k, b& _" ]: \0 w{4 r8 s5 L# Z# ]) j" i' t. B$ s9 x7 t
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];3 `+ U% v4 j8 n, D
info.NormalizePrice(sl);
* g- P) e' T) O+ ?0 ?- ~4 ~0 h( Xif (sl > SL). N7 o8 Z$ ]* l
{! z& ~. Q' a5 i$ A. @, ^
negocios.PositionModify(_Symbol, sl, TP);
$ M7 a* o1 g3 I2 g+ L3 g} n- K: A9 V5 b; r2 S5 Z W
}
0 S+ C/ k/ ~# n0 K( i7 v6 e1 d}9 |9 u% h, w) f. P9 Q) b
else // tipo == POSITION_TYPE_SELL& n6 V3 V x2 x9 r! E
{. ]& z2 s* M, Q0 r# g6 [, T
if (cotacoes[1].low < cotacoes[0].low)0 ~6 q$ w5 N3 h
{
# S2 A( R6 ~5 ^7 d8 Rreturn true;
8 c9 D, F9 i- o0 T( m5 R: q& [}
- [! E6 H4 W! y) R* q' G// there was no position
7 g3 L5 k2 s/ o7 lreturn false;; J: e% a/ s" v" X$ b3 t: p" L
}
, [+ Q0 L2 B" _* m$ B* d我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。& Y; ]8 s) y: T7 n) }5 j
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |