启动交易模型,并构建 EA, O3 v, V$ u7 `
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
" }# @* J+ P) G1 A为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。. T6 i- I/ b G8 I o j7 ]* A! Y
以下是制定这些规则的代码。
7 s& I' j' a% j9 I0 D//--- Indicator ATR(1) with EMA(8) used for the stop level...
V+ E( H2 @5 i& b1 g1 B" }int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);* Z; L. M4 X. r& t: E6 z9 U
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);* ^" ?; M) m3 ^1 o( [6 T1 z
//--- Define a variable that indicates that we have a deal...
/ R& U! g: c9 Obool tem_tick = false;& s( B m3 Z5 l& z( s2 m: b
//--- An auxiliary variable for opening a position/ K/ D4 P3 e" U' Z8 s6 ~6 b1 l
#include<Trade/Trade.mqh>: N0 Y) {' M: P5 ?" e# x" j8 }; |0 O
#include<Trade/SymbolInfo.mqh>. g! b% u, X8 v- X
CTrade negocios;
# B5 c% E/ b- d4 ]. SCSymbolInfo info;
~- [, z, g% U. l/ O' ?//--- Define in OnInit() the use of the timer every second
7 A* T) C7 Q) Q//--- and start CTrade& u% @; ~2 A* F k1 a& {
int OnInit()
: k8 X( Z( v C" Q! K" N0 R{- h/ x0 W- I" k; c5 P
//--- Set the fill type to keep a pending order
4 H2 H9 G( E' ^; b+ L2 [! }; z2 r//--- until it is fully filled
1 K! D5 \0 J- i K& M% ynegocios.SetTypeFilling(ORDER_FILLING_RETURN);
$ {4 |: s# {1 M: r* P9 f//--- Leave the fixed deviation at it is not used on B3 exchange% [+ l% S& P& n
negocios.SetDeviationInPoints(5);. V, ~' v5 U/ l7 Z
//--- Define the symbol in CSymbolInfo...
- |' U' x/ L6 c1 ^ Qinfo.Name(_Symbol);% K- T6 k7 B, G0 M8 i( `" p+ Z
//--- Set the timer...$ L+ C: e) [" z7 {# A, Y5 [2 Y" ^" t! I
EventSetTimer(1);% B/ ?' G& f9 p6 Q- C0 w2 q* `
//--- Set the base of the random number to have equal tests...$ o6 d5 h( ]4 \( B' X! R8 {6 w
MathSrand(0xDEAD);- F& S& r5 z: ]& E$ b
return(INIT_SUCCEEDED);' Q l( D1 d$ t. h1 O% q, E; k
}
7 o J/ K3 H9 N. q7 L# D//--- Since we set a timer, we need to destroy it in OnDeInit().& l, c4 F& B( H' E* b4 ]8 _
void OnDeinit(const int reason). U( L& E2 _8 D1 J6 Y" G1 J: D: P
{
# o" a) y) X9 g' k4 k+ X# iEventKillTimer();0 L1 _0 p+ m& ~. {
}
- { c0 s7 I$ X//--- The OnTick function only informs us that we have a new deal
9 o4 e8 P. E" G3 Hvoid OnTick()
2 n5 S- A8 U0 N6 S{) w3 O- R: L, i& \# V5 V
tem_tick = true;) a, [; T* k5 O4 P
}' ], F/ t% v+ z- M$ n- U
//+------------------------------------------------------------------+
4 Z5 i. q! ?0 ~0 `//| Expert Advisor main function |
U- t W( `* m+ F( d! p2 G2 v6 R//+------------------------------------------------------------------++ @+ Z8 `9 ]7 K6 g0 G- M
void OnTimer()% J0 a$ A1 i4 b4 Z
{
, N. v3 t* E2 y5 Y0 CMqlRates cotacao[];
2 S3 @1 a% N7 I3 e$ P% Ureturn ;
* I2 b; p- y# [! H& B& m) B' Xif (negocios_autorizados == false) // are we outside the trading window?! i; ?& n: c/ |: C$ Q+ O; w
return ;
9 e& M1 l/ X& v% l& t' j1 M//--- We are in the trading window, try to open a new position!
" p: p& j0 B) Q) m3 l5 k! Rint sorteio = MathRand();
% T8 u$ J5 x: ~7 `& U( m; N% {//--- Entry rule 1.1
$ ]5 a( H/ U% Q# G- o6 dif(sorteio == 0 || sorteio == 32767)/ x X y) i9 t+ X. t) @2 j K
return ;
- M( m5 _: Y& `& |. O: J5 F" T& Wif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy8 N }* ^2 O" ~
{
5 \* H( Q1 v- R- m$ s1 ~negocios.Buy(info.LotsMin(), _Symbol);" Z! z# p' |' K0 d7 j
}
0 q" t# v/ i4 ]# W* X5 l# r0 aelse // Draw rule 1.3 -- odd number - Sell
5 ^. ?1 K( I5 ^* H7 l; W{
. _5 Z. y1 d2 N# pnegocios.Sell(info.LotsMin(), _Symbol);' V6 y" N- B6 `1 g
}' D \$ [1 b8 n
}6 R& \% W! |6 }
//--- Check if we have a new candlestick...0 f( j" W6 _* i9 B h
bool tem_vela_nova(const MqlRates &rate)
6 S4 H( C" x/ `& V; Z& |" V{
Y- k Q" i& O; [{: Y0 t7 E+ k# U* X; C" i
ret = true;
9 L/ Q1 v+ U$ v5 y. pclose_positions = false;
9 t4 H/ m& W+ U# X5 ?4 A' }5 X! G* B}
( ^7 x; S$ H J: B C |* {. j4 y' B' kelse% i7 p- ~" G8 R1 Y
{4 H3 ` u9 S( g5 _7 i" V$ j. q. \
if(mdt.hour == 16)
, n4 ?2 N5 N5 Z, Lclose_positions = (mdt.min >= 30);2 U; P2 ]- p! r2 S) [4 X7 N* m) ~. f
}7 F( u8 g" H5 h) Z" |4 w
} E" \2 ]0 [2 X
return ret;# W. F" s3 R1 Y! r. _
}, h' M3 _( f9 N6 N: k) L
//---
% { x9 S! U; r1 ]( M0 rbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
/ x* A2 K a1 _# Z$ q! u. r1 A{
& u1 q: w: N* r- m$ x$ aif(PositionsTotal()) // Is there a position?
' g& h* ?9 j& v{
1 [! I9 _5 @- ~3 B6 i9 mdouble offset[1] = { 0 };
1 U# D7 e' b, a7 j" N6 cif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?! `$ @$ ]& s7 K0 s1 h% U+ X
&& PositionSelect(_Symbol)) // Select the existing position!$ y2 h& P: ]( @# k6 S+ n6 _
{
8 ^2 i& p# @/ j6 L+ N: k; w& _. H- P" Z( ~ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
0 w9 {/ n7 c: f2 n2 n; ^double SL = PositionGetDouble(POSITION_SL);
- e) d3 T& q0 d( gdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
" Z L; f6 C# U1 bif(tipo == POSITION_TYPE_BUY)
" {& j Q$ p: O. u" X{7 v0 ]3 G1 ~' y0 J2 j# Z. z/ y
if (cotacoes[1].high > cotacoes[0].high)
9 O. f, K G9 u) b- Y% b0 D% `( Q{
+ n! Y) a) G; V, @double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
" w7 n% c+ p5 @) J, K z3 z# uinfo.NormalizePrice(sl);
' ]" D2 O9 U8 sif (sl > SL)3 m5 \0 D, K8 U7 b' [
{
* n2 h1 c* N k; I0 v. V3 gnegocios.PositionModify(_Symbol, sl, TP);! g4 O, o1 N& N; B( W' y
}
! F. g- S0 h5 T4 {0 k/ z) H}
' I: @& r, i3 b}
, }! F# P( B; H% Yelse // tipo == POSITION_TYPE_SELL
/ K) t. E' L' y. a5 k0 S- m6 H{
. p( I4 }5 M) u: _0 R( U+ dif (cotacoes[1].low < cotacoes[0].low)
- x6 w# y0 Y8 X3 U% E{; m; c+ n# o) T3 z+ g8 G/ m5 I
return true;
. M5 F/ K6 |/ H! T4 F- I}
* P# a$ ]. \ e& I- o9 _* u$ i: Q// there was no position# C6 I1 m+ l9 N* G: h& L r
return false;! S% c+ g# g; L# q, h! f
}
( G# ^; D6 x, j l我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
. R( ~4 d t( |. |: l' O到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |