启动交易模型,并构建 EA8 n* a& A* g9 o0 ?3 W6 c5 V
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
4 a; ^! |; h& t为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
; I$ O7 ]& G6 w! v! W/ Q4 ?5 c$ t( k% u以下是制定这些规则的代码。& w9 W7 k; j# v. v% o) k. e
//--- Indicator ATR(1) with EMA(8) used for the stop level... l& ^. j- ~5 D- N; w3 H8 t9 d
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);; o4 Y; g7 z* ^2 `
int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
# m. [6 C) S q3 m8 D5 d//--- Define a variable that indicates that we have a deal...& p5 |; _& |! R* k% r
bool tem_tick = false;5 R+ e" Q8 I/ c0 f$ l4 J
//--- An auxiliary variable for opening a position- w$ W/ T+ }- [% D, d+ T
#include<Trade/Trade.mqh>& o g4 V8 N# [+ q
#include<Trade/SymbolInfo.mqh>$ v/ z j, C6 j7 R
CTrade negocios;$ [3 ]. P* I' f$ |" z
CSymbolInfo info;+ q3 \ o2 M i) T/ k: [- i: T
//--- Define in OnInit() the use of the timer every second
/ K+ m! @" M. D& G" Q1 n/ c3 O: D( [4 Q//--- and start CTrade) ] l, W- T) n4 Z0 @4 x& E
int OnInit()
) s% Q3 _/ p6 Y. _& G1 i{- s7 ]7 g* l" D4 J5 C
//--- Set the fill type to keep a pending order
5 b; A9 Y: ]5 ~' N( J$ z//--- until it is fully filled
2 y6 d' K* [. y' |negocios.SetTypeFilling(ORDER_FILLING_RETURN);
+ @; e. G. n! T |; b//--- Leave the fixed deviation at it is not used on B3 exchange9 g# T! C" q/ Q4 P" F1 x
negocios.SetDeviationInPoints(5);. N9 R$ ~4 F" W' a; G4 d9 n. Z
//--- Define the symbol in CSymbolInfo...
" O, [) G. a3 g5 b4 K9 ~2 zinfo.Name(_Symbol);
~ N' e2 D" v7 z' @ O! r//--- Set the timer...
6 Q& ~, F" f9 w- U/ g4 p+ ZEventSetTimer(1);
' ?' D' z1 ?9 C//--- Set the base of the random number to have equal tests...
$ c' _0 {% \- G* {5 k, tMathSrand(0xDEAD);% @' J. D4 }7 @7 w- ^; C& [8 M. v0 v
return(INIT_SUCCEEDED);
4 a4 g1 S: Q4 t9 V7 T/ ~: A}
0 F z7 c! t) W//--- Since we set a timer, we need to destroy it in OnDeInit().
6 [$ [0 E0 z. Bvoid OnDeinit(const int reason)* h( P' X0 x$ G: z1 W( t# W
{% K9 Q j* s: a( `. c
EventKillTimer();8 M, s4 [4 F- w4 `/ w
}5 B5 N0 G1 X% L
//--- The OnTick function only informs us that we have a new deal1 H* B" V2 I- W y# @
void OnTick()
2 I' \! u" _3 Q2 T) A% X1 `{
0 z0 S* l( |. i, ?0 etem_tick = true;# p/ Z/ {" I C0 n5 W% _
}0 _0 A5 Q! {% J/ L& E7 S, M8 ^. e) h
//+------------------------------------------------------------------+
6 R: L4 b( ]- @! B1 r6 b//| Expert Advisor main function |7 K" I2 a! O! c4 f
//+------------------------------------------------------------------+
! F1 X' J# j6 a: vvoid OnTimer()) ~9 N* |+ n1 w- y9 ~; f
{
( ^/ I1 z0 ]4 @0 f! f9 MMqlRates cotacao[];6 h% C: k# r8 \% x* t+ `
return ;
; a" X0 @6 I0 v4 @2 J% n2 {4 D1 Wif (negocios_autorizados == false) // are we outside the trading window?6 \$ n H: w5 a9 r4 v
return ;/ f+ d( B" n, v: l
//--- We are in the trading window, try to open a new position!2 t0 t6 e2 q* o2 F" K# h4 [
int sorteio = MathRand();0 O; s" T3 I1 m& L2 G4 {9 W$ \
//--- Entry rule 1.1
# R& O, S# ~0 K! Q4 Pif(sorteio == 0 || sorteio == 32767)
1 z/ Y- ]% K u3 m+ D8 Preturn ;+ j/ O+ }! \4 @8 b+ y3 b: l% u- ]4 C
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
( A1 J) `7 A, t& I. J1 f/ s- ~$ f{
+ Z4 g& k: |: C: s3 w' M# |! Xnegocios.Buy(info.LotsMin(), _Symbol);0 n" }) v! K; L3 s% t: t
}
; ~9 ?2 N: e9 D- s' s" n9 \else // Draw rule 1.3 -- odd number - Sell
0 o) S' v& b! D{
5 [+ M* }: \' h! y8 C4 Snegocios.Sell(info.LotsMin(), _Symbol);
0 C3 y, `$ |% {9 ]/ E+ V}, ~' }5 E1 ^$ `5 P7 V* E5 `( W
}1 Z" Q; M( s9 V
//--- Check if we have a new candlestick...8 h+ {: I: O. N2 }2 q
bool tem_vela_nova(const MqlRates &rate)
" e# i0 B$ y( Y1 g. L# J{
4 _, d/ H( J d{
: I) D. o% w0 B& c4 iret = true;
& d* E# |- z% ?/ A4 kclose_positions = false;
' Y3 L# T% T) p g$ B4 A: m} P4 ~6 r4 j8 Y/ s: A, G
else( a: B$ X" e# x3 |
{# g+ c) w% |+ C
if(mdt.hour == 16)$ ]% u3 P" r! S$ s! B1 V
close_positions = (mdt.min >= 30);4 r6 a1 m3 C; c4 f
}$ l" b9 n* G+ }4 E+ n% Z
}
6 ~0 Y# d: ]7 wreturn ret;/ B& {" r+ c" f: i, j z
}
2 P9 ?5 [9 |6 H2 q P) _//---
5 B. F/ Q! l% c0 ?bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])" |8 j1 q) F( h; o8 ?" D6 P& C
{ S, M& [4 E7 u) h5 E/ g
if(PositionsTotal()) // Is there a position?
& e4 b" t0 v$ D4 U( N# t& L( H{
; E" r% E* T" v6 O Odouble offset[1] = { 0 };
( y" t( G" Q0 L8 h) kif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?" d/ Q ^( M( ?! \ w& ~; X
&& PositionSelect(_Symbol)) // Select the existing position!
3 e7 d. |0 U0 D; _5 O. |, l{
% U6 b# g4 j" ]2 _& hENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
t8 q7 `% M# Ddouble SL = PositionGetDouble(POSITION_SL);
$ ^0 x( F; K. D% v+ C, Y. ydouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));- d5 ^/ A6 C |: k
if(tipo == POSITION_TYPE_BUY)! \0 m/ ^% K5 l6 J n
{
. f1 K+ m; g/ pif (cotacoes[1].high > cotacoes[0].high)
7 H: E/ n0 u$ l( @8 `2 `{
+ V8 b$ ~+ U+ e5 _double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];
8 a2 l( R8 \ I; H4 Minfo.NormalizePrice(sl);
4 R5 U6 V2 k) @9 n- zif (sl > SL); f: W$ X+ g- S; E0 `
{% P) h" m @$ C5 O
negocios.PositionModify(_Symbol, sl, TP);
+ x$ C- S9 m( R8 n}, T+ t6 Y' I" S
}- i% c8 D" Y! T: R" z: c
}
/ _$ [/ x3 {1 |& n1 `else // tipo == POSITION_TYPE_SELL5 t- O3 f8 m+ E$ q- L
{
5 X+ M. n& ]' Oif (cotacoes[1].low < cotacoes[0].low)
# K8 _ Z% I7 c2 H{4 e- @6 Q' i1 \' K
return true;( |6 O' c' @! ?) z! U
}$ T0 k* j7 A1 [
// there was no position2 L0 H$ \4 T. s+ M1 K! s
return false;
% X) U n" B( P" Z}& P* ?0 s) D% D p
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。7 h4 ^/ T! C5 D: o
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |