1. 我们会用到什么模型呢?6 K! x' o# D! B* r
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。+ \ t. l9 m" o9 `1 H
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进
& }5 n5 b1 C- G) y4 m, {( R//| https://www.mql5.com |1 y4 p$ m1 B- Y& f% F5 K# W
//+------------------------------------------------------------------+
7 K% z* z' M/ K9 I5 V3 t//--- price movement prediction$ D6 A0 r7 W$ `. b/ U
#define PRICE_UP 05 q2 f, g1 g N# y' d
#define PRICE_SAME 1
/ i7 c& m% G, j4 Z& S#define PRICE_DOWN 2$ r( W1 s6 K+ i- b, O8 m
//+------------------------------------------------------------------+
" T& f3 F( `5 V7 H8 ~//| Base class for models based on trained symbol and period |
% `$ _5 _8 x! k3 W- E! W//+------------------------------------------------------------------+
4 A' H( ^/ ?- C: ` ]& X* fclass CModelSymbolPeriod
$ i6 b3 y7 J `$ B+ d! v{
: O6 w* ]8 `% J6 [, Q* J6 s& yprotected:5 E9 b* @8 ]" A8 Q
long m_handle; // created model session handle
- ?0 P: r' N5 [$ u, C3 Jstring m_symbol; // symbol of trained data
: o3 L) N! t( V: T: d, { b: w$ A1 aENUM_TIMEFRAMES m_period; // timeframe of trained data* A( v6 x8 D2 e i V
datetime m_next_bar; // time of next bar (we work at bar begin only)
7 k4 W2 r2 k1 O+ O' N! }double m_class_delta; // delta to recognize "price the same" in regression models3 }+ V8 S7 U N
public:
) D6 A+ g0 ~' k" k6 P3 F//+------------------------------------------------------------------+; A( u5 m% w. b9 w$ a9 H8 d9 M5 v ?
//| Constructor |2 x& {2 R1 T& Y9 J
//+------------------------------------------------------------------+
, |' F, K& x M# ?! O2 v7 QCModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
6 a& e" y0 M- {* h{
& Y* S4 u g5 `9 z L% a$ p5 \6 ym_handle=INVALID_HANDLE;4 L) p# f. z$ ?- A$ }0 ~
m_symbol=symbol;" f: Z8 x! P: q! W5 O# P4 X7 d
m_period=period;
, S" Q5 W/ A/ s5 _m_next_bar=0;
% e2 x- k8 @/ ?7 D ]% Q* n) q1 Hm_class_delta=class_delta;
* A) f5 N) b8 c5 P/ O* m, u9 P1 K; n$ W}' {; {4 Z: V& b, Z" h
//+------------------------------------------------------------------+( U$ @( H. q' R: P8 L0 b
//| Destructor |4 u- P. U' K3 s% c
//| Check for initialization, create model |, H6 g; C: f* a' ~
//+------------------------------------------------------------------+ Z2 G2 J" B% b! L" S/ K9 i
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
0 ~- z% L! H2 P+ q: S4 f{
- J* ?2 ]+ B N. D. E3 k//--- check symbol, period8 I6 K5 Q4 a1 w+ H+ ~+ c" z Y
if(symbol!=m_symbol || period!=m_period)+ i0 ^2 b9 v8 v. d
{2 ~& R$ p3 P- e7 H$ k) |! o S
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));4 s% M" u+ z: V: Y& N# I9 p
return(false);
: S8 o* q/ Z+ g' }# ~ s} ~5 ~& H% @' J
//--- create a model from static buffer
& D6 i5 ?, [* [+ rm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);% H' L2 z, t' g# ], d$ i3 J
if(m_handle==INVALID_HANDLE), q6 u- `% _! }
{
6 n0 ^3 l+ b- \. PPrint("OnnxCreateFromBuffer error ",GetLastError());0 G/ f L4 \9 x+ S6 {1 p" \
return(false);2 n9 `" W$ y E
}6 X0 M# o2 ?. V* [3 m8 K# u- }. {
//--- ok9 Y; [- P' Z& V6 M9 C* o
return(true);2 b9 R. ?( J* ?1 q5 \
}
$ ~6 r: q2 I2 l8 h2 ?0 x//+------------------------------------------------------------------+
2 l6 M" b0 O6 @0 `m_next_bar=TimeCurrent();
7 t$ F0 b% R/ q8 O" @4 X3 {m_next_bar-=m_next_bar%PeriodSeconds(m_period);# E; {% U7 P$ n/ W8 Z
m_next_bar+=PeriodSeconds(m_period);
7 ]4 E) l9 y( _3 j: d" M//--- work on new day bar. G% \! @5 _2 s8 d: s
return(true);* p) G: h# A! o p' E' ^% G+ o
}: J3 U1 T* x) V5 O+ s
//+------------------------------------------------------------------+
) \4 M/ d2 c4 {* t//| virtual stub for PredictPrice (regression model) |
+ _+ u: y4 L& u: R1 ^( W: w0 Q: H//+------------------------------------------------------------------+2 z& }! q+ Y' y9 @" |" _% @
virtual double PredictPrice(void)& H4 O6 A$ q5 Y& w3 Y8 s$ }% J. w+ P
{
/ x+ r# [ l7 Greturn(DBL_MAX);
' d, q' O! Z7 k} P, _: e2 \: M: y' P% C F7 C/ s
//+------------------------------------------------------------------+* V5 E. \8 _* {! x7 R
//| Predict class (regression -> classification) |: u3 a1 A, G. O( d1 l; y6 u
//+------------------------------------------------------------------+2 ^4 w: W% L4 v+ K% v9 F1 Z) T0 V
virtual int PredictClass(void)
* v# T2 q& C/ W{ w% {% B* G& r2 j, e/ J( e
double predicted_price=PredictPrice();, t. O7 ]/ ?5 B6 P7 ?
if(predicted_price==DBL_MAX)8 G" ]4 t) G0 E) f% s- v
return(-1);
2 M' A0 k! e& E: Z3 Bint predicted_class=-1;% U, V: R; ^" V
double last_close=iClose(m_symbol,m_period,1);* }! K- }4 U( v% s+ m* j
//--- classify predicted price movement
7 |2 B/ [0 t0 _8 f- r- cdouble delta=last_close-predicted_price;
9 p+ z. |9 i8 d! w5 K: Rif(fabs(delta)<=m_class_delta)
8 x1 S+ ~( R, ^9 D, apredicted_class=PRICE_SAME;, x6 W2 F8 f1 `8 V; e- b3 n3 k- `. c* ?6 J
else3 {. b9 ]! p$ f2 X5 T/ q& e
private:
* ?' B/ A! v8 D4 pint m_sample_size;
9 F/ E4 J/ N0 Z6 K* r//+------------------------------------------------------------------+0 ?% `6 O6 h) f4 r
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
% H7 L% g) {( n0 ]{6 k+ a- [' F/ a/ _. r6 y. @( f: {% M1 l5 c
//--- check symbol, period, create model
1 ~" l* q; r# Z. e; J' c6 {if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))% ^. Y+ j$ B L2 O9 h
{
7 u5 c- r3 C- o/ L& I7 G e0 T( b0 yPrint("model_eurusd_D1_10_class : initialization error");* q; I3 R/ V& X( ~6 D% {% V1 a5 s
return(false);
, h9 _/ q2 r( x9 h+ b( ]2 A& z0 @, G$ C}+ z G! y( V0 Z: }- @8 K! S. a
//--- since not all sizes defined in the input tensor we must set them explicitly5 C- W; U9 i N9 M* I( S7 q
//--- first index - batch size, second index - series size, third index - number of series (OHLC)( X4 m. z1 ]$ P( R$ d
const long input_shape[] = {1,m_sample_size,4};; A% j" N: n, G8 \
if(!OnnxSetInputShape(m_handle,0,input_shape)), j4 [" [ G+ q% I2 }
{
' q, Z1 }. I% F5 p* O- YPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());, U7 {* c0 [3 f/ H6 C/ {4 f
return(false);
% c! I! n7 W1 f. a}; D( h3 A# }1 G% [8 y
//--- since not all sizes defined in the output tensor we must set them explicitly0 y3 e( L6 h& S3 d2 o% A
//--- first index - batch size, must match the batch size of the input tensor
# J8 m* w; T3 _/ f Z5 B, [5 S7 _//--- second index - number of classes (up, same or down)3 `5 {6 X: I, q" A4 N2 l
const long output_shape[] = {1,3};
4 K! k3 B, s& k1 x/ p" {% n8 @9 [if(!OnnxSetOutputShape(m_handle,0,output_shape))
+ {# m" \- l5 G! F5 T1 \* h/ W+ l{" E$ c3 z8 e2 G& J' `# E
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
1 m4 ^0 I1 g+ B9 s/ Kreturn(false);
, m! A `$ B: C2 S, P}" p! H4 s, y8 m9 ^! K4 x' A: j& `! r
//--- ok
2 Z0 e- O( K" K* K* Wreturn(true);
: w& s$ X, N' ?: A6 F( i8 _0 Q: k}- l# ^, Y+ t* G
//+------------------------------------------------------------------+
! c, O0 k) `! ?) ?, Y7 J- Z//| Predict class |
, U5 L* p& C' A2 ?' {//+------------------------------------------------------------------+
# i a0 u4 \8 ^( svirtual int PredictClass(void). [; ]" m: g# n7 p
{ |