启动交易模型,并构建 EA @8 o/ l% D5 Y1 n; z& u, C2 `
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。( x" {" u+ t W6 u
为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。7 P _' b$ m9 y$ m
以下是制定这些规则的代码。/ G4 w( Q" Y% Z/ M
//--- Indicator ATR(1) with EMA(8) used for the stop level...
1 ~4 A& V( d: I# mint ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);5 ~* S. G8 E o' v- R' V% Z
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);' a2 o/ x7 a9 O! p1 h
//--- Define a variable that indicates that we have a deal...
/ i) x9 ^4 r0 B3 X" k) v& Q/ s, E6 Lbool tem_tick = false;# G' v9 K: b, m6 L: O- J3 ^9 a, M
//--- An auxiliary variable for opening a position
7 l b0 [* K' X# `% Z. E# `#include<Trade/Trade.mqh>
* i0 O+ o% o! J a3 k! v% Z7 I, N#include<Trade/SymbolInfo.mqh>
5 M# Z, @% M) ]8 zCTrade negocios;; u; Y: h' C, [
CSymbolInfo info;. N* H0 e% a* n: O* m2 Z
//--- Define in OnInit() the use of the timer every second
# D% \# m- `' h+ i4 F//--- and start CTrade
% M3 M9 H/ g2 k6 M# v- N) rint OnInit()7 R" d4 e. g8 P3 }
{
+ z5 x3 k2 n+ ?$ ^; d1 s- @3 I//--- Set the fill type to keep a pending order6 B( A7 p* U6 v, M4 k: L
//--- until it is fully filled0 F q2 `! l0 L
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
) J6 X4 O% n" F" B, V" v//--- Leave the fixed deviation at it is not used on B3 exchange+ Q4 \, a0 Q7 h
negocios.SetDeviationInPoints(5);
: {# S- V) {4 l7 J: ]//--- Define the symbol in CSymbolInfo...& ] W% r- ]! @
info.Name(_Symbol);
/ s' ` p3 \; q) l, }//--- Set the timer...8 E8 O- \) k/ w. E8 K9 B
EventSetTimer(1);
) D3 i3 T& F% m2 C* j" G: {//--- Set the base of the random number to have equal tests...5 U9 p9 s; }, e1 F/ _. ?' l% Z. z
MathSrand(0xDEAD);
z2 Y" `4 x) }/ |5 l1 _return(INIT_SUCCEEDED);
; U" G7 b5 ], U. z. I}
+ I/ H+ L q7 e: \ A- D* q5 v//--- Since we set a timer, we need to destroy it in OnDeInit().
& j' E5 K3 v1 X' ]* h0 xvoid OnDeinit(const int reason)
- s! { ^( X9 V! `! L9 L" [9 ^4 N1 b{
. Q" o) N' `9 r! \EventKillTimer(); B* E8 k' ~7 x! h2 W3 M
}
7 L5 a0 q- c4 h6 l//--- The OnTick function only informs us that we have a new deal
; j0 I& |6 J9 P! E! zvoid OnTick()( F8 v$ ^& Z* T
{! ?3 z# A- V& d, Z& y8 X6 R
tem_tick = true;( `( K+ c0 A) m2 J7 R0 s; K0 m
}0 h) l' b" M4 E+ R: z
//+------------------------------------------------------------------+. v) B) [* `- s3 h4 J. L: C
//| Expert Advisor main function |
% k7 V1 F2 g! @$ A5 Z3 g//+------------------------------------------------------------------+
3 H! O B( C4 v; v# M1 _8 c; Z9 Fvoid OnTimer()
4 s" Z7 {: b6 h9 \' E9 h( |, `{- d6 \* {; l1 y2 d
MqlRates cotacao[];
$ x2 u2 x. D; ^4 R9 _return ;1 n& L4 e' U" a2 A' V. G# Y
if (negocios_autorizados == false) // are we outside the trading window?
. E- N9 R* |. B( ?! d: P4 Ureturn ;
% R4 V# o8 Z" L+ E/ `* @//--- We are in the trading window, try to open a new position!
! a, [! F1 F( a$ Vint sorteio = MathRand();8 G% c4 w, m8 [
//--- Entry rule 1.10 ?2 T+ A9 k7 S) ]1 A
if(sorteio == 0 || sorteio == 32767)2 ^, E( W j. U. _+ c I
return ;" S; e4 ?. c2 I! ~0 k5 X; S, P
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy' P6 x8 e- Y* G1 \
{1 G# T1 x9 A" t' x& \
negocios.Buy(info.LotsMin(), _Symbol);9 ]& ^. l/ w& O
}
* h1 p" }6 a4 g+ |: ]4 G% uelse // Draw rule 1.3 -- odd number - Sell) Z" @6 t8 m: M/ Q
{3 i5 ]/ N3 u& J/ M& {
negocios.Sell(info.LotsMin(), _Symbol);
9 ^- V* T& f3 ~}5 P3 O% F# C# \, {9 z8 G: e
}
2 n+ g0 C( R4 A# D! |) ~//--- Check if we have a new candlestick...
# X! _/ Z' M/ g1 @+ W+ e! Ebool tem_vela_nova(const MqlRates &rate)
7 n+ M6 Y, E2 j: N$ K0 [5 k{' o) `4 V8 p# | g2 H
{
. H" \3 L5 P& cret = true;+ i; j# e: S6 X9 X
close_positions = false;
7 H+ c& E( P6 x6 w3 d8 \. P+ G}
! \. Q& O' p& |else. k9 r9 |; A! ^& N
{
2 F% }" O0 p$ Vif(mdt.hour == 16)% t: ?8 D2 o$ f8 q0 Z7 |
close_positions = (mdt.min >= 30);2 a; I( { R! N$ b1 \
}
H1 z, x$ u. V" U/ z9 a8 P}
' _ W1 g L; s* `% X" Q( b# _& M8 lreturn ret;) Y# ?8 L$ g) P' D$ D* Z2 D
}
' y% V* g9 Q, {0 `& I* p. c//---' H$ |+ W; J {
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])+ l( [8 f& j6 I" j; g
{1 a9 M5 ^" x! [3 g) J0 d6 X2 Y
if(PositionsTotal()) // Is there a position?
2 e4 \5 D) H; J1 I/ ?# i{
3 x8 ^9 X3 s1 r6 K3 Xdouble offset[1] = { 0 };
' ]* [9 Z7 N8 j1 F, g) F, d" Vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
5 h* o! ^; E8 e4 |/ S7 ~ d&& PositionSelect(_Symbol)) // Select the existing position!. p( x( t- q" \- h% | g! w# X+ M
{
! m: s- Z1 {& c# H* n0 {" P/ ~ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
' u0 A! E. V Q# G( pdouble SL = PositionGetDouble(POSITION_SL);
8 f7 w+ l8 r- u$ I' ~6 Ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
( E/ A* } H, Z5 n' R& z3 m3 Hif(tipo == POSITION_TYPE_BUY)) `1 J% h* `/ Y1 ]4 f
{& K. D5 M4 ?* j9 w/ @* ^
if (cotacoes[1].high > cotacoes[0].high)- F! q3 b3 Z9 V9 q5 E% E+ b. s1 Y6 i
{1 L6 l1 m, z9 c+ K6 _
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];' y, U/ g& v; B ?3 A6 R
info.NormalizePrice(sl);" G0 {% [, P: r& t- s
if (sl > SL)
9 O. v! J$ L2 j9 ?+ K5 E{+ s ?0 v/ M) b
negocios.PositionModify(_Symbol, sl, TP);
. I3 B% M& D9 W( A9 t% L}
" h, r, C) y6 M7 Y0 I}
! o4 {! f, j" [- _* T6 F( b}
$ L6 l% Q1 @# Z9 b; Q* Gelse // tipo == POSITION_TYPE_SELL0 K! Z& M7 t- i
{
+ x0 i. L, S3 G! `if (cotacoes[1].low < cotacoes[0].low)5 J. S& `6 N% F7 W5 X* Y; E
{0 X" D R& Q* c0 \- ?
return true;
# h/ I, q/ ?# D1 Z1 b}
; [& E% x6 C3 _/ a2 Z; c% T4 [$ k// there was no position4 u: l7 ~, ?9 ~. F9 V
return false;: Q W+ E; g% B( o$ M
}
2 U( w! o; f. `: w g/ c我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。$ S: ^3 z8 b# ?& \ C8 N
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |