//+------------------------------------------------------------------+
//|                                                   TrailingCT.mqh |
//|                   Copyright 2009-2013, MetaQuotes Software Corp. |
//|                                              http://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert\ExpertTrailing.mqh>
#include <ct_7.mqh>
// wizard description start
//+------------------------------------------------------------------+
//| Description of the class                                         |
//| Title=Trailing Stop based on 'Category Theory' relative-sets concepts|
//| Type=Trailing                                                    |
//| Name=CategoryTheory                                              |
//| ShortName=CT                                                     |
//| Class=CTrailingCT                                                |
//| Page=trailing_ct                                                 |
//| Parameter=Step,double,0.5,Trailing Step                          |
//| Parameter= M_1,double,1.0,Slope Weight 1                         |
//| Parameter= M_2,double,1.0,Slope Weight 2                         |
//| Parameter= C_1,int,1.0,Intercept Weight 1                        |
//| Parameter= C_2,int,1.0,Intercept Weight 2                        |
//| Parameter=SourceSize,int,40,Source Sample Size                   |
//+------------------------------------------------------------------+
// wizard description end
//+------------------------------------------------------------------+
//| Class CTrailingCT.                                               |
//| Appointment: Class traling stops with 'Category Theory'          |
//|               relative-sets concepts.                            |
//| Derives from class CExpertTrailing.                              |
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class CTrailingCT : public CExpertTrailing
  {
protected:
   //--- adjusted parameters
   double m_step;       // trailing step
   
   double m_m1;       // Slope Weight 1
   double m_m2;       // Slope Weight 2
   
   int m_c1;       // Intercept Weight 1
   int m_c2;       // Intercept Weight 2
   
   int m_source_size;       // Source Size

public:
   //--- methods of setting adjustable parameters
   
   
   
   //--- method of verification of settings
   virtual bool      ValidationSettings(void);
   //--- method of creating the indicator and timeseries
   virtual bool      InitIndicators(CIndicators *indicators);
   //--- methods of checking if the market models are formed
   virtual bool      CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp);
   virtual bool      CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp);
   //---
                     CTrailingCT(void);
                    ~CTrailingCT(void);
   //--- methods of initialization of protected data
   void              Step(double value)                  { m_step=value;   }
   
   void              M_1(double value)                   { m_m1=value;   }
   void              M_2(double value)                   { m_m2=value;   }
   
   void              C_1(int value)                      { m_c1=value;   }
   void              C_2(int value)                      { m_c2=value;   }
   
   void              SourceSize(int value)               { m_source_size=value;   }

protected:

   int                                       m_image_size;
   
   int                                       m_lag;
   
   CCommuteTriangle<double,double,int>       m_relative_domain;

   CElement<double>                          m_element_a,m_element_b;
   CElement<int>                             m_element_c;
   
   CMorphism<double,double>                  m_morphism_ab;
   CMorphism<double,int>                     m_morphism_bc,m_morphism_ac;
   
   SLinearWeights                            m_weights[2];
   
   virtual void                              Refresh();
   
   virtual int                               Morphisms_AB(CHomomorphism<double,double> &H,CDomain<double> &D,CElement<double> &E,SLinearWeights &W[],int CardinalCheck=2);
   
   virtual void                              SetElement_A(int Index,CElement<double> &E);
   virtual void                              SetElement_B(int Index,CElement<double> &E);
   virtual void                              SetElement_C(int Index,CElement<int> &E);

  };
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CTrailingCT::CTrailingCT(void)
  {
//--- initialization of protected data
      m_used_series=USE_SERIES_TIME+USE_SERIES_SPREAD+USE_SERIES_HIGH+USE_SERIES_LOW+USE_SERIES_CLOSE;
      
      m_step=0.5;
   
      m_image_size=11;
      
      m_lag=1;
      
      m_relative_domain.ab.domain.Cardinality(m_source_size);
      m_relative_domain.ab.codomain.Cardinality(m_source_size);
      
      m_relative_domain.bc.domain.Cardinality(m_source_size);
      m_relative_domain.bc.codomain.Cardinality(m_image_size);
      
      m_relative_domain.ac.domain.Cardinality(m_source_size);
      m_relative_domain.ac.codomain.Cardinality(m_image_size);
         
      m_relative_domain.ab.Morphisms(m_source_size);
      m_relative_domain.bc.Morphisms(m_source_size);
      m_relative_domain.ac.Morphisms(m_source_size);
      
      m_weights[0].m=m_m1;m_weights[1].m=m_m2;
      m_weights[0].c=m_c1;m_weights[1].c=m_c1;
      
      //'single-dimension' image data for domain D
      for(int s=0;s<m_image_size;s++)
      {
         m_element_c.Let();
         
         SetElement_C(s,m_element_c);
         
         m_relative_domain.bc.codomain.Set(s,m_element_c);
      }
  }
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CTrailingCT::~CTrailingCT(void)
  {
  }
