启动交易模型,并构建 EA. }1 b. k8 r7 J- _, z* |3 ^
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
C2 F, a3 e4 y2 ^; X为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
" a- K+ s( y, m, {7 |以下是制定这些规则的代码。
( ]9 o( x3 c3 G8 Z0 `+ A//--- Indicator ATR(1) with EMA(8) used for the stop level...2 V" _# X0 M* _; n, Q
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 U5 J' Y+ @7 C0 ^! q1 e2 V% }
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);2 u# F/ Y6 x5 F/ W3 E
//--- Define a variable that indicates that we have a deal...
W1 N R% e) n4 K8 jbool tem_tick = false;
1 A# @( q- ?, j8 R4 O9 t' g//--- An auxiliary variable for opening a position
/ m' p/ B6 r# i M2 R: O#include<Trade/Trade.mqh>
& a4 S7 F _) F M* ^' u: ?! c8 t! N#include<Trade/SymbolInfo.mqh>
7 ~( Y5 g4 ] A& zCTrade negocios;
) ^# V2 x4 q9 R N+ ]6 {CSymbolInfo info;0 W1 O$ Y$ G+ r. @( D6 o1 V
//--- Define in OnInit() the use of the timer every second' i" g3 p0 i. m2 n
//--- and start CTrade
' {3 C/ Z- f, l7 ?; X8 c, Sint OnInit()# z1 `" I& U& Z0 U+ s; k9 Z; g* w
{7 C3 f9 D! m+ I. y0 b
//--- Set the fill type to keep a pending order* E( l0 h4 s0 i/ {) p& f% l
//--- until it is fully filled
( V+ Q1 o3 t8 X3 `! X7 u+ enegocios.SetTypeFilling(ORDER_FILLING_RETURN);
( ]7 I+ ?3 b9 J+ O9 D8 }//--- Leave the fixed deviation at it is not used on B3 exchange7 p% }8 e) i3 P& }2 j
negocios.SetDeviationInPoints(5);
! E8 a+ t( H4 V% N3 y7 ?2 d; w1 j; D//--- Define the symbol in CSymbolInfo...
+ Y8 i' {. Z: E9 J- R6 hinfo.Name(_Symbol);
- y& M! V; \4 |; f, I/ X, [//--- Set the timer...6 Q) a1 L/ m5 I1 ^
EventSetTimer(1); |: P* _) u* k
//--- Set the base of the random number to have equal tests...
& n8 F- v: E( E, ]MathSrand(0xDEAD);
8 U: I7 C9 ]4 U7 Z$ S6 i [return(INIT_SUCCEEDED);
J2 m; Q& i8 p" |}
% [2 N( W! @) x) k! H7 x, s//--- Since we set a timer, we need to destroy it in OnDeInit().
8 c4 m+ D1 q( R5 f; }* Svoid OnDeinit(const int reason)3 Z Z, y$ S" n9 [5 S8 K4 V! O
{
/ O/ ]% l% ^! T* l4 w gEventKillTimer();
( y: R- X3 e& |; U. P}! K2 v$ N, h& \2 P% _
//--- The OnTick function only informs us that we have a new deal
8 [ g }4 Z* N5 j3 Qvoid OnTick()
* |& V+ y1 h5 j& V{# j' V, g/ j0 _& b; j
tem_tick = true;
$ V' a+ A$ K% V3 a- S}
* W1 g6 u1 E6 B& w+ `, z& D2 A//+------------------------------------------------------------------+. S+ k6 R2 A( z. `/ X, b
//| Expert Advisor main function |
0 E& w9 o; w# q' A//+------------------------------------------------------------------+
2 T# [+ V) D+ ]& Jvoid OnTimer()1 x. c% N& B$ A7 I0 D/ B2 L: m" o
{
$ x# q$ }. l6 cMqlRates cotacao[];/ J# U q5 Z' I& U0 I* R# ?
return ;2 y# k4 b4 o* `" i
if (negocios_autorizados == false) // are we outside the trading window?
! `1 e ?, @/ N. I$ W2 Wreturn ;3 k1 D5 V5 l2 l3 l; ~# x
//--- We are in the trading window, try to open a new position!
; ~! [' ^4 w/ J# u4 L; k4 D# K! dint sorteio = MathRand();
q! B9 x- v0 ]5 J! A1 B( E//--- Entry rule 1.1% x: c. d2 Y( E2 i8 R
if(sorteio == 0 || sorteio == 32767)
8 S5 K n& W, a* C4 c. f' R% V: hreturn ;
5 V9 Z: l# k* `if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy$ p# }+ E: S, M) f5 Y( ^# S
{6 B0 c9 t4 ~4 [
negocios.Buy(info.LotsMin(), _Symbol);
! r* e, W9 `/ s6 ?/ g/ B% i}
& y7 q6 s' c5 x, o. I w4 F+ {else // Draw rule 1.3 -- odd number - Sell
; D8 J2 ?( c. Y{
. j; v& K- ^; {2 c5 dnegocios.Sell(info.LotsMin(), _Symbol);& T+ c1 @3 t1 J) z: j
}
5 n7 R/ u8 A; l0 J; ?7 X}' ^8 t6 j9 _7 d$ H
//--- Check if we have a new candlestick...( a) N7 }/ I+ v5 t: U( F2 c0 K! l5 O
bool tem_vela_nova(const MqlRates &rate)6 ?+ c9 S- j: ]+ u, D
{8 N6 K6 B- ]2 K* U% v0 T$ Y4 a4 z
{
) E, h: G) D1 w, h/ Yret = true;, m X4 Y9 C6 l1 h
close_positions = false;
7 x$ u3 ?0 {( I5 Y# e4 F}4 N% r& ?" T8 d7 P1 X; L+ M7 G3 Z7 e
else
Q" @$ @$ g! E$ j{+ u* w1 r9 ^( X5 I& F# Z/ Z
if(mdt.hour == 16)
- w* w, c# n+ k: \1 C( oclose_positions = (mdt.min >= 30);$ q2 m6 b8 A' ^# Y& D3 n
}
, G0 W' p+ {" |' L}
/ G m+ u7 q* `9 mreturn ret;
! r; h$ j0 L/ R! Q+ X. s( V( I}7 H; ]& k! n$ O% Y; N
//---5 H. a, t+ E$ |7 q& l6 o% |1 s
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])5 Y. t# I+ i9 L
{: J( q& l b3 x _
if(PositionsTotal()) // Is there a position?
0 _ U5 \1 }5 N" t" M3 r+ g{
. D Z: y7 \" W, d6 r6 Y9 ?double offset[1] = { 0 };
- W, b; r$ \0 |8 p* M8 [if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
! R8 S+ Z% O, f- l) m+ B6 n* _( t&& PositionSelect(_Symbol)) // Select the existing position!; d0 @+ x: K. n/ q3 [
{
4 B" n d. @4 Z0 p! ?ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
( K! w9 n, ?2 R5 i3 f5 S6 [double SL = PositionGetDouble(POSITION_SL);
( c- L R* V8 T' @double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
% U+ d; M9 h7 y q u, uif(tipo == POSITION_TYPE_BUY)7 q8 S( l2 ^' n9 s" m% w
{
* G2 y; v& U: L8 _% i0 g: s; P: \! Lif (cotacoes[1].high > cotacoes[0].high)
' l$ @0 J! d$ U{
4 l! G0 c0 q6 [% f/ ^, Udouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];6 |, I; X' U2 j5 Z/ |% B8 h: k! p( I
info.NormalizePrice(sl);, w, F, H& j% q0 t) s3 O0 U
if (sl > SL)) r. w; _# E# X' Y% m0 Z
{
- e- S- R1 S7 u* G% Z: jnegocios.PositionModify(_Symbol, sl, TP);- v1 t- s, D8 j2 s
}9 r9 X* N+ `' G$ ]4 j5 B; u% \% e
}* ^. E. ~- ^! |" l: H2 V' V( o& `- s7 a
}3 n& b" X1 d/ D1 E
else // tipo == POSITION_TYPE_SELL8 r# h2 ?4 ~$ ~
{
4 x. P5 a; z# r" [if (cotacoes[1].low < cotacoes[0].low)
( s4 ?/ P, }/ Q" s( C{/ C0 |0 L2 O7 N/ ~* S Q7 J" I; d
return true;! J; e3 ?, w5 U
}
3 p& j) \; R. ]// there was no position$ O0 z; _2 u Y! H# h. T- N
return false;
' @: a! h+ ]% }8 r% \5 Y: o+ c}
: } p1 x/ E' ^6 x: g我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。) O% _, n _- J
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |