1. 我们会用到什么模型呢?
& {/ M6 Y! g" Q& a! E# K2 I- Y在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。6 T: a2 p' R. X( r ]
我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进
; W6 P, w( I: z# [//| https://www.mql5.com |2 K, u! L4 g, S# v5 t9 T% S" [
//+------------------------------------------------------------------++ C) H6 A2 V# K g( }" L. n; o8 H
//--- price movement prediction7 w) I9 Q. t) }
#define PRICE_UP 0
; R2 F: H# K. ~. `+ @* k3 }( K- ?3 D#define PRICE_SAME 1
3 q8 ~) T) k& ?! r9 p5 f#define PRICE_DOWN 2 t; I% A- j1 X; q+ w2 u; [
//+------------------------------------------------------------------+" w; ]; s. n$ k2 V* ]7 a$ U! V
//| Base class for models based on trained symbol and period |0 W1 }7 K! K( C7 R
//+------------------------------------------------------------------+3 |8 U( P' Y& B- p! c
class CModelSymbolPeriod
" X5 h. q& [5 I{
q6 E% p: Y2 E$ w! ~0 q+ P/ qprotected:
, F1 U' ^1 u3 I2 g: Qlong m_handle; // created model session handle) @* m. ?# k& }" n
string m_symbol; // symbol of trained data
6 R/ n, r- }2 N% ^ENUM_TIMEFRAMES m_period; // timeframe of trained data
3 Y# d9 U- Z! o8 M8 S$ K" P& tdatetime m_next_bar; // time of next bar (we work at bar begin only)
% q0 h* {2 `- U g3 |double m_class_delta; // delta to recognize "price the same" in regression models5 \4 }/ B4 e% B2 L! e
public:
6 k+ A4 Y! u3 ]3 d7 m3 ]& Y//+------------------------------------------------------------------+
% {( Y! u0 a; t1 t7 G: v//| Constructor |7 S k3 r/ L+ \9 I% H0 p
//+------------------------------------------------------------------+3 V' B2 K2 B. [; |% k% m2 ^
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)/ D$ `+ {2 L8 T7 ]+ N$ \5 `
{/ G7 j1 g5 V+ r9 K
m_handle=INVALID_HANDLE;
$ n6 s) M( K' [- Em_symbol=symbol;
1 `0 R! i! b* C1 A8 y* n4 Mm_period=period;0 c" N% Q7 H2 g: P: C. C
m_next_bar=0;
1 c& y3 @2 o8 V, J$ zm_class_delta=class_delta;( h; P+ h( k- g" J. q. k
}
0 {$ T% g, x- d0 G7 s! g' I//+------------------------------------------------------------------+; }* S+ h1 n: ^; a9 ~
//| Destructor |# @6 J( ]" J- ]9 W- L6 ]: x
//| Check for initialization, create model |
& C+ H' D. p% [. h3 l4 |1 [//+------------------------------------------------------------------+
8 a. H( h, `7 `' A$ c9 Rbool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[]); Q7 j- ^6 u9 P2 W* j
{1 o q: l- \8 n, P+ [+ c
//--- check symbol, period
2 t, q4 Y5 \1 P, Y8 z7 e0 N$ F2 Bif(symbol!=m_symbol || period!=m_period)
, s, r- T# b5 @1 ? T4 `5 @+ A{ u- k. F N$ ~* S' ]
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
0 b2 ?- C Y0 F3 |, i8 g! v) u }return(false);
) A& m* F% C) h1 O* L}
3 R- } l& ?- V' P0 W1 a/ h/ }//--- create a model from static buffer. }4 _: `9 S( \1 o+ |
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
s; v5 o# w# B# uif(m_handle==INVALID_HANDLE)
& @7 v% C* C- i! T" \- r{
4 {$ a" K/ P* X3 M. K# nPrint("OnnxCreateFromBuffer error ",GetLastError());
& S6 k" N: N# G/ H+ M3 M Ereturn(false);! G; L6 W4 @# v! ]; U, W, D3 \
}4 w$ b+ q2 v7 ^
//--- ok
7 Y8 Y) I- M( G) zreturn(true);4 J. z; {8 T+ M2 H% |7 k
}
, o$ i6 W% J( I//+------------------------------------------------------------------+
+ R' d1 a4 t( ]4 qm_next_bar=TimeCurrent();
8 Y P) e4 M/ t6 a% } N$ pm_next_bar-=m_next_bar%PeriodSeconds(m_period);
+ F2 u6 \4 \" {; Q" b& a6 Om_next_bar+=PeriodSeconds(m_period);
3 V6 s4 f8 W! r v8 h8 b//--- work on new day bar
* d( w# R6 F9 X I) `, Ireturn(true);! o/ J( v0 Q) y" a$ k% c/ `* i- {
}- S. K% Y! d* i6 m; {5 z
//+------------------------------------------------------------------+, ?5 o Z# g2 m3 H+ K
//| virtual stub for PredictPrice (regression model) |5 S2 N' l) P; l9 w2 Q
//+------------------------------------------------------------------+
: g* i8 K* t) a; i' ~6 |6 nvirtual double PredictPrice(void). d E, J" I: f* F# n7 Z
{+ ]. s- d, ^) v- y! Q7 _
return(DBL_MAX);
% u& ^+ U/ |9 ?# g% @0 o}% t- v& g* @; p
//+------------------------------------------------------------------+
" h4 ]0 [/ K( {8 x; A# h, U+ ~//| Predict class (regression -> classification) |; y A. i& I1 Q2 ?8 Q8 b) }8 i
//+------------------------------------------------------------------+- ]8 K* d2 l8 y" ~7 G( e
virtual int PredictClass(void) H3 l- A0 {& v
{
+ |, u' z; \& `double predicted_price=PredictPrice();
* I$ `. L. g! e) L* ^$ A: pif(predicted_price==DBL_MAX)' E- M0 M, s/ l/ E% K( W
return(-1);, O) m8 X& k, J: g8 r* `
int predicted_class=-1; T3 t; X6 O9 I0 b" g. Q, r2 Z( m
double last_close=iClose(m_symbol,m_period,1);
# i5 B: ?* N- z, {/ I* m//--- classify predicted price movement+ a7 N# U9 P( D- y4 L
double delta=last_close-predicted_price;
' S5 d. S. V( c. O/ k9 gif(fabs(delta)<=m_class_delta)
6 H; x0 f5 [2 W9 a* V+ `! zpredicted_class=PRICE_SAME;
/ A. Q9 I5 C# d' u8 i! J3 ]9 Zelse
D+ x1 a' Z0 Yprivate:
7 ~# ~4 I/ z% r% w2 E. Gint m_sample_size;
" z# K/ k# H* {" {# B//+------------------------------------------------------------------+
" P! R- Y0 ~9 ]+ L0 Kvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)/ h! X7 Y* s( y5 c9 j
{
% Q# [3 B" v# a3 x1 n$ R//--- check symbol, period, create model
! N) o% r. ]2 L0 |% h+ `if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
' D/ T2 I7 f- W1 B{$ h( r8 s0 `. y+ j! U: \, t
Print("model_eurusd_D1_10_class : initialization error");0 C4 h. S- x n: j# ]/ q
return(false);
! h, Z5 Y4 ^% j1 Q}
, e6 T' u6 n, _$ a//--- since not all sizes defined in the input tensor we must set them explicitly
; k, [7 J% \& T2 M//--- first index - batch size, second index - series size, third index - number of series (OHLC): F' k9 X) p# V& \- j4 U+ e
const long input_shape[] = {1,m_sample_size,4};
1 q7 T( D* [. n" [$ Sif(!OnnxSetInputShape(m_handle,0,input_shape))8 C, O/ q# d9 ]7 G2 T5 I0 l
{% ?: F: J0 E5 f0 W4 G& z' L
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());& t; L; j& l+ k5 @- i* ?2 _6 L/ T
return(false);
2 N+ b |" R$ i6 E- d2 C; L) \}
0 b$ [1 l7 w5 j4 H: A//--- since not all sizes defined in the output tensor we must set them explicitly
" f4 n6 R, H, h0 F7 o//--- first index - batch size, must match the batch size of the input tensor
+ A- k, J9 I( c& }8 m, H//--- second index - number of classes (up, same or down)
2 L* N" H0 z x1 a6 Y4 Rconst long output_shape[] = {1,3};
) g8 X( y* e, t+ p' R! k" X Kif(!OnnxSetOutputShape(m_handle,0,output_shape))5 `1 z w( Z: q3 h4 d
{
1 }8 B" I/ X# D* q% aPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
4 x! x" \( B: |7 @, ]return(false);
5 B- {3 n& K9 W7 s; n}0 V& C K; o- n5 q8 _" p. x( c
//--- ok
# O" ~, h7 O+ s4 F, j& W0 Dreturn(true);/ @7 _5 C+ I9 |6 q _( Y
}
# u' h T! W% o& T* a3 c* E+ u//+------------------------------------------------------------------+& y0 v# y' d2 L) {: f& M. ]0 g
//| Predict class |: S( V# v. l! F i& x& o
//+------------------------------------------------------------------+' T; w9 @5 I, z; u
virtual int PredictClass(void)5 E. o7 I& ^6 t' U
{ |