1. 我们会用到什么模型呢?7 q! _3 m+ F4 a4 |
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。 O* g8 I6 U( n0 g% k6 Y
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进; B* s7 l' H/ k% R% A3 m
//| https://www.mql5.com |4 D( d3 t2 _& p- @1 v! e: i
//+------------------------------------------------------------------+2 u4 Y: w/ s' m8 Z0 a
//--- price movement prediction
: d. v' g! H' q#define PRICE_UP 0
5 p4 ^7 O: k1 v1 x7 F6 L) u* {#define PRICE_SAME 1( Z7 x4 d# i* S$ B& _. T8 T8 ?
#define PRICE_DOWN 2' ]% y: Y3 w: A5 C0 W2 ?$ _/ G
//+------------------------------------------------------------------+7 ]' O6 V/ [' L* h
//| Base class for models based on trained symbol and period |
% w. v* v* S8 Q7 d//+------------------------------------------------------------------+1 ^, q# a$ Q/ f/ J* O; b, ?, K3 q
class CModelSymbolPeriod, {! b+ p1 d* r+ [: b+ ^
{
: q, ~: R7 S! C- d3 {7 T8 |protected:
, A$ O' O2 r: F9 Q+ Z% q1 zlong m_handle; // created model session handle
# H/ c, Z1 F, c8 B" z0 pstring m_symbol; // symbol of trained data
1 P( D+ @# E8 y4 M: o. b5 tENUM_TIMEFRAMES m_period; // timeframe of trained data
' B* `9 X$ o& U0 {! ]" N; G$ k _: ddatetime m_next_bar; // time of next bar (we work at bar begin only)2 P- x3 Q0 P" X& V+ u
double m_class_delta; // delta to recognize "price the same" in regression models
) [. F# H) m3 s8 x% m1 _public:
* Z3 c; x5 i1 r, q0 q! j//+------------------------------------------------------------------+
$ [: ?- c1 L/ N2 i//| Constructor |) Y! _& ?5 Z; {, B8 L. a) W
//+------------------------------------------------------------------+, Q) x# }1 F3 g
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001) W' b1 H* \* v5 |8 U1 I" m
{
& J( H* j1 @4 O$ S) ~" c+ N( Vm_handle=INVALID_HANDLE;
7 {- p% h7 `+ F1 T, om_symbol=symbol;
" a7 S9 j: A; d: m) z7 M, ~) [5 Zm_period=period;
& v [. }: Q! R; Z. H2 B% Km_next_bar=0;
* S- _/ u3 C! \m_class_delta=class_delta;
' d0 A7 ]) p' j}& N6 R! h: v3 Z# V0 G; Q6 c1 f
//+------------------------------------------------------------------+
/ I% E. G& p6 X3 g- Q, F3 U: `//| Destructor |
. Y% q& M4 j# [2 ?- ~# P6 Q//| Check for initialization, create model |/ |" @5 {1 Q4 ~
//+------------------------------------------------------------------+/ m$ ]7 `8 c4 ]2 N
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])0 ~+ J3 R6 T6 [3 a$ `) m
{
4 e4 ~' s- _6 Q/ p: ]" i//--- check symbol, period3 q% j6 ?* K, K+ q7 v
if(symbol!=m_symbol || period!=m_period)
: V; }; }1 K7 ~5 s{
- ?7 ^, l9 E- @! l' ?7 o, cPrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));, [9 q; r" \ z0 S. n
return(false);
- K1 v" |- ?: G" N}3 i9 \( w: y/ H& ?2 A- Q2 `
//--- create a model from static buffer
5 V. e" m/ \9 h% x, Pm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
7 Y( j" ?/ N) t# ^* {/ }" w. E+ U# xif(m_handle==INVALID_HANDLE)
9 W2 L6 \2 y$ m: s3 _0 E{* P$ f$ g' j$ J$ L
Print("OnnxCreateFromBuffer error ",GetLastError());
% }3 F7 t8 V. _) e& |0 Freturn(false);
3 E5 P0 u- k: `9 ^6 ]' i. k9 I}
& g. o0 J- O+ Y1 ]6 d4 H//--- ok; G! D9 d7 ]* \" C$ h
return(true);% E7 A4 P( s+ P- y
}
+ z7 E# N8 {: Z6 `1 N( z" l//+------------------------------------------------------------------++ b% s& Z! Z5 c) h1 V
m_next_bar=TimeCurrent();/ u/ A- W; q+ o. }7 V1 Z
m_next_bar-=m_next_bar%PeriodSeconds(m_period);0 G) v9 u' O) k6 U$ s8 B4 L
m_next_bar+=PeriodSeconds(m_period);
- ]. A2 X5 j" Q: w+ K//--- work on new day bar
1 ^4 a# H4 p. Q) ?: f1 y0 Kreturn(true);) k* K9 u/ S& Z8 _4 c
}
; d4 C; e [- G# I/ `//+------------------------------------------------------------------+
- E3 j4 v, z) q% U+ B//| virtual stub for PredictPrice (regression model) |" \6 O, r+ A* ]) E! C
//+------------------------------------------------------------------+# k/ U0 e# ?+ ]( v7 g0 j% y
virtual double PredictPrice(void)
3 [( N/ k ^: [1 i/ p) ]8 S( ?; U{: A* K: H7 g2 ` X# h( d' E
return(DBL_MAX);6 e- B% w+ h- i8 f( C7 _4 j
}4 d8 f. B8 a* F: G/ }, N- b: ^
//+------------------------------------------------------------------+9 f9 A. X! U* }- n* _& e0 l; E o
//| Predict class (regression -> classification) |
0 z, Z# [+ y' k% | q+ Q, `4 Q//+------------------------------------------------------------------+; q G+ ^& \0 f' w7 g
virtual int PredictClass(void)6 e/ z4 v$ y1 S# h# j- G8 w
{
P) ?1 d- _2 S: i; d* edouble predicted_price=PredictPrice();
6 b7 E) d" p) w8 q, ?5 t8 tif(predicted_price==DBL_MAX)% n7 y: b' W' M$ k6 f
return(-1);
7 ]$ t- F0 L$ v4 r# g" Sint predicted_class=-1; R5 i' k/ R! s7 D
double last_close=iClose(m_symbol,m_period,1);
6 E5 `5 D$ x1 n//--- classify predicted price movement
( P+ {) T3 {2 ^- [" ?double delta=last_close-predicted_price;
; k$ ]" i- {9 |# g$ P% Jif(fabs(delta)<=m_class_delta)
5 b4 @& N8 ~2 n5 Gpredicted_class=PRICE_SAME;
7 g3 V) a8 k9 Y$ t- s$ Belse
1 ~$ G$ f0 u* @5 ^/ M! iprivate:
7 r: |. _5 o3 e' }int m_sample_size;+ g! ~1 }& p7 U# n9 x
//+------------------------------------------------------------------+9 f2 X5 B9 s6 ? v; A. s( Y
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)$ r8 p: _5 g+ v5 Y6 t* h a
{: i3 O/ z: D5 k- y; G7 X- A0 ]. c/ Y
//--- check symbol, period, create model9 ^4 e# ^ A% {) d( \" Y2 _
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))4 H8 e' x/ f! }5 {: u& F
{8 @6 e. I O# f' f4 z
Print("model_eurusd_D1_10_class : initialization error");
% x6 u: e) e8 U! ]4 {- {return(false);5 L4 w/ Q: x( N/ W/ z8 X; _( I
}" h9 ~# U# \* _1 H
//--- since not all sizes defined in the input tensor we must set them explicitly" ^3 C7 q* f3 A1 R) U
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
$ D( `# ]' W2 B& `* F1 zconst long input_shape[] = {1,m_sample_size,4};
' b" y. x* ^1 T8 Kif(!OnnxSetInputShape(m_handle,0,input_shape))
1 A. {$ U7 ]! g. k- L* l- y4 P{
2 ? i. q) F' X. `; }$ w; |Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
- S) _1 S& ?, u2 M9 jreturn(false);
0 Q$ l: M* Z. p}, k I5 L( _ {, w/ _: C5 s
//--- since not all sizes defined in the output tensor we must set them explicitly% L# L$ _- R1 w' c/ g! a# \; H
//--- first index - batch size, must match the batch size of the input tensor8 Q3 Y, Q" `0 B% i
//--- second index - number of classes (up, same or down)
7 d/ q, L+ ?, h2 u/ _3 p7 J0 Econst long output_shape[] = {1,3};
6 I9 h, C0 I! s2 Z8 w, |: Jif(!OnnxSetOutputShape(m_handle,0,output_shape))
( P6 _ \3 S! I* T7 A9 `* l9 y{& e! ~* }+ A, c, \7 r" O
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
! ?) }9 Y) X* p" X( H; @2 Z4 {return(false);
4 y/ ^) @0 J8 b0 z! a}
" K" C( g3 u6 u//--- ok
) E/ r- H$ |: l! l! E2 @return(true);
% x1 s- N! \ A6 s6 b ~6 p2 U}1 b) u |; F- v
//+------------------------------------------------------------------+" w5 q, P: H- p! s$ I" w2 f
//| Predict class |
/ c# f) z5 h9 x" Y) g, B1 `1 ?* q" j, D//+------------------------------------------------------------------+0 E2 k/ e7 V" A3 @* Z0 l: @
virtual int PredictClass(void)
" ?* j- S) D3 Q! y B{ |