1. 我们会用到什么模型呢?4 e3 I9 s* n+ \7 D
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。3 N6 Z0 z! {) v% {# X" c
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进; w2 E# m# J! c& @
//| https://www.mql5.com |* l& Y- P/ [1 a0 O" I
//+------------------------------------------------------------------+
$ ]/ G4 p# m+ k$ Y//--- price movement prediction
2 n/ g: R) Y: @4 Z% _ U; o1 ?#define PRICE_UP 0
; j8 f, P) k* I6 c3 a6 z#define PRICE_SAME 1
7 |* v& P$ `6 P; l; Q8 K#define PRICE_DOWN 25 a0 ~+ O* l7 F% M% D+ B( X* X
//+------------------------------------------------------------------+# {( C+ j/ X# a6 V, P
//| Base class for models based on trained symbol and period |
1 j: s6 y; U& A//+------------------------------------------------------------------+% v( E3 e& n- Y# ~8 Y3 z" @; P# p
class CModelSymbolPeriod( y4 j4 o; h3 R0 ^/ S$ j
{
* D1 Y1 d p( Eprotected:
$ K1 O/ E- P: h; X8 ?( E: jlong m_handle; // created model session handle, L) t3 j5 ], y F! H+ e
string m_symbol; // symbol of trained data- I. k0 H: E: X% t* s3 u5 J' V
ENUM_TIMEFRAMES m_period; // timeframe of trained data! G0 S2 e+ M- y3 a* u, t2 M* N! k
datetime m_next_bar; // time of next bar (we work at bar begin only)$ o, q# D7 R3 D9 N) G D
double m_class_delta; // delta to recognize "price the same" in regression models
4 R2 |" r; @/ n5 |* i2 A2 \public:8 i3 l& m& n3 k8 @( g( V9 i
//+------------------------------------------------------------------+5 L! L' R4 u* a, W* z
//| Constructor |
* R+ `- n, D4 A//+------------------------------------------------------------------+" k, V0 g; g! ^
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)6 Q) T7 V h& S* h) e' f/ e: y
{
5 C# V$ F7 j7 S" N/ g |* D: hm_handle=INVALID_HANDLE;
/ o& j- j* O6 N: R' Tm_symbol=symbol;9 b9 n6 Z3 l Q4 H( z* p3 f# z
m_period=period;
% g6 c' ?5 r5 T8 mm_next_bar=0;
& A0 Y1 m0 a6 W' ?( q5 T" v* Dm_class_delta=class_delta;
! {( h% g$ K; e) }# s! y4 n- j: D}
: T7 d. h2 z. W1 [% }& M6 u//+------------------------------------------------------------------+7 j0 U$ W; \5 x
//| Destructor | L% v/ |1 o* p ~. `4 E8 e, M- f" Y
//| Check for initialization, create model |
" f+ N7 h N+ a P: {- B) W5 v+ N% O//+------------------------------------------------------------------+9 F2 F2 m- @9 }
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
. ~6 w) [5 Y0 I: e2 q# C! G{
# v' q; V- g& i* q6 D//--- check symbol, period" ~) |5 w5 z/ A* r* @
if(symbol!=m_symbol || period!=m_period)3 {- M/ b7 P( @5 A% Y) f$ X/ C
{: _" `9 |, ^5 j5 E* V( \
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));, ~" ?4 n q+ y* }( u8 P1 s
return(false);
8 A% D# w+ N3 x: u3 ]}
5 B: U# ^# e7 \* C/ Y//--- create a model from static buffer
) X+ D( d3 |# Y+ B. `( ^m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);$ n# a; F0 U7 ?1 l
if(m_handle==INVALID_HANDLE)
7 b7 W; ~! [; q0 k- |3 S! E{; ?9 K' b" l/ h% }
Print("OnnxCreateFromBuffer error ",GetLastError());, c- P0 J. v$ R+ b7 \* \
return(false);( A. |2 }) d: Q: O
}* R; a# X& L9 e' D4 h
//--- ok
& M# q9 c+ U7 T6 J4 H: X% I* hreturn(true);2 J1 f# E/ c' s
}
' u K& t) P; V' {& L- y/ E//+------------------------------------------------------------------+$ [ [9 |$ _2 \" w
m_next_bar=TimeCurrent();
& Z) ?7 E: h% J- Rm_next_bar-=m_next_bar%PeriodSeconds(m_period);
" h& l# I) Y) e' W- o5 Lm_next_bar+=PeriodSeconds(m_period);& x' G/ Y( B7 {0 R4 q# @; T. C7 |0 }7 g
//--- work on new day bar
4 o8 m; E. {1 G8 n0 ^3 U. h& Mreturn(true);
$ l, B, f( T6 s$ ]* w$ e2 v}. P0 D5 P' q3 D" |5 F9 j+ p
//+------------------------------------------------------------------+
# e5 T2 M, E- B. \: C0 J# l//| virtual stub for PredictPrice (regression model) |/ W3 |: j; p# y+ _- W% C7 O) d# L
//+------------------------------------------------------------------+
4 J9 t$ h: \8 \0 lvirtual double PredictPrice(void)
/ }/ Z0 g+ z2 G+ m{
) ^- ]1 P! b5 c2 f: y: q# K7 |return(DBL_MAX);
: G4 {: J" {2 f$ h B. g}. O" v2 s) H5 l0 @; q
//+------------------------------------------------------------------+
' J; `* P$ u; `# B; d5 U//| Predict class (regression -> classification) |
, H' F8 F. r# ?+ c. d m( v//+------------------------------------------------------------------+
7 M) m+ {. x" g# ~7 D+ b4 bvirtual int PredictClass(void)
6 g; l( e4 n ~2 W{1 T* N% M. W! S4 r3 [
double predicted_price=PredictPrice();
$ \& {$ _/ B! |8 r- {! G' Tif(predicted_price==DBL_MAX)( c4 t( ?4 h9 m. d1 G9 O. y0 v+ t5 ~
return(-1);& @5 Y# e1 x7 @" d1 G8 ^/ \. s
int predicted_class=-1;# G* i/ P, j/ r* e
double last_close=iClose(m_symbol,m_period,1);
+ {2 W V- y' u% R//--- classify predicted price movement
4 _( k3 P8 H1 v9 b. X# o: R- [double delta=last_close-predicted_price;2 K& u/ l! [9 _+ D# O. l
if(fabs(delta)<=m_class_delta)
7 |6 [* X O! z P' l% f$ Cpredicted_class=PRICE_SAME;$ m, ]( \& n8 L
else( w% r, B5 V1 J% a
private:
9 h' V1 u* a! s$ _5 U W! e& ~int m_sample_size;% ]0 M4 M; K$ I# L
//+------------------------------------------------------------------+% `6 y% i6 C) p& X0 \
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
$ V. Z3 ]" E1 x- b$ C! ^{
9 @9 I3 e8 `3 F7 E- s//--- check symbol, period, create model$ ?# }8 x: ~3 V) L& v+ j m% M
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))9 e- |0 c8 p. B3 H) j" R& `: T9 @
{
" t Y, P5 ~, z# h* q$ yPrint("model_eurusd_D1_10_class : initialization error");8 C! G% h: e) Q
return(false);
0 E" }+ ?; u* [6 \8 T. g8 I; A}( }" y5 H! Q' ^$ a5 |5 B+ w5 L
//--- since not all sizes defined in the input tensor we must set them explicitly
4 J3 y$ e) B* u: [; s4 _1 T" }$ o6 T//--- first index - batch size, second index - series size, third index - number of series (OHLC)
+ S8 q6 N5 |. Aconst long input_shape[] = {1,m_sample_size,4};
x% P' P1 `5 k8 c3 Y; fif(!OnnxSetInputShape(m_handle,0,input_shape))
& w. l' Q+ P9 Y1 G{
& r( |# ]; H' O; T) {& l( ~8 bPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
! l1 O( s; U9 `; preturn(false);- K) o# M7 W+ F, i
}3 |/ i q+ ~& R2 Z
//--- since not all sizes defined in the output tensor we must set them explicitly
' q7 G1 y1 K5 B7 O: c: F$ k//--- first index - batch size, must match the batch size of the input tensor
4 I; d% q& T- r2 x* o//--- second index - number of classes (up, same or down)
+ d6 K* u" ]' T5 W; ^+ v; }- t9 Cconst long output_shape[] = {1,3};
4 J0 `' C3 g) R3 _; ?, @if(!OnnxSetOutputShape(m_handle,0,output_shape))
( G" e# V4 f5 Y3 z0 P5 f" w7 O{
% w; l% w1 j/ |0 }" z4 X0 [' w1 f! l' TPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
) H- ^! n: f- breturn(false);0 {) M, F9 p* Z4 p6 {; k# w5 ] M
}2 o$ ?) s; e; g! e
//--- ok2 l9 W% U8 \2 `+ X8 c
return(true);4 b* r+ D7 Y ]7 ]# K& v
}" u8 a5 R S3 @7 ?
//+------------------------------------------------------------------+; e }; ]$ o1 f5 e% q' {1 S
//| Predict class |. V" q: z% d) {# v. h0 F8 z- Y" i
//+------------------------------------------------------------------+
J& D @$ P* M3 kvirtual int PredictClass(void)3 ` h, x, }& T6 ]
{ |