1. 我们会用到什么模型呢?
- E$ M ` o# |2 J e在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。1 d" _. {/ u. E9 M/ o; _
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进" C. r" a8 e. ?, k' a4 l
//| https://www.mql5.com |* A& r/ M7 b" t g! A2 g: E( q
//+------------------------------------------------------------------+2 {1 E$ Q, o$ y. ~7 v& _) F
//--- price movement prediction2 c6 V- `* c5 N5 g& q: J
#define PRICE_UP 0
5 A0 s6 E7 b) ^0 d w/ B3 l9 v#define PRICE_SAME 18 E( t U1 k- I0 G! ]9 m7 |
#define PRICE_DOWN 2
6 e; J& [! K: Z0 T+ I+ }- }. j//+------------------------------------------------------------------+
/ n1 y$ S7 t* R//| Base class for models based on trained symbol and period |; w/ o, v6 f+ h9 ~& z+ s1 d
//+------------------------------------------------------------------+
% _( d( B' s: H& l' E0 mclass CModelSymbolPeriod
& N1 K# j0 x1 u) q b5 f9 h{8 @9 b2 P( o! [0 y1 l
protected:
: t* J# c _0 j: Rlong m_handle; // created model session handle* j a+ k- I: c) e0 J& [
string m_symbol; // symbol of trained data/ @. N! e: m3 `- V# T6 |+ h, O
ENUM_TIMEFRAMES m_period; // timeframe of trained data
) K: y* ?: ?6 ^* I4 ^. C2 qdatetime m_next_bar; // time of next bar (we work at bar begin only). @+ y8 [ L2 I" F1 y1 M: c
double m_class_delta; // delta to recognize "price the same" in regression models5 W' v. z) ?0 @1 |: Y; T4 L
public:6 c7 S$ {1 t2 s5 @8 ]' z5 ?
//+------------------------------------------------------------------+
/ k$ Z" A/ O9 z, m. P% K9 F2 H//| Constructor |
) a0 y$ R# C! P4 `* m2 B+ p6 C//+------------------------------------------------------------------+& R) S* E: k% O# s
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
5 |# I9 i# n: v, w* P{" L& P$ P& k, k
m_handle=INVALID_HANDLE;" d6 w* D l; n3 u, | W. I, b
m_symbol=symbol;
* }7 H W9 Z) V( n0 W& Jm_period=period;/ @8 i- n* D ?
m_next_bar=0;
4 U) w" X; Z7 E" ]' c6 vm_class_delta=class_delta;
/ U' G4 n7 ]$ E& q}1 ~1 n( _( ~- R% r
//+------------------------------------------------------------------+. n+ h# Z8 k4 U# Q4 o- d
//| Destructor |7 C' l; H! b2 T+ S
//| Check for initialization, create model |
, s. L# j% m( F3 [, \//+------------------------------------------------------------------+
, L7 ]2 G1 m/ i$ Vbool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
' X# v2 }1 f- x# M2 R* K W L! n{
$ Y& z% E/ t( P. O6 \//--- check symbol, period
5 z8 Y& s; P" O" p, wif(symbol!=m_symbol || period!=m_period)- p, a* t2 ?4 g9 \% ^; c" Z
{8 M. T' I q$ \
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
7 h. M: R7 l" {# e. Y6 x3 D/ xreturn(false);
7 e" T/ A. C$ V. J9 U, Q: ]}4 Q) q9 C% N9 }0 @, d
//--- create a model from static buffer2 R( a, e9 c. j+ \ J' p
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);3 u$ |+ I- `3 k* n X
if(m_handle==INVALID_HANDLE)/ L% \0 X) r$ N) g! b. w
{: V, i7 Y0 x \; D
Print("OnnxCreateFromBuffer error ",GetLastError());
F! x" Z% W/ K2 Yreturn(false);
7 F, v+ P4 F: i& O( v$ g% P: n! B7 T}
0 [4 o i% ]" y//--- ok
3 {2 q( y( g z' b# B1 @/ m( oreturn(true);" r/ C3 ?9 b2 z5 X3 s) H: D
}
9 {! ^ ?8 Y" }* I7 w# y' y//+------------------------------------------------------------------++ W( A0 W$ ~( _& d
m_next_bar=TimeCurrent();$ J ?- u. y+ M' b
m_next_bar-=m_next_bar%PeriodSeconds(m_period);
1 a. P0 l; W) R5 M2 v# K& pm_next_bar+=PeriodSeconds(m_period);* x; C2 g3 j# k: U. _3 w
//--- work on new day bar
0 J2 R( w( A p2 @$ }return(true);
' N( F7 k1 S) D N' @}
w S/ w1 [7 `5 v7 }( f//+------------------------------------------------------------------+) k! e! {3 t7 J$ e2 ?/ p, }
//| virtual stub for PredictPrice (regression model) |% w2 }9 |( ~% j8 b4 S9 a
//+------------------------------------------------------------------+
g9 r0 O! F- \- r, Cvirtual double PredictPrice(void)
* g" s9 {- U# m$ |) b4 A{. }3 o' W6 y3 U$ {9 {
return(DBL_MAX);
) n2 x$ ^; l; E9 {4 }& k}$ K1 Y z* m/ r7 o$ P2 H
//+------------------------------------------------------------------+8 ?+ x8 |( H; S5 `
//| Predict class (regression -> classification) |
* `$ n! V2 p% E: q8 ]& H ]//+------------------------------------------------------------------+
. t: s6 Q& _6 o( _( uvirtual int PredictClass(void); M+ ?; D9 K. R; g
{
, i9 E( l* i) T( r# {9 zdouble predicted_price=PredictPrice();7 C# h" v/ I! u$ V
if(predicted_price==DBL_MAX)5 x D( _# `7 {; c8 u2 T8 N3 c. f( A2 _
return(-1);
# A. ?3 B0 H/ e. j# wint predicted_class=-1;
7 e; e( p: ~. D" l8 @double last_close=iClose(m_symbol,m_period,1);& i' X( b& @' n+ \7 V; ?
//--- classify predicted price movement% j% n+ {8 x( d! N" {' Q+ u) f
double delta=last_close-predicted_price;
( i0 r2 p2 S: y( l( f$ U* r) Aif(fabs(delta)<=m_class_delta)
' _ l' \" o9 ~) |( Rpredicted_class=PRICE_SAME;- i7 E( d( M- X! V! b' N+ n
else
. w6 } L4 [( }1 |, Tprivate:
" j# A' f: T8 y7 E1 J. H# }int m_sample_size;
# F; x; G% } J0 L//+------------------------------------------------------------------+
0 m; i+ H8 V, N$ a/ Zvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period): @- d! K" G* i- p7 `; o) m
{+ D+ V" P& j/ D! Q
//--- check symbol, period, create model- ^2 V8 m2 x) O7 N% q$ b
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
/ j1 R" e; P5 E/ t4 n; {9 m{
# p. c% b- V, z7 O! a$ QPrint("model_eurusd_D1_10_class : initialization error");
# W9 ]2 R& w9 j! Oreturn(false);
' H3 R0 S9 B" d6 S9 m}
0 v) W A1 |$ S" u6 A//--- since not all sizes defined in the input tensor we must set them explicitly
' y. U. j% N0 P+ ?6 Y" _//--- first index - batch size, second index - series size, third index - number of series (OHLC)
; V: ~' @% ~3 ?const long input_shape[] = {1,m_sample_size,4};0 e" T5 ^9 V4 k: S: b' [
if(!OnnxSetInputShape(m_handle,0,input_shape)): {' y* T/ X+ a; }1 `: `9 S
{8 h1 d5 o/ n2 }9 Y* W4 j
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
( y7 K' |( u1 U$ c7 z3 l% Nreturn(false);0 [* j5 ]1 N5 x: {1 g" I
}* V, Q( Y& o) E
//--- since not all sizes defined in the output tensor we must set them explicitly
O7 T7 J! g- k: Q7 Q$ o' L0 u+ [//--- first index - batch size, must match the batch size of the input tensor
% q" Z' k6 Z: i5 ^0 f0 d/ a1 n" P//--- second index - number of classes (up, same or down)
3 H3 I" o7 S; K/ fconst long output_shape[] = {1,3};3 D% u5 D1 q' X4 B4 G
if(!OnnxSetOutputShape(m_handle,0,output_shape))
, [# O" }- ]& @4 E! L" X{0 M3 S4 {. N9 L: G3 M R h! ?
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
2 ]8 U+ F* u% I% ?) _return(false);
- l- X: e, p' Q}
6 l8 @4 L8 W8 }" B( T//--- ok
% U1 F4 T0 a6 Y( Hreturn(true);9 O8 p5 c0 ]; z; R& j- m5 Y1 a9 W
}& N, m5 W" L( @! R" }8 _/ D
//+------------------------------------------------------------------+
* j; f# w& f" \* W) D& ^//| Predict class |
# J2 b! q, i5 u/ s! R//+------------------------------------------------------------------+
# Y1 ` C, P! tvirtual int PredictClass(void)
' r1 t0 J% n/ m; X7 P q. J{ |