1. 我们会用到什么模型呢?
6 `" K8 }8 f* r& T) v在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
; }( r! }& l7 z6 P我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进
# o" g7 O4 G/ z//| https://www.mql5.com |, \5 y# G6 q& Z0 Y0 C
//+------------------------------------------------------------------+
- {" b- \2 M- p" L2 ^! P" t: n/ ]7 K l//--- price movement prediction
/ ]9 v) F2 t3 _: I1 C3 ~#define PRICE_UP 0
8 B ~# G8 L: w; B! l, {#define PRICE_SAME 1
1 D' K& e9 G# }9 x: [5 z#define PRICE_DOWN 22 S" f2 ^. D- |/ ~+ S/ o
//+------------------------------------------------------------------+4 P" O( K [+ s
//| Base class for models based on trained symbol and period |
! ]# z2 ?, F, C4 U! s: M, \8 u. r8 D//+------------------------------------------------------------------+/ \/ Y# [; ?* x
class CModelSymbolPeriod" L/ |( @8 P, F0 T" ?# u! g0 k& ]
{# B: |" b+ s7 f7 }+ i1 m
protected:
; t6 C8 r2 j& z: @6 Wlong m_handle; // created model session handle
& A. |" V3 ?9 [/ i% x. dstring m_symbol; // symbol of trained data
& T8 \ z% k2 `ENUM_TIMEFRAMES m_period; // timeframe of trained data- k" P* ^- P" y: i# [& q) w6 ~
datetime m_next_bar; // time of next bar (we work at bar begin only)
- [& X: l) e+ }. `) p( c) ?double m_class_delta; // delta to recognize "price the same" in regression models
+ A. B) V; x* }3 S2 Kpublic:& O7 E1 w9 y3 U( ?# h
//+------------------------------------------------------------------+5 l( M+ q0 n5 o% `% n
//| Constructor |, m! ]; \. Y8 `3 F
//+------------------------------------------------------------------+& W I4 e' S4 y! `8 k
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
8 ~- E* O* c9 t4 {{
; r! E$ h( t& m6 r+ Nm_handle=INVALID_HANDLE;- @9 k: \& q9 n* ?- i% a6 I
m_symbol=symbol;9 G; c" U) h, E7 N
m_period=period;
6 b, M) n7 ?& X2 f6 tm_next_bar=0;. s9 b9 Q. A; d. v
m_class_delta=class_delta;
8 I/ U+ k: O7 c}
/ p' }0 G; O1 G7 f2 \9 e1 D) N) T1 z//+------------------------------------------------------------------+
9 I, d' l$ g3 m7 C3 h' W- \! I: p//| Destructor |
: e( h$ v8 ^5 i# m- k//| Check for initialization, create model |- n m3 m. A" X
//+------------------------------------------------------------------+
5 H( r: |- k$ H" }8 k; qbool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])* ~2 r4 K8 ^0 u1 {$ K. X" t- G/ T
{5 l9 W) |2 B7 N
//--- check symbol, period
* t- b4 } h/ F* R m5 v1 zif(symbol!=m_symbol || period!=m_period)
7 X5 F3 d% t M% ~# W d8 ^{) \7 k+ i8 y o( y- ]
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
0 W) L" `# o# h( Rreturn(false);7 K3 M; \% \( @0 y5 T
}
. U X( F4 P# {+ C# `//--- create a model from static buffer
& `# U2 o: [0 mm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
7 E" R3 l$ w6 R; z! \9 U# c# A$ Sif(m_handle==INVALID_HANDLE)' C3 o: w8 A+ K" u' |) {; [
{8 _% c: A' o' n: o- s/ U
Print("OnnxCreateFromBuffer error ",GetLastError());
4 V. |* y) \+ n6 W4 Rreturn(false);
1 _6 s0 P2 E6 t. h+ n2 Z}
; S$ A* j' m- ^7 I4 i! P2 z2 O//--- ok$ Z. ]: A+ k- a8 @. A; q
return(true);
1 j% W9 b/ T. W+ |9 W% I}
/ i/ n4 h6 y5 v8 K//+------------------------------------------------------------------+7 w/ j5 v, u9 {1 X* f
m_next_bar=TimeCurrent();
7 @& y3 S4 i; d5 H; vm_next_bar-=m_next_bar%PeriodSeconds(m_period);
# b; y2 o3 G! y9 p7 d( n7 cm_next_bar+=PeriodSeconds(m_period);8 c/ U0 L9 a$ {! o
//--- work on new day bar
% j1 W; Y) o/ O/ v9 |. a$ d7 B& Ureturn(true);
' c0 m- ]! U' S/ x2 w}
# m, g6 B* p) s, O; L; |//+------------------------------------------------------------------+
: W7 b9 |+ o+ J" P0 D/ ~8 s" a* i' S//| virtual stub for PredictPrice (regression model) |
& M$ w( Y# p% t, U; h/ O5 _) A//+------------------------------------------------------------------+
% C: F! Y1 J5 b; A" V8 y8 K6 Nvirtual double PredictPrice(void)0 ?) v& l F4 _ V& j. L
{
3 c* M) D1 g9 h% b1 ureturn(DBL_MAX);
U/ u0 c8 ~+ q6 r) p. Z+ s: ]; m% \}5 B1 u* I! {: d" }; r4 u; b
//+------------------------------------------------------------------+
: S8 A" U' I: h: u3 A y//| Predict class (regression -> classification) |
- v& y# f- n' S" q' Q: E//+------------------------------------------------------------------+6 a. X" C9 f: G- Q! G' U$ O+ N, y
virtual int PredictClass(void)
4 f+ f$ W+ z1 @2 w{
' }9 J, D, B$ V+ J: J# {; Jdouble predicted_price=PredictPrice();
1 p" f$ ^* i3 _if(predicted_price==DBL_MAX)
5 H- \8 }3 x! v, }$ x2 C# |. b) ^return(-1);
3 g, d. h" \* t3 V o" ^1 Hint predicted_class=-1;
. Y6 O3 y, F# }# H% E: A5 I7 Adouble last_close=iClose(m_symbol,m_period,1);, N# `- L5 w- p0 y) F! G
//--- classify predicted price movement: }# ?# K7 F) T6 N5 ]' q
double delta=last_close-predicted_price;0 o, N; A5 f2 b
if(fabs(delta)<=m_class_delta)4 h' l( Y4 y" |5 R
predicted_class=PRICE_SAME;
! `/ A. p* V9 O! @/ oelse
$ ~+ C N& q- h! I8 [( |private:1 m. \ o8 j, d5 q
int m_sample_size;
6 q9 f# h7 ^! ?$ t( w//+------------------------------------------------------------------+
3 ?8 \( s2 y( }; E; ]9 B9 Gvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
) ], a! y- w* m{
+ j" c. G% E" K. l& [ T" z% G) ?//--- check symbol, period, create model0 B9 l% n7 Y. _
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))9 R. N* N6 s S8 x2 @' }# M
{
4 `/ R. |3 g. C9 ^$ SPrint("model_eurusd_D1_10_class : initialization error");2 I2 v* L# ?( R
return(false);% n( H' e: x! x9 h9 P- C) D
}
. r) v7 D$ S5 f8 ?//--- since not all sizes defined in the input tensor we must set them explicitly
i4 ]4 e2 T+ M//--- first index - batch size, second index - series size, third index - number of series (OHLC)
* W# e( x, T7 I, R' \! Jconst long input_shape[] = {1,m_sample_size,4};
* [! I' |/ B" } J; e/ @; V7 Yif(!OnnxSetInputShape(m_handle,0,input_shape))0 T G, Y, P; m9 u3 [$ Q
{
- X, s5 V3 q: PPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());1 X* T6 M2 \+ [: ^% @
return(false);& [3 x. J# x' Y7 r: E* V. N/ P! K
}- A9 D6 N& Z6 N q7 ~
//--- since not all sizes defined in the output tensor we must set them explicitly J$ k' ?/ d1 e6 C" U4 l
//--- first index - batch size, must match the batch size of the input tensor
9 v6 C& q/ [% J( a1 K( a& s//--- second index - number of classes (up, same or down)3 ?- G5 _, m1 K: A8 l. Z; u: y
const long output_shape[] = {1,3};
3 k! G3 |6 l6 |$ O1 Bif(!OnnxSetOutputShape(m_handle,0,output_shape))8 i) U h5 @- O# G# N7 a/ U+ y3 m0 F
{
/ C& t3 v' s4 I; K# C$ [Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());! d; L8 o+ s% t8 E: F
return(false);
2 ^4 n/ y b6 r}
0 A0 r( d* m* C( e8 s8 Z. P2 _4 ?4 h. h//--- ok4 i+ o0 H0 K2 J& } @ E
return(true);4 Y2 r3 N% w3 a
}
! U+ Z5 t* s7 J( [! i$ X8 r//+------------------------------------------------------------------+
; k" d* H5 U" M3 Q3 A//| Predict class |
0 B8 ] a. f% n1 n* v1 U( d3 g: y+ @//+------------------------------------------------------------------+
: P+ z! j) ^" Svirtual int PredictClass(void)
5 C5 x& u* c Q$ ]9 \{ |