Neuronové sítě bez kouzel: Occamova břitva a pohled programátora


Problém bez mlhy: co skutečně potřebujeme


Derivace: jediná „povinně volitelná“ kapitola


C++ a MQL5: Matematika převedená do praxe


Occamova břitva v bodech

  • Aktivace: tanh/sigmoid/ReLU jako obyčejné funkce.

Co mi tato cesta dala


Závěr


Stažení (EA / zdroje)

NNMQL5 Dokumentace:


Odlehčená DLL knihovna s C API pro jednoduchou MLP (stack hustých vrstev) s:

  • dopřednou inferencí (NN_Forward, NN_ForwardBatch)
  • učením na vzorku i dávkách (NN_TrainOne, NN_TrainBatch)
  • správou více instancí sítí přes handle
  • manipulací s váhami (NN_GetWeights, NN_SetWeights)

Síť je stavová (váhy v RAM), neukládá se – perzistence se řeší v hostitelském kódu.

API (rozhraní C)

int  NN_Create(void);
void NN_Free(int h);
bool NN_AddDense(int h, int inSz, int outSz, int act);
int  NN_InputSize(int h);
int  NN_OutputSize(int h);
bool NN_Forward(int h, const double* in, int in_len, double* out, int out_len);
bool NN_TrainOne(int h, const double* in, int in_len,
                 const double* tgt, int tgt_len, double lr, double* mse);
bool NN_ForwardBatch(int h, const double* in, int batch, int in_len,
                     double* out, int out_len);
bool NN_TrainBatch(int h, const double* in, int batch, int in_len,
                   const double* tgt, int tgt_len, double lr, double* mean_mse);
bool NN_GetWeights(int h, int i, double* W, int Wlen, double* b, int blen);
bool NN_SetWeights(int h, int i, const double* W, int Wlen, const double* b, int blen);

Ukázka použití v MQL5

#import "NNMQL5.dll"
int  NN_Create(); void NN_Free(int h);
bool NN_AddDense(int h,int inSz,int outSz,int act);
bool NN_Forward(int h,const double &in[],int in_len,double &out[],int out_len);
bool NN_TrainOne(int h,const double &in[],int in_len,const double &tgt[],int tgt_len,double lr,double &mse);
int  NN_InputSize(int h); int NN_OutputSize(int h);
#import

int h=-1;
int OnInit(){
  h=NN_Create(); if(h<=0) return INIT_FAILED;
  if(!NN_AddDense(h, 32, 64, 1)) return INIT_FAILED; // ReLU
  if(!NN_AddDense(h, 64,  1, 3)) return INIT_FAILED; // Lineární
  return INIT_SUCCEEDED;
}
void OnDeinit(const int r){ if(h>0) NN_Free(h); }

void OnTimer(){
  static double x[32], t[1], y[1]; double mse;
  // naplnění x[] a t[] daty...
  NN_TrainOne(h, x, 32, t, 1, 0.01, mse);
  NN_Forward(h, x, 32, y, 1);
  Print("y=",y[0]," mse=",mse);
}

Rychlý přehled (návratové hodnoty)

FunkceÚspěch (true/>0)False/0 znamená
NN_CreatePozitivní handleAlokace selhala (vzácné)
NN_Free— (idempotentní, bezpečné volat opakovaně)
NN_AddDenseVrstva přidánaNeplatný handle / nesoulad velikostí
NN_InputSizeDeklarovaná vstupní velikost0 (neplatný handle / prázdná síť)
NN_OutputSizeDeklarovaná výstupní velikost0 (neplatný handle / prázdná síť)
NN_Forwardout[] naplněnoNeplatný handle / nesoulad velikostí / prázdná síť
NN_TrainOneProvedena aktualizace vah, *mse obsahuje MSENeplatný handle / nesoulad velikostí / prázdná síť
NN_ForwardBatchout[] naplněno pro celou batchNeplatný handle / nesoulad velikostí
NN_TrainBatchProvedena aktualizace vah pro batch, *mean_mse obsahuje průměrné MSENeplatný handle / nesoulad velikostí / prázdná síť
NN_GetWeightsVáhy a biasy načteny do bufferůNeplatný handle / index mimo rozsah / nesoulad velikostí
NN_SetWeightsVáhy a biasy nastavenyNeplatný handle / index mimo rozsah / nesoulad velikostí
dark_html = r“““ NNMQL5_Predictor — Příklady (Dark)

NNMQL5_Predictor — Příklady (Dark)

Ukázky kódu vycházející z indikátoru NNMQL5_Predictor.mq5 (MetaTrader 5 • NNMQL5.dll).

Hist +1 Hist +2 Hist +3 Hist +4 Hist +5 Future

Import DLL (MQL5)

// NNMQL5.dll — importy
#import "NNMQL5.dll"
int  NN_Create();
void NN_Free(int h);
bool NN_AddDense(int h,int inSz,int outSz,int act);
int  NN_InputSize(int h);
int  NN_OutputSize(int h);
bool NN_Forward(int h,const double &in[],int in_len,double &out[],int out_len);
bool NN_TrainOne(int h,const double &in[],int in_len,const double &tgt[],int tgt_len,double lr,double &mse);
bool NN_ForwardBatch(int h,const double &in[],int batch,int in_len,double &out[],int out_len);
bool NN_TrainBatch (int h,const double &in[],int batch,int in_len,const double &tgt[],int tgt_len,double lr,double &mean_mse);
bool NN_GetWeights(int h,int i,double &W[],int Wlen,double &b[],int blen);
bool NN_SetWeights(int h,int i,const double &W[],int Wlen,const double &b[],int blen);
#import

Vytvoření sítě (topologie)

int h = NN_Create();
int Lookback=32, Hidden=64, Depth=2, HiddenAct=2; // 2=TANH
NN_AddDense(h, Lookback, Hidden, HiddenAct);
for(int i=1; i<Depth; i++) NN_AddDense(h, Hidden, Hidden, HiddenAct);
NN_AddDense(h, Hidden, 1, 3); // 3=LINEAR (regrese)

Dataset z ceny (z‑score, sliding window)

void MeanStdSlice(const double &arr[], int first, int last, double &mean, double &stdev){
  int n = last - first + 1;
  if(n<=1){ mean=0.0; stdev=1.0; return; }
  double s=0.0; for(int i=first;i<=last;i++) s += arr[i];
  mean = s / n;
  double v=0.0; for(int i=first;i<=last;i++){ double d=arr[i]-mean; v+=d*d; }
  stdev = MathSqrt(v/(n-1)); if(stdev<=1e-12) stdev=1.0;
}

Mini‑batch trénink

bool TrainEpoch(int h, const double &X[], const double &T[],
                int N, int Lookback, double &lr, double &mean_mse, int BatchSize){
  if(BatchSize<=1) return NN_TrainBatch(h,X,N,Lookback,T,1,lr,mean_mse);
  double acc=0.0; int cnt=0, B=MathMax(2,BatchSize);
  for(int base=0; base<N; base+=B){
     int b=MathMin(B,N-base);
     double xin[]; ArrayResize(xin,b*Lookback);
     double tgt[]; ArrayResize(tgt,b);
     for(int bi=0; bi<b; ++bi){
       int src=(base+bi)*Lookback, dst=bi*Lookback;
       for(int k=0;k<Lookback;k++) xin[dst+k]=X[src+k];
       tgt[bi]=T[base+bi];
     }
     double bmse=0.0; bool ok=NN_TrainBatch(h,xin,b,Lookback,tgt,1,lr,bmse);
     if(!ok) return false; acc+=bmse; cnt++;
  }
  mean_mse = (cnt? acc/cnt : 0.0); return true;
}

Historické predikce +1..+5

for(int step=1; step<=FutureH && step<=5; ++step){
  bool ok = NN_Forward(h, state, Lookback, y, 1);
  if(!ok) break;
  double den = y[0]*g_std + g_mean; // de‑norm
  // ulož do bufferů Pred1..Pred5
}
Barvy linek odpovídají MT5: +1, +2, +3, +4, +5.

Autoregresní future path

string pref = StringFormat("NNFUT_%s_%s", _Symbol, EnumToString(_Period));
// výpočet kroků dopředu a řetěz OBJ_TREND
Budoucí trajektorie se vykresluje barvou DeepSkyBlue.

Minimální indikátor

#property indicator_chart_window
#property indicator_buffers 5
double Pred1[],Pred2[],Pred3[],Pred4[],Pred5[];
int h=0, Lookback=32, Hidden=64, Depth=2, FutureH=5;
int OnInit(){ SetIndexBuffer(0,Pred1,INDICATOR_DATA); /* … */ return INIT_SUCCEEDED; }
void OnDeinit(const int reason){ if(h!=0) NN_Free(h); }
© 2025 Remind

GitHub RemindCZ

Autor: Tomáš Bělák — Remind