启动交易模型,并构建 EA' L- z+ Q6 C8 ^8 O- y! E4 i
在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
0 R: O: q- Z' _7 _% N5 |为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
: c: {4 s- c5 |, v! e2 V1 p以下是制定这些规则的代码。, M3 ]7 o9 o% I+ U1 A) H" p
//--- Indicator ATR(1) with EMA(8) used for the stop level..." Y* A, e: V% @' ?4 l' E4 l
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
- M) T6 S1 w& Q1 @4 ^$ {6 {int ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);: m5 e. N( e7 M, q
//--- Define a variable that indicates that we have a deal...+ O8 P1 C* d" [; T
bool tem_tick = false;
h- ~( d' H, j/ J* q//--- An auxiliary variable for opening a position/ x! ]) x: ~" O# G4 a3 ^& l# P
#include<Trade/Trade.mqh>
: ~1 D ]" R' \( I$ {2 G#include<Trade/SymbolInfo.mqh>( {& j7 n( B* x6 ^1 c" h; T
CTrade negocios;7 }# @9 L6 M& Q" x+ z3 h5 G. F* J
CSymbolInfo info;% `! L" x. t1 q: w+ n7 K) a
//--- Define in OnInit() the use of the timer every second) \8 n/ _7 i3 N. q) h
//--- and start CTrade
' F7 B" o# W; J* t# G; t: E5 qint OnInit()
# G1 c+ C; h% l{6 O, ?% N7 O" Y* x
//--- Set the fill type to keep a pending order5 R. v3 [4 Z" t5 C9 ?5 I4 N+ z
//--- until it is fully filled7 \$ U( @( y3 _0 @
negocios.SetTypeFilling(ORDER_FILLING_RETURN);
6 s( N/ n) k/ B7 R//--- Leave the fixed deviation at it is not used on B3 exchange
, l, G' Q% h- \! ^negocios.SetDeviationInPoints(5);
+ m" k2 F7 \: \, g//--- Define the symbol in CSymbolInfo...% K+ y1 u% r, {
info.Name(_Symbol);, \; [9 j. i* N2 u
//--- Set the timer...1 W/ ?0 n: f/ |% J
EventSetTimer(1);
! V7 c& [7 b1 C* b" \//--- Set the base of the random number to have equal tests...
" \+ w/ u. u1 a" H* m: O3 ?MathSrand(0xDEAD);4 G3 {/ C* `. {" d( U
return(INIT_SUCCEEDED);3 G8 P/ `( A+ C' |- Y B6 R( X! D
}
! `9 V' N1 f* \) h0 E( Z1 H8 M//--- Since we set a timer, we need to destroy it in OnDeInit().0 u1 p' U+ [, n5 w& v) s
void OnDeinit(const int reason), P& p$ d3 {- i9 Q6 Y* y
{- {) `! `# q. {% n5 F4 k
EventKillTimer();. u2 u- [, |/ u( R) \
}
: |6 A- j2 M4 {* i/ w, K: P//--- The OnTick function only informs us that we have a new deal
, u e9 K& \/ W0 W* G+ W& I7 E( g% xvoid OnTick()+ k! `, `' T( E7 C' O
{
8 I3 w+ k+ c5 ?# Otem_tick = true;: {8 f D6 ?' P7 d) E
}
' L9 | Z* d# w//+------------------------------------------------------------------+( S! u! e& K* N0 r
//| Expert Advisor main function |" s" a9 K. B. z. ]5 f# _
//+------------------------------------------------------------------+
0 g3 H# D+ h( ~3 X( tvoid OnTimer(); p, n) d% N) l" a. o# H8 H
{1 `& S. ~: ?; v6 B7 a R
MqlRates cotacao[];
- I: O7 S! B& F; U) W; @return ;+ [% B8 c2 d `* A7 \3 t
if (negocios_autorizados == false) // are we outside the trading window?
% H7 j: Z, h# X! {return ;# @2 q* w& B2 {( e% r4 ?
//--- We are in the trading window, try to open a new position!+ c. L# e" f2 h0 u1 i( {( g
int sorteio = MathRand();. M, u+ i7 n: }* U$ R
//--- Entry rule 1.1: X; {) f4 b8 u5 C! T
if(sorteio == 0 || sorteio == 32767)0 T# |, h( u* E# M& U
return ;
: e0 T- s7 |- i& ^( m! P! N7 Vif(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy2 n; e! S: J# z
{& `7 `) l6 C+ N! v/ o u; A
negocios.Buy(info.LotsMin(), _Symbol);% t# k8 }- K# l, r9 w4 ~2 H L. H
}# m& o8 H1 d% H
else // Draw rule 1.3 -- odd number - Sell
& `: i) Z6 q' l9 k* G9 }" A{6 M, U. `0 @! O" P
negocios.Sell(info.LotsMin(), _Symbol);
% V# e* k' h3 A8 g! p1 n! D, G( i}
" \& u' w n6 x& u}' _' [% b% }) k' V# F3 ~
//--- Check if we have a new candlestick...
6 g! R! y" y) s: z+ qbool tem_vela_nova(const MqlRates &rate)
& L$ N8 f3 y0 F4 e& y& t( f$ A{
$ f; u/ ?8 u& ]2 J% F% e{1 h! l% e# ? [. g/ B+ I
ret = true;
. w/ X/ ?" a; T( k x0 a) V. Wclose_positions = false;
, H! A4 m J: J; P( a# ^}, [1 {, L* V0 L+ k( g
else
. p3 U' l/ L" p& X4 [6 w{
' O" j" ^$ s% y; z$ T. @if(mdt.hour == 16)- Q' _1 y6 ~3 `1 [1 S
close_positions = (mdt.min >= 30);
5 `# x6 e' Z* N* Z}, b) J( D7 ?* _- e6 c/ ?0 O
}: q& E# j: A( k5 N/ S9 x! Q2 B, Z- r# ~3 W
return ret;! I4 F' \4 @6 a) S7 ~
}
4 Q9 G. e( {' e, Y" G/ [. l7 G3 G//---
- [& I- _7 k# Z* C7 [4 g& obool arruma_stop_em_posicoes(const MqlRates &cotacoes[]), _$ B% Z: g# x2 b: U
{
! u& ~! @$ L1 I3 M) P! _. l6 mif(PositionsTotal()) // Is there a position?
/ X# `% R5 J @% c& X, @6 @$ M8 h0 h{
8 U, t Z1 H6 F" Cdouble offset[1] = { 0 };9 h+ b& ^9 R' F. X
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?0 k6 H( k. O3 q5 y
&& PositionSelect(_Symbol)) // Select the existing position!* I9 i& m9 y" _6 i2 `
{4 o+ ^% ^# ?8 d- I
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
- U+ E1 ?; P) Q* j, o. n( sdouble SL = PositionGetDouble(POSITION_SL);
D- o& m0 r5 i: m5 Z0 Kdouble TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));8 x: `5 X, r$ x9 g( y; Y
if(tipo == POSITION_TYPE_BUY)* l! Q+ o5 _$ D# B# s' P$ F
{
- C2 j# d% i- @# ~if (cotacoes[1].high > cotacoes[0].high)
+ N" N* F8 R: r& [{
& `6 M# B) V8 s$ o/ @/ Ndouble sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];) L* h* z8 F0 c
info.NormalizePrice(sl);% a2 W& `7 V; m( i% i5 S
if (sl > SL)
1 W, t9 j& {8 ?{
- b" ?! E* e4 A) qnegocios.PositionModify(_Symbol, sl, TP);9 v5 j+ h$ P+ A& T+ f6 ^& ?
}
$ u9 r% M% Y8 I+ u. F. J) _ \}
! y$ I- J4 \( f4 g& ~# t/ R}7 D+ j6 y& i) ~1 e' S4 x+ e* k
else // tipo == POSITION_TYPE_SELL" F) w& S) q2 T) v/ Z
{# P& n) t) R2 v- R
if (cotacoes[1].low < cotacoes[0].low) o9 L: A( X0 I
{
a3 V! z4 i' S* {5 }9 F0 nreturn true;* v* ~9 B; M6 u$ W u+ P
}1 H1 s. y, g& W/ q4 d
// there was no position
/ x( G: D' P% c! x- X \% b" W/ {return false;
, T" R/ g. Y* l" d, D$ X}4 k" M4 a2 L5 {
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。6 {$ t/ x: n! F4 A
到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |