启动交易模型,并构建 EA
1 E2 e, v" O: b6 W8 a7 H在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。" Z7 w( X% J" ~6 d& w) K
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
6 W6 l; G. ]: `1 J- b3 z- U以下是制定这些规则的代码。' r+ v7 J/ l( c5 O
//--- Indicator ATR(1) with EMA(8) used for the stop level...0 C- i4 K' |/ r
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);& R* U+ o, ? l! D% r1 H
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);# F# p& z$ d$ F3 U# K+ \- C
//--- Define a variable that indicates that we have a deal...
# s' ]2 X9 z2 | V/ E9 [% cbool tem_tick = false;
/ e6 a$ g) a7 d* n//--- An auxiliary variable for opening a position
# A+ p* u, O. X- D5 i9 }% J#include<Trade/Trade.mqh>5 F9 b9 o; n0 f. D
#include<Trade/SymbolInfo.mqh>
X4 E$ _# S r' h# c) R+ O9 |CTrade negocios;: ^- Y* [& M2 f4 A) S
CSymbolInfo info;/ ^/ }3 @5 C) v# }% }7 p6 d
//--- Define in OnInit() the use of the timer every second
* q* G0 w3 A# i, P9 r//--- and start CTrade' S( H( ]8 j8 x8 e0 {
int OnInit()
. z! B8 Z* n' ^* u4 F{
8 C2 }( w6 G. C2 ]' M* }& @//--- Set the fill type to keep a pending order
' A- {! U3 f0 Z/ N" V% p//--- until it is fully filled
9 Q5 a# z7 n% y f& c" unegocios.SetTypeFilling(ORDER_FILLING_RETURN);3 u, m" R! R7 A3 E1 C' w6 g. k
//--- Leave the fixed deviation at it is not used on B3 exchange8 A& Z) G1 h" L9 m/ a% R4 J
negocios.SetDeviationInPoints(5);7 v# ~; _ M8 d6 B
//--- Define the symbol in CSymbolInfo...
0 h/ K, G/ v. {" P. u" [info.Name(_Symbol);
8 E6 \! q% D( `5 F//--- Set the timer...
. Z( v3 J) O2 J$ g7 kEventSetTimer(1);3 c! t; _2 f) F# y% M! ~; n- q! P
//--- Set the base of the random number to have equal tests... p7 ]4 ^7 H1 L% q
MathSrand(0xDEAD);. t$ C2 C4 J0 t6 s
return(INIT_SUCCEEDED);& U" M/ s! d7 E
}( e2 m0 u& |* s/ z6 H4 }
//--- Since we set a timer, we need to destroy it in OnDeInit().
/ S$ k" f) E( S( P6 a: Y) U# j5 gvoid OnDeinit(const int reason)
. |( j! b( Z% u( r{
' z2 z( e- D% SEventKillTimer();$ t! G! q$ e1 c7 \. o7 a( |# F
}1 Q. H7 a3 D* G6 E6 X- C1 l, L
//--- The OnTick function only informs us that we have a new deal0 s$ m( r p' ~' c$ L& O: Y# G( a' D
void OnTick()( p7 \& W, C9 Z& e; [3 Z/ f: T
{
: C- n }5 {8 k3 O/ {3 A% etem_tick = true; J) e. L* ~6 S$ ~+ c( b. X5 ]
}8 w" Y* N/ k3 h" s
//+------------------------------------------------------------------+6 i5 I- O- U" q& g
//| Expert Advisor main function |" G* h& i; D& ~2 R6 l( Y
//+------------------------------------------------------------------+
) c1 N, j4 x p, Qvoid OnTimer()
+ h/ K2 S4 L! R3 k; L& p{3 @/ K l9 ~- S& c/ Y4 Q
MqlRates cotacao[];6 t. g7 }' }; y; b2 v- U
return ;+ `4 e" o) Y; \# u2 {& c$ l6 H
if (negocios_autorizados == false) // are we outside the trading window?* m, k$ N5 [- N7 ^# a
return ;
& @8 p+ t4 \! a//--- We are in the trading window, try to open a new position!
* `1 |; |( K6 Oint sorteio = MathRand();
9 x: m+ g! s# B//--- Entry rule 1.1
+ S. L# U, l: a1 h" t, Qif(sorteio == 0 || sorteio == 32767)
, G7 R& r0 Y1 T2 V5 vreturn ; V* X0 X x0 E3 n# ?9 L6 `
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy, l6 a9 I. ]: s5 [0 X
{9 z: I# m7 C. K& H3 i
negocios.Buy(info.LotsMin(), _Symbol);
4 i2 T. ^0 S7 [; W7 n ^& D}5 P, ]- B9 K/ T( E% K# P4 S/ _
else // Draw rule 1.3 -- odd number - Sell6 g; o& Y! u9 Y; t5 p
{
% I9 v" S* t, \& Tnegocios.Sell(info.LotsMin(), _Symbol);
9 l' w/ v- Y( i$ I. `}8 r. R7 r8 N3 F& g
}
" a( d7 S& e1 r% v" S* c//--- Check if we have a new candlestick...
8 B9 g, K& v/ F3 y$ Nbool tem_vela_nova(const MqlRates &rate)) {( k+ K9 w# Q
{" g8 J y1 ^3 y: m/ D
{/ b; W' y: o# v6 f/ R2 E
ret = true;
7 ]6 y6 y. e5 K) m) r, Kclose_positions = false;* ^% [1 [. R0 ~
} F- S; e" _; G& G6 h# t4 d3 t
else1 ^' b; s, A+ n6 X# H. I! p
{
) P' j% R: o9 w+ V" Q2 x9 eif(mdt.hour == 16)0 e4 Y+ o0 h- u8 \+ }: I. {
close_positions = (mdt.min >= 30);8 l, @% }2 M8 A2 Y
}7 T( a3 V2 t1 y4 F4 y1 v
}0 ~, z* j" i8 B& l+ k/ D/ t! W/ c: J
return ret;% t( f/ ^1 k: l- ?, u
}
. v! J: |/ }! c( V* X//---
4 l! ~7 R& T" I6 z3 d: I! Bbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
/ \8 e: F0 e& Z; H{
* K* u- ~' q! D Uif(PositionsTotal()) // Is there a position?
$ o T8 R, ~; A0 m* k- q1 R* O{5 r% S6 \! x3 h$ @% Y0 z
double offset[1] = { 0 };
3 t1 C6 i, [) |$ oif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?) r* N" J$ s( V
&& PositionSelect(_Symbol)) // Select the existing position!
. i% A; ?+ J+ h9 W( ~% {{
3 f( P1 X4 _0 L8 S7 n* WENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);: m, @% X2 l' |9 T
double SL = PositionGetDouble(POSITION_SL);6 ]& @# T9 @/ u: d1 A: a m# j; u
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
$ F; D$ G- m+ m& {4 [if(tipo == POSITION_TYPE_BUY)
* v" U6 s6 Q8 |4 v{) s. v0 y( M4 B) [7 ^
if (cotacoes[1].high > cotacoes[0].high); W* D; E9 M& O* H7 K6 {
{
' O l& t& Y& T/ udouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
5 F6 y- t h; y0 A$ _4 o) binfo.NormalizePrice(sl);3 Q# e! \4 l& G0 [; m$ K+ q
if (sl > SL)
1 U& _/ ^4 e. x& L4 |2 Q{
# T4 V/ y( I6 c4 f: ?, ?" \7 vnegocios.PositionModify(_Symbol, sl, TP);
# _* {; y: O& }: D7 v& V2 j}8 A9 d/ p6 h% F" l
}
6 X0 ?( }' y3 t8 |}
3 M' U0 j4 ?, Qelse // tipo == POSITION_TYPE_SELL
+ n/ K! W0 m6 |5 J& G{
1 M# L' S1 O1 i, l% L6 \2 q- a3 Qif (cotacoes[1].low < cotacoes[0].low)
& K( }" F1 O; N" J' q{
. Z4 ]5 ^' s+ `8 U3 H; |return true;
3 D7 g( W* f" g}: j, r4 |# j* u# P. P( B, i
// there was no position0 a% \" G% d/ a9 d$ U# g- Z
return false;
8 s. @+ x7 N/ c' _" l' f( R* ]}% s0 ~; g3 S: E2 n
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
- Q5 G+ ^9 o" R1 a3 A$ _到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |