1. 我们会用到什么模型呢?# \+ i/ V" M+ r) b s* `
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。9 d3 \3 O& [- b, X) x2 E
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进" v; t# u) S4 o" n$ Y1 @6 ]
//| https://www.mql5.com |
9 }6 B6 q8 u" E//+------------------------------------------------------------------+
# }3 f9 f/ p0 d" M4 G4 S: g: L//--- price movement prediction7 A. a6 t6 y# J' v4 R! R5 |
#define PRICE_UP 0
( C. c! I' x! m, h( k" b" b#define PRICE_SAME 16 i B. M8 t+ Z+ f$ N* T
#define PRICE_DOWN 2) P) d. \$ x* w9 t) z
//+------------------------------------------------------------------+
* t% ? \! P) [: P//| Base class for models based on trained symbol and period |0 x. D3 W1 A+ \' M1 W) A
//+------------------------------------------------------------------+! U- g- ^9 G3 \9 Z% C
class CModelSymbolPeriod! Y) l- X+ ?( d- c% w7 r: b; Z
{1 `1 E$ c5 h$ m: ], U
protected:
; ^( P. Z" E4 `, E# Zlong m_handle; // created model session handle
% k4 e' B E" l' b6 u, Cstring m_symbol; // symbol of trained data
0 h% ~% S0 m! o+ W& s0 }ENUM_TIMEFRAMES m_period; // timeframe of trained data' }0 N1 _- ~5 T# r: v
datetime m_next_bar; // time of next bar (we work at bar begin only)
3 m. \2 L! Y5 _! U( a% V& xdouble m_class_delta; // delta to recognize "price the same" in regression models
. v! J! [. l3 M/ cpublic:
9 N* H% e$ l g7 M% F/ L+ k {& M; g//+------------------------------------------------------------------+$ h8 P/ r- f% W. h8 R( F) H, A
//| Constructor |7 G! @; N' H3 }/ H
//+------------------------------------------------------------------+
! P$ e+ Y/ o$ ~& q+ L( {& O% fCModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
# y' r" W, K& k; H{" z6 Q8 u1 \( o H. b9 ~# a" F0 P U! J* `
m_handle=INVALID_HANDLE;& i6 [4 _3 d- {; N& r3 o
m_symbol=symbol;6 e" n5 a$ @: q% y* G% i6 `, E3 n8 B
m_period=period;, N; M ~; z& R1 x- `% P8 N
m_next_bar=0;
1 O" {* T E+ m4 h. e( tm_class_delta=class_delta;
9 N/ H% g! i3 ^2 k5 y}# T6 D( J7 F2 t; [! P0 K6 \
//+------------------------------------------------------------------+
: L7 u' `8 |9 v# K. K6 m//| Destructor |
! N) B( h& C( p9 a//| Check for initialization, create model |
! J$ l$ `5 t+ x/ ?* }//+------------------------------------------------------------------+5 L% u# Z7 M# P4 I3 d" L+ @( a
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[]); @3 ]! E- g& v4 h+ m
{
, r' g1 ?* N8 n# p+ q8 x0 ^% P8 z//--- check symbol, period! ~6 o1 K6 y2 }
if(symbol!=m_symbol || period!=m_period)" D" n4 u1 p$ u; V6 _" n! B/ o) x
{8 Q8 n; E; }, S& Y. u2 u
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
# X' o5 i0 h o s3 T/ O0 Hreturn(false);
- w6 T1 s/ A1 s( t# S8 ^}
( T5 \ R! }" B5 [# S//--- create a model from static buffer
( _- J& Q- Q+ N2 s; z% um_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);$ ^( o7 k& o; G7 W$ u* l
if(m_handle==INVALID_HANDLE)
W1 c6 S& U) V2 T# D- I{
$ H9 z2 @( n+ c6 G2 E3 s2 y# gPrint("OnnxCreateFromBuffer error ",GetLastError());- C3 b) R0 ]7 @* K! @
return(false);
. E3 S; A' i3 V}* y( i# b9 v" u( ]! o) ~
//--- ok
D/ |2 _0 M! e4 T, N4 ]8 `( B- Hreturn(true);
+ a ^ e5 z% y: B4 G, C}( a( _7 N% M) N; ]; g
//+------------------------------------------------------------------+, h5 S0 r( t9 i$ ?. x% O
m_next_bar=TimeCurrent();
7 ~0 H! M! V9 ^/ M; em_next_bar-=m_next_bar%PeriodSeconds(m_period);5 ~9 ~- [! k {0 }+ U6 K( }
m_next_bar+=PeriodSeconds(m_period);
' I# z/ F6 r5 w, i" t+ O//--- work on new day bar
+ z) a: J+ W g2 W9 o, c7 Areturn(true);
! L8 H8 @2 F0 z}* _$ j. E! q( O7 Z' `
//+------------------------------------------------------------------+
/ Y% P* a+ Y& x F( C+ d//| virtual stub for PredictPrice (regression model) |/ k8 R) q! T0 q2 v
//+------------------------------------------------------------------+, _) n( Z8 w' I4 Z
virtual double PredictPrice(void)
9 S* T. y0 [8 o5 ]" p* U{
; b3 c0 _: \& o) l6 Y6 V- Sreturn(DBL_MAX);3 [5 P+ n7 K9 Z+ k k' o
}$ M z7 ?) d. X
//+------------------------------------------------------------------+9 L* [3 t8 X* N ?5 P8 `" W
//| Predict class (regression -> classification) |% g2 @0 C) `% z! ~9 J
//+------------------------------------------------------------------+
# ]2 J! y1 _3 L( n6 E* q- ]9 qvirtual int PredictClass(void)
) Q6 K- Z7 v$ E{
( O2 p1 r% x; u" Sdouble predicted_price=PredictPrice();, X& b& v- B `" Q. g6 v, L5 i
if(predicted_price==DBL_MAX)2 g) ^' L/ {/ }1 K7 _! ~
return(-1);( c1 d& ~6 l7 A% H# j8 @3 u
int predicted_class=-1;0 V, E+ z! M: u! L2 \/ h1 |
double last_close=iClose(m_symbol,m_period,1);
' l, y1 }9 f4 ]1 v//--- classify predicted price movement
/ k0 u: L2 m7 S5 I* x" |- Adouble delta=last_close-predicted_price;) {$ b4 M4 @3 d/ M- V* L
if(fabs(delta)<=m_class_delta)
* y) k* v. L' l( ]7 Dpredicted_class=PRICE_SAME;; M9 Z5 k1 \4 I G+ n0 n
else i4 V" O7 l3 W# ~
private:2 _; R( h9 T% i9 F* i# @
int m_sample_size;
0 F/ T1 n8 k9 s: `! m//+------------------------------------------------------------------++ _/ ~! C7 x U7 q
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)0 P3 L0 P1 ?* B3 t, V7 L# s4 z
{
4 o% s4 D( M- E: n7 U//--- check symbol, period, create model$ x+ y0 T% {. J
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
6 J* p4 o I0 n* H{
5 H( D& J3 U: r" z# m+ }Print("model_eurusd_D1_10_class : initialization error");7 X w% W" H9 U9 M& j1 s
return(false);
* [2 L% Z( ^( K7 _}
5 m- x. `- M2 \: }( l, a+ E//--- since not all sizes defined in the input tensor we must set them explicitly* S7 I4 s. \6 G# ?2 B1 F; ]% I1 {, ^7 v
//--- first index - batch size, second index - series size, third index - number of series (OHLC). ]# \1 f; J; C6 g$ h% L
const long input_shape[] = {1,m_sample_size,4};- p, ]8 a0 r; w4 q3 `' P1 ?
if(!OnnxSetInputShape(m_handle,0,input_shape)) B' _0 ~3 N o; ]/ |. {
{# I3 r5 i+ H! |
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
% w/ m8 |2 W) c; V1 j" breturn(false);& S% {3 b$ X9 K" z/ h, H8 w
}, D1 u' i7 V, m1 ^4 N: R
//--- since not all sizes defined in the output tensor we must set them explicitly; V. o- @9 o5 `) s. b
//--- first index - batch size, must match the batch size of the input tensor3 {' u% |; a% D: R, u9 ], f( i
//--- second index - number of classes (up, same or down): p' V: j* M" ~6 O7 n+ Q' h3 T
const long output_shape[] = {1,3};
5 K$ Z7 V6 m2 kif(!OnnxSetOutputShape(m_handle,0,output_shape))
0 L0 @5 W0 v1 S{' K, o9 v* c8 L) U/ Y/ B
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());- K2 r* p) x2 e& G7 K# y" K8 _
return(false);, {6 W0 o" t/ c: e
}% S0 D1 d! P4 B7 H1 }7 @9 K! A6 r
//--- ok- I1 {. H; X1 {0 T( { p1 Q5 \
return(true);1 g* k+ ^; q! y( ?" l' ^
}4 Y( S0 I$ U2 L
//+------------------------------------------------------------------+6 ~" I* g+ T4 u
//| Predict class |
- Z8 l) @4 G8 k! Q* n//+------------------------------------------------------------------+5 J6 v- K% \8 a# |" r
virtual int PredictClass(void)# h- T0 I; s, B8 L
{ |