启动交易模型,并构建 EA
) \4 V$ I. M, Q/ \1 h' P: _# H' @在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。( f/ M/ a# {3 q" H; P) P
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。' c, [- {4 Q# u2 @3 ?; s( ?" ?
以下是制定这些规则的代码。
7 y- L6 B ~9 s/ x) |, B0 d& G( k//--- Indicator ATR(1) with EMA(8) used for the stop level...
2 m: D+ P( h0 |# ~int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
$ ]* @* J! Q9 U- A/ xint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
. Q8 \1 R# i! o//--- Define a variable that indicates that we have a deal...
9 \4 K0 [$ [' @% c( c0 r5 ~bool tem_tick = false;
9 h/ c5 P* x' h, [% v//--- An auxiliary variable for opening a position* p+ y4 S/ H- q% D$ z+ m& `
#include<Trade/Trade.mqh>
4 E2 w: a( ^. _7 `/ O/ N#include<Trade/SymbolInfo.mqh>; U) N# ~" Q4 |
CTrade negocios;% Q4 i- |/ v/ Q/ f
CSymbolInfo info;
* F) S6 @0 q4 P k" T6 Z& r% Q//--- Define in OnInit() the use of the timer every second$ k1 J1 L$ n1 x4 t
//--- and start CTrade
2 Q( R$ i) O O6 i ]int OnInit()
4 d! l7 v1 R8 L$ N{8 X# \' R% d! y8 N! T$ g
//--- Set the fill type to keep a pending order" N- D Q1 f+ }- E9 `
//--- until it is fully filled
' ]% u: x) Q3 R' Znegocios.SetTypeFilling(ORDER_FILLING_RETURN);
" K) r, x; P& q7 |7 T//--- Leave the fixed deviation at it is not used on B3 exchange+ Z4 {% C8 M& i* m3 u
negocios.SetDeviationInPoints(5);" p" c8 X' _* N A0 t! m/ ~7 [
//--- Define the symbol in CSymbolInfo...
8 c+ U% p- I# d+ X8 ?info.Name(_Symbol);- G$ S# o9 y$ D4 ^' \: t! ]+ a1 |
//--- Set the timer...: V1 O) t+ C0 c2 S/ s% z! _
EventSetTimer(1);
9 q! f4 x$ p! @5 q) t" g8 C+ ^" K//--- Set the base of the random number to have equal tests...5 [1 o: T% f1 s- H# l) l
MathSrand(0xDEAD);
- ~1 }, M, Q2 R6 e4 r; Ireturn(INIT_SUCCEEDED);$ U- m; ~' y/ N1 V6 r% S
}
" ?1 D. z6 p% l) o1 q: ?' U G7 S//--- Since we set a timer, we need to destroy it in OnDeInit().% Q5 c8 c% M& e$ Y: w# I3 q
void OnDeinit(const int reason)
- r9 A8 u& @* Q9 R/ U/ o8 W0 p{
; _3 ] G+ y$ d" eEventKillTimer(); A! y6 p* a9 v. I: @7 m
}
! p$ _- \9 `# y* c4 G//--- The OnTick function only informs us that we have a new deal( J5 m9 g; u# {/ Q1 v
void OnTick()6 p1 d' q$ w9 `& F) i! K( C" G9 U" t
{) K7 v9 R$ J' A. m9 O4 B
tem_tick = true;
]* G5 A$ _; i8 [0 a2 q}! P! L( T7 t5 \6 @
//+------------------------------------------------------------------+
2 s4 a5 T5 m2 u4 y//| Expert Advisor main function |
) Q: p0 M. y/ x+ P2 r8 m//+------------------------------------------------------------------+
. |- F- g8 u/ y( ^void OnTimer()
. a* g7 Z$ x4 J3 R: P{5 `$ j9 b: r$ F0 X4 G5 T3 C- y) ^
MqlRates cotacao[];
- K0 R$ K" C1 i3 J, J$ breturn ;, b! @4 ]7 R0 X& f" W
if (negocios_autorizados == false) // are we outside the trading window?0 {# l/ a( p K" q2 t
return ;
% F6 H; R1 M1 ]2 D//--- We are in the trading window, try to open a new position!3 g9 G p( M* r8 {& R
int sorteio = MathRand();) X2 s$ B2 P' u; k4 G- K8 s
//--- Entry rule 1.1
* X6 n# O% u% G8 U! J4 X! fif(sorteio == 0 || sorteio == 32767)
& R7 R2 w+ a6 L* |0 w n Ireturn ;1 {' z3 _6 { u8 f
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
* j% o$ z7 L; }( f+ L{
# s& k& U2 k" G( `$ Snegocios.Buy(info.LotsMin(), _Symbol);
& ]( v" ]. ?$ A/ g- ^: m}$ a- c. D6 m* |4 F: b
else // Draw rule 1.3 -- odd number - Sell
: ~2 ^/ L5 l" D/ E/ {8 D2 A{
1 V& U9 R7 U; Lnegocios.Sell(info.LotsMin(), _Symbol);' X& o1 t, D v* {4 M, e0 M
}
+ x. V* J3 M. C$ ?}# J! ?, H7 z6 a6 @9 M9 F9 C
//--- Check if we have a new candlestick...9 [: i' E9 _! E$ Q9 c
bool tem_vela_nova(const MqlRates &rate)
, D$ s \$ C, d; R! q9 h) C{! O8 E" M; L$ X- h
{+ M3 F4 i1 d. E7 h; v
ret = true;
2 |: Y5 g1 B4 A4 ]0 Z4 q [$ H3 fclose_positions = false;
) c8 n% G7 _- G5 ^! E0 w( u}1 b) E7 R7 j$ K
else! F/ W6 O6 Q4 K4 }2 D2 ~
{+ Q9 @& U8 a. Z) W- J" {
if(mdt.hour == 16)* `% U+ S" I" u0 l
close_positions = (mdt.min >= 30);
1 r9 Q5 U3 s( |! j' j& c. }* j}, ]: e" k3 u$ x, h4 G/ c
}( A! ~1 c8 E* j; o, O0 C( ]9 H. _
return ret;
v$ G2 H4 R& k0 R! [8 y5 \, ]! R4 [}9 H8 i ?: C; \
//---
$ l0 I, Z, P4 e5 M& ?bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
+ g; L* E# G- w* R! L{
: |' a- ~3 H/ n7 oif(PositionsTotal()) // Is there a position?4 Z- w- }/ n1 b7 Y* Y) A( C
{0 a6 p8 v( p- P$ M9 R. Z5 V
double offset[1] = { 0 };5 t$ `4 h0 l: m) t4 C; {
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
) e: T4 C4 M: q; F&& PositionSelect(_Symbol)) // Select the existing position!
o1 i3 Q+ X# u2 c, ~; U7 c{, L' u/ @6 I+ u( x& M1 L
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);- ]4 w6 Y: S# u* i# l
double SL = PositionGetDouble(POSITION_SL);
( f+ l( m! A. Z0 u: d7 P4 ?* adouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));* ~1 J) O# E9 o
if(tipo == POSITION_TYPE_BUY)
8 \6 t; ]8 j' I* h' [" e" l{3 U" l# t+ s# q5 p9 p8 N
if (cotacoes[1].high > cotacoes[0].high)
" W6 j8 P% s: w& Y# R; A1 u{
) |, M: R) L" ^* ^" e/ Kdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];& }' ~/ q, c* \: H9 V$ l# O8 ?% T4 L
info.NormalizePrice(sl);+ L. U& ^ V4 ~$ u( @9 h
if (sl > SL)7 _! _! w" h0 U/ {: ~3 q7 f
{
, s3 L( a& k6 \+ j" W+ `negocios.PositionModify(_Symbol, sl, TP);
' E. ?+ ^3 |" L4 D& t) {}
; s% V, l$ o, k$ n9 C}
0 ^' g& o+ j4 n% C: \4 k/ L Q! V}4 Q; m7 X) R G2 e
else // tipo == POSITION_TYPE_SELL
) |, C7 I4 V( C. d{$ D! |0 { g* A4 H
if (cotacoes[1].low < cotacoes[0].low). B; K4 k6 P8 F4 X9 l, [
{
$ |* e* n7 f( T A* ireturn true;0 ]$ H8 T' z$ x( i" N; K
}
8 c/ L- ]* ^! c# @, J# w// there was no position
9 t ~8 e- B* \6 Rreturn false;4 ?9 v' h, w% j
}* `# L# r5 m/ ^
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
( J- A/ R% j9 f% \/ ] k到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |