pass generic class data field

 




//+------------------------------------------------------------------+

//|CLASS instrument                                                  |

//+------------------------------------------------------------------+

class instrument

  {

public:

   string            symbol;

   double            marginRequired;

   double            spread;

   double            csi;

   int               digits;

   double            stopLevel;

   double            lotSize;

   double            lotStep;

   double            lotMin;

   double            pointSize;

   double            tickValue;

   double            tickSize;

   string            descr;

   double            bid;

   double            swapLong;

   double            swapShort;

   string            swaptype;

   string            tradeAllowed;

   string            profitCalcMode;

   double            adx;

   double            adxr;

   double            atr;

   //--- Constructor

   void instrument()

     {}

   //--- Set Values  

void setValues(string Sy,string des)

     {

      symbol=Sy;

      marginRequired=MarketInfo(Sy,MODE_MARGINREQUIRED);

      spread=MarketInfo(symbol,MODE_SPREAD);

      digits=int(MarketInfo(Sy,MODE_DIGITS));

      stopLevel=MarketInfo(Sy,MODE_STOPLEVEL);

      lotSize=MarketInfo(Sy,MODE_LOTSIZE);

      lotStep=MarketInfo(Sy,MODE_LOTSTEP);

      lotMin=MarketInfo(Sy,MODE_MINLOT);

      pointSize=MarketInfo(Sy,MODE_POINT);

      tickValue=MarketInfo(Sy,MODE_TICKVALUE);

      tickSize=MarketInfo(Sy,MODE_TICKSIZE);

      descr=des;

      bid=MarketInfo(Sy,MODE_BID);

      swapLong=MarketInfo(Sy,MODE_SWAPLONG);

      swapShort=MarketInfo(Sy,MODE_SWAPSHORT);

      swaptype=InfoToStr(MarketInfo(Sy,MODE_SWAPTYPE),MODE_SWAPTYPE);

      tradeAllowed=InfoToStr(MarketInfo(Sy,MODE_TRADEALLOWED),MODE_TRADEALLOWED);

      profitCalcMode=InfoToStr(MarketInfo(Sy,MODE_PROFITCALCMODE),MODE_PROFITCALCMODE);

     }

   void calcADX(string Sy,ENUM_TIMEFRAMES timeFrame,int period)

     {

      adx=iADX(Sy,timeFrame,period,PRICE_CLOSE,0,1);

     }

   void calcADXR(string Sy,ENUM_TIMEFRAMES timeFrame,int period,int adxBefore,int mBars)

     {

      adxr=iCustom(Sy,timeFrame,"ADXR",period,adxBefore,mBars,3,1);

     }

   void calcATR(string Sy,ENUM_TIMEFRAMES timeFrame,int period)

     {

      atr=iATR(Sy,timeFrame,period,1);

     }

   void calcCSI(string Sy,ENUM_TIMEFRAMES timeFrame,int period,int adxBefore,int mBars)

     {

      csi=iCustom(Sy,timeFrame,"CSI",period,adxBefore,mBars,0,1);

      int debug=1;

     }



//+------------------------------------------------------------------+

//| sort by csi                                                               |

//+------------------------------------------------------------------+

void sortCSI(instrument *&Array[],int size,string mode,string field)

  {

   int currLocation;

   for(int j=0; j<size; j++)//current csi to the left sorted

     {

      currLocation=j;

      for(int i=j;i<size; i++)//ASC: csi to the right unsorted

        {

         if(mode=="ASC")

           {

            if(field=="CSI")

              {

               if((Array[i].csi<Array[j].csi) && (Array[i].csi<Array[currLocation].csi))

                  currLocation=i;//ASC:currLocation value to the right of leftmost sorted values                

              }

            else if(field=="SPREAD")

              {

               if((Array[i].spread<Array[j].spread) && (Array[i].spread<Array[currLocation].spread))

                  currLocation=i;//ASC:currLocation value to the right of leftmost sorted values              

              }

           }

         else if(mode=="DESC")

           {

            if(field=="CSI")

              {

               if((Array[i].csi>Array[j].csi) && (Array[i].csi>Array[currLocation].csi))

                  currLocation=i;//ASC:currLocation value to the right of leftmost sorted values                

              }

            else if(field=="SPREAD")

              {

               if((Array[i].spread>Array[j].spread) && (Array[i].spread>Array[currLocation].spread))

                  currLocation=i;//ASC:currLocation value to the right of leftmost sorted values              

              }

           }

        }

      instrument  *temp=Array[j];//ASC: value is currLocation of all right values - swop it!

      Array[j]=Array[currLocation];

      Array[currLocation]=temp;

     }

  }
 

I have a sort algorithm that sorts on class data fields I want to pass a generic pointer of the data field to the sort instead of making the decision inside the sort

Anyone know how to do this in mql4?

 
When you post code please use the SRC button! Please edit your post.
           General rules and best pratices of the Forum. - General - MQL5 programming forum
bapo101:

I have a sort algorithm that sorts on class data fields I want to pass a generic pointer of the data field to the sort instead of making the decision inside the sort

Anyone know how to do this in mql4?

  1. MT4/5 doesn't have pointers, so cant be done.
  2. Either go the CObject route where a int is passed to the overridden compare method.
  3. Or go my route, a custom comparator function. Sort multiple arrays - MQL4 and MetaTrader 4 - MQL4 programming forum
 
bapo101:

Anyone know how to do this in mql4?

I agree with whroeder1; there's no way of doing this for any arbitrary object in MQL.

It's possible in something like Javascript, because any object is just an associative array (nothing to do with "pointers"), and Object.x is equivalent to Object["x"]. Therefore, in Javascript, it's possible to write code such as the following:

// Sorts by a.high compared to b.high
var strSortByMember = "high";
arr.sort(function (a, b) {
  return a[strSortByMember] - b[strSortByMember];
});

But there's no MQL equivalent to that.

Like whroeder1, I'd also suggest a "custom comparator" function, but I'd propose quicksort rather than insertion-sort; it's faster on average for any general usage. Example attached.

Files:
Quicksort.mqh  7 kb
 
whroeder1:
When you post code please use the SRC button! Please edit your post.
           General rules and best pratices of the Forum. - General - MQL5 programming forum
  1. MT4/5 doesn't have pointers, so cant be done.
  2. Either go the CObject route where a int is passed to the overridden compare method.
  3. Or go my route, a custom comparator function. Sort multiple arrays - MQL4 and MetaTrader 4 - MQL4 programming forum

Nice link...thanks. I will adapt when have opportunity. re-post source - can't see how to but my question is answered

 
JC:

I agree with whroeder1; there's no way of doing this for any arbitrary object in MQL.

It's possible in something like Javascript, because any object is just an associative array (nothing to do with "pointers"), and Object.x is equivalent to Object["x"]. Therefore, in Javascript, it's possible to write code such as the following:

But there's no MQL equivalent to that.

Like whroeder1, I'd also suggest a "custom comparator" function, but I'd propose quicksort rather than insertion-sort; it's faster on average for any general usage. Example attached.


Your comments have been absorbed. The situation is clarified. Its a script and not time critical however I have archived the link you provided for future works.

Many thanks

 
JC:   but I'd propose quicksort rather than insertion-sort; it's faster on average for any general usage.

Your version of quicksort is terrible; it partitions down to 16 items and insertion-sorts below that. All good implementations that I know of, stop partitioning at 16 items, and performs one final insertion-sort.

If there are less than ~30 items then just insertion-sort will be quicker on MT4/5 where array accesses are 5-10x slower than other languages. This is why I only provided IS and not my complete (but untested) QS, because most lists will not exceed that limit.

 
whroeder1:

Your version of quicksort is terrible

If we're going to get personal, I quickly adapted it from MarcoNeri's old post some time ago in the thread where you and he/she were exchanging comments. His/her code - of which mine is just a templated adaptation - may be "terrible", but I also did a benchmark which said that, despite being terrible, it still outperformed your insertion sort in any plausible scenario. Attached.

(Underlying JIT compilation of the MT4 platform may have changed in the interim, affecting the results.)

 

I think the answer you're looking for is using the standard library collections. In order to implement pointer sorting you have to derive a class from CObject and override the compare method. Then you add the pointer to the collection object and sort as needed. 

//+------------------------------------------------------------------+
//|                                        instrument_class_sort.mq4 |
//|                                      Copyright 2017, nicholishen |
//|                         https://www.forexfactory.com/nicholishen |
//+------------------------------------------------------------------+
#property copyright "Copyright 2017, nicholishen"
#property link      "https://www.forexfactory.com/nicholishen"
#property version   "1.00"
#property strict
#include <Arrays\List.mqh>

#define SORT_SPREAD 0
#define SORT_NAME 1


class Instrument : public CObject
{
public:
   string            symbol;
   double            marginRequired;
   double            spread;
   double            csi;
   int               digits;
   double            stopLevel;
   double            lotSize;
   double            lotStep;
   double            lotMin;
   double            pointSize;
   double            tickValue;
   double            tickSize;
   string            descr;
   double            bid;
   double            swapLong;
   double            swapShort;
   string            swaptype;
   string            tradeAllowed;
   string            profitCalcMode;
   double            adx;
   double            adxr;
   double            atr;

   void Instrument(string Sy,string des=""){setValues(Sy,des);}

   void setValues(string Sy,string des="")
   {
      symbol=Sy;
      marginRequired=MarketInfo(Sy,MODE_MARGINREQUIRED);
      spread=MarketInfo(symbol,MODE_SPREAD);
      digits=int(MarketInfo(Sy,MODE_DIGITS));
      stopLevel=MarketInfo(Sy,MODE_STOPLEVEL);
      lotSize=MarketInfo(Sy,MODE_LOTSIZE);
      lotStep=MarketInfo(Sy,MODE_LOTSTEP);
      lotMin=MarketInfo(Sy,MODE_MINLOT);
      pointSize=MarketInfo(Sy,MODE_POINT);
      tickValue=MarketInfo(Sy,MODE_TICKVALUE);
      tickSize=MarketInfo(Sy,MODE_TICKSIZE);
      descr=des;
      bid=MarketInfo(Sy,MODE_BID);
      swapLong=MarketInfo(Sy,MODE_SWAPLONG);
      swapShort=MarketInfo(Sy,MODE_SWAPSHORT);
      //swaptype=InfoToStr(MarketInfo(Sy,MODE_SWAPTYPE),MODE_SWAPTYPE);
      //tradeAllowed=InfoToStr(MarketInfo(Sy,MODE_TRADEALLOWED),MODE_TRADEALLOWED);
      //profitCalcMode=InfoToStr(MarketInfo(Sy,MODE_PROFITCALCMODE),MODE_PROFITCALCMODE);
   }
   void calcADX(string Sy,ENUM_TIMEFRAMES timeFrame,int period)
     {
      adx=iADX(Sy,timeFrame,period,PRICE_CLOSE,0,1);
     }
   void calcADXR(string Sy,ENUM_TIMEFRAMES timeFrame,int period,int adxBefore,int mBars)
     {
      adxr=iCustom(Sy,timeFrame,"ADXR",period,adxBefore,mBars,3,1);
     }
   void calcATR(string Sy,ENUM_TIMEFRAMES timeFrame,int period)
     {
      atr=iATR(Sy,timeFrame,period,1);
     }
   void calcCSI(string Sy,ENUM_TIMEFRAMES timeFrame,int period,int adxBefore,int mBars)
     {
      csi=iCustom(Sy,timeFrame,"CSI",period,adxBefore,mBars,0,1);
      int debug=1;
     }
     
     
   int Compare(const CObject *node,const int mode=0)const override
   {
      Instrument *other = (Instrument*)node;
      if(mode==SORT_NAME)
      {
         if(this.symbol>other.symbol) return 1;
         if(this.symbol<other.symbol) return -1;
      }
      if(mode==SORT_SPREAD)
      {
         if(this.spread>other.spread) return 1;
         if(this.spread<other.spread) return -1;
      }
      return 0;//same or sorting not implemented.
   }
};



void OnStart()
{
//---
   CList list;
   for(int i=0;i<SymbolsTotal(false);i++)
      list.Add(new Instrument(SymbolName(i,false)));
 
   list.Sort(SORT_SPREAD);
   
   for(Instrument *i=list.GetFirstNode();i!=NULL;i=i.Next())
      Print(i.symbol," has a spread of ",i.spread); 
}
//+------------------------------------------------------------------+
 

I was hoping to convert to an indicator for use on smaller time frames ... after initial loading of indicator I think it would be a relatively quick update on a time frame rather than a tick basis. 

CList implementation below is much easier to manipulate

Many thanks.

 
#include <Arrays\List.mqh>
#include <stderror.mqh>
#include <stdlib.mqh>
#define SORT_SPREAD 0
#define SORT_NAME 1
#define SORT_CSI 2
CList list;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES tfEnum[]={PERIOD_M1,PERIOD_M5,PERIOD_M15,PERIOD_M30,PERIOD_H1,PERIOD_H4,PERIOD_D1,PERIOD_W1,PERIOD_MN1};
//int sizePeriods=ArraySize(tfEnum);
extern int IndPeriod=14;//Period
extern int adxAgo=14;//Period
extern ENUM_TIMEFRAMES tf=PERIOD_D1;
int TotalSymbols;
//int totalWatchSymbols;
string Symbols[1000];
string descr[1000];
int fontSize=8;
int fontSpacing=14;
string fontType="Windings";//Times New Roman";
string comment=NULL;
color clrVar1=clrDarkGray;
color clrVar2=clrLemonChiffon;
color clrHeader=clrAzure;
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
class instrument : public CObject
  {
public:
   string            symbol;
   double            marginRequired;
   double            spread;
   double            csi;
   int               digits;
   double            stopLevel;
   double            lotSize;
   double            lotStep;
   double            lotMin;
   double            pointSize;
   double            tickValue;
   double            tickSize;
   string            descr;
   double            bid;
   double            swapLong;
   double            swapShort;
   string            swaptype;
   string            tradeAllowed;
   string            profitCalcMode;
   double            adx;
   double            adxr;
   double            atr;

   void instrument(string Sy="",string des="",ENUM_TIMEFRAMES timeFrame=PERIOD_D1,int period=14,int adxBefore=14,int mBars=2000)
     {
      symbol=Sy;
      marginRequired=MarketInfo(Sy,MODE_MARGINREQUIRED);
      spread=MarketInfo(symbol,MODE_SPREAD);
      digits=int(MarketInfo(Sy,MODE_DIGITS));
      stopLevel=MarketInfo(Sy,MODE_STOPLEVEL);
      lotSize=MarketInfo(Sy,MODE_LOTSIZE);
      lotStep=MarketInfo(Sy,MODE_LOTSTEP);
      lotMin=MarketInfo(Sy,MODE_MINLOT);
      pointSize=MarketInfo(Sy,MODE_POINT);
      tickValue=MarketInfo(Sy,MODE_TICKVALUE);
      tickSize=MarketInfo(Sy,MODE_TICKSIZE);
      descr=des;
      bid=MarketInfo(Sy,MODE_BID);
      swapLong=MarketInfo(Sy,MODE_SWAPLONG);
      swapShort=MarketInfo(Sy,MODE_SWAPSHORT);
      swaptype=InfoToStr(MarketInfo(Sy,MODE_SWAPTYPE),MODE_SWAPTYPE);
      tradeAllowed=InfoToStr(MarketInfo(Sy,MODE_TRADEALLOWED),MODE_TRADEALLOWED);
      profitCalcMode=InfoToStr(MarketInfo(Sy,MODE_PROFITCALCMODE),MODE_PROFITCALCMODE);
      adx=iADX(Sy,timeFrame,period,PRICE_CLOSE,0,1);
      adxr=iCustom(Sy,timeFrame,"ADXR",period,adxBefore,mBars,3,1);
      atr=iATR(Sy,timeFrame,period,1);
      csi=iCustom(Sy,timeFrame,"CSI",period,adxBefore,mBars,0,1);
      double normaliseTickNotEqualPoint = MarketInfo(symbol, MODE_POINT) / MarketInfo(symbol, MODE_TICKSIZE);
      double priceOneLotThisStopDistance=spread * MarketInfo(symbol,MODE_TICKVALUE) * normaliseTickNotEqualPoint;
     }

   int Compare(const CObject *node,const int mode=0)const override
     {
      instrument *other=(instrument*)node;
      if(mode==SORT_NAME)
        {
         if(this.symbol>other.symbol) return 1;
         if(this.symbol<other.symbol) return -1;
        }
      if(mode==SORT_SPREAD)
        {
         if(this.spread>other.spread) return 1;
         if(this.spread<other.spread) return -1;
        }
      if(mode==SORT_CSI)
        {
         if(this.csi>other.csi) return 1;
         if(this.csi<other.csi) return -1;
        }
      return 0;//same or sorting not implemented.
     }
  };
//+------------------------------------------------------------------+
//|OnStart                                                           |
//+------------------------------------------------------------------+
void OnStart()
  {
//set and count the symbols data
   TotalSymbols=FindSymbols();
   ArrayResize(Symbols,TotalSymbols);
   ArrayResize(descr,TotalSymbols);
   string var="variable";

//set Headers 
   int posY=0;
   displayHeaders(var,posY);
//---
   for(int j=0; j<TotalSymbols; j++)//all Instruments
     {
      if(!IsSymbolInMarketWatch(Symbols[j]))
         continue;
      //list.Add(new instrument(SymbolName(j,false)));
      list.Add(new instrument(Symbols[j],descr[j]));
     }
   list.Sort(SORT_CSI);
//Display sorted symbols data
   posY++;
   displaySymbolsData(var,posY);
  }