1. 我们会用到什么模型呢?/ Q3 H8 W" W8 L% T; C8 X, W
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
: r2 h4 L5 x# q6 w2 `' G/ W) q9 M我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进! n/ R8 p9 B9 [% t0 ?: h, M4 Q
//| https://www.mql5.com |
T, F2 \) Z( ]8 e/ `//+------------------------------------------------------------------+
' O/ [8 c( @$ j# W9 e- W//--- price movement prediction3 L" W" B- p6 N! C
#define PRICE_UP 0
6 g l( w# Z5 o9 r- ?#define PRICE_SAME 10 F* R) q3 p( ?
#define PRICE_DOWN 2
# M7 S' b4 ?! w& U. e1 S, h0 b//+------------------------------------------------------------------+
- ?( x# f% k* C/ @2 c9 W$ _$ a. h7 _/ Q//| Base class for models based on trained symbol and period |
: g1 G% B! c( `: Q//+------------------------------------------------------------------+8 y- ^: {! T4 ?* X. S
class CModelSymbolPeriod
/ ~7 K, w1 a3 w' [7 d{. n! P% a) n5 ~+ I# j1 c6 \
protected:, u+ R' x/ ] u) s8 {8 K
long m_handle; // created model session handle
& Y# y }1 U+ astring m_symbol; // symbol of trained data
- t8 S; C; {, o/ m0 I( ?& eENUM_TIMEFRAMES m_period; // timeframe of trained data6 y5 N* @/ Q" q- m! Z! ^
datetime m_next_bar; // time of next bar (we work at bar begin only)& }, s! U* s9 Z+ ]
double m_class_delta; // delta to recognize "price the same" in regression models3 F! x; d8 o- W3 m& t
public:3 W, \0 A" K' t9 C x1 y
//+------------------------------------------------------------------+
* H$ ^# }0 x0 r//| Constructor |
# I- K% v; w* R//+------------------------------------------------------------------+% f: T3 {1 f* g p5 E9 g8 N
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
4 ~5 u! F" U1 U) r$ [- h& @: r G# k{
% P4 s8 N( P6 v1 C6 l vm_handle=INVALID_HANDLE;
& T0 ?- \* l. O- A) b0 Q; a! Fm_symbol=symbol;/ l' y" s8 S4 ^% S
m_period=period;
8 y" a4 e y U, {- a9 Km_next_bar=0;- G8 {! B% |0 L$ J
m_class_delta=class_delta;- K3 {4 S" z7 x5 ]) c
}' ]) X4 K9 X, G# [$ J o4 I
//+------------------------------------------------------------------+
! q) W! Y6 E0 t2 @# [ J1 s6 M//| Destructor |
" A* \. y/ h# D1 Y: z//| Check for initialization, create model |: b# i; o$ D1 M+ u; U' X: s8 G
//+------------------------------------------------------------------+
8 Q) M2 s" z2 `) Pbool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[]). _& z% s$ e- F1 P! I
{! c5 L7 w/ T% b& X1 w: }
//--- check symbol, period* D" W! }* T# V4 K! B) z
if(symbol!=m_symbol || period!=m_period)
4 e3 C! @( z, P+ C{% b8 z5 r, C% y
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));( I* M; I9 Z% s( e0 p
return(false);
6 [6 O. ~0 n% {* G2 U( a5 t9 K+ g}
, w. _: p$ T5 M8 x: y//--- create a model from static buffer
& ]7 a$ F+ o" gm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
8 d+ ?! `5 \' U" i1 _, W2 t" \if(m_handle==INVALID_HANDLE)
: Z' |0 p5 U1 H' \ ?5 s6 c6 S{
8 ^) f% s) R& d. a5 K# h4 f2 CPrint("OnnxCreateFromBuffer error ",GetLastError());
) A1 k1 _- j% e, a, Q7 e7 Dreturn(false);7 N! U* w9 k" Q
}7 C* b3 `* \, X% ~2 w
//--- ok% D8 _9 C/ Z- c
return(true);
6 F3 q( ~ N0 ^; u}9 B ^5 E' R0 n5 Q" S. n
//+------------------------------------------------------------------+1 b% D# b7 B$ y C4 S" P% B, _
m_next_bar=TimeCurrent();
. p0 U: U) ~6 o" g8 r1 _3 Qm_next_bar-=m_next_bar%PeriodSeconds(m_period);0 M$ r; ^+ x- n* l9 V( c, O
m_next_bar+=PeriodSeconds(m_period);6 ?! U5 q- b+ E6 Y ~: O
//--- work on new day bar
4 q# @$ U( f8 l# b& b+ Rreturn(true);
. i: }; W3 b) h; T7 P: R}4 G5 b8 V" L ]" X9 o
//+------------------------------------------------------------------+8 e% M& @, }, N+ q7 X3 N
//| virtual stub for PredictPrice (regression model) |
, T* k" V8 S; E i4 y//+------------------------------------------------------------------+
0 o* c( C) T% Pvirtual double PredictPrice(void)) f5 F9 x! o6 Q, a1 V$ U) U
{
. Y( |1 h- ^: qreturn(DBL_MAX);
( }! w' p, I+ s) I: q}
6 ?( l Y% ?, e; C0 R% v1 v//+------------------------------------------------------------------+2 U5 R1 K5 S0 ?. \
//| Predict class (regression -> classification) |' T" k8 a/ o. \" k# i5 r, S6 s
//+------------------------------------------------------------------+' R) S* K6 y5 G+ k6 s
virtual int PredictClass(void): q# M# M2 z3 j M; }
{2 o" g7 U# j5 h3 F& M. E" y
double predicted_price=PredictPrice();
" Y, [9 s2 C) ?if(predicted_price==DBL_MAX). j: F9 i* x, f3 ~1 b! Z9 ^9 P( R. N% J
return(-1);
7 n8 W8 H4 b8 M* I* S, H+ iint predicted_class=-1;
% N2 [. D5 y. I" c2 p/ ~. T( ?double last_close=iClose(m_symbol,m_period,1);
7 c* g1 ]1 b- a9 O! ^* q//--- classify predicted price movement
5 h/ _$ a n8 r" Q- T$ Vdouble delta=last_close-predicted_price;( g. i2 ^9 h6 q' |& @4 `" d
if(fabs(delta)<=m_class_delta)
6 E% R E$ o6 _* n: \# ]4 ~predicted_class=PRICE_SAME;4 P% b% E2 l8 a5 {1 w( ~$ R3 o
else5 M% p6 P0 ^' k% u* u0 B) D
private:
6 A1 e4 Q: x: o1 V/ iint m_sample_size;
. X* y! b+ x$ K- M4 _9 T//+------------------------------------------------------------------+$ @. v$ D0 y8 D, p- C
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)) G" g# ]. ?8 [( o; B0 ?
{
. T1 ~8 b+ D, w+ s//--- check symbol, period, create model
+ O9 E: y% B# l4 G; Lif(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
4 Y8 k% f u; C0 P{
6 N1 {' b1 A; R& @& h9 cPrint("model_eurusd_D1_10_class : initialization error");
8 |- o" q2 N* Y8 N+ _ hreturn(false);; D( t: V! V k: Q
}
/ t4 D4 e- R7 v1 x* o" @% _//--- since not all sizes defined in the input tensor we must set them explicitly
; e- ^1 r2 u9 e- @//--- first index - batch size, second index - series size, third index - number of series (OHLC)
. I4 o" W. F3 [7 X3 C) v9 t( |const long input_shape[] = {1,m_sample_size,4};4 B, g4 _* H$ {0 }
if(!OnnxSetInputShape(m_handle,0,input_shape))* ~6 p, `7 b" @6 M* e c% k& |
{% l {3 ?7 s; M+ }+ N
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());9 X8 T9 G6 g0 \, ]- f9 S/ c
return(false);/ U, ?" B2 d- k& q6 E) e. \0 G
}- P9 ^+ a7 e9 K, K" U. c
//--- since not all sizes defined in the output tensor we must set them explicitly& L3 v" k! P5 x0 E, R8 A9 _
//--- first index - batch size, must match the batch size of the input tensor
% |& t; Q# g- S% r9 F! m//--- second index - number of classes (up, same or down)* n) G' B) I7 D* S Z0 u
const long output_shape[] = {1,3};- R4 K4 z. X. d; ?: \% i \! n
if(!OnnxSetOutputShape(m_handle,0,output_shape))
( u1 d1 s4 S" K1 s; Z{
6 h6 R. {* E5 N3 H2 mPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
6 \) ?+ ~5 W: ^" J& [( k1 X0 Ureturn(false);
& M0 F$ N$ P7 E6 K$ z}% G* O3 d7 {( D. r2 J& J/ W
//--- ok: ?! G, m( G) p; Z
return(true);# M8 ~5 }, U4 p9 l
}8 q8 `2 Y. d! \9 r/ q+ K% D
//+------------------------------------------------------------------+5 @! K; V+ k& Z+ V+ [6 x( Y
//| Predict class |
. t% D6 r1 U5 b' [5 E+ K1 o//+------------------------------------------------------------------+
8 x+ y% |9 g( } U lvirtual int PredictClass(void)1 d# K$ |! f& w5 S0 n1 F, w
{ |