1. 我们会用到什么模型呢?* ~6 B7 j6 ^2 R+ j0 q
在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
% `* d! \0 w5 @- d! P3 Q a我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进. D: b* F/ Y, t& b8 u5 X, `1 Z3 L
//| https://www.mql5.com |
. E7 I& k- i. f7 B1 s i//+------------------------------------------------------------------+$ j5 Q/ @! C ^- k3 a; I
//--- price movement prediction
2 z% D) d! L+ M5 q; x- _: z0 O" s#define PRICE_UP 0
. n7 v C4 ~& P#define PRICE_SAME 1
, V+ X, A( q* q2 p* j! K/ r$ [#define PRICE_DOWN 2: \4 Q) `5 ~3 L1 P% B! X1 m
//+------------------------------------------------------------------+
9 y% C5 k& H p( z; k//| Base class for models based on trained symbol and period |7 K z. T/ s4 l4 V5 u3 q. \
//+------------------------------------------------------------------+
6 F' j$ _' _% |1 a; C$ p: ~; Lclass CModelSymbolPeriod
) v0 T& H, q0 u{4 _4 s* @' `" O, Y& @: C% j7 }
protected:
, I3 U) `0 S+ w' b& Y, \: f: elong m_handle; // created model session handle
- z0 L% w7 M0 U6 b' e4 {( n$ t% j5 estring m_symbol; // symbol of trained data* J5 Y5 @" f3 ^6 F2 ^0 Z" N
ENUM_TIMEFRAMES m_period; // timeframe of trained data
2 P, T+ C: }, r; u9 @datetime m_next_bar; // time of next bar (we work at bar begin only)) x9 e, u; v% u3 ^. J1 y; \
double m_class_delta; // delta to recognize "price the same" in regression models0 [ W+ \ {) C4 |
public:2 F, A. ?$ |6 m
//+------------------------------------------------------------------+4 D% o) f/ }5 ^$ a' j9 f/ u0 X
//| Constructor |
: T. K* e; |; [: I//+------------------------------------------------------------------+7 F% A- [( m: V) v: l% Y
CModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)& z0 A) \8 I: A% k# |/ h
{5 l3 f) m' R( m9 C6 o! n+ r4 t5 }7 k6 x
m_handle=INVALID_HANDLE;( {6 Y/ ^0 c. ^( y8 @/ l# v
m_symbol=symbol;9 K( L! M5 w# z8 j
m_period=period;, G) Z$ J% }2 |8 r
m_next_bar=0;
" f, A- n' U5 Z$ zm_class_delta=class_delta;" U" q& x+ D2 }1 `
}
) I V/ m! Z/ X& A! q" a//+------------------------------------------------------------------+
4 C, S# d* G; h//| Destructor |
9 I/ C+ g5 N7 @& @$ h//| Check for initialization, create model |: }( n# D9 M: o
//+------------------------------------------------------------------+ S' P: f j) F" H7 Z; W! J6 V9 g
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[]): O6 j" | {- H
{
$ O0 ? [: P: }//--- check symbol, period7 ]0 N. I8 e. t7 @( B1 @/ n* w
if(symbol!=m_symbol || period!=m_period)! A$ V7 f( g0 M% O
{& ~6 ]4 e. y' w5 [# V: E
PrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));; k1 r1 H7 X/ W, W
return(false);9 z5 J2 A0 L! S4 I
}
! F5 F5 K3 x# i! l2 V//--- create a model from static buffer
# J2 [$ f5 q# R4 K4 h0 M3 A" T# Tm_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);8 r: Y8 `0 p0 j- J/ \$ C& o
if(m_handle==INVALID_HANDLE)
1 b1 }& W8 P4 b, r3 U. j; n{
; R9 k5 ~5 c D% N7 pPrint("OnnxCreateFromBuffer error ",GetLastError());1 e" x# C i( _8 S, p
return(false);6 V. t% c# G. a/ c) Y* _2 f# r
}
( |; ^. Y. |& h- ~$ j% \; x//--- ok
f$ r) I5 F s% qreturn(true);
; Q; r- G. s, T- b}
2 H7 j- \( f% F, Q, [4 L$ D//+------------------------------------------------------------------+
' H; [0 ]3 Q. G0 Am_next_bar=TimeCurrent();/ L$ w& z* z1 [) L+ U
m_next_bar-=m_next_bar%PeriodSeconds(m_period);
4 _& W+ a2 j- ~6 f9 c5 t5 f) ym_next_bar+=PeriodSeconds(m_period);. Q+ }, h5 }) p+ M
//--- work on new day bar
0 f1 d5 O) n2 b! \/ e. H; a7 Freturn(true);
- r* f" G k9 `8 B8 l" i- Q}, G* q' |) [9 T* x& Q; X/ y
//+------------------------------------------------------------------+1 V8 J I5 w/ A
//| virtual stub for PredictPrice (regression model) |4 U3 Q1 C" E9 s2 `4 Z" b- j. A) I
//+------------------------------------------------------------------+
+ Q1 c0 W, N! _+ X9 V6 }virtual double PredictPrice(void)8 j( l T" n, l- J* t$ Z
{
8 }& p* S O/ |$ o3 Ureturn(DBL_MAX);- |( K; Y( ]( u- T/ B$ l' k
}, M! m+ U. _3 O- M- E/ Y4 y
//+------------------------------------------------------------------+
9 Z( [& k8 m) ^, o+ ~9 Q//| Predict class (regression -> classification) |
6 a5 \# S7 A. M3 K" R1 L0 X" H//+------------------------------------------------------------------+
9 e: [1 O( C4 M! r) K* f, Pvirtual int PredictClass(void)
7 q& n5 t4 }1 n* [{$ d5 |. j* j6 o) `
double predicted_price=PredictPrice();
& l. o; Y( q0 oif(predicted_price==DBL_MAX)& C1 z& L/ w- c0 z
return(-1);
3 X) P4 b% {3 Y7 Tint predicted_class=-1;* }8 s! y( p3 L0 B$ a
double last_close=iClose(m_symbol,m_period,1);
4 {2 u0 H7 e' ~7 \. p//--- classify predicted price movement
, B3 I+ M7 s9 r( `9 z+ ?double delta=last_close-predicted_price;1 z3 N \9 F, q
if(fabs(delta)<=m_class_delta). U1 d3 j8 F7 J$ D6 r# q; l, G& x
predicted_class=PRICE_SAME;. c. w* `2 P1 H8 }' J; P7 i
else
; H2 B% b2 m! P1 c0 u' M7 f0 [private:( ?' H; Z( Y0 t3 N" k3 ^2 P1 E
int m_sample_size;
1 v4 P' W! _& q$ A- \//+------------------------------------------------------------------+: A" R9 }' {7 _0 u T i
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period): V" ?) i7 {& |5 g6 x" ~
{5 l( O2 s5 M; a' k
//--- check symbol, period, create model/ x- W+ }8 Z1 e, M4 {# _% B
if(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))0 ~1 J0 m/ [; a, W/ L% f- A. c
{8 }8 ~1 c7 ^9 w) p4 M
Print("model_eurusd_D1_10_class : initialization error");
+ E; Q" `2 G, a' I' Ereturn(false); z W' M- P. @/ i/ Z' l
}7 p- C3 C; H0 q
//--- since not all sizes defined in the input tensor we must set them explicitly2 p$ [; F5 K9 }1 Q$ M$ K2 y
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
2 M& M2 C6 D; |: \' kconst long input_shape[] = {1,m_sample_size,4};# v: D& e- E1 p' K
if(!OnnxSetInputShape(m_handle,0,input_shape))$ r3 M- X7 K \; `' z
{/ ]! z/ L# ]8 [, H# Z" s
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());
1 j3 e# p3 }) a2 k0 J) ureturn(false);
' ?; @+ R7 _5 i1 a8 }}
. c8 K% Y7 v" H; q- C5 X9 L& j//--- since not all sizes defined in the output tensor we must set them explicitly1 \+ g" F1 A6 @. Z% d* u* |
//--- first index - batch size, must match the batch size of the input tensor, X0 @+ F) W; y
//--- second index - number of classes (up, same or down), q+ `4 x9 P8 D/ p3 x' I" a
const long output_shape[] = {1,3};
6 t9 ]' q0 L: L+ s/ B8 fif(!OnnxSetOutputShape(m_handle,0,output_shape))
1 s5 @- d" b& Y; ?) s{
6 z( d/ c0 k$ s: g' XPrint("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
$ u* n1 w0 N2 w7 |return(false);
: Z$ M# K1 ^; e) F# _}! p. Y& S3 n. \1 s8 B: x
//--- ok
& r& G; v5 F; Dreturn(true);/ I( U+ [8 q' j2 }4 M( z
}
8 y2 c5 `% k" L8 }# A9 t//+------------------------------------------------------------------+
7 C4 p* \1 a5 P& q; k//| Predict class |
5 {5 H6 H8 ~% [1 \//+------------------------------------------------------------------+' N" B9 w- Y8 J0 B
virtual int PredictClass(void)% w9 A$ o: M# |; {: W& [0 u/ r
{ |