启动交易模型,并构建 EA
& S$ A( g5 X. n( e在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
: N c k1 R' x8 U8 ?5 G为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
) L- A" `1 V! x/ k: V以下是制定这些规则的代码。
8 x$ @& \: H& C! A1 V//--- Indicator ATR(1) with EMA(8) used for the stop level...$ B( N/ T- x) V' ^% P2 J
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
7 {( h# J# x, q, a+ Fint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
+ T) _3 o. w. \8 K4 C7 }/ z//--- Define a variable that indicates that we have a deal...4 @9 L6 k, A: v5 y: p
bool tem_tick = false;
0 V8 q' w# q9 n1 @' u//--- An auxiliary variable for opening a position
$ U) x$ K; A e/ [6 h" @#include<Trade/Trade.mqh>: {+ P& i. x( N W, f
#include<Trade/SymbolInfo.mqh>
) p+ O# T4 v( VCTrade negocios;
( R3 A; `. y: @, S9 B! S" wCSymbolInfo info;
. D, C6 @9 z( {9 N: f2 e//--- Define in OnInit() the use of the timer every second3 P1 A3 C r# x. T$ M9 d9 l
//--- and start CTrade& A* j& j' t) s# U5 |/ x$ e
int OnInit()
, r$ W" p% J8 E: a) ~{1 {" T+ a7 i& j
//--- Set the fill type to keep a pending order' r; p6 O. `7 a. H6 D* I' @2 \
//--- until it is fully filled
# r+ l& L+ m5 w9 qnegocios.SetTypeFilling(ORDER_FILLING_RETURN);
3 G" e4 V* t1 n( Q- R2 }//--- Leave the fixed deviation at it is not used on B3 exchange3 ] ^6 l6 E) u
negocios.SetDeviationInPoints(5);
4 R( ^+ ?# X/ c" _//--- Define the symbol in CSymbolInfo...
6 e1 ]( l/ k# N* `" P( Einfo.Name(_Symbol);3 m/ G( @) n- d) C; D
//--- Set the timer...
+ v$ b: z: n3 N$ I0 i/ WEventSetTimer(1);7 {+ h) \& N. s
//--- Set the base of the random number to have equal tests...
& k8 B+ O, j) ^' C& j* lMathSrand(0xDEAD);
+ n1 f6 I" V; n; G& b9 \- y- [0 p5 ^return(INIT_SUCCEEDED);
- v% L& ?7 b1 t1 k' H1 F1 n}2 ~ R: q0 `7 C/ i( R
//--- Since we set a timer, we need to destroy it in OnDeInit().0 N' e- p# }& l6 |0 o {3 x+ b
void OnDeinit(const int reason)
7 }' x0 C- z- i# ~3 y# m; k! I{
9 a ~2 x- [, ^2 p1 z( oEventKillTimer();
7 F+ l- t& g! u! Z}* E& g4 Y+ N! e- m H+ `
//--- The OnTick function only informs us that we have a new deal
8 P9 v' Q: C. a3 _) J* Q# Q4 @void OnTick()
- _: q' t7 q$ P% s! w" ]{
- x' Z% z+ u5 W* Vtem_tick = true;
" s8 d4 c+ t% s" S7 F} \! g0 J! B( G. V
//+------------------------------------------------------------------+
; r) |, Z! b6 I2 a$ }0 H4 g//| Expert Advisor main function |
* @1 @- z H5 _5 m//+------------------------------------------------------------------+: ^8 k5 E0 E+ j6 r3 N
void OnTimer()
, ^& \; h6 l7 U$ s( l" p+ k; |{
$ G3 J# b% k( I9 K2 WMqlRates cotacao[];- u' j/ a0 b! o5 k( K! G: q; W3 D
return ;9 n% L+ b: |* _8 } M' a
if (negocios_autorizados == false) // are we outside the trading window?8 g) U$ ]9 o$ M0 F
return ;
6 D# n( j' P* O. p, d//--- We are in the trading window, try to open a new position!7 E( ?7 w% O5 R
int sorteio = MathRand();$ M$ P2 e1 w0 A& r
//--- Entry rule 1.18 q0 t# H. T$ U+ ^: T. |0 w
if(sorteio == 0 || sorteio == 32767)
0 p; a* Z5 j% k+ c( X! Preturn ;
2 q& ~* p' G% [+ ~if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy) q n+ y6 p( G, o% Z7 l
{4 S4 B9 }& h+ @ ~
negocios.Buy(info.LotsMin(), _Symbol);
; t6 F# h& ^& R* \2 ~3 H8 P! G( {/ C}
# N- |- ]1 A0 `8 ^" Yelse // Draw rule 1.3 -- odd number - Sell4 V' S% X. Q4 Y v5 {7 h; v' k
{8 P; m; D6 C$ v6 M! S K: r
negocios.Sell(info.LotsMin(), _Symbol);9 M8 \% i5 n3 o0 S8 ?
}7 j* n/ n, d& v# T- q7 c
}
: b, L& f( o/ Q6 v//--- Check if we have a new candlestick...
7 H s L4 i9 [: Zbool tem_vela_nova(const MqlRates &rate)$ \8 a% j8 P/ F- I' ]
{
/ c0 s! m8 i0 z' e- x4 k, n{
0 [+ D5 I# M. ]! ]( P8 @% }% Q* mret = true;8 K2 [% x9 G% \$ n# a D1 o4 R
close_positions = false;* x# U" U3 F! D) G$ r( {
}0 y$ {/ Y. D5 Z+ J. K- [! A1 u- c) V
else
/ a" D( v2 H' {1 ~$ o( T{# a+ `/ r" _6 j7 C. u8 }" l
if(mdt.hour == 16)
5 @/ n6 l3 I) F! j% L4 l% t# Kclose_positions = (mdt.min >= 30);
/ R8 ]+ P/ L/ \1 Q0 z* `}3 k. q4 S" A/ z) L) L, N' q" K* X3 K
}* ]" r: C4 B, _# a) V2 ^' @6 H0 j8 S
return ret;
. }3 d9 @ |) @, E6 X}
* E# {- e& }, [ ^+ W: q//---
6 `/ `. Y/ b; `$ L- S5 ~/ h$ Obool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
I& z' k+ t3 D6 t2 g{: {3 K P$ C7 g6 `& Z4 q
if(PositionsTotal()) // Is there a position?5 r6 y+ D, w8 D/ ~+ _
{
8 f7 u& E. {6 K0 Gdouble offset[1] = { 0 };
) N# v1 G" A: |if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
: v# t* ~9 D, P. h. L4 h% K# |&& PositionSelect(_Symbol)) // Select the existing position!
! v! z* d4 n/ H3 q! d{+ W2 P! |+ h3 t
ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);
0 g1 N3 a+ G6 s2 Bdouble SL = PositionGetDouble(POSITION_SL);$ V1 C: T. [4 E% [0 C' [! u, U
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));+ E8 m) ~7 w# [) I
if(tipo == POSITION_TYPE_BUY)
! A- M8 i" h4 j/ y1 `; }* q( y; L{% @2 A# ^* s) V1 G
if (cotacoes[1].high > cotacoes[0].high)
! v$ p- p, e" b1 P+ `{1 M. f+ \* R8 C) k# J, e* z
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];* n4 Z4 ^7 C! B
info.NormalizePrice(sl);
- |9 V6 m7 d# [, ?if (sl > SL)
: i6 J0 u, o# q" z0 a{
6 a1 }8 `9 M' |* unegocios.PositionModify(_Symbol, sl, TP);6 ]6 q% E5 d: ?& U2 c1 g, ^4 l
}# j: d; b. n F8 I$ V
}
5 M5 Q9 d8 ^7 j+ W1 M. t* g3 G5 j- t9 k}2 K8 `9 w7 {7 X, B" O: X9 s
else // tipo == POSITION_TYPE_SELL
8 `" C. O; B! W{
1 W1 ?& O1 s6 mif (cotacoes[1].low < cotacoes[0].low)5 a' w( s! {1 ^8 d) m2 Y
{
+ o8 p5 B, O, n3 `" @7 z/ creturn true;
5 j4 \- S" o5 |9 O$ m}" J% n6 L9 m& {# f! A: J3 @
// there was no position' ^; E+ N" o, o% a, D& d
return false;
# g4 P& s& n- t1 N2 Y}
$ T! K8 ~; G1 q* e# B; k. A/ N我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
8 K; \6 ^) D+ y( e& F9 Q$ W# B到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |