1. 我们会用到什么模型呢?
5 W* C2 u0 n* A1 G在之前的投票分类器中,我们用到了一个分类模型和一个回归模型。 在回归模型中,我们在用于计算分类时,用预测价格替代预测价格走势(下跌、上涨、不变)。 然而,在这种情况下,我们不能依据分类得到概率分布,而对于所谓的“软投票”这样是不允许的。
0 _8 |- O+ I* x) |) W7 ]% k我们已准备了 3 个分类模型。 在“如何在 MQL5 中集成 ONNX 模型的示例”一文中已用到两个模型。 第一个模型(回归)被转换为分类模型。 基于 10 个 OHLC 价格序列进行了培训。 第二个模型是分类模型。 基于 63 个收盘价序列进$ p* c h+ y! v: ^/ f* y
//| https://www.mql5.com |
$ A5 {' G! i, V; V0 l//+------------------------------------------------------------------+
/ U9 N/ r3 t+ n0 E$ A# b! P//--- price movement prediction, o- P! U+ K$ A- U+ u9 e
#define PRICE_UP 0
) k9 N* G3 f% y3 H% `: x#define PRICE_SAME 1
- v+ x! f4 N3 F# n+ m#define PRICE_DOWN 2
( g e2 n r& g6 Z( z# B0 V//+------------------------------------------------------------------+
8 W6 M4 q& j A( O//| Base class for models based on trained symbol and period |7 H% B- H2 J* a- }7 h; r$ g
//+------------------------------------------------------------------+$ m, Z, z- H0 U& d: h7 L" c
class CModelSymbolPeriod! o6 z+ }0 R6 J. g" Y8 e3 k9 D
{
) y% ^% C! e# q* l& \. tprotected:
) e4 k5 V) { nlong m_handle; // created model session handle2 ]4 I7 T7 r% E( G, K0 m. |
string m_symbol; // symbol of trained data" a& b4 b. g; h
ENUM_TIMEFRAMES m_period; // timeframe of trained data1 P4 h% C; n$ b# G
datetime m_next_bar; // time of next bar (we work at bar begin only)+ T6 D* p( b5 J; w, g1 p3 y7 R
double m_class_delta; // delta to recognize "price the same" in regression models
A1 z6 k( m$ v3 dpublic:
8 m8 a H$ A8 y+ V% k; ]//+------------------------------------------------------------------+& i) `/ U5 f2 y5 z! G3 |( A
//| Constructor |3 w9 C; r- P0 I9 R m3 v: c
//+------------------------------------------------------------------+
( i. [4 |. `' {" b- B7 x! MCModelSymbolPeriod(const string symbol,const ENUM_TIMEFRAMES period,const double class_delta=0.0001)/ U) F4 T+ Y9 ^! e
{
5 c7 t5 O& C- E. X! ]; Qm_handle=INVALID_HANDLE;6 ~3 l6 ?0 a) q+ g/ f
m_symbol=symbol;
* X- f/ ]" y' N/ B& G8 qm_period=period;
; z. E7 I3 o* j- |7 ?7 K$ }2 @m_next_bar=0;
) U& S2 _* n. ~) S# ]: L: gm_class_delta=class_delta;+ k/ a' T1 ^& x0 M
}# S8 \: Q: Q; H& [1 n3 Y
//+------------------------------------------------------------------+
- P. _, N t6 p; n) t% O1 T//| Destructor |
+ X7 x. p8 a# c5 E% {//| Check for initialization, create model |
! t+ Y* J9 N2 D F4 k2 O7 N" L//+------------------------------------------------------------------+4 F- n' ^0 I5 q' X& D, d- G
bool CheckInit(const string symbol,const ENUM_TIMEFRAMES period,const uchar& model[])
1 p: |* p2 n; G e2 `6 B9 ^{8 e* ]2 Z9 B" b7 j0 V+ e) X2 S! s
//--- check symbol, period
! w) Y0 R4 {5 m% j: n8 uif(symbol!=m_symbol || period!=m_period)
{) S! q0 a* T' b' Z( ?) y{
9 V: M& O7 ]* i1 x! lPrintFormat("Model must work with %s,%s",m_symbol,EnumToString(m_period));! _: C: ^* } V: t" F. ]5 D
return(false);+ {- E: ^9 s/ x2 i6 A/ t
}) k K. ~0 \; c9 I/ ^9 b- q
//--- create a model from static buffer6 U% i5 n3 K9 w3 J
m_handle=OnnxCreateFromBuffer(model,ONNX_DEFAULT);
0 Z B5 s( s6 E/ @if(m_handle==INVALID_HANDLE)
# e1 t8 c4 D. @ ^- P{4 n j" A& L `' t- |$ D
Print("OnnxCreateFromBuffer error ",GetLastError());
+ R4 N( s. l# U0 Breturn(false);
. p+ p8 b' o! c) Z6 s3 n}- z. a/ { j' F V1 O
//--- ok1 p' q4 l+ v) L% s' ~$ F
return(true);4 l# }! Y2 ^; r8 a* g) A6 P
}( M! t& i! x. c* P: \
//+------------------------------------------------------------------+; Z" ]; o+ Q) B$ J1 D6 @/ j, h$ Q& K
m_next_bar=TimeCurrent();) r3 ^- d* x) h7 @1 ^. @
m_next_bar-=m_next_bar%PeriodSeconds(m_period);
8 `2 c) ^/ n s9 W% _m_next_bar+=PeriodSeconds(m_period);
/ U' I/ E* [: ~/ i: @3 s//--- work on new day bar4 P1 X) ]" h7 u# P) |# k5 @0 s$ O7 Z
return(true);' c* Q* t3 h% |1 X) z6 |
}
9 T2 ?" \ J; ?' N; F# H2 L//+------------------------------------------------------------------+
% W1 [4 t: o& Y7 ?$ K4 {$ W* R//| virtual stub for PredictPrice (regression model) |
% g. y" Y$ p4 r; [, A) v: ^8 }/ w3 b/ [//+------------------------------------------------------------------+
* g/ t' I7 G$ k; V% O" _ `. [" Zvirtual double PredictPrice(void)
+ B, l% r1 D. `; o" E. N6 _) A: f{
+ o% N; n/ g$ @- i9 G* Treturn(DBL_MAX);
- ^! G1 D8 [2 }4 t4 z}
- e/ U! A6 x3 y+ E' W0 n% O$ M/ e//+------------------------------------------------------------------+3 ]- ?( h% g+ b& p* Z, L% s
//| Predict class (regression -> classification) |# y0 i9 `3 d% \: q$ f
//+------------------------------------------------------------------+
; m- N+ A0 j6 tvirtual int PredictClass(void)/ x3 b" j* g' f5 w" S
{9 ^- \- X1 b' B$ [! P5 S- R3 ~
double predicted_price=PredictPrice();
5 u1 n( A V6 ]# g% c3 s: s/ n$ W" \if(predicted_price==DBL_MAX)
$ |- `" O# Z# N3 {: o9 freturn(-1);
& O- B( A0 \ v" Z) U9 G4 Lint predicted_class=-1;' V1 U4 l, w* W* ]3 o
double last_close=iClose(m_symbol,m_period,1);
N, i& {* t8 W/ ?5 M& k' O A//--- classify predicted price movement& g6 I0 L2 {, x7 i5 V. {' w, c
double delta=last_close-predicted_price;
6 p2 B: z3 g1 n% {0 `' Mif(fabs(delta)<=m_class_delta)
8 D/ s. W C: l% v4 i ~predicted_class=PRICE_SAME;) {7 @& f& q& E8 \9 O ^/ }
else( d( d# _# g9 @! N$ u
private:
# f0 Z# ^, {+ zint m_sample_size;! ]/ U" z6 r1 Q: ]- z7 B: d
//+------------------------------------------------------------------+4 [5 W# U" y1 J+ H5 Q, w" P
virtual bool Init(const string symbol, const ENUM_TIMEFRAMES period)' {+ Y# w* ~7 p% }. [- {
{2 n4 ~, r; |! I
//--- check symbol, period, create model
9 D9 k" W, n2 T, B+ O6 Jif(!CModelSymbolPeriod::CheckInit(symbol,period,model_eurusd_D1_10_class))3 y5 S/ G. ~0 Y
{
$ y" R2 u/ M, G, Y9 N* O+ rPrint("model_eurusd_D1_10_class : initialization error");
' o. @/ X) h8 u- Creturn(false);; s4 u$ F' W$ `* o
}
1 o9 ]' m; N1 M1 \! U3 _//--- since not all sizes defined in the input tensor we must set them explicitly* ?+ ~' X6 y+ n. {. U: x) \
//--- first index - batch size, second index - series size, third index - number of series (OHLC)
* j) T4 c% i$ yconst long input_shape[] = {1,m_sample_size,4};
r1 p1 q& v. ?+ ]+ \- m; }7 Cif(!OnnxSetInputShape(m_handle,0,input_shape))9 `* w2 D1 A2 l% r! Z9 u
{% i4 V2 U! H) r
Print("model_eurusd_D1_10_class : OnnxSetInputShape error ",GetLastError());- n+ M# r! U1 ~% h+ v
return(false);9 d2 t/ |, ~$ p! F& N7 I
}6 M1 F: p* X9 L" y# W2 r
//--- since not all sizes defined in the output tensor we must set them explicitly' A" ]# S$ @6 u. f
//--- first index - batch size, must match the batch size of the input tensor
9 Z5 C. J# y: {' u. _0 K0 V/ A//--- second index - number of classes (up, same or down)/ U/ g# i1 {, T3 N- U l
const long output_shape[] = {1,3};& ~1 g% M8 K. s# J% Y- n) F% }
if(!OnnxSetOutputShape(m_handle,0,output_shape))4 ^. R# t* K$ Z9 ]
{6 E7 K( X8 C' i, \3 v- _
Print("model_eurusd_D1_10_class : OnnxSetOutputShape error ",GetLastError());
+ m Y, D0 p3 q0 n( ^6 V5 M# nreturn(false);
; A% m- f& N) e' Y}
5 K8 l" B2 k0 C |//--- ok
8 O! ^: l' z( n! M9 `' l; B7 rreturn(true);
% C8 [* Z% @. z V# J- k6 w}* j- C7 ]% B V. z8 a, N" m
//+------------------------------------------------------------------+# ]$ [0 e+ {( O+ U9 W$ q7 e9 l
//| Predict class |
7 p* @0 B! |+ B0 D" c//+------------------------------------------------------------------+
7 t7 ?- [6 Y/ V. [virtual int PredictClass(void)$ y6 I1 P, `9 F. a+ @- v. t+ w
{ |