启动交易模型,并构建 EA
/ O7 b; P+ X* q0 U) N8 f# U' j8 l5 c在解决系统品质因数之前,有必要创建一个能在测试中使用的基本系统。 我们选择了一个简单的系统:我们先选择一个随机数字,若它是偶数,我们就开仓做多;否则,我们开仓做空,因为数字是奇数。
& v5 C1 B E1 q为了保持随机抽取,我们调用 MathRand() 函数,它提供一个介于 0(零)至 32767 之间的数字。 此外,为了令系统更加平衡,我们将添加两条互补规则。 有了这三条规则,我们将努力确保系统更加可靠。
# b+ q7 {1 I( I以下是制定这些规则的代码。
) T! o& n9 b4 j; V) d" m//--- Indicator ATR(1) with EMA(8) used for the stop level...6 `1 M V9 W5 C+ @7 K
int ind_atr = iATR(_Symbol, PERIOD_CURRENT, 1);
9 I Y0 P! R. I# q$ \( ^. wint ind_ema = iMA(_Symbol, PERIOD_CURRENT, 8, 0, MODE_EMA, ind_atr);
5 h% Y5 [+ M5 G/ D$ h+ ~% f3 f/ f9 j//--- Define a variable that indicates that we have a deal...& n+ A/ p) m# ^. o% l0 A5 {
bool tem_tick = false;4 M. @4 i* k7 h. a3 l
//--- An auxiliary variable for opening a position' ^4 _& Z& ?" m
#include<Trade/Trade.mqh>
% h9 L9 d! u+ k9 v4 G, g) B#include<Trade/SymbolInfo.mqh>
, F6 a& c7 U- H* Y8 \6 KCTrade negocios;
: C) K$ W. z" a! CCSymbolInfo info;
8 A9 Q& H5 R$ X8 M//--- Define in OnInit() the use of the timer every second( f: Z- z3 T5 `* U8 Y+ r" X
//--- and start CTrade+ {9 }/ e+ c2 d* ] u6 o/ j* L( [8 ]
int OnInit(): v7 {6 c; p' y+ S4 P
{
, B, Y# R: r( d6 J( o//--- Set the fill type to keep a pending order" }. i6 x, b9 B% B
//--- until it is fully filled
$ r/ _- P" n7 K' s. ?negocios.SetTypeFilling(ORDER_FILLING_RETURN);
" c% p- A/ B0 G3 t9 c//--- Leave the fixed deviation at it is not used on B3 exchange" T+ p& Z9 k$ r% U$ {+ o8 V
negocios.SetDeviationInPoints(5);
* ~0 Q8 f# M- D |//--- Define the symbol in CSymbolInfo...+ W% A, W2 a- F( _9 k, }
info.Name(_Symbol);
. M$ O5 t1 U! h2 _ U8 }//--- Set the timer..." q. I0 l M( M; {5 L3 ?/ j7 i' O
EventSetTimer(1);9 b6 R3 a8 Z3 x; ?9 Y
//--- Set the base of the random number to have equal tests...
8 x# h6 }* G4 {0 N4 m fMathSrand(0xDEAD);
3 N( D0 u2 B9 a/ K( Areturn(INIT_SUCCEEDED);/ ?* O! O2 d$ K( e! o9 B
}
( `; U+ }: z- T+ E0 M//--- Since we set a timer, we need to destroy it in OnDeInit().) n+ E! e3 ^% n( k2 b2 u7 ~# k
void OnDeinit(const int reason)
/ s, {- q4 [ s! m+ k0 l5 f{6 y5 L7 J. ?# b ` {
EventKillTimer();
7 U8 p2 {% F [9 S}' B, F# z w. @4 a. P% ?: |
//--- The OnTick function only informs us that we have a new deal
. \4 @& W' P4 }void OnTick()8 T& y6 u% X0 C
{
( y5 y- @% X7 t( V/ c# e2 N1 d5 ^tem_tick = true;. n4 P7 ~8 V8 j4 L1 p1 j2 i. l
}
5 x( a" j3 i, |1 V/ {0 r; ^. k//+------------------------------------------------------------------+
7 B4 H3 I, r" m1 D2 X//| Expert Advisor main function |7 e: g5 A! @1 A1 h
//+------------------------------------------------------------------+
) u0 r1 {4 j% D) cvoid OnTimer()
2 }, w/ D% K7 {{
/ _% r+ Z9 P1 ~% g3 U: K: RMqlRates cotacao[];1 F1 b. q" \0 d, j* Z0 f' \$ o0 ?
return ;
6 L F( @5 e7 M8 W! Bif (negocios_autorizados == false) // are we outside the trading window?
! k2 n$ H3 c: P9 D5 p& Q' x' breturn ;
5 P+ @) E# x' r//--- We are in the trading window, try to open a new position!
3 g# l2 i( P/ \: H4 d$ c1 Xint sorteio = MathRand();
`1 y) {1 X# W. C; }; j; Z3 ~//--- Entry rule 1.1
( E1 E9 V: `- L7 i% \8 sif(sorteio == 0 || sorteio == 32767)
& Q6 v# U6 h: T* o# e3 g$ G0 b8 Sreturn ;0 J0 o) U# ~, o0 o) m0 G1 a# i
if(MathMod(sorteio, 2) == 0) // Draw rule 1.2 -- even number - Buy
% m8 l8 P7 @1 s5 J9 {1 ~( [{
, E$ S; Q, E$ ^, Y: q% Q- Enegocios.Buy(info.LotsMin(), _Symbol);
4 r) B4 t# e& Q o% c' m% v+ F}
8 |' M, v" t' v$ ], F5 uelse // Draw rule 1.3 -- odd number - Sell
& P. n1 P8 n% X; E{3 y$ w! M/ Q) A7 `) j# P. P
negocios.Sell(info.LotsMin(), _Symbol);& i, _4 Q- b' j b
}
) U; G7 z7 u& r+ t% I4 i" N$ p}% ?5 R7 S1 t1 U' Q* @' C4 y) P" ^
//--- Check if we have a new candlestick...
) g* T* W7 V' L1 ^2 {9 ebool tem_vela_nova(const MqlRates &rate)
# ~% h, y" y- K{2 z0 g) l' r @$ B8 a
{% o/ _3 b" j- Z ]' Z% M+ G$ F
ret = true;
" P- P; L, G, O5 Q$ K+ ^- Kclose_positions = false;
8 L+ w! j8 m- X}3 E9 F: t" \- I+ F: m( K
else
; a$ G# i8 \# J' U6 [2 C{
/ A" n I8 K- V( f* ~4 Dif(mdt.hour == 16)' j0 {& m1 I; }3 u+ B
close_positions = (mdt.min >= 30);
) y. ]" P5 ^2 O6 m}
1 a6 T& n# F) \8 T. F( M& H9 W}
2 i1 F: u% R% a3 o B% @/ [return ret;- K- x( e( H6 {! Z: f% N7 o; q
}
0 T' ]! ^# h; U2 i- ^8 J//---; \9 A# h, R% F/ j; X/ Q% a
bool arruma_stop_em_posicoes(const MqlRates &cotacoes[])
% r! Q1 g, M7 o4 ]{8 U6 r6 o+ |( ]* h) L: e
if(PositionsTotal()) // Is there a position?
: [1 n/ L: _0 O- M0 D{& Q7 E1 `# [0 l1 ^; `: v! n: i
double offset[1] = { 0 };/ `) @9 [. d2 J3 d0 K9 J; E
if(CopyBuffer(ind_ema, 0, 1, 1, offset) == 1 // EMA successfully copied?
" H; G/ } l* l1 N&& PositionSelect(_Symbol)) // Select the existing position!2 z1 l5 g" w/ G+ S' G0 ?: \$ Q
{
$ L+ m) _; S0 L. e$ v: `ENUM_POSITION_TYPE tipo = (ENUM_POSITION_TYPE) PositionGetInteger(POSITION_TYPE);9 e# [' V2 S1 v3 G9 J$ Y$ Z
double SL = PositionGetDouble(POSITION_SL);1 {5 v4 h' k$ V5 ^0 j5 T/ Y
double TP = info.NormalizePrice(PositionGetDouble(POSITION_TP));
* U. l J/ z" ~" F* p, J8 A3 `8 Eif(tipo == POSITION_TYPE_BUY)
5 T3 i4 I( [4 x% W" D; o7 ?{
% z1 B% r3 A. L9 Aif (cotacoes[1].high > cotacoes[0].high)! h( V0 H, r1 K- q
{$ J2 {1 p. l0 R: X0 E/ ~5 p2 q3 A. K
double sl = MathMin(cotacoes[0].low, cotacoes[1].low) - offset[0];: k- y$ a% V0 K, L/ `
info.NormalizePrice(sl); S# T/ ?% K+ Q, ~: R
if (sl > SL), J7 r* K' j: q& j G9 @( _* w$ Z
{
* |4 t. k9 w1 ]3 O3 mnegocios.PositionModify(_Symbol, sl, TP);* f9 [# }& M, V0 w: K
}
. U( j) f( F" `$ W" \}
9 U0 ]; [7 P) i1 A9 s}0 x& S9 \" P# |) k8 i* ]9 a
else // tipo == POSITION_TYPE_SELL/ Z* \0 h& ~7 c5 s
{5 G, v/ p7 v0 k& x" t) T- _' f
if (cotacoes[1].low < cotacoes[0].low)
! {9 ]1 n& Z j1 P4 l6 } |{
* f( \' R4 E% f) F* }) s# \- \return true;
w8 x! v r% m- t5 Q& m1 e1 Y}9 w/ ]2 K- h4 X5 ~* ]8 K' E/ y
// there was no position
: x2 I3 r$ k: z* Zreturn false;. d$ b: e+ z* `7 W+ e2 w3 l
}! z6 z6 ^& x9 y; ^$ I% K O
我们简略研究一下上面的代码。 我们将经均化计算的 ATR 值来判定止损步长,即我们发现当前烛条超过前一根时,将止损价位放置在烛条的边界。 这是在函数 arruma_stop_em_posicoes 中完成的。 当其返回 true 时,已有设置,且我们无需在 OnTimer 的主代码中前进。 我使用该函数取代 OnTick,因为我不需要针对每笔执行的交易运行一遍大函数。 函数应该在所定义周期的每根新烛条建立时执行。 在 OnTick 中,设置 true 值表示前一笔交易。 这是必要的;否则,在休市期间,策略测试器将引入暂停,因为即使没有前一笔的交易,它也会执行该函数。
+ p5 d6 L: d- ~; s$ f到该处为止,一切都严格按照定义好的计划进行,包括两个指定的窗口。 第一个是开仓交易的窗口,在 11:00 到 4:00 之间。 第二个是管理窗口,它允许算法管理持仓,移动其止损价位,直至 16:30 — 此时它应该把当天的所有交易了结。 |