启动交易模型,并构建 EA1 A/ G$ L7 s o; s; u. h' ?0 L
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。$ W I1 D; r( N; j- n$ |/ U# A* Y
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。) u: I; ]7 K! J$ M
以下是制定这些规则的代码。
/ p; I: ?& H4 O//--- Indicator ATR(1) with EMA(8) used for the stop level...
( G- ]* d7 L9 K9 Lint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);7 U# X" P; D) z8 _/ e; U
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
* H V/ K' W- Q2 G/ ?& c# r//--- Define a variable that indicates that we have a deal...* A1 [) P) P2 O: A: e/ J+ X. s* j3 w
bool tem_tick = false;( ?$ k2 q) s9 i1 {0 Z3 o5 @
//--- An auxiliary variable for opening a position
1 {' v9 D Q/ ^' a#include<Trade/Trade.mqh>
# J- G* M3 f4 A# m# h+ C#include<Trade/SymbolInfo.mqh>
0 ]$ V: `3 S7 y: eCTrade negocios;
6 X3 K: z* E3 k; O' i3 Y$ gCSymbolInfo info;
( N! ~; y# A! q: }/ l//--- Define in OnInit() the use of the timer every second7 C8 | P$ d% `1 e
//--- and start CTrade
. \; r/ j( Q1 P5 [2 G( I! ]* Zint OnInit()3 \8 @5 ^0 U8 `$ Y' P6 }+ ^
{+ h# q5 H& m, g
//--- Set the fill type to keep a pending order6 J5 M9 D7 ]$ M. V4 H; z% a
//--- until it is fully filled+ ^# h+ O8 w' I
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
3 r1 r. L5 o1 G, E//--- Leave the fixed deviation at it is not used on B3 exchange
7 d- b3 F+ I9 Unegocios.SetDeviationInPoints(5);
- {# _/ H5 @5 w" K- F- N//--- Define the symbol in CSymbolInfo...& e- R% }9 O2 v/ z. O' f
info.Name(_Symbol);* v8 e: J" e" A+ x2 d# D! C
//--- Set the timer...
, ]6 ]3 {" w9 a$ L5 p9 JEventSetTimer(1);
: l! A. g: O/ s4 l- B- b! x* M//--- Set the base of the random number to have equal tests...
8 R3 ^4 o6 b" e" U8 `MathSrand(0xDEAD);+ |) }) F3 T( D2 c! v0 d0 k6 ]" G) o
return(INIT_SUCCEEDED);' ?& O. B$ {" Q
}
8 G6 b I8 I2 d$ `& |: e//--- Since we set a timer, we need to destroy it in OnDeInit()./ A' n' b9 f0 m: I$ A8 V
void OnDeinit(const int reason)
9 w: |2 t2 Y- X- Q- R1 g# h( x{6 {; k" _& i W( m5 b
EventKillTimer();. _/ \- k s& E# K9 T
}
8 r. Z' p o4 L. Z% p1 h( r: G6 a//--- The OnTick function only informs us that we have a new deal
) \# \1 }' o: ~void OnTick()$ y* P6 C" c+ o* b* q
{9 [, I- T3 h" ]1 `
tem_tick = true;$ v9 s3 D, o9 I( t4 d
}
! o2 Z/ |' i% \; {! K//+------------------------------------------------------------------+& R% \: s9 e) w2 Y2 R+ b& _
//| Expert Advisor main function |
, }# Z& Y4 y: Q5 n2 v' `//+------------------------------------------------------------------+
" z/ @! `- W# `. k0 E8 o) l9 pvoid OnTimer()6 V6 T/ _ q' r' ]' e' ^
{
8 R6 S7 U: g4 I% _. x" g2 ~MqlRates cotacao[];
0 e) ~7 t* z* vreturn ;
% p) R, l( g! Z) @: m! Iif (negocios_autorizados == false) // are we outside the trading window?
- i+ q0 r; V! N: D4 Dreturn ;
/ p v# y) t# k4 f) J//--- We are in the trading window, try to open a new position!
) g! h1 d9 _$ M+ `/ F7 dint sorteio = MathRand();* Z" Y7 Q) J }3 r- z
//--- Entry rule 1.1/ X9 ^1 R9 {3 C
if(sorteio == 0 || sorteio == 32767)& v4 L( N; V" m$ d+ F2 ?( n# \
return ;
2 i0 Q# |, ]! T: K" b1 I) f1 ?if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
5 I9 q' r$ y5 Y) n; b' k{
* G8 W ?! s; e0 Anegocios.Buy(info.LotsMin(), _Symbol);
, A `8 \$ F9 M# b' c}
! h. t6 r0 L% U+ t! z- P* W$ D4 V8 Telse // Draw rule 1.3 -- odd number - Sell
$ v9 B* j; ]4 x8 G{
. G/ a- X3 D, O: R/ e/ {; }negocios.Sell(info.LotsMin(), _Symbol);
8 c1 m8 l* `3 ^0 S4 E}
# l f5 N& h& _3 {} ]( d: U ^, C; ?* c8 y
//--- Check if we have a new candlestick...: N9 X3 G# s7 u6 X, Q
bool tem_vela_nova(const MqlRates &rate)1 v2 V3 Q1 L/ S, o. r* O
{
/ @2 w5 Z W7 Q3 X* D4 h8 ^{
- o0 H# m a( ^7 iret = true;5 h. G1 ]- m1 c7 X/ i
close_positions = false;
3 q7 a& U+ A( @7 F+ K& a8 j3 c}4 q# l, ~; ]: H; ~8 H, j) Z
else
( \. [2 ]1 @5 p3 D{+ {4 n/ @( [& ?0 [1 @
if(mdt.hour == 16)
% S8 Q0 k* I: q8 w( h4 nclose_positions = (mdt.min >= 30);
& @, L* P% o6 W. h% [}4 _7 c" l/ s, w$ e$ H" {( ` ?
}
$ e. F' }5 G3 K L$ r: i% r3 ?$ breturn ret;
/ r+ ]# E' y, |7 |) k+ m}5 Y6 f! r2 d4 V6 T5 G
//---
7 O6 I* ]& C1 `4 X# dbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])0 @ L! W5 }) ?
{
3 N+ a3 Y" D# t/ h4 H. Nif(PositionsTotal()) // Is there a position?
' H v4 W; Z- Q{$ w* o6 I. A; s( `; X$ b; V" F
double offset[1] = { 0 };- ~" e) J* x& Y+ n9 b
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?3 z1 u- E2 @2 m- |8 u7 x) W" I
&& PositionSelect(_Symbol)) // Select the existing position!' `2 k4 N2 ^0 x4 q: ^+ _; `
{
5 `% {$ V* M+ y( E1 nENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
0 K& p. y2 E& n6 b# }5 Tdouble SL = PositionGetDouble(POSITION_SL);5 `2 K6 G- Q6 C. m
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
. x: I/ Y- J }0 J5 C/ oif(tipo == POSITION_TYPE_BUY)
% u0 j' T' o& E{. v5 v0 a: P) M R6 v- i/ v$ P- d7 }' ]
if (cotacoes[1].high > cotacoes[0].high)
; h) _ j0 v% Z8 ]+ \1 T{% Z; Q( x- I" y( Y9 c R
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];2 F/ F5 ?4 {6 a! c5 P' Z' i7 _: I4 G
info.NormalizePrice(sl);
+ H" |; c2 y5 iif (sl > SL)3 k, g( @: _/ V" w5 j: b' Y
{# w8 i: R0 k, w- ~1 X2 O8 k G
negocios.PositionModify(_Symbol, sl, TP);% g2 h: y; F6 b2 \
}
/ Z2 k+ i N q q; \}* [4 Y# C! H5 o h& K7 @
}# W9 A. O9 k1 G- B* s
else // tipo == POSITION_TYPE_SELL
8 I& Z. I$ H3 V# X" K3 D{
" K3 p0 Y* t/ yif (cotacoes[1].low < cotacoes[0].low)
6 h7 k- D- k. o. P6 N/ S{
9 v1 _' B: Y4 H% d' J/ creturn true;
; B# k* _& x; a: N- N}$ R9 o2 `- P2 Z% z: n P, h
// there was no position
/ ^) z8 Z/ G, n$ [return false;
7 b5 Z8 h# J+ i* j3 s" |' K7 L$ u}
" u9 q0 V& t) U2 T1 R; ?* d& F我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。- m1 E* r4 j/ t
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |