1. 我们会用到什么模型呢?
% e# ~# r) O7 H+ J在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。5 x' x" J) |/ l( ]1 O& f) u
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进) w( i4 k" o3 t* E: n) a _ D
//| https://www.mql5.com |
$ _1 W/ T* ?" Q$ ^, i//+------------------------------------------------------------------+! m- U( }( Q* @- q* e& e. _; _
//--- price movement prediction
) j& x9 C8 V6 {# b; H* S#define PRICE_UP 0
* M* M' o, H5 i#define PRICE_SAME 1! b" F9 Z3 u- ^7 w m4 [
#define PRICE_DOWN 2* x2 f4 D- k' M0 [) ?# |( Q
//+------------------------------------------------------------------+
5 m0 ]0 G! e9 o% V+ v//| Base class for models based on trained symbol and period |
* }, S& I7 i2 ]//+------------------------------------------------------------------+0 `0 r/ O' N5 y, H. M8 N' T
class CModelSymbolPeriod) [( t" C) T; g: }: T
{
# d" O- c; F. X6 P& xprotected:
; N6 E- i" ]# I h2 ^long m_handle; // created model session handle& C J7 e3 m$ r9 t) F& E( k
string m_symbol; // symbol of trained data
1 a7 v. K1 ?9 b7 t6 b+ z3 NENUM_TIMEFRAMES m_period; // timeframe of trained data8 |" C/ O' N+ a8 q
datetime m_next_bar; // time of next bar (we work at bar begin only): q# x2 \# U, F5 l
double m_class_delta; // delta to recognize "price the same" in regression models
_2 D9 c1 i( k! q, V1 Epublic:. h% j8 F& k8 U5 Q2 G! I' T
//+------------------------------------------------------------------+
, g5 s6 i. X! G; k+ i8 n//| Constructor |, Y& [; H7 h$ b9 E& B! u, r1 N" c
//+------------------------------------------------------------------+) D; X5 Q7 {4 y0 L# ^) f
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)0 @0 B7 Z3 ~% ^. q G# e
{
3 `& c$ {9 U& h. J% o3 O/ a7 c2 @+ Em_handle=INVALID_HANDLE;
8 I2 E5 c5 q) pm_symbol=symbol;5 `7 j9 B# |& J/ K
m_period=period;2 r) t. y+ p1 }5 h0 j, x
m_next_bar=0;( c: }- D0 U/ Q+ k" Q
m_class_delta=class_delta;
- m, U: x) k+ q8 D}
& W# Z. Q+ |, p1 r8 W7 V//+------------------------------------------------------------------+
6 d: Q3 L8 w1 e//| Destructor |. O/ c: h" F, S, m; O4 v( P+ ?
//| Check for initialization, create model |7 |$ v; }6 y9 a* ^! b/ V3 \1 E) G1 L
//+------------------------------------------------------------------+
8 i3 z& [# {4 R5 s% |bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])( ?( V4 g+ c* I, e8 h" h
{
! h5 Z$ z" V" m2 ?* O! E) B! M//--- check symbol, period2 {- C- Z9 w& ]- \1 d$ B
if(symbol!=m_symbol || period!=m_period)+ z. E9 p: H3 ^0 _
{
' C2 r* Z) O6 l' z% p$ \PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
0 ^; G& Z9 P& k) M, }& areturn(false);
0 ?8 o; e1 [* e9 Q9 ~0 ~; V( _}& D- n& d, G$ ^' v: m! ? C4 j
//--- create a model from static buffer8 ?" s$ T4 C# j5 A" R
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
7 e$ k7 R; R6 c- } ^- k7 wif(m_handle==INVALID_HANDLE)
; R$ f- Q4 P& [) S: \& ~{
: Q5 p& o, g HPrint("OnnxCreateFromBuffer error ",GetLastError());$ t9 ]+ s. ~5 l+ [- j7 u# ]
return(false);- D3 L9 b, f, A/ O6 t+ _7 |
}
4 J- H# T+ S$ R# j+ ^" D//--- ok5 A" A3 A- P# O; W# a
return(true);
' B7 _2 e) _( J}# P. M! @# {: s8 ]; b4 N* X
//+------------------------------------------------------------------+
$ B8 u4 J6 v% G9 N1 u4 S2 [5 ?) cm_next_bar=TimeCurrent();
9 j- W* Q2 s# V8 Im_next_bar-=m_next_bar%PeriodSeconds(m_period);
' {3 g: _7 N! L* O, ]/ D6 Xm_next_bar+=PeriodSeconds(m_period);/ _+ \$ z& b" c) Z+ h7 B
//--- work on new day bar
" p. X, d g0 a, y4 O" \9 Y/ l$ Oreturn(true);
A3 K& Q8 V: G}$ C& _9 D1 Z: a. `) G
//+------------------------------------------------------------------+
, U! I2 x+ S& g! r//| virtual stub for PredictPrice (regression model) |
* [7 v7 N( S+ i) o6 P% e//+------------------------------------------------------------------+. T( w5 E) i* d7 d: k
virtual double PredictPrice(void)5 C: H" x( E# ^! h; I# B# i) u3 }7 Z8 B
{ q9 K0 n0 Z" k: @' K' d
return(DBL_MAX);6 y9 ] c3 ^0 S5 @1 r" y% f+ f; n
}/ M3 m1 I: K7 y _4 n
//+------------------------------------------------------------------+
; `+ j1 m1 W1 U) s% M//| Predict class (regression -> classification) |
: `# H4 W" w+ I8 F/ l! o# j$ M3 t//+------------------------------------------------------------------+
& \5 j* m/ ?) R8 `- Y2 vvirtual int PredictClass(void)2 M: O, `1 F% i" A/ l
{, K" V8 A& q+ u! U( \2 W8 V$ _' f
double predicted_price=PredictPrice();
- j" g9 p5 I; {' e& l) Gif(predicted_price==DBL_MAX)# N3 R+ `# B# W1 M# _
return(-1);
) H- h: @ P0 q+ W4 g1 Aint predicted_class=-1;, ?0 K# J( P4 @. ], E
double last_close=iClose(m_symbol,m_period,1);
! P7 g; S! J$ _, ~//--- classify predicted price movement
0 `. i1 Q. H. m8 y$ X+ zdouble delta=last_close-predicted_price;0 t% w* ?$ Y& V! Y
if(fabs(delta)<=m_class_delta)
( {: {: f/ F# w6 Wpredicted_class=PRICE_SAME;- E, ]: b1 a0 ?) s
else
* M7 R* r: m$ S9 oprivate:
$ s5 H5 a0 h( L) T$ Y! m7 K* fint m_sample_size;
3 ^! P/ B0 i$ V' n2 A//+------------------------------------------------------------------+# U( Y9 d! N& @% \$ D* |
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
+ C V4 _3 U0 y% w) E{
: ?% T# G3 P* @5 N* }: c//--- check symbol, period, create model% B" i t4 P: x3 m1 C) j [ ]
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))( _2 y9 m2 p5 z0 U1 h& G& x7 m8 }0 l
{ s" I% ^4 _0 K, l& I+ p8 m8 B# H
Print("model_eurusd_D1_10_class : initialization error");
8 _! i6 I+ l; x, {; `return(false);
2 s# s/ p) M" f' h3 M$ p}, j; ?" x7 d) A& J% q; ?
//--- since not all sizes defined in the input tensor we must set them explicitly
8 E$ D# W6 f$ p$ i//--- first index - batch size, second index - series size, third index - number of series (OHLC)
$ t! ^: Y7 L" B) v" e% i' N: H/ cconst long input_shape[] = {1,m_sample_size,4};
; d: r% C% Y O5 ?if(!OnnxSetInputShape(m_handle,0,input_shape))' {" f5 R4 y' n0 U+ U( L) P
{
$ ]6 E4 }8 H1 b& ~Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());+ C9 I8 E% c: M: f
return(false);& t z0 H3 f7 j
}' V8 e7 r. Y8 a( i7 d( H; I: D1 M
//--- since not all sizes defined in the output tensor we must set them explicitly
* }- D' p+ ?" c4 }0 e//--- first index - batch size, must match the batch size of the input tensor
/ d1 b: }0 v8 T7 T) W//--- second index - number of classes (up, same or down)% [9 u$ {% b3 u! @
const long output_shape[] = {1,3};
+ J1 Q' [- z1 ?( Sif(!OnnxSetOutputShape(m_handle,0,output_shape))
5 q% x! B! e/ S- r{6 w1 p5 A$ S' I. t% K6 _
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
0 I1 ?8 t6 [& k& K+ S: F! Hreturn(false);- v. ^ h3 P9 T x( Q8 p$ [
}8 Y6 \! w6 M6 v! C9 \0 r
//--- ok- V2 s1 g5 u' [0 `7 h5 F0 ]: U
return(true);
* o/ ~* Z4 ]2 V. A. q4 u}
) ^. I) A* ^- ?, D4 t//+------------------------------------------------------------------+# O; s0 S7 R. N: ?* A2 Q
//| Predict class |0 e; E: }$ n5 E$ f1 X
//+------------------------------------------------------------------+
# }1 a! z. q* cvirtual int PredictClass(void)
9 ?% m3 o' N6 r9 {3 c4 ~/ }. Y. m$ J{ |