1. 我们会用到什么模型呢?* e1 y$ C! O( }* H- b/ g3 t( Z
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
^/ `1 E9 r% y6 [& n. W! K- r0 G我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进/ w' Q2 B: m0 B: m# a: \2 V3 |. o6 R
//| https://www.mql5.com |
. F# }/ {4 a# s" `, G% ~//+------------------------------------------------------------------+' P4 G3 ]7 o$ H3 P
//--- price movement prediction
; X3 V" }; ^% g$ F' J% a# ~#define PRICE_UP 0& l: {8 J _/ D+ y% \* v6 Q
#define PRICE_SAME 1
/ |6 s# ^- p5 \8 l. a+ T#define PRICE_DOWN 2
% D! v$ @" i Y+ d. A% g! ^//+------------------------------------------------------------------+
' ~7 ^: @5 i, ~7 g, {' h//| Base class for models based on trained symbol and period |
. u0 J) @$ f7 \9 a6 I- T' |//+------------------------------------------------------------------+
3 E. A1 x% {; u; Rclass CModelSymbolPeriod
) [& z: Y3 M. @( D' X" e8 i6 F{9 v/ E- z# Q2 P J. T
protected:/ K& Q# l1 @5 U9 y
long m_handle; // created model session handle
3 n. w, v& T9 jstring m_symbol; // symbol of trained data
2 T4 k0 H" ?. G/ {( tENUM_TIMEFRAMES m_period; // timeframe of trained data; w% y: @8 n1 K8 P0 y) I% s9 y
datetime m_next_bar; // time of next bar (we work at bar begin only)0 P6 f" q6 W1 D" e& ?9 I0 b
double m_class_delta; // delta to recognize "price the same" in regression models
; I+ |% W: H5 S+ r o! Q5 z( gpublic:5 k$ Y, |. _- f" X: H+ Y4 |0 o. G
//+------------------------------------------------------------------+
- {; d1 F# n5 K//| Constructor |# `9 i5 V1 z; K& W# s1 I% J4 _+ Z
//+------------------------------------------------------------------+0 v5 \, }( v2 C3 y) M8 l
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
% d5 g5 I0 F) R7 A) U! w* `/ L{' ~% o5 ?4 M! T6 O- w( e; N& L
m_handle=INVALID_HANDLE;
* ]" g5 ]5 {; D; Hm_symbol=symbol;8 b8 J" Y; L4 u8 D t
m_period=period;, W2 I2 V3 D9 w& Z
m_next_bar=0;
+ [. g U/ i/ I6 i. I$ n7 Im_class_delta=class_delta;
! p' Z8 M9 M4 y8 D}6 i6 G! \; \8 _) L" t5 i2 ]0 f" {
//+------------------------------------------------------------------+9 c- ` R+ V" c2 p# k
//| Destructor |' r0 e. P$ C! x
//| Check for initialization, create model |
# P% T; Z; G6 F/ X//+------------------------------------------------------------------+
( u& O# _' ^7 {" Obool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
g* ] t0 o3 D. ?+ K{
! A& B5 j. c: ? X. h//--- check symbol, period g: s4 L- w/ V. t" M
if(symbol!=m_symbol || period!=m_period)
2 z/ w6 ?% e/ y/ }" B) n{
' m4 }$ L, m1 u% m: E/ [* pPrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));0 w4 t9 t4 j, Y, q. E5 F
return(false);
, E: P2 @' y: o0 e2 T}! a$ W% [# O( }$ o
//--- create a model from static buffer
8 [" {4 A5 @; k$ W- bm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);: e# q. i! ^' i% [7 Y t1 h
if(m_handle==INVALID_HANDLE)
, z. |0 h$ X" O{5 H+ m) K$ T$ A, p0 x, X" R# I1 F) k/ z
Print("OnnxCreateFromBuffer error ",GetLastError());
; S! ]) A* G: n lreturn(false);
8 e( s3 Z. b" Y' \2 k% v}
" K0 s: B! s1 G, I {4 S//--- ok* m2 y3 i! k% p d' K ~
return(true);
8 ~5 P' H% _7 p) S}1 T9 z& X% E) u( N
//+------------------------------------------------------------------+
0 @$ ^6 {; \5 m! Q* j. Q" om_next_bar=TimeCurrent();9 `# H: F5 w- f8 q# G+ g( W
m_next_bar-=m_next_bar%PeriodSeconds(m_period);" I+ ]1 D# k. G8 E0 z
m_next_bar+=PeriodSeconds(m_period);
* `! T7 k; _) y, t//--- work on new day bar, o, n! ?$ L) k% W" `, _
return(true);
- h7 N# U# g0 a}
/ F. g k4 r2 Q3 j//+------------------------------------------------------------------+6 Y/ ?4 b' K+ U1 ~
//| virtual stub for PredictPrice (regression model) |
. c/ T( t+ e8 p! A+ V2 \# G//+------------------------------------------------------------------+
( a ^ V, H9 |9 f/ e" S# Svirtual double PredictPrice(void)2 F; P2 [, K4 J9 e7 b4 J
{! m) U6 m. v- W' O& m
return(DBL_MAX);! ^# h/ h+ ^6 Z& z6 r, V8 |7 i2 @
}8 _) C3 C$ t5 A' k+ }' j9 k- }
//+------------------------------------------------------------------+4 k5 T+ B$ D' J: Z3 k' u
//| Predict class (regression -> classification) |5 B# z0 {- V N4 d- E8 J3 t
//+------------------------------------------------------------------+6 I. g1 h; q Q# ^0 @' t
virtual int PredictClass(void)
6 t2 N( t' i) f% [4 p{% N6 k3 H1 z2 X% e! Q5 Q4 V: H
double predicted_price=PredictPrice();
, E# N$ H" M& a/ y9 uif(predicted_price==DBL_MAX)
. u- m( Q* H1 x0 C% Jreturn(-1);
& x h, J2 }: `int predicted_class=-1;( k/ P+ V7 ?, u+ R
double last_close=iClose(m_symbol,m_period,1);4 B" m# \ m6 A& t4 \
//--- classify predicted price movement# ?- K( f9 J/ n( O0 k
double delta=last_close-predicted_price;, W5 o) b% ]$ S/ y% i% Z. v2 h
if(fabs(delta)<=m_class_delta)
4 m5 G' o6 |7 A/ r& ~0 u) q$ Opredicted_class=PRICE_SAME;
7 B" l) H/ [0 I, eelse1 a( B9 j0 v1 g
private:, ~4 o- a6 O% v8 @' t z/ F
int m_sample_size;8 W- _. t7 D) S* e% k! Y& x
//+------------------------------------------------------------------+
6 O. S& @0 ]$ Yvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
* M4 H/ x! G$ G8 r' T/ z& t{5 h" d* a1 P& |1 ^% e K
//--- check symbol, period, create model+ V9 ` x8 _+ X( d
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))" r! Q' a* c8 V! c- g
{/ N, [8 ~$ u0 t+ C/ g4 [2 B ^4 K
Print("model_eurusd_D1_10_class : initialization error");6 ~. D! p4 y: m8 ^
return(false);/ }; {! _5 w! U, `3 r S* H
}
! u- z: | f: a) k, A6 Y0 B% [//--- since not all sizes defined in the input tensor we must set them explicitly
7 J/ `. l- v: D: t0 g//--- first index - batch size, second index - series size, third index - number of series (OHLC)
6 s G+ ^& M! j( ^+ e% j, h$ {const long input_shape[] = {1,m_sample_size,4};0 l3 w- Q6 R% Z
if(!OnnxSetInputShape(m_handle,0,input_shape))
8 T+ T. I" R/ V6 _8 x( w{
, U3 ~3 o W" dPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());. E0 t0 J% t* b
return(false);
" O2 f+ p' f7 G1 D9 @}& j' Y) i6 p8 w% s' T( f: H
//--- since not all sizes defined in the output tensor we must set them explicitly% j* n8 Z8 l. J7 O% T4 T* T- y
//--- first index - batch size, must match the batch size of the input tensor) C' d4 H' {7 |
//--- second index - number of classes (up, same or down)# p1 W5 u6 Q* O
const long output_shape[] = {1,3};
: g8 `: m! l: G% xif(!OnnxSetOutputShape(m_handle,0,output_shape))" V/ [; s# j0 K' X. |# L* N# J
{
6 @" X$ @/ z, q: |Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
# ]% w3 q/ r6 ^return(false);
, |3 a5 n) o$ H: t}
# ?3 a8 j1 k+ e4 F* A" t, j! F5 k//--- ok. r" R o! z' N3 ^0 {" \
return(true);
! ?) ~: s i3 i1 G} l; ~" R$ F2 W1 _) h/ o8 l
//+------------------------------------------------------------------+( s; y9 l0 q; T& b8 ~
//| Predict class |" v0 Q c; T- f4 L0 h
//+------------------------------------------------------------------+
6 i8 t$ H0 I& ?: D/ tvirtual int PredictClass(void)
8 d9 w/ x4 N4 \0 R: B0 r{ |