1. 我们会用到什么模型呢?
1 i" V; k5 [ [/ k9 J在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
0 ^3 L, Y: }( R! o! K1 ^& X/ x2 T+ f( M我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进+ u$ W' [0 c3 U) L& X M$ s
//| https://www.mql5.com |
/ x( E' g) ~# G# ]/ U//+------------------------------------------------------------------+% \1 |0 D1 X9 `5 f1 W9 P& ], S# O
//--- price movement prediction
& g5 I/ ]- I5 P7 |% D( ?#define PRICE_UP 01 w0 }% g: h9 m+ t/ I4 L9 A. h8 i
#define PRICE_SAME 14 N3 \( ?2 X+ B8 X" J2 ^9 j: N
#define PRICE_DOWN 2
/ \2 B% f; l7 ^. H" p: L& G- i" S//+------------------------------------------------------------------+: z, [7 h: y& t/ F4 B! h
//| Base class for models based on trained symbol and period |
* p5 z! V9 t) P6 ~9 K$ r" }//+------------------------------------------------------------------+/ z' @$ [) Z& q- w3 e
class CModelSymbolPeriod# l" v. h/ L0 E0 S% o1 v
{2 W+ F- \0 Z) \" C L) g+ u+ U
protected:
, Q" S( t1 F5 u; ulong m_handle; // created model session handle8 q" Q: W1 x7 \$ x; f
string m_symbol; // symbol of trained data
. }/ H# G! u2 G" rENUM_TIMEFRAMES m_period; // timeframe of trained data) G$ Z! n- O/ T! U' C n
datetime m_next_bar; // time of next bar (we work at bar begin only)
) k" E( l3 W1 e9 I, i% |double m_class_delta; // delta to recognize "price the same" in regression models
. ?5 T% T: Z7 J7 jpublic:
. U: t( o5 u- U//+------------------------------------------------------------------+
' g7 q0 [' t3 w% m//| Constructor |6 L$ o/ S% X* E
//+------------------------------------------------------------------+* s* i4 A& X1 t$ h
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001); c0 B# P( m0 r; [1 L+ ^
{
* S8 e# c: ]! {" c& M4 l. Xm_handle=INVALID_HANDLE;
4 M' Y( ^+ V) [' ?2 X, `) _m_symbol=symbol;
: b/ {3 C2 V0 l0 r Qm_period=period;
- O' ^" E9 e* }% r* ]* }m_next_bar=0;
+ t: [4 j8 i+ R' {7 d' i; I. n6 C- _m_class_delta=class_delta;
5 ^3 a. {8 a! d. I# i}
. r5 B* R ?5 H, D1 V//+------------------------------------------------------------------+9 U7 z1 Q E& K7 m2 F
//| Destructor |/ Q) s9 l4 o: b- g% O5 ^' g4 g7 `
//| Check for initialization, create model |) {' F! w+ N4 K" r: U: I6 {$ L
//+------------------------------------------------------------------+
6 q9 u1 S1 N4 m9 lbool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
/ }1 j+ K8 E9 g: y$ y1 K! L N5 \{
5 d8 |' u+ I" T, M% y/ Y//--- check symbol, period7 J5 ?0 q2 y5 ]% m3 M( C, s
if(symbol!=m_symbol || period!=m_period)9 ^& H z$ o/ b9 ~* g
{' \$ u% t& W4 x( }1 e8 j
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));/ J2 Z/ D/ z9 e- G: j0 w9 H
return(false);
$ F' g' h# _& H8 l! J4 b+ e U2 i}
; ^ P: {6 y; M) P* [# @0 q- W' N//--- create a model from static buffer1 t. R/ t( e9 |* {
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);: [6 D B! L% p. O. \" |
if(m_handle==INVALID_HANDLE); _* h# M8 C0 f, R
{9 e9 {& @4 x. n) Y
Print("OnnxCreateFromBuffer error ",GetLastError());
+ J& t& U, b0 y" p/ a% Breturn(false);/ g; Q2 n6 T8 F, j
}
" S$ M: Q/ ?4 n; H+ X: {7 s0 Q8 K$ V* e//--- ok+ v+ d; W7 f( }6 u) R. T; J
return(true);9 t: h8 H2 @, J3 G0 ?- I0 D
}" X. B3 }4 ], B" ?* O$ }. J/ G
//+------------------------------------------------------------------+# s6 @" x8 J' P7 R
m_next_bar=TimeCurrent();
, h3 a8 l+ I: |, K6 t8 Wm_next_bar-=m_next_bar%PeriodSeconds(m_period);9 G; h1 J/ ^' H$ t) P
m_next_bar+=PeriodSeconds(m_period);, Y6 A+ D+ i, w
//--- work on new day bar' l' o: X7 `1 |! @( h
return(true);
6 p5 u4 g; j8 G}
" M9 L7 t7 Y) h" U2 |% N3 |- c//+------------------------------------------------------------------+
' h& N, j# S" S7 o6 H8 }% E//| virtual stub for PredictPrice (regression model) |5 E4 J5 P4 M. m/ K# n; [* d
//+------------------------------------------------------------------+* }: F: B- V [. e
virtual double PredictPrice(void)5 M( j. | K4 U9 \& s- m' g/ o$ D3 K
{( T$ I) p: S- S0 W
return(DBL_MAX);
, [. P) P, j6 r% L) F}
# y0 l: ~4 u' o, h3 O" n//+------------------------------------------------------------------+
, A* ?8 G! m' Q; ]. Z//| Predict class (regression -> classification) |
# E0 a1 d' R) q# p% B" q: L7 w//+------------------------------------------------------------------+4 \# ]. r" h6 N: F
virtual int PredictClass(void)
- p! ]6 K* ?% Y) m+ O3 q{ g/ s5 s( F) e' A# c F! s
double predicted_price=PredictPrice();( U/ k; V- s" `( K( p
if(predicted_price==DBL_MAX)
D! N) B, r4 n" \5 Lreturn(-1);/ i7 w" u) h! l6 o2 i
int predicted_class=-1;
2 O' B. B7 I0 v# Q) u- l3 @double last_close=iClose(m_symbol,m_period,1);
, c0 y) Y2 p. S( W0 B5 g& U9 t/ Z1 i4 s$ [//--- classify predicted price movement+ L2 ^6 V+ _1 H$ @; u2 _( x4 z. m
double delta=last_close-predicted_price;" x! o5 p# w/ U# O- A
if(fabs(delta)<=m_class_delta)
% L6 L% C8 g1 Qpredicted_class=PRICE_SAME;
" t4 N2 x4 y" M/ T$ q5 M8 }else- _$ b! e5 P+ \7 y9 v
private:
. J& N+ F5 s8 P; K. Cint m_sample_size;; A# S: B; V4 Q1 n1 k
//+------------------------------------------------------------------+. j$ g* @' j8 ~+ w- \% j
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
8 |% u& B+ \9 x) B* I7 N{
0 p: V6 F4 i4 N: j6 R% T1 f3 e$ D//--- check symbol, period, create model7 M+ I8 d2 d2 @" z& r# ]0 f
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))) L) g5 Z9 p4 G% J
{
7 t! H& y6 G9 M0 N0 b" z# JPrint("model_eurusd_D1_10_class : initialization error");
/ g; I) r) k# B5 k& c# x+ f5 lreturn(false);
" C2 {, ^% [+ B' a- S Z* z. Z}" z, N2 y8 O( R4 h6 G0 z
//--- since not all sizes defined in the input tensor we must set them explicitly
! W3 s, I5 C q//--- first index - batch size, second index - series size, third index - number of series (OHLC)! x9 H' \# k+ `! p; D! R6 S
const long input_shape[] = {1,m_sample_size,4};
. H b$ N' [- j* Z. j; V% |( Sif(!OnnxSetInputShape(m_handle,0,input_shape))* T2 {9 Q3 X, _! `1 K
{# e4 ]( N; e9 Y- B5 F; v" s1 C, Y
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
' {+ @0 l3 R# H# kreturn(false);
: O8 N, g @% v1 C}$ k6 \7 C' e8 b8 E6 E8 h( s; {
//--- since not all sizes defined in the output tensor we must set them explicitly
( l( h! t- q8 G//--- first index - batch size, must match the batch size of the input tensor; P9 L+ q4 c, @
//--- second index - number of classes (up, same or down)7 E; c' M( M9 s1 Z) {3 Q
const long output_shape[] = {1,3};
7 Z) j2 }; A' @' i" _, D% v$ nif(!OnnxSetOutputShape(m_handle,0,output_shape))# {5 o# |6 F# i- y) G
{
3 H) O4 g" _ D# d! ^; OPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
5 o( m/ {. \# g1 p& sreturn(false);
( R) _- s4 e9 z" Z}
" _9 j2 d) x, A: J6 ?//--- ok
+ D5 u: g, y2 R! u5 Ureturn(true);
+ ~2 Y N8 C4 Y4 U ~% p0 A}
1 Y% E5 \0 }/ |9 v* M//+------------------------------------------------------------------+% v2 e% g2 A, L" Y7 ~
//| Predict class |
6 ?* C+ d3 K/ F8 l! o7 V: M//+------------------------------------------------------------------+& a K% X! e) |$ M& S V# Z% U* N
virtual int PredictClass(void)# e2 |9 ]' o' _6 C
{ |