启动交易模型,并构建 EA! k/ ^7 u$ w8 s( g; |; J! F' g
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
# m: Z: o, A: c9 T: h为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。3 z, g5 d+ g. K: H
以下是制定这些规则的代码。
: s/ i% w6 q% b, }//--- Indicator ATR(1) with EMA(8) used for the stop level...% W, H% G# `- }: z' H% d
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);' V- c9 M B1 B) \8 l( l
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);& r: D* x( C$ k3 `1 b! }
//--- Define a variable that indicates that we have a deal...
' b7 R3 C8 t8 obool tem_tick = false;
5 W- y% v# G% f# P//--- An auxiliary variable for opening a position
) W3 L! h1 A) v#include<Trade/Trade.mqh>
+ b L3 v3 e5 \% h% y3 j#include<Trade/SymbolInfo.mqh> T% o7 P9 I2 y" E' _
CTrade negocios;, h( E. w2 |! H' u6 L1 e
CSymbolInfo info;
7 x& J+ U1 }% T# q C! r//--- Define in OnInit() the use of the timer every second
, }9 }' w" b. P//--- and start CTrade, x! \) l. l, _0 g' l+ X
int OnInit()2 Q6 o, z: [1 g& j! x8 |9 u: x
{
+ x S2 a7 ^& @1 {. b5 g5 |3 J( _//--- Set the fill type to keep a pending order/ M& t, A2 P' B0 Q" P
//--- until it is fully filled
! A9 x# D- o* r$ w2 Wnegocios.SetTypeFilling(ORDER_FILLING_RETURN);) [% \3 F9 f. f1 F6 u
//--- Leave the fixed deviation at it is not used on B3 exchange
7 H5 ?" P* p9 ?" nnegocios.SetDeviationInPoints(5);: z) A, c8 m8 }. T7 T" g
//--- Define the symbol in CSymbolInfo...* A7 L u8 y! {2 X" C$ f
info.Name(_Symbol);
, l6 }% \# @4 [5 F+ d//--- Set the timer...3 m, e3 }0 [2 E C; B- G; d. D
EventSetTimer(1);
. H6 R: ?3 M, T! t+ X- K//--- Set the base of the random number to have equal tests.... l+ |2 ~: E0 F1 T, ^0 h0 E
MathSrand(0xDEAD);
5 v5 Q& g: [- J# {$ J9 e3 x' q, D% T% Qreturn(INIT_SUCCEEDED);, y8 X( [$ C3 M8 U8 q
}: }) k' O; s8 L5 H6 x4 W8 Q
//--- Since we set a timer, we need to destroy it in OnDeInit().
5 O: d/ b! H& m# j. cvoid OnDeinit(const int reason)
3 C# {) c. s- ?) ~{9 _$ k( y( H2 C% l# \6 r$ C7 N' Z
EventKillTimer();3 t- l1 v, l D, w
}1 b( ]' S& `' w" @; o4 q
//--- The OnTick function only informs us that we have a new deal
, l( l' R# A s. Z& Mvoid OnTick()3 ^1 E# s% c% v
{
* ?! {9 e) Y/ n2 b& ^: l" |tem_tick = true;8 _6 b! o/ b9 [1 w4 l/ E% D8 }
}
1 L# {) F% y2 i# a2 T5 p//+------------------------------------------------------------------+8 U2 H/ a$ e$ p5 V
//| Expert Advisor main function |
/ g6 c: X$ G, Z4 ~/ Z. t//+------------------------------------------------------------------+
7 a+ ?( i# ~) T5 ]3 K u+ Yvoid OnTimer()2 x! P* U+ [4 w/ A( ?
{& g0 s4 T7 X; a$ [5 }# J5 i7 R
MqlRates cotacao[];
* n$ _. e& q4 ^' m( p+ Areturn ;' ^! I1 u, b/ s$ U, o
if (negocios_autorizados == false) // are we outside the trading window?& [& |; G1 R1 N) f, b! E
return ;9 Z9 c: e2 U: J8 P
//--- We are in the trading window, try to open a new position!
" K1 v8 t% _1 M0 x; B4 Jint sorteio = MathRand();
# G; z( W# U' S5 a! f//--- Entry rule 1.1/ ]0 [! U$ y& D! e/ U
if(sorteio == 0 || sorteio == 32767)5 E1 G0 J q0 i: I2 T
return ;
8 ^" }9 K9 J3 ^9 z( b- {8 W" @if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
# z! K8 T0 x6 ]9 S3 M{
0 e& W( _+ v! g4 }negocios.Buy(info.LotsMin(), _Symbol);
$ S1 w) P, b1 ~( j}& n# G. d6 |0 n; p& v3 N# @& F
else // Draw rule 1.3 -- odd number - Sell% d( |; W% A$ H! Y
{
% f7 s$ k) J3 y2 L& k6 u: n% Qnegocios.Sell(info.LotsMin(), _Symbol);2 C8 }5 }) j3 f! {; K
}; B& w% w8 X4 G( m
}
, z; u) h9 V5 [//--- Check if we have a new candlestick...% F2 M6 ]2 Q( E, Z$ l0 k
bool tem_vela_nova(const MqlRates &rate)
! p2 C4 ?3 v7 s{
2 K2 }- T5 S7 ]{
; m7 C, [5 ]3 Q+ h- x; wret = true; F% i1 g' X, y8 Y+ \1 P: {$ F$ ~
close_positions = false;# _" Z1 B- l; y% w, M
}
# G. k" C! j7 N, j* qelse ~& n" W6 u7 O5 x1 `
{/ [8 f( l& @% U0 u
if(mdt.hour == 16)
/ o3 H" e- t& d/ T( mclose_positions = (mdt.min >= 30);+ L; w% X5 Y. b& |
}
. V H9 H7 b# q: t}- J- [' e# s1 K, M
return ret;
3 N' Q. F7 W' g& p% _* c0 s4 |6 e}
/ N G; Z; V8 \' i, J//---& X& v9 F1 P. ?0 N q3 u
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])$ `& E6 g* |6 H/ D: P+ c3 w% m Z( u
{( X% T3 c$ a$ ^% h5 _4 W8 k
if(PositionsTotal()) // Is there a position?
9 \6 e" J3 ]! p" ]# K, h{
& T; f- U X" _# g& R4 ^double offset[1] = { 0 };+ p- [' o+ T1 @" P: g
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
9 |( ?# s& J/ [&& PositionSelect(_Symbol)) // Select the existing position!
; N2 S7 a) X& E4 H; g' h. |{
) E7 a# n5 O* q3 `7 t9 W. ]ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);. }# {; \+ Y% r3 O* y
double SL = PositionGetDouble(POSITION_SL);
^8 p. ^+ B; t8 W) m( Ddouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
8 H$ {1 h1 Z, G: |$ ], D: k0 }if(tipo == POSITION_TYPE_BUY), [/ H3 K H; y- n7 X& j. \
{
1 \- H, U. f, _% o7 L2 D# Pif (cotacoes[1].high > cotacoes[0].high)
. A0 d: {# Y3 R) O7 z3 l) a( r8 X{% K: r% M" H, _' {9 n
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
; B% o% k$ Y. m) c* _0 Ginfo.NormalizePrice(sl);: r* g) ?' H8 x1 `9 B3 X
if (sl > SL)9 y3 A. {+ _6 e8 Y
{
1 ?: u+ O2 V" s/ s( ~6 o# y/ G$ ^. [negocios.PositionModify(_Symbol, sl, TP);+ h0 K- ^ ]# z% G! | H
}! T6 l8 _/ z1 f/ V Q: g
}
4 B% L0 S: O, x5 ^/ X7 ^# Q}
6 E+ L, [; g7 ]: |( A- u; G, F3 Jelse // tipo == POSITION_TYPE_SELL
' }- g- Y9 {1 }" e7 r! U+ s" O{
0 D b w( f/ k; U# P) Oif (cotacoes[1].low < cotacoes[0].low)& p0 u& E e( Z u5 N
{$ w% m' F+ M( n: V6 l
return true;1 H1 d2 v( x# l; p) u4 E( r& n
}7 S' e$ n8 h) C2 O" o
// there was no position
6 @0 o, E+ T3 P2 Rreturn false;% j: P( I0 }" F
}
* P1 D) h. J- H N我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。: U' o4 J& b9 v# Y. w+ \( }2 `
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |