启动交易模型,并构建 EA3 V" m4 U8 M' Y# |) ^: n0 z
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
9 t8 ]3 C' W% s9 ]为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。0 t f/ n, K( f8 a
以下是制定这些规则的代码。( k0 W6 n, {/ ^( ~
//--- Indicator ATR(1) with EMA(8) used for the stop level...# @$ @, E% t: r/ c
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
' D% E# V4 @% _& x6 s! A/ J3 l" vint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);# i/ A' @0 g6 E% T
//--- Define a variable that indicates that we have a deal...3 }# k( r7 ]* m; ^1 N: A
bool tem_tick = false;
) G( ~$ J3 O1 e//--- An auxiliary variable for opening a position: s' F, J6 b, v% \- m6 C7 i. S( C
#include<Trade/Trade.mqh>6 x7 }4 z) I! E/ `: g* q
#include<Trade/SymbolInfo.mqh>2 k4 E. H; K! n) X/ P) G
CTrade negocios;; T) N$ @7 y- r" C& R
CSymbolInfo info;
@' ^/ @$ [0 e; W( R) I. V) ^//--- Define in OnInit() the use of the timer every second$ f: H3 ]3 J: I: t3 I- K
//--- and start CTrade, {& [, z. }0 u; [& D; ^
int OnInit()
( _& t. y9 b/ U{. _6 \; t) |" ?3 D* V& V' J3 {
//--- Set the fill type to keep a pending order; |* G- m' M" a% ~
//--- until it is fully filled
' P- \5 E( T3 V) T# H. znegocios.SetTypeFilling(ORDER_FILLING_RETURN);/ Z! q7 M1 F. D
//--- Leave the fixed deviation at it is not used on B3 exchange+ ~) ~! Q% b4 a/ A. g# D
negocios.SetDeviationInPoints(5);9 q" ?; K$ m) g' O% f" p+ [
//--- Define the symbol in CSymbolInfo...
1 o3 k& C$ N; _. j, `7 `# b& Z8 ]info.Name(_Symbol);
. l# g8 |6 ~* z4 I, e//--- Set the timer...
/ ~1 w" q+ x$ T$ Y) fEventSetTimer(1);' M+ _! K5 ~! n2 f1 y
//--- Set the base of the random number to have equal tests...
Y; [2 l% F M8 ?. yMathSrand(0xDEAD);
~2 F2 Z# `& P9 \/ d& m$ M7 N! Ereturn(INIT_SUCCEEDED);. f8 Z0 D) s, l
}6 f# ]8 k8 Z3 n7 _! Z+ U. m
//--- Since we set a timer, we need to destroy it in OnDeInit().
2 y' _! t+ R/ C% v1 D9 o. O6 avoid OnDeinit(const int reason)% L5 @. |( i- ]% A6 X: X
{ c7 v* F1 {1 x
EventKillTimer();2 i6 R5 i- ?" C
}
5 K, j1 A7 h$ @6 f7 A//--- The OnTick function only informs us that we have a new deal- {% p: Q0 f& D- O; [6 Z$ V) ~
void OnTick()- O+ P( k7 _6 L4 E; X' R
{
* ~2 \) {: ] X( T5 z# n4 T( ^tem_tick = true;4 d1 q- S- o C' v! ~ ^4 {
}! g2 m5 z2 k1 n2 h$ L+ {8 W4 h
//+------------------------------------------------------------------+
7 `9 c! o w& g1 {//| Expert Advisor main function |
! j2 a* p. y W6 C V. b//+------------------------------------------------------------------+
6 }- ~9 s2 A: w7 k8 `void OnTimer()' s6 F5 f, p* P, r7 y) C a
{7 U, ^, ]: }" `6 V& B) B" F" @
MqlRates cotacao[];+ {2 m2 }7 W: @4 l2 d x
return ;( M7 ?1 S2 i- s6 y
if (negocios_autorizados == false) // are we outside the trading window?, z4 R5 V. K# W9 P7 I7 U
return ;
6 A- ~+ [5 s5 Q. q//--- We are in the trading window, try to open a new position!
" J- |- Z; q# @int sorteio = MathRand();
1 T* g5 E7 e- F6 O2 p, l2 u//--- Entry rule 1.1
; a0 l& h1 C7 i! N% l# O: cif(sorteio == 0 || sorteio == 32767)
& J* O# n+ ^9 |1 A2 j2 u- u* treturn ;1 d$ W8 z1 n3 o0 N7 b
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
L& y8 S$ P7 A* H9 E5 K{
$ X1 _# I7 k9 x) j3 @5 Gnegocios.Buy(info.LotsMin(), _Symbol);6 i' r7 K+ m. n/ W
}' i1 ~- [8 n9 c3 p
else // Draw rule 1.3 -- odd number - Sell
3 \7 I* M0 z1 v9 S) s. E{. T9 T# ]7 V3 z
negocios.Sell(info.LotsMin(), _Symbol);# o) E, [4 F# w1 E- H1 D) f5 E$ ^
}
8 i9 O0 y4 r2 S- e9 A6 [}
% T0 ^4 Z4 H+ g! W+ d( h. U//--- Check if we have a new candlestick...* i1 p( x6 c' v, K4 K
bool tem_vela_nova(const MqlRates &rate)+ ?! n+ g# B0 t! G3 C. |
{- Z7 e3 n8 I$ E& b
{
% C, k% T& X Y! r9 ?ret = true;
" P+ d, w) i x6 B Vclose_positions = false;
^4 Z; E8 T/ V# m}
9 `' `9 o+ m8 {7 b( x) `else3 [4 l6 j; D, l3 ]5 X8 ^) [
{
4 q9 R, B2 [4 m3 B; c5 _) Lif(mdt.hour == 16)9 I2 e$ t& S# p0 C
close_positions = (mdt.min >= 30);- h2 `( S, j; E( s: N
}! B* U' D) D! J1 t( _) `
}4 d T; r) L6 O+ J! r
return ret;
0 \& ] E5 S) }" Y0 ^7 @- Y3 o}2 d7 }3 n( g/ G
//---
% ], w, ?$ R$ f# lbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])& O/ L2 J5 J7 Z
{
a! s5 [6 B! p; o$ c5 b/ kif(PositionsTotal()) // Is there a position?
8 w* ?, t5 H. X; z, d{) _* q# j' E3 j0 C" B. N/ R; P
double offset[1] = { 0 };
, p+ R8 ]; \8 I3 l" X7 x2 U! vif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
% M) ^. L# g: l&& PositionSelect(_Symbol)) // Select the existing position!
$ t: [) C# ]1 u4 l% }! b* F+ t) y{+ z" W8 q4 K" W! K: H2 O
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);8 S3 M& H) p2 d/ a) x5 h
double SL = PositionGetDouble(POSITION_SL);
3 a7 i+ u$ ~5 O! h1 V) F' Qdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
, K3 |* r5 T" }: V* @/ aif(tipo == POSITION_TYPE_BUY)
( @+ r' V( W. d0 a! l{. F/ ~* V% B1 A1 @0 R! N; z
if (cotacoes[1].high > cotacoes[0].high)* o$ V( B1 r& l. q) @0 u: \: R
{7 e5 o# s# d2 ?" F
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];; u- g8 H7 y3 @: C' u5 U6 H
info.NormalizePrice(sl);) g5 x" Z9 R9 @! ~+ H' v
if (sl > SL)
. B# F- q! o" Y7 y0 Q1 [, w{
& ?7 D+ D! s5 I8 }# _; `negocios.PositionModify(_Symbol, sl, TP);
|) m; Y2 C$ X/ O( G}
5 n* Q5 G* G& ]# f5 v8 E) \}
$ C- [. L1 [* r" O. A}$ a' R2 ?5 z/ z+ |6 K
else // tipo == POSITION_TYPE_SELL
1 d$ O9 n Z; {4 K* _- P2 J{
& s; Y) B# k& D5 t/ pif (cotacoes[1].low < cotacoes[0].low)8 K: x6 k% A# O7 }
{
8 p5 n- L) u! y6 j0 preturn true;
) I' m! n3 X) {; l}
4 Y* e* k4 U( w' ?// there was no position X5 Z+ c6 J4 k: O
return false;
0 j: ]* }% d& m% w: q' D& T}
! n, l5 t2 t, ]! C- `! c+ r0 D我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。; m! Q$ C, S- y/ ?9 v! Y
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |