1. 我们会用到什么模型呢?
( J0 C1 G# D+ I9 f在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
* l0 v$ f; b6 @4 L1 ?' \我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进; P$ K( m( f8 J& I
//| https://www.mql5.com |6 P' i% @7 g2 H
//+------------------------------------------------------------------+
& Z+ g: G! x+ f0 e/ ^7 g8 ^//--- price movement prediction; u ^ [" [, g/ g* w
#define PRICE_UP 09 b; S, R4 J- n! Q8 J4 [1 V
#define PRICE_SAME 1+ y: y$ \! n, _4 Z6 h0 e! t5 Q6 c% C
#define PRICE_DOWN 2- k, u9 o# t) I \
//+------------------------------------------------------------------+
) h4 |7 n4 y- r7 H; @( z% g; T//| Base class for models based on trained symbol and period |8 U# A$ y E+ I" {' B/ u8 h
//+------------------------------------------------------------------+
8 X5 Z/ I) K/ Uclass CModelSymbolPeriod t+ J; c; j- O$ K4 E9 A# x4 M$ s6 s% g% T
{4 s# c4 N" z9 N' K7 a+ x
protected:& d- \0 ~/ i5 P" t' Y1 L0 w! q
long m_handle; // created model session handle
$ N3 l7 ^/ a" q8 w bstring m_symbol; // symbol of trained data4 b+ z( A8 q# T+ s4 j: q
ENUM_TIMEFRAMES m_period; // timeframe of trained data" S( I3 g( U9 g) o# E
datetime m_next_bar; // time of next bar (we work at bar begin only)% _* |' X( D4 v: v5 E% x
double m_class_delta; // delta to recognize "price the same" in regression models8 d% P% i1 c e, M
public:8 b! a4 ?: [: z; S/ I/ C
//+------------------------------------------------------------------+
( l) o3 g' H$ d j# R" [: k//| Constructor |
& D/ |0 B* v* {3 R* f//+------------------------------------------------------------------+
" q, z. G0 W3 {7 o HCModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001). I U* r, b& [6 `) Y
{" c+ V3 K! p5 S4 Y1 e( I4 u& P
m_handle=INVALID_HANDLE;
$ Q) ^9 m0 R& {7 w5 f y3 g! Ym_symbol=symbol;
9 S7 t% a+ e) J) z- [9 ~m_period=period;! F! p7 f- O7 Y6 x4 Y1 G
m_next_bar=0;6 X! H3 W+ v# o0 f+ o
m_class_delta=class_delta;
b( p% ?8 H E* L5 @}
3 k/ b+ ^9 c; w; N- C4 y: X5 S5 F//+------------------------------------------------------------------+) Q! R0 h: q4 d, y) p' ^' J$ \
//| Destructor |
6 f% o8 J; x& v/ t//| Check for initialization, create model |, f6 \/ F5 _$ u
//+------------------------------------------------------------------+6 d$ v C2 ]2 f% F: R. U* P5 D
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])" E, ?& j% n/ ?' n, g! E, u/ @6 \
{5 N: G8 S. `, j
//--- check symbol, period
T5 [7 H7 Y# lif(symbol!=m_symbol || period!=m_period)
5 ?- \3 Z3 T# P8 i6 i{. M+ w; q) Z/ b
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));
K) ~6 Z* b' Zreturn(false);
8 ~1 {+ E: p" \. V; \}
, q! `$ S- b" L" \% F( u# O; e% D. J//--- create a model from static buffer
! C& ?7 n* M; l4 e# {m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
5 H' e+ d& c. D+ d& b: ~if(m_handle==INVALID_HANDLE)
* V7 h$ n' D7 ^{
: B5 q0 `6 Z3 I3 P6 cPrint("OnnxCreateFromBuffer error ",GetLastError());( u2 V/ z. v( K! V6 U/ h* M0 o, f
return(false);# Y4 }2 D0 Y' M0 b
}+ v/ I0 J. n7 R5 p
//--- ok7 o* _+ ?0 T$ B _1 A( F
return(true);
9 y! {* R* i' K; l) J5 }. P}- {. R+ `0 p6 i. ~8 i, f' X9 ]& Y
//+------------------------------------------------------------------+# T/ N9 q6 J: t) M. ?& ^" X! ~- J g
m_next_bar=TimeCurrent();4 x& U$ i+ P7 K4 o
m_next_bar-=m_next_bar%PeriodSeconds(m_period);/ t9 j9 @$ v% U6 n8 \" F* H! b$ r
m_next_bar+=PeriodSeconds(m_period);# W, x! s7 C6 I
//--- work on new day bar
- {1 k+ j, R0 B/ C @: U6 breturn(true);
. B; A* n5 d& S2 k6 ^" }: N0 `" M}" d' A3 ?" [7 X- h
//+------------------------------------------------------------------+0 Z& g7 S9 W8 I7 t( f; V7 {
//| virtual stub for PredictPrice (regression model) |5 N$ p! i v) `" ^4 N1 j ?- z
//+------------------------------------------------------------------+
0 c7 _* P, @# p' B. vvirtual double PredictPrice(void). j1 p1 v3 y7 D0 a _1 ^# B
{
3 k7 J: Y1 ?' H8 |- m6 F, zreturn(DBL_MAX);$ }" ^' h& B( x/ Z8 ?& S
}
6 i# N1 [% I" [8 n A0 ]- s4 E5 u//+------------------------------------------------------------------+
* w0 B8 u: t. i% u//| Predict class (regression -> classification) | o9 j' o3 _# H/ M+ n! w7 {
//+------------------------------------------------------------------+' t" p; ^; }+ B1 t' y
virtual int PredictClass(void)
8 n- u7 m) k* W% ]- v+ v/ c{
5 ~, j) c7 P% Z5 [" p- z7 K: Ndouble predicted_price=PredictPrice();4 Z0 B1 v5 A5 K( p( K8 I% e
if(predicted_price==DBL_MAX)
+ J/ w5 ^% p) z% p# x7 Z, h6 |- Nreturn(-1);
" h5 @. Q6 ]6 x$ J+ |6 f+ pint predicted_class=-1;8 A1 R5 Y2 S0 k9 o) V2 D
double last_close=iClose(m_symbol,m_period,1);8 j# G/ H! Y5 B- r! L0 X( w2 M
//--- classify predicted price movement3 g% d% r3 }' Z4 h9 f: a& `( f7 B
double delta=last_close-predicted_price;8 a% _8 z6 i) c
if(fabs(delta)<=m_class_delta)7 t$ a. Z- C6 d5 t
predicted_class=PRICE_SAME;- g+ [0 g7 o# J9 z2 Z* q
else6 D: M2 F: J* B# C* N: u/ h
private:
2 H) b/ F$ s0 Nint m_sample_size;8 H; V+ c0 j+ u
//+------------------------------------------------------------------+
- [9 [1 s5 I) C; Yvirtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)9 J: l. s! }- v) m/ i& s# f
{- k. A$ G. h3 z s; i
//--- check symbol, period, create model
" v: z2 ~5 u; ~2 G n1 L- _0 Uif(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))
. f5 P9 j" R; b! K; C' q- [1 {9 u{
! @: }( O& _6 N4 NPrint("model_eurusd_D1_10_class : initialization error");
' S! w5 m) A" P# ?* ]! Freturn(false);( W% [ Y; W0 } E; ~0 |+ T
}; I& Y/ M( a- }8 q! ^2 n9 \
//--- since not all sizes defined in the input tensor we must set them explicitly
4 w: q4 U" h" G% q2 M//--- first index - batch size, second index - series size, third index - number of series (OHLC). d8 V( s- V/ V, H2 C6 Z
const long input_shape[] = {1,m_sample_size,4};- n2 v% X/ D& q( X5 {7 A
if(!OnnxSetInputShape(m_handle,0,input_shape))
* r A# Z0 x% Z0 t{
_/ x) W6 R6 t4 H2 G' X, T- ?4 JPrint("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());. ?# l7 \$ B4 v X; \! M9 e% ^% E1 O
return(false);
. M6 C/ Y: T; A/ U' p1 q, E}
( @! v% {! v8 h- Z/ N. d5 K//--- since not all sizes defined in the output tensor we must set them explicitly
1 R& A4 c# e7 I) o6 ^5 O//--- first index - batch size, must match the batch size of the input tensor
: y8 r" R, `8 ]4 ?* w, v//--- second index - number of classes (up, same or down)
1 g* v& x% W) M4 P' dconst long output_shape[] = {1,3};
5 U. D/ |% p" k) P+ N9 S3 y+ oif(!OnnxSetOutputShape(m_handle,0,output_shape))
9 }+ n3 R/ R+ { \/ Q0 e{; X- J# @% y" L/ |/ @ D# ~ M
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
' d) \7 b3 v! K0 e4 n- Q( Y) hreturn(false);
' }( v j3 _* q% |# i}
8 C, r3 n, \4 p) R, F3 o//--- ok
9 r3 \9 o1 u7 p2 u/ Q* `% Breturn(true);
7 {+ {3 _0 e/ S6 I/ B, Q3 N+ a}! ]8 V8 T* N) ^' b& w& [
//+------------------------------------------------------------------+
, z# r" E( O& o5 R" {" A//| Predict class |
% N5 `" d* f& D! `6 E//+------------------------------------------------------------------+" ?) F [6 Q; c% o
virtual int PredictClass(void)5 @4 _# B# \" I8 O: W3 L! T1 F
{ |