1. 我们会用到什么模型呢?
! i8 @0 a$ g0 P! J; r在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
# ]: S: B0 x8 V, z J1 S& t我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进
) k. h; o2 v6 o; u0 H//| https://www.mql5.com |
0 C) E9 i9 O9 I0 R6 [ e//+------------------------------------------------------------------+! ^4 u0 i2 ]% q3 ~7 b
//--- price movement prediction. g# E- `1 @7 l/ L
#define PRICE_UP 0
# y7 O- ?6 X# M#define PRICE_SAME 1, J- v; q+ m5 q& R6 m
#define PRICE_DOWN 24 j- n) L4 A: l# B" D
//+------------------------------------------------------------------+
- F7 {* B- R' C//| Base class for models based on trained symbol and period |
8 g' n1 U2 f( U5 Q% n//+------------------------------------------------------------------+
$ x- K& ~8 |* f$ Oclass CModelSymbolPeriod/ }6 F9 w0 `! F3 S% R( X
{+ P: D8 H. x$ {2 E# T1 E
protected:0 I/ |9 Q6 M" A
long m_handle; // created model session handle" f! i5 M* G+ k' |2 l, v( Q: H
string m_symbol; // symbol of trained data9 t4 ~! Q) w, z2 ]* E9 A0 J4 x8 Z; w
ENUM_TIMEFRAMES m_period; // timeframe of trained data H* k% o6 {/ z% N% m2 U- t* e; z+ B
datetime m_next_bar; // time of next bar (we work at bar begin only)9 J+ d0 }. {+ d$ }" j
double m_class_delta; // delta to recognize "price the same" in regression models
# M$ e$ ^4 Q$ g' v! I4 ~2 Q1 |5 Kpublic:5 B' g7 }9 z% l( R& J: C# R
//+------------------------------------------------------------------+( m) {0 [& r! j# a& @5 h
//| Constructor |* H1 P8 O1 w, z0 Q2 x! u0 k \
//+------------------------------------------------------------------+6 {$ } | |. x' M" H) @
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)( f6 _4 h9 ]5 d) M$ w6 V' l
{
8 b% W \; X3 J+ A8 om_handle=INVALID_HANDLE;
* J* \" {8 r/ A& jm_symbol=symbol;
& }9 P: D- E# B# n9 A4 S. J, b/ rm_period=period;
: {$ g% D; F8 |- _m_next_bar=0;
8 r; n( x( O q: j; k! ~3 sm_class_delta=class_delta;
) |0 d. Z. Y6 _3 [+ e3 b6 H0 N}
" O/ } }" H! ~//+------------------------------------------------------------------+
7 h( e9 N/ d( k4 l; f. z//| Destructor |
7 d% h7 I" t; l3 K o//| Check for initialization, create model |9 r2 a6 V6 B7 A0 R/ A1 ^5 Y
//+------------------------------------------------------------------+
. k" z% E/ \6 m$ f# abool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
" ^( w: {' W: Z& x0 J8 G7 V{
x# Q7 y+ ~' G; e, l; ]' q% ?2 L//--- check symbol, period3 o' C. I, S4 `( e
if(symbol!=m_symbol || period!=m_period)
8 [# y0 v3 h3 b* x# w$ [{* z, h+ R" k- g& ?& l( U4 h2 [& s6 t6 D
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));+ {) {% z- F* Y
return(false);6 E9 H/ T% n ?2 d- f+ D5 `
}
& i. A7 U0 e5 o/ s//--- create a model from static buffer
- J, ]1 `. M4 i# q7 A" ]$ Mm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);0 y4 Z, [" y# Z& ^
if(m_handle==INVALID_HANDLE)
7 R6 M1 b; B' K, v{
0 ]4 U' u9 S6 W4 APrint("OnnxCreateFromBuffer error ",GetLastError());
' i% Q I8 d! ireturn(false);
$ k$ p6 ?( c- r6 m& f6 `3 t}
# N2 G. E. G* Q0 _& @4 |3 f ?2 I//--- ok
% F/ |1 c5 y3 e, s; p$ ^: G& }return(true);
: U6 A7 ~- f( E7 f% i}
8 J5 s+ r W: Q$ W1 e. D. L//+------------------------------------------------------------------+7 u @2 K4 `3 i+ q5 \
m_next_bar=TimeCurrent();
4 r2 u* F/ x" Sm_next_bar-=m_next_bar%PeriodSeconds(m_period);/ q. H7 f% F |9 m' H! c( {8 a7 U
m_next_bar+=PeriodSeconds(m_period);/ F# t8 D( y( D6 ~6 Z; ]$ D
//--- work on new day bar
" }. Z8 K- C8 [" Creturn(true);
/ B: \& U. e/ R4 _+ P; r}
2 c G4 [3 z: }//+------------------------------------------------------------------+
{" B& a& w" j! {% N8 t//| virtual stub for PredictPrice (regression model) |
/ ?# g4 Y j. W3 Z0 s# D//+------------------------------------------------------------------+) Y, H7 {! ~6 l F
virtual double PredictPrice(void)
4 u, o Z+ {6 \8 U1 D, ~{
" m, q4 E& s6 x3 u+ j% lreturn(DBL_MAX);# M4 D0 d5 U' b0 q5 C
}
3 b X: J0 g8 ^0 s//+------------------------------------------------------------------+
* C9 `1 a3 q9 y//| Predict class (regression -> classification) |
6 ^: r1 X( A5 d: l//+------------------------------------------------------------------+ x0 {9 W7 O8 [& g; _' k6 [
virtual int PredictClass(void)' d' K- B, I, \6 u2 M. w
{# q4 p- G5 ]: {5 H
double predicted_price=PredictPrice();
2 Y! P/ ?1 n$ Y) z4 ]if(predicted_price==DBL_MAX)8 \/ E. j5 @( w
return(-1);5 q( S) M& A0 A T$ _
int predicted_class=-1;! C1 w' l1 v1 k. A8 i7 Z) N: Y
double last_close=iClose(m_symbol,m_period,1);
" u v% v' H8 \( w4 @4 I, g- ^, g) E//--- classify predicted price movement4 p! X3 F" S4 M
double delta=last_close-predicted_price;
/ m# L8 u# e& @if(fabs(delta)<=m_class_delta)
/ N Y- y" G$ G" T; F; w: k( E' Mpredicted_class=PRICE_SAME;' H% }) n; E/ m' W/ L9 u
else, A6 m( m, l3 l2 b0 x
private:
: |/ i+ ^6 ^5 }# A- {int m_sample_size;
W, a( {3 B8 F) m1 A* z( b//+------------------------------------------------------------------+
1 \6 v }. l( _) \! m/ Svirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
5 y, ]' \: s" i [# }. I5 |{
. r }+ S3 \( n) z. K//--- check symbol, period, create model
* I0 `/ U# m$ b, H$ Q, L- _if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))( K6 o& M3 y+ C7 A7 b5 R) b
{; l y" Y( U5 V0 U- c
Print("model_eurusd_D1_10_class : initialization error");
; T! |/ @: Y) s, kreturn(false);6 w/ J) }% v5 U9 S/ r% P
}( R* q2 a1 ]/ r9 I( e
//--- since not all sizes defined in the input tensor we must set them explicitly* W+ x' r2 R* V) @- G0 K/ A+ u
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
) M, K/ i: R0 N# Z' `const long input_shape[] = {1,m_sample_size,4};
( Q, \& V- d6 u- t! c0 @' Yif(!OnnxSetInputShape(m_handle,0,input_shape))
7 O. w% ^; ^ V5 ~% J5 p$ w{
5 c# c ~6 O6 |4 }6 EPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());1 R+ ]% r# u1 |6 z' y
return(false);9 x5 z% J; p, c& ?6 `' H3 R
}
: C* k @) v, Z" T1 W' O7 j0 O//--- since not all sizes defined in the output tensor we must set them explicitly- Z5 F9 t$ ?7 b' J1 R6 d
//--- first index - batch size, must match the batch size of the input tensor+ T/ p. n3 L+ ~) u0 ~4 ~% T
//--- second index - number of classes (up, same or down)
: q% n! X1 Q( p m/ V p' Hconst long output_shape[] = {1,3};
. J6 Q6 d6 i9 r+ F. Aif(!OnnxSetOutputShape(m_handle,0,output_shape))
& N3 o2 a, D- e5 ]{
" k# T) ]/ F5 U% K" m8 R' vPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
! i: _( s/ M+ b* oreturn(false);, I( @5 P q' G2 V, `
}" C7 @ U. j) w. `+ @0 G
//--- ok
8 ^. \. t5 F* g4 Lreturn(true);# j6 t" v- u. l" k& u0 d2 ]! l5 k
}
) V9 t' [, _' P$ A//+------------------------------------------------------------------+
( ~' V5 F3 O) k: E' A. R: K2 G//| Predict class |
' ~; G8 z A; o//+------------------------------------------------------------------+
g2 N4 Y, h( {0 O) tvirtual int PredictClass(void)
, Y, t% s6 S5 F) h& N0 I{ |