1. 我们会用到什么模型呢?' H( }2 Q8 [7 J; i! l
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。4 t' Y1 Q/ H- w4 S! K& Q
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进( W. m5 W3 a, g5 X! n8 C
//| https://www.mql5.com |; ^* Z Z/ j5 x1 k S% C
//+------------------------------------------------------------------+9 I" q" _' d$ W. O3 O
//--- price movement prediction
5 j6 [2 V2 [& Y& G9 Q" a3 C#define PRICE_UP 0
* O9 T( S9 D& o' H+ V7 ^#define PRICE_SAME 1
( d5 z+ F5 q; B/ b0 M#define PRICE_DOWN 21 J! e+ p Y6 X+ H7 Y
//+------------------------------------------------------------------+
- E5 l Q. ^. Z }4 i//| Base class for models based on trained symbol and period |
( E, P6 X; T% Z4 K) u) ?0 C4 }. Z//+------------------------------------------------------------------+
, G$ P6 W3 |$ \2 J; Q( Z- n( R9 Qclass CModelSymbolPeriod z" v' R3 B# r7 @) R. U
{/ ]: G$ ~4 W% B, w
protected:- n! G7 T0 u5 D4 J7 `2 T, w
long m_handle; // created model session handle7 ?# o) }( Z: O3 }; q7 S
string m_symbol; // symbol of trained data4 B- c4 x. ^( e% R: n, i( N4 `9 b
ENUM_TIMEFRAMES m_period; // timeframe of trained data. b8 p! l' }( D. X/ Q
datetime m_next_bar; // time of next bar (we work at bar begin only)7 x0 w/ ]( W( ^
double m_class_delta; // delta to recognize "price the same" in regression models( i- O: c/ k4 k- v* v1 G
public:
- v. e( |% H+ E) s//+------------------------------------------------------------------+
/ |2 `! U7 ?) [- G. w//| Constructor |) @% d8 c; A8 d7 w5 F- ?
//+------------------------------------------------------------------+- j$ G% o( z6 o7 N; x2 T8 t
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
; m: L+ F1 t* V{
7 p- x; U4 } L) I4 O3 Z1 ym_handle=INVALID_HANDLE;
1 Z7 k) Q2 K* O8 h- F$ Sm_symbol=symbol;+ W8 J) `* h5 R; E: r" C( k' [8 @
m_period=period;6 d% h+ O, C+ ~ E& J. I
m_next_bar=0;
6 n1 T' R( x: f" c3 }* ?. z" Qm_class_delta=class_delta;
3 F* h* I$ f( L7 u% P}
( w4 {' O7 k- [# z$ o//+------------------------------------------------------------------+
$ E( p! c5 h' p: J//| Destructor |
) C4 x8 G Y/ e7 t, y//| Check for initialization, create model |( k6 |' E2 E: H* r/ H+ c( e
//+------------------------------------------------------------------+
" {$ L v2 o; l' R% Y8 y+ \bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])" t. D8 @+ [$ W6 }6 q
{; W+ b% U/ ^9 j2 |
//--- check symbol, period$ @9 v+ n- ~1 Y; Z( q& ~
if(symbol!=m_symbol || period!=m_period)( C3 T" n2 j. b" \. E
{
+ t- y& }$ O3 w9 P: K: s% dPrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));! x6 G* R% M0 w' ?) L
return(false);4 C6 n5 G" A3 d+ Z9 G. A
}
( k% u; D1 @9 V9 T//--- create a model from static buffer# h3 f# O& o0 L. M' u) X# O/ Z
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
7 f7 C" m' @: S; N) ?if(m_handle==INVALID_HANDLE)
2 X1 u4 \0 ]2 R- P4 z7 F& ~8 \{0 d: b! J8 g$ X7 L1 t& |
Print("OnnxCreateFromBuffer error ",GetLastError());
! i' E/ Z7 I( l( Q! H$ wreturn(false);
5 n9 x$ e& p7 P$ W}) x9 D5 X, O$ b+ @ U! X
//--- ok
: H! o1 r# s$ f) v5 v) Z& @return(true);
. A& L' |/ i# B% [) k |. w}
: e/ r3 F, n* E; f//+------------------------------------------------------------------+2 L& }/ }: f9 _( c! H3 u
m_next_bar=TimeCurrent();# @8 ?/ r% T2 r. Z' R! W# _
m_next_bar-=m_next_bar%PeriodSeconds(m_period);
" M$ }. t7 F! K( l) gm_next_bar+=PeriodSeconds(m_period);+ Q2 z5 ?+ }3 w9 `7 i4 \- I; u( o
//--- work on new day bar
& ~6 z; h+ ?0 |$ P1 I0 U# Vreturn(true); | S* s* x" _: k3 _5 h" m0 |, s
}
8 |. I& q( P3 l1 @" X* e//+------------------------------------------------------------------+
; l6 Q( ~2 x+ w' o0 ]1 V3 s//| virtual stub for PredictPrice (regression model) |9 S7 h+ M3 `' \9 l
//+------------------------------------------------------------------+" S8 G; j* n7 @" k8 \
virtual double PredictPrice(void)( M3 G; m0 z" i& m n! J4 A% H
{0 v9 E1 C! X7 `# t. O. ?% ^8 {& P
return(DBL_MAX);1 J$ G/ c* S* m$ D& T$ \; L2 d
}
" I! p' W; T) ~//+------------------------------------------------------------------+/ n% {6 n! k% D3 W9 x3 ~) T: o
//| Predict class (regression -> classification) |: l ~+ b1 q7 V, Z t
//+------------------------------------------------------------------+1 D: Q; {- B* u4 s% X4 C
virtual int PredictClass(void)8 P, S( L8 @% o' ?/ s
{
4 e! a5 v! z! p5 v" B+ Udouble predicted_price=PredictPrice();3 V& ]1 U4 ^" _! W
if(predicted_price==DBL_MAX)& K/ K1 A o: m0 Q
return(-1);9 M+ U" f+ c# b# n
int predicted_class=-1;
6 | D1 z- Q3 L' h" J7 U' hdouble last_close=iClose(m_symbol,m_period,1);" a) l, a$ E; W$ L* ^
//--- classify predicted price movement
+ F) \, O5 C" g, Y7 w9 idouble delta=last_close-predicted_price;
1 z& ~. Q7 }4 E G. eif(fabs(delta)<=m_class_delta)
) `1 J3 B- o& o/ w) L4 Cpredicted_class=PRICE_SAME;
) \3 H0 M( Z; h; jelse7 S, W* T& J1 c$ A
private:% Q5 G( C% |* ~6 w& X0 a: ?
int m_sample_size;9 A3 s+ K3 J7 ?# F/ _
//+------------------------------------------------------------------+: k& P4 a( A, b& k( C
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)4 Z) @* k2 }! c& f- G
{
( ^3 ?, M6 {( J3 P2 `" T//--- check symbol, period, create model! R5 G. o2 y, u, P8 ~7 C
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))" V, o \' x3 {; `) K1 w8 _( f
{
3 K% ^6 {! I' z5 }# l* nPrint("model_eurusd_D1_10_class : initialization error");: S. p* y' J% {/ j" A
return(false);
: X( f" K; [: n}
3 ~! a3 v+ s. V! }: S//--- since not all sizes defined in the input tensor we must set them explicitly
/ I# R- b5 i% X//--- first index - batch size, second index - series size, third index - number of series (OHLC)( i6 v) o; e1 r
const long input_shape[] = {1,m_sample_size,4};
! t A1 H0 F& ~6 n5 ]if(!OnnxSetInputShape(m_handle,0,input_shape))4 t9 j& |' D" @; h2 Q& C) `
{
* g+ F5 \) {0 a/ HPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
0 [9 l+ h5 y. z" ]: y1 yreturn(false);
' D/ N1 R" j, F. `9 H! l+ [}8 P- K/ y- {1 Q5 q, N* I
//--- since not all sizes defined in the output tensor we must set them explicitly3 ~" [* a1 j+ f4 w
//--- first index - batch size, must match the batch size of the input tensor
9 U; N9 u5 _% r1 E q//--- second index - number of classes (up, same or down)# W* p% g3 r$ l: g( g8 e- {# |. q. ^
const long output_shape[] = {1,3};, y- }* S1 K7 \6 w# x
if(!OnnxSetOutputShape(m_handle,0,output_shape))
" e- E& n$ l. t0 d/ D{ `5 l! P1 H7 R l7 d
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
' \# o4 r) n oreturn(false);! {' M3 c* X( F' o" @
}" R) n( j1 n: v& N* E
//--- ok
' l8 I& h' u% b/ C$ L1 Wreturn(true);
/ d/ h' }) O2 r9 Q}, Z, g! O8 b+ r- n7 k1 I8 w
//+------------------------------------------------------------------+2 y3 Q7 A& N0 s7 S$ r" F5 T: r
//| Predict class |
" [4 x2 l- h6 W6 R+ t9 T& S//+------------------------------------------------------------------+# f( ~" V; h" ~6 F
virtual int PredictClass(void)3 O& h, b+ p" y2 B# t6 I
{ |