1. 我们会用到什么模型呢?" L2 {8 P- Y# b# w
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。: \5 F' n5 \& b% A+ y' m
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进+ i% @6 m5 m# Q" b! F" \
//| https://www.mql5.com | _: X# p/ a( W8 {
//+------------------------------------------------------------------+! n N- p3 Q! Q
//--- price movement prediction
2 j a6 t# C7 H8 j8 ^. {: P#define PRICE_UP 0$ @ Z' L7 j8 \
#define PRICE_SAME 1, q' T4 e, F4 h( N
#define PRICE_DOWN 2
! I7 i" b0 ?, y//+------------------------------------------------------------------+
1 J6 P# {, X! b; Q" c//| Base class for models based on trained symbol and period |$ ?' G$ @& Y7 Y
//+------------------------------------------------------------------+
: K# V0 d2 V2 E/ Hclass CModelSymbolPeriod
3 {$ P+ @: M4 f3 Z- ]$ T0 n{
/ \+ f; M# }$ A: \) A: eprotected:
) ?- ]0 A/ x1 u; r4 q4 w9 Plong m_handle; // created model session handle
9 R, N- |5 I7 K) ?, ?5 F8 j' I/ Ystring m_symbol; // symbol of trained data4 d" Z u% P5 j0 G$ @7 j
ENUM_TIMEFRAMES m_period; // timeframe of trained data
$ H+ ?. M. F9 k" g% z% jdatetime m_next_bar; // time of next bar (we work at bar begin only)5 ^- e( k! X8 M- S$ } v9 d
double m_class_delta; // delta to recognize "price the same" in regression models
: K6 n: ?1 v5 I8 epublic:
3 Q! h: @% F: t5 O//+------------------------------------------------------------------+
# S# ^' c" L# j//| Constructor |5 w" w. p- n6 P* `, X$ ^* P
//+------------------------------------------------------------------+% L7 @# {' S* x7 H* o: b( b; j! x
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
+ O2 S4 l5 ^2 y5 v2 {* w{
* y( J2 s8 V6 V/ p8 C5 [ Fm_handle=INVALID_HANDLE;
- a" P1 p& a; N" D( p) Sm_symbol=symbol;5 W8 E+ q' f$ U5 R0 Y: n
m_period=period;) i! W4 n" W3 K+ I, r
m_next_bar=0;2 F0 n# L; U$ ` N4 p9 k; ]- @
m_class_delta=class_delta;
6 _* t" e# }) f9 S5 N% T, I7 s}' u, m* u X! P* G) ?& h( o, a4 {
//+------------------------------------------------------------------+) G& F& J, X3 K' s, D" l4 \
//| Destructor |, |0 b2 n" O: i% [+ e3 e7 k
//| Check for initialization, create model |0 q' U9 r( ]( O' F& {! z/ R" R8 n
//+------------------------------------------------------------------+! V z. e( Y1 ]* S; n
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
& K& j+ j0 E f4 ~$ ?{
' [4 K9 Q4 i* l/ U2 t1 r. N- w//--- check symbol, period- P- @4 z+ ~) P% e# d
if(symbol!=m_symbol || period!=m_period)
/ k2 ~4 H$ M; s: s. f{' B1 n" F8 l3 V C2 K$ n2 O1 H& F2 z
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));2 ~' a2 n% Y1 G
return(false);& D" w( \! m7 D( r" ~
}
7 @1 ]1 n( m: t3 U" x2 n3 a4 z z//--- create a model from static buffer% i9 t8 K# ?# ?
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);. E- q: k' [: i8 @+ A' q
if(m_handle==INVALID_HANDLE)
1 z0 H8 v" y1 T0 _) y{' R6 e$ ]( K, {, B& C) G r9 Y- U
Print("OnnxCreateFromBuffer error ",GetLastError());, F8 L6 ^, |& Z$ {$ b' Y6 l
return(false);" x5 C# y" o$ |. B
}
; `5 h4 W; }2 |4 g$ \//--- ok
* q; x' j) {+ x a5 Q; x$ q" L+ ureturn(true);2 |, W4 A5 W& m+ ^/ {7 k) t" J
}
5 W, A3 b1 l' e2 r, b7 `% C//+------------------------------------------------------------------+
0 ]) @! d% ]) y! l# [# r* e, nm_next_bar=TimeCurrent();
: c7 e( E. T) fm_next_bar-=m_next_bar%PeriodSeconds(m_period);
& J* O, ^- U$ T7 d6 xm_next_bar+=PeriodSeconds(m_period);0 y% s7 T) E/ u# p8 v q ?
//--- work on new day bar3 Y( v# c9 k' w s$ Z$ u
return(true);
1 L4 C7 j; x. z}0 m4 F' Z8 h" j9 C5 Z+ j! u
//+------------------------------------------------------------------+
, O+ A, }) D! P: c//| virtual stub for PredictPrice (regression model) |
& {+ j' c5 D# N4 y0 e) S//+------------------------------------------------------------------++ ]2 C' I6 g, j6 L9 H5 c+ F
virtual double PredictPrice(void)
2 o) G. ?5 q" T. h4 Z{7 x* a3 O$ j8 _& G* j0 U3 k
return(DBL_MAX);
4 e: }1 X& k0 b}
" G2 e) b7 \- p* a//+------------------------------------------------------------------+) }, F U. A" s
//| Predict class (regression -> classification) |
. X6 _7 l% I3 z O' g1 L//+------------------------------------------------------------------+
( t: \6 |0 i0 B& ?/ S0 I1 O3 |virtual int PredictClass(void)
$ ~" J8 q. `" W) v* y! I' L; r4 B{
/ d8 H: C2 ?2 y; r) n% M3 B" F2 j+ Jdouble predicted_price=PredictPrice();* y8 g2 I2 r: U: F8 y, f7 s$ T% i
if(predicted_price==DBL_MAX)
5 u( a$ ^2 z4 a8 n" J; ^return(-1);1 t- I6 `; D7 L
int predicted_class=-1;
# G Z" ~0 [" k- j1 _0 D; Cdouble last_close=iClose(m_symbol,m_period,1);: a; x2 f3 I. R" L# }( h5 x
//--- classify predicted price movement. ~& W2 D/ ~5 k( [& D& R1 T- w
double delta=last_close-predicted_price;
/ O y2 T- y- w/ A% \8 Y% {: r Z, Bif(fabs(delta)<=m_class_delta)
/ N) Y7 K2 S% ]) [predicted_class=PRICE_SAME;1 k: w. S" E8 h2 N' n1 J
else0 w5 g0 V: U9 V& |9 C* m
private:
& w' y% x: V3 [ Z) S1 H: `0 I3 Pint m_sample_size;! z, H3 ~1 F* o& b; w- r( k+ E
//+------------------------------------------------------------------+
: M; o J0 _; ~2 X7 J& W: y+ C8 Xvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)! ]' k' \, o: ]8 @
{! K8 L/ k9 b2 c0 S
//--- check symbol, period, create model8 A: e/ u' P* O% ?1 ^* o
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
$ s3 J* }6 q0 B( L/ X' t{* I! W6 ?% i0 b3 V! O7 V
Print("model_eurusd_D1_10_class : initialization error");% H+ P' C/ _/ W- m0 v6 W% f9 s
return(false);
. k9 [9 r) h% x/ V, H}* m; p; E) C0 F% M* A I# ^
//--- since not all sizes defined in the input tensor we must set them explicitly$ W7 ?" S) l. e. @) O4 w
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
5 F+ v( N' k% R: Xconst long input_shape[] = {1,m_sample_size,4};
* o- P& A& E3 l% bif(!OnnxSetInputShape(m_handle,0,input_shape))
. I: J& V/ s4 k6 Y" P* s0 M{: q2 F2 r/ k+ s! S$ r- p
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
) W7 C$ |! ^) o9 }return(false);' [" y4 I" o; G, h) R, c) V
}( Z; W9 g( N. \3 L0 {
//--- since not all sizes defined in the output tensor we must set them explicitly, |% W5 Q7 j7 N" j. S5 T1 C
//--- first index - batch size, must match the batch size of the input tensor
1 i" g) h! j/ s8 L# b4 C; a% \0 C& C//--- second index - number of classes (up, same or down)
9 t/ y: x. U% C E9 [8 mconst long output_shape[] = {1,3};
! t( p3 ~9 p% r# wif(!OnnxSetOutputShape(m_handle,0,output_shape))8 D0 ~ N5 p, O$ a% I1 r
{( z# C/ d x3 {) k4 \
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());7 B% s- V) U5 O" @) ]7 X- Q' ]
return(false);
/ }% t9 k7 l8 P5 v* l}2 E7 y0 i* v8 u3 Y8 Z4 T) F( c4 w
//--- ok
- E! U+ q1 i8 t- \4 k' H4 ]return(true);. i5 y( E" v+ S* h B& [4 ]$ w/ r( F
}. B. E: [& {2 f5 f! ]2 y. I
//+------------------------------------------------------------------+! s& |6 Q! w* R1 q( D* u
//| Predict class |
# A% L( g! h$ R7 l1 {( [//+------------------------------------------------------------------+
. ~7 z3 Q* T6 k. h: j, nvirtual int PredictClass(void)9 l# W W' Y3 H
{ |