//+------------------------------------------------------------------+
//|                                                        fann2.mq5 |
//|                        Copyright 2010, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2010, MetaQuotes Software Corp."
#property link      "http://www.mql5.com"
#property version   "1.00"

#import "Fann2MQL.dll"
int f2M_create_standard(int num_layers,int l1num,int l2num,int l3num,int l4num);
int f2M_create_from_file(string path);
int f2M_run(int ann,double &input_vector[]);
int f2M_destroy(int ann);
int f2M_destroy_all_anns();

double f2M_get_output(int ann,int output);
int  f2M_get_num_input(int ann);
int  f2M_get_num_output(int ann);

int f2M_train(int ann,double &input_vector[],double &output_vector[]);
int f2M_train_fast(int ann,double &input_vector[],double &output_vector[]);
int f2M_randomize_weights(int ann,double min_weight,double max_weight);
double f2M_get_MSE(int ann);
int f2M_save(int ann,string path);
int f2M_reset_MSE(int ann);
int f2M_test(int ann,double &input_vector[],double &output_vector[]);
int f2M_set_act_function_layer(int ann,int activation_function,int layer);
int f2M_set_act_function_hidden(int ann,int activation_function);
int f2M_set_act_function_output(int ann,int activation_function);

/* Threads functions */
int f2M_threads_init(int num_threads);
int f2M_threads_deinit();
int f2M_parallel_init();
int f2M_parallel_deinit();
int f2M_run_threaded(int anns_count,int &anns[],double &input_vector[]);
int f2M_run_parallel(int anns_count,int &anns[],double &input_vector[]);
#import

int ann;
int input_count=4800;
// InputVector[] - Array of ann input data
double InputVector[];
// symbols list
string slist[];
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
// symbols list
   int symb_total;
   symb_total=SymbolsTotal(false);
   ArrayResize(slist,symb_total);
   for(int i=0;i<symb_total;i++) slist[i]=SymbolName(i,true);

//   

// Creating NN
   f2M_parallel_init();
   ann=CreateAnn();
   TrainNN();
   get_res();
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

//ann_save(ann,TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\1.ann");
   ann_destroy();
   f2M_parallel_deinit();
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   get_res();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void get_res()
  {
//---
   ann_prepare_input(0);

   if(f2M_run(ann,InputVector)<0)
     {
      Print("Network RUN ERROR! ann="+IntegerToString(ann));
     }
     double nxt_price = f2M_get_output(ann,0)/GetDelim(_Symbol);
     draw_line(nxt_price);
   Comment("\nNext Price Target: "+DoubleToString(nxt_price,_Digits)+" MSE: "+DoubleToString(f2M_get_MSE(ann)));
  }
//+------------------------------------------------------------------+
int CreateAnn()
  {
   ann=f2M_create_standard(4,32,16,16,1);
   f2M_set_act_function_hidden(ann,6);
   f2M_set_act_function_output(ann,6);
   f2M_randomize_weights(ann,-0.4,0.4);
   Print("ANN: created successfully with handler "+IntegerToString(ann));
   if(ann==-1) Print("ERROR INITIALIZING NETWORK!");
   return(ann);
  }
//+------------------------------------------------------------------+  
void TrainNN()
  {
//for(int i=0; i<input_count; i++)
   for(int i=input_count; i>0; i--)
     {
      // ArrayResize(InputVector,0);
      ann_prepare_input(i);
      double cl[];
      ArrayResize(cl,1);
      cl[0]=iClose(NULL,_Period,i+1)*GetDelim(_Symbol);
      ann_train(ann,InputVector,cl);

      ArrayFree(cl);

      f2M_run(ann,InputVector);

      Comment("Training NN# MSE:  "+DoubleToString(f2M_get_MSE(ann))+":"+IntegerToString(i)+" Result="+DoubleToString(f2M_get_output(ann,0)/GetDelim(_Symbol),_Digits));

     }

  }
//+------------------------------------------------------------------+
void ann_prepare_input(int pos)
  {
   int inp_vec_size=0;
   for(int i=0; i<ArraySize(slist); i++)
     {
      datetime time1[0],time2[0];

      //Print(IntegerToString(ArraySize(slist))); || StringFind(slist[i],"#",0)>0
      if(CopyTime("EURUSD",_Period,pos,1,time1)!=1 || CopyTime(slist[i],_Period,pos,1,time2)!=1) continue;
      if(time1[0]!=time2[0])
        {
         ArrayFree(time1); ArrayFree(time2);
         continue;
        }

      double res;
      double iClose[];
      if(CopyClose(slist[i],_Period,pos,1,iClose)!=1) Print("Copy rate failure symbol="+slist[i]);

      res=iClose[0]*GetDelim(slist[i]);
      ArrayFree(iClose);

      ArrayResize(InputVector,inp_vec_size+1);
      //InputVector[inp_vec_size]=NormalizeDouble(res,SymbolInfoInteger(slist[i],SYMBOL_DIGITS));
      InputVector[inp_vec_size]=res;
      //Print("Pos=" + pos + " Symb="+slist[i]+DoubleToString(InputVector[inp_vec_size],_Digits));

      inp_vec_size++;
     }

  }
//+------------------------------------------------------------------+
void ann_train(int ann,double &input_vector[],double &output_vector[])
  {
   if(f2M_train(ann,input_vector,output_vector)==-1)
     {
      Print("Network TRAIN ERROR! ann="+IntegerToString(ann));
     }
//Print("ann_train("+IntegerToString(ann)+") succeded");
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ann_destroy()
  {
   Print("f2M_destroy("+IntegerToString(ann)+") returned: "+IntegerToString(f2M_destroy(ann)));
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double iClose(string symbol,ENUM_TIMEFRAMES period,int index)
  {
   double result;
   double iClose[];
   if(CopyClose(symbol,period,index,1,iClose)!=1)
     {
      return(0);
     }
   result=iClose[0];
   ArrayFree(iClose);
   return(result);
  }
//+------------------------------------------------------------------+
void ann_save(int ann,string path)
  {
   int ret=-1;
   ret=f2M_save(ann,path);
   Print("f2M_save("+IntegerToString(ann)+", "+path+") returned: "+IntegerToString(ret));
  }
//int GetDelim(string Symb)
double GetDelim(string Symb)
  {
   switch(StringLen(DoubleToString(SymbolInfoDouble(Symb,SYMBOL_BID),0)))
     {
      case 1: return(0.1);
      case 2: return(0.01);
      case 3: return(0.001);
      case 4: return(0.0001);
      case 5: return(0.00001);
      case 6: return(0.000001);
      default: return(0.1);
     }
  }
//+------------------------------------------------------------------+
void draw_line(double price)
  {
   string name="TargetPriceLine";
   if(ObjectFind(0,name)<0)
     {
      //--- создадим объект Label
      ObjectCreate(0,name,OBJ_HLINE,0,TimeCurrent(),price);
        }else{
      ObjectSetDouble(0,name,OBJPROP_PRICE,price);
     }

//--- отрисуем на графике
   ChartRedraw(0);

  }
//+------------------------------------------------------------------+