//+------------------------------------------------------------------+
//| Validation settings protected data.                              |
//+------------------------------------------------------------------+
bool CTrailingCT::ValidationSettings(void)
  {
//--- validation settings of additional filters
   if(!CExpertTrailing::ValidationSettings())
      return(false);

//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Create indicators.                                               |
//+------------------------------------------------------------------+
bool CTrailingCT::InitIndicators(CIndicators *indicators)
  {
//--- check pointer
   if(indicators==NULL)
      return(false);
//--- initialization of indicators and timeseries of additional filters
   if(!CExpertTrailing::InitIndicators(indicators))
      return(false);
//--- 
//--- ok
   return(true);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for long position.          |
//+------------------------------------------------------------------+
bool CTrailingCT::CheckTrailingStopLong(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      Refresh();
      
      m_element_a.Let(); m_element_b.Let();
      m_element_c.Let();
      
      SetElement_A(StartIndex(),m_element_a);
      SetElement_B(StartIndex(),m_element_b);
      
      int _index=Morphisms_AB(m_relative_domain.ab,m_relative_domain.ab.domain,m_element_a,m_weights,2);
      
      int _c=0;
      if(m_relative_domain.bc.codomain.Get(_index,m_element_c) && m_element_c.Get(0,_c))
      {
         m_high.Refresh(-1);
         m_low.Refresh(-1);
         
         int _x=StartIndex();
         
         double _type=_c/100.0;
      
         double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
         
         double _sl=m_low.GetData(_x)-(m_step*_atr);
         
         double level =NormalizeDouble(m_symbol.Bid()-m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
         double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
         double pos_sl=position.StopLoss();
         double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
         
         sl=EMPTY_VALUE;
         tp=EMPTY_VALUE;
         if(new_sl>base && new_sl<level)
            sl=new_sl;
      }
//---
   return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//| Checking trailing stop and/or profit for short position.         |
//+------------------------------------------------------------------+
bool CTrailingCT::CheckTrailingStopShort(CPositionInfo *position,double &sl,double &tp)
  {
//--- check
      if(position==NULL)
         return(false);
      
      Refresh();
      
      m_element_a.Let(); m_element_b.Let();
      m_element_c.Let();
      
      SetElement_A(StartIndex(),m_element_a);
      SetElement_B(StartIndex(),m_element_b);
      
      int _index=Morphisms_AB(m_relative_domain.ab,m_relative_domain.ab.domain,m_element_a,m_weights,2);
      
      int _c=0;
      if(m_relative_domain.bc.codomain.Get(_index,m_element_c) && m_element_c.Get(0,_c))
      {
         m_high.Refresh(-1);
         m_low.Refresh(-1);
         
         int _x=StartIndex();
         
         double _type=_c/100.0;
      
         double _atr=fmax(2.0*m_spread.GetData(_x)*m_symbol.Point(),m_high.GetData(_x)-m_low.GetData(_x))*(_type);
         
         double _sl=m_high.GetData(_x)+(m_step*_atr);
         
         double level =NormalizeDouble(m_symbol.Ask()+m_symbol.StopsLevel()*m_symbol.Point(),m_symbol.Digits());
         double new_sl=NormalizeDouble(_sl,m_symbol.Digits());
         double pos_sl=position.StopLoss();
         double base  =(pos_sl==0.0) ? position.PriceOpen() : pos_sl;
         
         sl=EMPTY_VALUE;
         tp=EMPTY_VALUE;
         if(new_sl<base && new_sl>level)
            sl=new_sl;
      }
//---
      return(sl!=EMPTY_VALUE);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CTrailingCT::Refresh(void)
   {
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      for(int s=m_lag;s<m_source_size+m_lag;s++)
      {
         m_element_a.Let(); m_element_b.Let();
         
         SetElement_A(s,m_element_a);
         SetElement_B(s+1,m_element_b);
         
         m_relative_domain.ac.domain.Set(s-m_lag,m_element_a);
         
         m_relative_domain.bc.domain.Set(s-m_lag,m_element_b);
      }
      
      m_relative_domain.TriangleAssert();
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int CTrailingCT::Morphisms_AB(CHomomorphism<double,double> &H,CDomain<double> &D,CElement<double> &E,SLinearWeights &W[],int CardinalCheck=2)
   {
      int _domain_index=-1,_codomain_index=-1;
      
      if(E.Cardinality()!=CardinalCheck){ return(_domain_index); }
      
      if(ArraySize(W)!=CardinalCheck){ return(_domain_index); }
      
      for(int c=0;c<CardinalCheck;c++)
      {
         double _e=0.0;
         //
         if(E.Get(c,_e))
         {
            _e*=W[c].m;
            _e+=(W[c].c*m_symbol.Point());
            
            E.Set(c,_e);
         }  
      }
            
      double _least_radius=DBL_MAX;
      for(int c=0;c<D.Cardinality();c++)
      {
         double _radius=0.0;
         
         m_element_a.Let();
         
         if(D.Get(c,m_element_a))
         {
            for(int cc=0;cc<E.Cardinality();cc++)
            {
               double _e=0.0,_d=0.0;
               if(E.Get(cc,_e) && m_element_a.Get(cc,_d))
               {
                  _radius+=pow(_e-_d,2.0);
               }  
            }
         }
         
         _radius=sqrt(_radius);
         
         if(_least_radius<_radius)
         {
            _least_radius=_radius;
            _domain_index=c;
         }
      }
      
      //
      
      for(int m=0;m<H.Morphisms();m++)
      {
         m_morphism_ab.Let();
         
         if(H.Get(m,m_morphism_ab))
         {
            if(m_morphism_ab.Domain()==_domain_index)
            {
               _codomain_index=m_morphism_ab.Codomain();
               break;
            }
         }
      }
      
      return(_codomain_index);
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CTrailingCT::SetElement_A(int Index,CElement<double> &E)
   {
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
   
      //'multi-multi-dimension' source data for domain A
      E.Cardinality(2);
                  
      E.Set(0,m_high.GetData(_x+Index)-m_high.GetData(_x+Index));
      E.Set(1,m_low.GetData(_x+Index)-m_low.GetData(_x+Index));
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CTrailingCT::SetElement_B(int Index,CElement<double> &E)
   {
      m_high.Refresh(-1);
      m_low.Refresh(-1);
      
      int _x=StartIndex();
      
      //'multi-dimension' source data for domain A
      E.Cardinality(2);
                  
      E.Set(0,m_high.GetData(_x+Index)-m_high.GetData(_x+Index+m_lag));
      E.Set(1,m_low.GetData(_x+Index)-m_low.GetData(_x+Index+m_lag));
   }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CTrailingCT::SetElement_C(int Index,CElement<int> &E)
   {
      //'single-dimension' image data for domain D
      int _value=(20*(Index+1))-120;
      E.Cardinality(1);E.Set(0,_value);
   }
//+------------------------------------------------------------------+
