启动交易模型,并构建 EA
) w! p6 q" A8 S7 b' ~在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
, Q& t6 S3 A8 w, y7 J$ O. W* X为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。8 q/ o; P6 x* ?3 u- [6 X# ~
以下是制定这些规则的代码。
. c; i* l/ g, \4 x# ~1 {' e//--- Indicator ATR(1) with EMA(8) used for the stop level...9 w* J# t- I, I, R. F
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
# z% p+ p9 @8 h* D$ Eint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
& r* w& ^$ o9 ]0 f4 p//--- Define a variable that indicates that we have a deal...( Y# C3 H2 U2 F5 ?( d9 z
bool tem_tick = false;
4 d5 z9 p- _' ?5 G4 R% ^//--- An auxiliary variable for opening a position
( ` ]3 P7 n1 l1 O- v2 ^8 E#include<Trade/Trade.mqh>
3 s* r2 F% P+ U#include<Trade/SymbolInfo.mqh>/ |0 J8 Y* J4 i Q/ m2 O
CTrade negocios;
5 @9 ^9 o7 h! l N" V3 d9 rCSymbolInfo info;+ I! y( [. l5 E$ P2 i5 ~, o& `
//--- Define in OnInit() the use of the timer every second
6 l4 T7 f5 h5 S//--- and start CTrade3 q6 a M7 k+ K
int OnInit()
0 C3 i% ~# h0 f7 u3 E2 x{/ z* c# c8 t; {% c
//--- Set the fill type to keep a pending order
, v4 a! K! |8 p4 }//--- until it is fully filled6 _9 _ \ e+ ]1 I
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
, m' c1 J* ?" {. {//--- Leave the fixed deviation at it is not used on B3 exchange. ~9 s6 P( q* T* l" r; M
negocios.SetDeviationInPoints(5);4 {6 H( Q7 f, G; o
//--- Define the symbol in CSymbolInfo...' }7 l) n- k0 f% r+ W
info.Name(_Symbol);/ H8 |- c* L- F8 }
//--- Set the timer...
& s$ U3 L8 c: d1 a( M gEventSetTimer(1);
% b; s! W, f6 c- o5 T# K' a! h" ?//--- Set the base of the random number to have equal tests...' G/ K4 a r. s# Y
MathSrand(0xDEAD);% ^! X9 L5 \7 \- c0 C, Q
return(INIT_SUCCEEDED);4 }3 v; E5 E+ l$ n6 | m- }( Y
}
' s$ Z5 I& m0 P, w//--- Since we set a timer, we need to destroy it in OnDeInit().
3 j0 n8 w' U! e& ?" Kvoid OnDeinit(const int reason) y# p3 {3 o( f; Y2 W5 j# M
{' \) y W. F$ K3 f0 d
EventKillTimer();1 c$ {. ^! e% J! E% P. z( O
}
" w6 r$ O: ]* b& [) N0 @2 c! S//--- The OnTick function only informs us that we have a new deal
$ j9 ?9 R& C8 fvoid OnTick()* R+ F1 g% q1 x: l% E
{
$ J! Z8 _' I4 \3 d0 ktem_tick = true;
2 \# `/ U$ m7 ]$ E}1 p7 \/ |2 N7 ?1 v" a5 L2 a, G
//+------------------------------------------------------------------+( p+ |2 K8 ~% ^/ L' Z
//| Expert Advisor main function |
. J; N6 j+ e, q+ |5 d//+------------------------------------------------------------------+ ]* v4 U3 x9 l1 o0 }
void OnTimer()
% L( R/ d5 M" X- l{
8 W4 T3 S: d& K6 X+ I% W8 KMqlRates cotacao[];6 L0 q; g& e, X* l7 ^( p
return ;. A1 ?" L& s5 m' d, R% ~
if (negocios_autorizados == false) // are we outside the trading window?* y; w' [& p- K% `/ U; ~
return ;$ `* s4 b+ h/ ]$ P
//--- We are in the trading window, try to open a new position!2 f8 ]6 n* q1 s/ U$ K
int sorteio = MathRand();
2 H* @* z6 \; ^- d8 P' V1 t//--- Entry rule 1.18 Z" x- y# Q i% D& u" `8 i
if(sorteio == 0 || sorteio == 32767)
# ]; C( v2 `' m d0 I3 g/ Treturn ;
4 ]( F c# b/ m) o4 x$ q' Aif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy6 l/ ]7 x6 \8 W
{6 E2 @4 }/ _! I; n) B/ @) d* ~) o
negocios.Buy(info.LotsMin(), _Symbol);
; D. x) [& r% n0 k3 ]}3 }; y' ^4 h/ ]: {
else // Draw rule 1.3 -- odd number - Sell
, r1 @2 H3 C' L1 c- ~; g- ?* A{: p( s" K( l2 v1 d3 h
negocios.Sell(info.LotsMin(), _Symbol);
8 f6 J/ c3 o: ^0 z5 u6 a6 a}: W6 C I% b5 F
}/ N. {) M* [4 L! n; ~3 f
//--- Check if we have a new candlestick...; x, i$ L$ |6 W( Z
bool tem_vela_nova(const MqlRates &rate)- N8 Q8 P+ i2 @( |; k+ W
{7 ^0 o9 t, Q- I/ o) z! U* D
{3 f6 r9 k- u1 i# ]
ret = true;
# l: b3 g6 N8 \) d7 \+ \* C' u) Mclose_positions = false;
5 j: B, X* y; q}
0 y0 y" @! m( v% \else' B0 r; v1 b+ v$ x1 F7 N
{: c) E% K2 o( D0 m8 ~
if(mdt.hour == 16)7 d: }0 e# S& w$ @1 P6 a1 \( [0 ?
close_positions = (mdt.min >= 30);. O& Y3 `6 I7 F2 S, p( e% g
}
$ h& L' m, G4 j9 x}
& ~" {- b$ S+ N7 A, S% B* Nreturn ret;
' Q1 ~1 y( C" ^. u8 O}
1 u# [9 c# ], R6 o8 |4 |//---
9 R8 o9 w6 L; e1 Rbool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
" ?/ g, X' r6 A5 l/ O0 @{
+ R4 ~: [. R S, {0 |if(PositionsTotal()) // Is there a position?+ [' t* \- q( p3 l
{
0 o2 s+ P$ X. r% Wdouble offset[1] = { 0 };
/ k j& W+ V" I/ ?# R, Aif(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
- A t0 a. P* W8 c2 n7 W&& PositionSelect(_Symbol)) // Select the existing position!2 |2 b1 j+ J1 w6 u& I% J
{
* Q7 P1 H" M6 d+ ]. CENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);$ m+ b1 y1 F, w
double SL = PositionGetDouble(POSITION_SL);
3 i y; _/ T( c1 mdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));1 I; m* |) P1 L7 E
if(tipo == POSITION_TYPE_BUY)2 `! L( Z6 ]0 l# V2 h& I
{
( c1 |; }+ X4 L6 K: B' _/ _- U4 @if (cotacoes[1].high > cotacoes[0].high)
) I* C7 r E3 A' \6 P0 s{
@5 t) |. g% B- i0 u0 G5 hdouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];% {& |: C1 f; i" p
info.NormalizePrice(sl);3 D5 e1 b9 g: W" m7 W3 ~$ M
if (sl > SL)
# q6 w1 f4 Y* Y# s{ }8 s6 n2 f0 m% V) B
negocios.PositionModify(_Symbol, sl, TP); K- [7 o4 F- p ]: `
}
# W0 R0 D: G/ r; w4 u! O: h1 f}
" s5 J l4 I& v8 k}
: X4 g8 R6 z1 C& C, X5 Telse // tipo == POSITION_TYPE_SELL
+ i* q: j+ ^3 _% G: X{ P7 D; p" G3 s7 U
if (cotacoes[1].low < cotacoes[0].low)! n8 ^6 p" ^& X0 G( s2 \
{! @8 ?7 e5 |, f* ]3 I; q, G
return true;
; r9 i, Y/ V7 X# \$ R}
2 M% t/ b6 d2 h# T; ^8 Z// there was no position. b. _0 u* v3 t* H
return false;; w2 b) G6 g% U ?7 J& Z( O7 T9 Z; L' {
}1 F: t. ?# w, Y5 \$ a. C5 ?, I
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。& F4 ~ t5 M; {
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |