1. 我们会用到什么模型呢?# j0 C: u) l& `% h, G
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。1 K" e( Z5 @4 P- Q
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进2 g8 \" p# f8 |0 H
//| https://www.mql5.com |
- m% f7 j+ j" U2 M2 {+ a//+------------------------------------------------------------------+2 @. L t$ ]1 o! b# r& F- n* f0 b
//--- price movement prediction6 `9 t) y) X; M( ], X3 j; ~* m
#define PRICE_UP 0
# v4 X# v3 X" B3 c! i; i. `6 b#define PRICE_SAME 1. i' ]' b$ c- [0 F9 M4 I
#define PRICE_DOWN 2
$ d% n; `& k' J0 O& H9 \//+------------------------------------------------------------------+
' ]$ M- N9 s; X% Q/ D q, j" g5 F//| Base class for models based on trained symbol and period |+ d2 @3 X: ~8 q1 B+ J3 N9 p
//+------------------------------------------------------------------+4 ^# u: `; w& h0 k. ~2 }
class CModelSymbolPeriod5 J5 L1 {3 I( W0 t9 J0 e: Y3 B! N
{* d, r. @* `6 M& c \6 o9 X3 P, A
protected:
. ]- s/ G" v" M/ i! ^' r3 j" \: H" Olong m_handle; // created model session handle
: {( l: X3 G8 x0 S) g4 gstring m_symbol; // symbol of trained data
( c8 x) k- m, |, c, ?; r( iENUM_TIMEFRAMES m_period; // timeframe of trained data
. {, L+ ^$ f' P1 F- {datetime m_next_bar; // time of next bar (we work at bar begin only)
8 c& }* s7 ], |: S' Z' K3 ^7 Qdouble m_class_delta; // delta to recognize "price the same" in regression models
6 c, `- \0 W; W( j/ J) m0 epublic:
e7 {; J& X7 g: n9 U" m//+------------------------------------------------------------------+
% x; L+ X& V3 ]$ ~//| Constructor |4 k1 A. ^. ~* T
//+------------------------------------------------------------------+4 l9 z" `: b U) }$ ^9 A0 }7 T
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
: U( X3 ^% t$ x{9 U4 L! v$ D, ]; h
m_handle=INVALID_HANDLE;& b# Q1 K' A$ X5 N( z
m_symbol=symbol;
* i. J6 P6 T5 u$ V) V) @" d/ E. L' em_period=period;! O2 |' d( k% J+ N: u) w4 ]
m_next_bar=0;% B3 i5 S! E+ H' a6 P
m_class_delta=class_delta;
% h( c* t8 P4 K# h* O7 n}; P3 A; \+ h. p. F x
//+------------------------------------------------------------------+
7 n" y' }) @ K. z5 D//| Destructor |0 u% P5 ]2 }& }( y3 G2 G
//| Check for initialization, create model | d" h( c( C4 o) w+ O5 k6 w( y
//+------------------------------------------------------------------+2 @# `# B/ Y, O( L( P0 B2 Q
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])4 }7 _' z3 ]% C- ~- Q9 p1 T$ j
{ G$ W/ ?# A' W
//--- check symbol, period! @0 y( H! e' j. y" F* h7 a
if(symbol!=m_symbol || period!=m_period)8 R9 B+ G6 o5 H. Z. V; s, i8 o
{# K4 x& V' r0 p# u# ?
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
1 h5 x: ?6 P+ b* E/ ureturn(false);7 B- f t2 _+ D5 ^" k" Q
}
+ s, c- x, {: T! }# O' v% B//--- create a model from static buffer
`# [: d' f0 @9 e5 O& om_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);" Q4 R( g) I$ y3 g6 d" c7 ~
if(m_handle==INVALID_HANDLE)
% m# d9 m9 o. N7 s{
0 Y9 l! @. Z4 Q& ~5 XPrint("OnnxCreateFromBuffer error ",GetLastError());, Z" p' J" _. h4 `* c Y! e
return(false);
' P6 @9 W5 n7 d- J- A& H1 d9 f* U}. N2 K. K. J B/ I8 i
//--- ok2 a. o! U0 L3 y: r% y: e
return(true);5 K: D r. e1 m; W% x
}
, x6 }3 L* D- l9 R l/ g) P//+------------------------------------------------------------------+
" q/ n. A' l V' F* U" T8 P- Om_next_bar=TimeCurrent();
& Y! P: v+ A: {* M* Gm_next_bar-=m_next_bar%PeriodSeconds(m_period);
# T, a+ N8 D8 x. N B& x9 u! J$ ?m_next_bar+=PeriodSeconds(m_period);$ U s3 s6 n" g" a9 \1 A3 P
//--- work on new day bar" _+ R8 J! t$ A. @% F
return(true);
\; ^7 j0 ?- |}
( f% ]4 \$ X, _2 z- T//+------------------------------------------------------------------+
( q f* x9 g4 U# H//| virtual stub for PredictPrice (regression model) |9 U. j/ P5 Z$ }8 d% x
//+------------------------------------------------------------------+
4 N: u6 q% I; _6 Fvirtual double PredictPrice(void)( X3 e0 |- j4 _
{9 f6 e2 S3 ]* n0 E' i# M* _ d. S
return(DBL_MAX);
. E8 r4 T) [4 a9 J e' @6 ]; B}$ z/ c$ o8 m% J H( E4 M4 e
//+------------------------------------------------------------------+) N, Q% \, A; V" H `2 J! ?
//| Predict class (regression -> classification) |
9 @* t6 J$ J' d7 O- C//+------------------------------------------------------------------+
% o) }; r6 _! hvirtual int PredictClass(void)
; i! @4 k5 a/ {# H( M{
9 }8 s0 N8 o2 {9 N; c+ q/ Hdouble predicted_price=PredictPrice();
, c! r, T7 n" @# ]if(predicted_price==DBL_MAX)
% L: T& m T$ w9 U% Breturn(-1); v; F* V' s1 Z2 z# B
int predicted_class=-1;
7 O; ~) r& _* A* V. j4 Udouble last_close=iClose(m_symbol,m_period,1);
1 h1 g& i# I+ y6 @//--- classify predicted price movement
5 t# y. r8 i2 b% S# edouble delta=last_close-predicted_price;7 O* S |$ U4 g! }9 E1 u
if(fabs(delta)<=m_class_delta)/ E- T) L, \- d
predicted_class=PRICE_SAME;
1 S6 k+ c& I# E; g2 r4 {else
9 [+ J+ K" ^. G ]- f4 E/ yprivate:
; }4 A* c) G% X# R+ |* mint m_sample_size;
" i' n+ L3 Y# t( b$ m//+------------------------------------------------------------------+2 c* Y% c. X( J" E0 F9 }% `6 `
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
' c, n- A8 K) Y- o; i5 P{( j3 B, h3 Y) \
//--- check symbol, period, create model
* g- j3 k; n( ?2 q1 z- H: l4 _# tif(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))2 R* K: R# r: l2 Z. G8 H% T! @; a
{* F% Y6 q/ b# E
Print("model_eurusd_D1_10_class : initialization error");
! }/ l4 u$ ^% Qreturn(false);
6 ]9 v; X, X. Q: O}
2 X0 i* r/ [9 t. a4 ?' w% Z//--- since not all sizes defined in the input tensor we must set them explicitly
! X6 P$ B8 e! x. X3 w* o9 W//--- first index - batch size, second index - series size, third index - number of series (OHLC)
2 T2 x& \4 C. a nconst long input_shape[] = {1,m_sample_size,4};
, N9 {! G/ |/ W: eif(!OnnxSetInputShape(m_handle,0,input_shape))
2 f5 K" W( ]7 O: P K{
/ ~1 ^2 \; n( B+ `6 E( H* O, ~! aPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());: c9 G) Q1 b: d& c% d8 S- |
return(false);! p- i6 ], v }0 Q& U7 l
}
9 m2 Y3 W) W9 g# J. q% h//--- since not all sizes defined in the output tensor we must set them explicitly% L' F- a' Q9 s$ k! v
//--- first index - batch size, must match the batch size of the input tensor
# t7 W7 C+ O; L6 X5 ]- P7 n. ~) k( m) w//--- second index - number of classes (up, same or down)4 M8 D5 I9 q0 b3 I) `
const long output_shape[] = {1,3};
4 M. R$ J8 W7 E9 iif(!OnnxSetOutputShape(m_handle,0,output_shape))/ z/ X# C3 G* \4 o
{
- _: K8 R! y0 g7 G2 pPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
: g" z5 k: g" b- F+ zreturn(false);; Q9 M6 q& ?1 g; g
}
A0 k, O2 C5 n% j! [2 z Z% x: n2 h//--- ok4 l" f6 f; |: S
return(true);
) g$ L. a8 {7 H! L0 ^- z- z; K/ N}
% j# O c8 I- i6 v! O. T! _* j' O//+------------------------------------------------------------------+! x8 d) d. ~/ \. Q$ Z1 h
//| Predict class |
3 i4 D# T( T7 p: |' b//+------------------------------------------------------------------+7 @* l# O( A9 {) W
virtual int PredictClass(void)
6 T/ m! o$ o8 t* V, b9 q$ V{ |