1. 我们会用到什么模型呢?
; @( P T; {0 }在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
' h( P4 G. q+ |* C$ y) _. N我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进! \/ w, n1 h/ Z* Y9 k
//| https://www.mql5.com |" ?8 }. g) N5 H2 B8 j
//+------------------------------------------------------------------+; L" T- P) u( b
//--- price movement prediction8 ^/ |( E2 q G J* E6 z! R
#define PRICE_UP 0
, l2 B' n% z& h$ H8 U#define PRICE_SAME 1
6 q# a0 D' u5 W/ c% @" A#define PRICE_DOWN 24 D3 m& ~8 d, N6 M0 `
//+------------------------------------------------------------------+) b5 I+ _+ \6 x; y
//| Base class for models based on trained symbol and period |
8 T2 b1 G0 }( l5 M% i! S//+------------------------------------------------------------------+, p( l. f% h" B, U% |
class CModelSymbolPeriod) z6 U; j- P5 U
{/ j. E! a [4 V/ J7 y8 h( {7 j4 U
protected:7 _0 B' b$ x( I. }1 g
long m_handle; // created model session handle6 F z3 r: I2 Q. U3 ~8 I( R* G
string m_symbol; // symbol of trained data
4 ]! M# [. l( ~7 b' rENUM_TIMEFRAMES m_period; // timeframe of trained data! u/ P* _1 Y" g9 V0 k
datetime m_next_bar; // time of next bar (we work at bar begin only)
; n, |: X+ ?. Qdouble m_class_delta; // delta to recognize "price the same" in regression models
) q: p1 Y* J: M5 x! z( ?( ^public:# s2 E6 A. V; a
//+------------------------------------------------------------------+
7 y6 n) p: v1 T# n% Z- I//| Constructor |. S- @9 q% H- a1 \# @. N/ d
//+------------------------------------------------------------------+
) g# Q* }8 d* j5 }) wCModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)
# }4 v+ o. Q T0 Y- v7 V' b; S{
" h* Z& E# | O$ t4 H8 pm_handle=INVALID_HANDLE;
; S, W- Q5 v3 I8 l$ i( t7 pm_symbol=symbol;
7 a, V% X9 _0 n$ x% Rm_period=period;
- y4 l' a7 k$ g# q/ X4 x0 M* Mm_next_bar=0;
/ k3 {. `) ]" z2 F$ Z! U: B; Mm_class_delta=class_delta;
: M% ^8 k6 B1 j: s! y. D}/ n t3 B. z9 U8 d3 s* h
//+------------------------------------------------------------------+; U* p! o; I: Q- c; u
//| Destructor |- t6 `( ~+ }3 Z' o/ O) g# G
//| Check for initialization, create model |
# L7 e7 ^; N' u+ J* t2 V( t b. ~2 C//+------------------------------------------------------------------+3 O; ^; Z/ W7 W6 Y
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
1 e" a) u9 z7 H9 @* n{
1 N7 {- b/ s C//--- check symbol, period5 M' X, a9 j. o; ?: R! a% Z
if(symbol!=m_symbol || period!=m_period)
# U# H4 f) q" f8 H W, S& U{
$ B2 U0 t s% g, b) ~" F4 t1 wPrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));8 z5 Y) M% ]$ |( l4 @0 }
return(false);
4 G1 N$ E A1 N}
" w8 G H& F9 r6 e# @' h% c) O//--- create a model from static buffer
. f; z, E5 j x- m# u7 jm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);# f3 _1 N0 z" b! x% C7 ~
if(m_handle==INVALID_HANDLE)% J- w- c0 P9 Q! f: m+ `
{
: u" t+ M$ a1 v: G9 I- n& O5 ^Print("OnnxCreateFromBuffer error ",GetLastError());
m/ I& b1 x, M1 m4 R' _return(false);; O$ Y# V' Y8 X/ f2 B4 G
} C- l) z! K/ h7 x* W$ f6 A3 S
//--- ok
! u+ ]2 F0 a: r1 o9 [return(true);3 W' f5 k4 U( o8 a& }4 P+ c0 z
}; K6 \; V8 k6 E0 d
//+------------------------------------------------------------------+
) z2 P2 q3 x2 w2 f$ A1 cm_next_bar=TimeCurrent();
V b+ `6 P9 [7 cm_next_bar-=m_next_bar%PeriodSeconds(m_period);$ e. e/ E8 N- s3 z, w7 i, X3 D
m_next_bar+=PeriodSeconds(m_period);: |) l1 ~4 |* |! C0 x( I* |
//--- work on new day bar6 _9 m6 U& { Q, V+ K- l0 a1 r* F
return(true);3 n( B3 J$ n1 L* w
}
( x. t; \6 Z' V2 c( Y//+------------------------------------------------------------------+; K( f3 Z/ d4 \3 L
//| virtual stub for PredictPrice (regression model) |
) R4 m7 w {! N2 q9 X1 ?& ^//+------------------------------------------------------------------+
- T, G& t1 h5 B5 Kvirtual double PredictPrice(void)( W5 F, U, A- u- g) ~
{
$ N U6 i, {% b0 h2 Creturn(DBL_MAX);% D# W" A) O1 K J# U$ S
}
4 l/ b+ F# e5 ~//+------------------------------------------------------------------+) T7 l1 J; f& I' s7 _; c K
//| Predict class (regression -> classification) |. O& ^1 s0 Q9 L
//+------------------------------------------------------------------+% H3 }, p G( k3 w# S
virtual int PredictClass(void)
" j. I4 x1 Q2 D9 C{
* R" `$ [& T! P% ]. ]7 v. M$ x; E2 hdouble predicted_price=PredictPrice();
$ y' N% n0 j( O C7 H& `! T8 t4 pif(predicted_price==DBL_MAX)
8 h4 k9 J( T0 N/ p2 p6 C: `return(-1);+ p3 m6 u# j7 I/ ~
int predicted_class=-1;4 D5 q" s& b, b1 y4 f$ l* [
double last_close=iClose(m_symbol,m_period,1);9 E$ W1 L) \$ ]/ }5 {+ o# T' Y; Y: |
//--- classify predicted price movement
" F0 ^% q7 f) i1 A, L, b; adouble delta=last_close-predicted_price;
. s0 t( j+ @! `- x6 A$ s2 nif(fabs(delta)<=m_class_delta)
6 p0 P3 c+ m7 U. n* [predicted_class=PRICE_SAME;
# O' S7 r/ u) ?1 p0 s0 _; i# ^else
9 d0 C1 Z( |7 A( r+ w# m vprivate:
+ D# m; @/ B% E1 T9 A2 ~ S% Q: N2 Lint m_sample_size;
: \& g! r4 E6 s* C+ b# I" M//+------------------------------------------------------------------+
1 [3 G3 ~3 r2 n3 P jvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)
D" l- @1 V, a" y' G. Y{$ n0 W# b# M2 L$ o; y" n
//--- check symbol, period, create model
/ y7 p9 `: E0 T9 K; s3 kif(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))& [4 D. ?5 i7 j% X8 H1 b
{
+ p5 s Z5 z% D }Print("model_eurusd_D1_10_class : initialization error");7 ~+ q9 P8 S$ G7 W& Y/ v2 P
return(false);
. c, V+ X X9 ?0 E/ q( v/ ~! H}' l6 [0 ^" E0 B' s8 X
//--- since not all sizes defined in the input tensor we must set them explicitly6 m0 m* `! F, Z& h
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
/ R2 A4 C- R" j) F) P9 k# Oconst long input_shape[] = {1,m_sample_size,4};
: Z5 r6 M3 }( H1 Q# o0 gif(!OnnxSetInputShape(m_handle,0,input_shape))
: M% Q4 Z& R8 U/ ~ n{$ L V8 {6 j7 A% j/ ]
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());! z1 F/ ?" f, s" c) E: |
return(false);3 T: A J7 O4 J2 m1 ]5 x! A
}+ x3 @6 N0 w* M9 d% X- Y/ j! o9 X
//--- since not all sizes defined in the output tensor we must set them explicitly0 T" d2 `) S" e
//--- first index - batch size, must match the batch size of the input tensor
1 |; _+ m; d' Q4 w2 `//--- second index - number of classes (up, same or down)/ i6 ~# E. k; g# M
const long output_shape[] = {1,3};3 M: m' h) j) d) {' c0 K$ g9 `& r4 [
if(!OnnxSetOutputShape(m_handle,0,output_shape))* \; [- G# }5 s7 [! r; v! _" n. _
{' }& ]" ~* f, e, P4 V: \
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());) v0 V; o: v& W* t
return(false);2 ^4 y# m- b) ]( K
}( ]2 w* L. D+ E' u' C
//--- ok. g( H" F- k9 Y0 ~4 p5 \
return(true);
* J7 j" R5 G# w# I9 S& j+ [& b}
* P2 F2 R( L; _) | F5 l//+------------------------------------------------------------------+) V/ s) o. m, q2 H: N3 A
//| Predict class |
2 Y; I& _ X0 A0 ]6 i9 v3 F8 n//+------------------------------------------------------------------+
d: W @* X& H" _virtual int PredictClass(void)
7 U% w( M: X# X" e) k2 x! D{ |