Discussão do artigo "Guia Prático MQL5: Implementando um Array Associativo ou um Dicionário para Acesso Rápido ao Dados" - página 3

 
Forex gold technical analysis exchanges, o número do grupo é 375124107, na verificação do grupo 77, obrigado pela cooperação!
 

Decidi usar essa classe em meu EA como um contêiner de estratégias do tipo (StrategyGUID, Strategy), em que StrategyGUID é um identificador do tipo ulong; Strategy é uma estratégia criada com base em uma classe com herança de CObject.

Dessa forma, declaro as variáveis necessárias, incluindo o CDictionary StrategyBook - o livro de estratégias ativas; crio as estratégias necessárias Strategy01, Strategy02, que, na função OnInit() do EA, iniciam vários parâmetros, inclusive atribuindo-lhes GUIDs exclusivos. No final de OnInit(), decido salvar as estratégias no StrategyBook chamando o código

StrategyBook.AddObject(Strategy01.strGUID,Strategy01);

StrategyBook.AddObject(Strategy02.strGUID,Strategy02); 

E então recebo o erro "StrategyXX - parameter conversion not allowed" em ambas as linhas.

Com base em minha experiência com C#, tudo foi feito corretamente. Mas, na MQL5, recebo esse erro.

A que isso pode estar relacionado?

 
Сергей Лебедев:

Decidi usar essa classe em meu EA como um contêiner de estratégias do tipo (StrategyGUID, Strategy), em que StrategyGUID é um identificador do tipo ulong; Strategy é uma estratégia criada com base em uma classe com herança de CObject.

Dessa forma, declaro as variáveis necessárias, incluindo o CDictionary StrategyBook - o livro de estratégias ativas; crio as estratégias necessárias Strategy01, Strategy02, que, na função OnInit() do EA, iniciam vários parâmetros, inclusive atribuindo-lhes GUIDs exclusivos. No final de OnInit(), decido salvar as estratégias no StrategyBook chamando o código

StrategyBook.AddObject(Strategy01.strGUID,Strategy01);

StrategyBook.AddObject(Strategy02.strGUID,Strategy02); 

E então recebo o erro "StrategyXX - parameter conversion not allowed" em ambas as linhas.

Com base em minha experiência com C#, tudo foi feito corretamente. Mas, na MQL5, recebo esse erro.

A que isso pode estar relacionado?

Pode haver vários motivos. O mais provável é que haja incompatibilidade de tipos ou trabalho incorreto com ponteiros. Além disso, não podemos excluir as peculiaridades do trabalho com métodos de modelo (eles também têm suas próprias nuances).

Em geral, é melhor usar um mecanismo de negociação pronto, pois você economizará muito tempo e nervosismo: https://www.mql5.com/pt/articles/2166.

Универсальный торговый эксперт: Торговые режимы стратегий (Часть 1)
Универсальный торговый эксперт: Торговые режимы стратегий (Часть 1)
  • 2016.01.07
  • Vasiliy Sokolov
  • www.mql5.com
Каждый экспертописатель, независимо от уровня своей подготовки, ежедневно сталкивается с одними и теми же торговыми задачами и алгоритмическими проблемами, которые так или иначе приходится решать для организации надежного торгового процесса. Данная статья описывает возможности торгового движка CStrategy, способного взять на себя решение этих задач и предоставить пользователю удобные механизмы для описания своей торговой идеи.
 

Sim, foi isso que acabei decidindo fazer.

 

Obrigado por todo o esforço, mas não consigo fazer com que nenhum dos exemplos de código funcione.

Parece que Dictionary dict; deveria ser CDictionary dict;

Que tal um exemplo simples que funcione?

[Excluído]  

Em relação ao novo MT4 (Build 1080, 12 de maio de 2017), esses erros ocorrem durante a compilação e impedem a execução:

'm_array' - estruturas contendo objetos não são permitidas Dictionary.mqh 303 25

não é possível converter 'DoubleValue' em 'ULongValue' Dictionary.mqh 252 14

 

Olá,

Como já foi dito por outra pessoa, não há nenhum exemplo compilável.

Apenas um arquivo com comentários em russo.

 
Olá, Vasily,

obrigado por seu artigo útil. Ao fazer o download e compilar o dictionary.mqh com a MQL5 build 2063, recebo os seguintes erros:

'GetKey' - a função já foi definida e tem um tipo diferente
'Compress' - função já definida e de tipo diferente

Por que isso acontece?

Atenciosamente
Gerik
 

Estou usando a biblioteca de Vasiliy com sucesso. É de grande ajuda!

Lembro-me de que também tive alguns erros de compilador e consegui corrigi-los. No entanto, não sei dizer quais eram e o que eu fiz.

E como fico extremamente irritado com a formatação do código MQL5 e sempre reformato tudo para um formato C++ moderno (recuo adequado, evitando colchetes desnecessários, sem confusão de comentários e assim por diante), é impossível dizer qual foi a mudança real no código. Tudo o que me lembro é que as alterações foram pequenas.

Caso você queira usar a biblioteca formatada corretamente, aqui está ela:

(Observe que estou usando tabulações, portanto, a formatação parece estar quebrada aqui, mas no MetaEditor não está!)

//+------------------------------------------------------------------+
//|CDictionary.mqh
//|Copyright 2015, Vasiliy Sokolov. |
//| http://www.mql5.com
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link          "http://www.mql5.com"

#include  <Object.mqh>
#include  <Arrays\List.mqh>

#define  FOREACH_DICT(dict) for (CObject* node = (dict).GetFirstNode(); node != NULL; node = (dict).GetNextNode())

class KeyValuePair : public CObject
{
        private:
                string                          m_string_key;
                double                          m_double_key;
                ulong                           m_ulong_key;
                ulong                           m_hash;
                bool                            m_free_mode;
        public:
                CObject*                        object;
                KeyValuePair*           next_kvp;
                KeyValuePair*           prev_kvp;
                template <typename T>
                void                            KeyValuePair(T key, ulong hash, CObject *obj);
                                                        ~KeyValuePair();
                template <typename T>
                bool                            EqualKey(T key);
                template <typename T>
                void                            GetKey(T& gkey);
                ulong                           GetHash()                                       { return m_hash; }
                void                            FreeMode(bool free_mode)        { m_free_mode = free_mode; }
                bool                            FreeMode(void)                          { return m_free_mode; }
};

template <typename T>
void KeyValuePair::KeyValuePair(T key, ulong hash, CObject *obj)
{
        m_hash = hash;
        string name = typename(key);
        if (name == "string")
                m_string_key = (string)key;
        else if
                (name == "double" || name == "float")
        
        m_double_key = (double)key;
        else
                m_ulong_key=(ulong)key;
        
        object = obj;
        m_free_mode = true;
}

template <typename T>
void KeyValuePair::GetKey(T& gkey)
{
        string name = typename(gkey);
        if (name  ==  "string")
                gkey = (T)m_string_key;
        else if (name == "double" || name == "float")
                gkey = (T)m_double_key;
        else
                gkey = (T)m_ulong_key;
}

KeyValuePair::~KeyValuePair()
{
        if (m_free_mode)
                delete object;
}

template <typename T>
bool KeyValuePair::EqualKey(T key)
{
        string name=typename(key);
        if (name == "string")
                return m_string_key  ==  (string)key;
        if (name == "double" || name == "float")
                return m_double_key  ==  (double)key;
        else
                return m_ulong_key  ==  (ulong)key;
}

class CDictionary : public CObject
{
        private:
                int                                     m_array_size;
                int                                     m_total;
                bool                            m_free_mode;
                bool                            m_auto_free;
                int                                     m_index;
                ulong                           m_hash;
                CList*                          m_array[];
                union casting_struct
                {
                        double d_value;
                        ulong  l_value;
                } casting;
                
                KeyValuePair*           m_first_kvp;
                KeyValuePair*           m_current_kvp;
                KeyValuePair*           m_last_kvp;
        
                ulong                           Adler32(string line);
                int                                     GetIndexByHash(ulong hash);
                template <typename T>
                ulong                           GetHashByKey(T key);
                void                            Resize();
                int                                     FindNextSimpleNumber(int number);
                int                                     FindNextLevel();
                void                            Init(int capacity);
        
        public:
                                                        CDictionary();
                                                        CDictionary(int capacity);
                                                        ~CDictionary();
                void                            Compress(void);

                int Total(void)         { return m_total; }

                template <typename T>
                CObject*                        GetObjectByKey(T key);
                template <typename T>
                bool                            AddObject(T key, CObject *value);
                template <typename T>
                bool                            DeleteObjectByKey(T key);
                template <typename T>
                bool                            ContainsKey(T key);
                template <typename T>
                void                            GetCurrentKey(T &key);
                bool                            DeleteCurrentNode(void);
                bool                            FreeMode(void)                                          { return(m_free_mode); }
                void                            FreeMode(bool free_mode);
                void                            AutoFreeMemory(bool autoFree)           { m_auto_free = autoFree; }
                void                            Clear();
        
                CObject*                        GetNextNode(void);
                CObject*                        GetPrevNode(void);
                CObject*                        GetCurrentNode(void);
                CObject*                        GetFirstNode(void);
                CObject*                        GetLastNode(void);
};

CDictionary::CDictionary()
{
        Init(3);
        m_free_mode = true;
        m_auto_free = true;
}

CDictionary::CDictionary(int capacity)
{
        if (capacity < 3)
                Init(3);
        else
                Init(capacity);

        m_free_mode = true;
        m_auto_free = true;
}

CDictionary::~CDictionary()
{
        Clear();
}

void CDictionary::FreeMode(bool free_mode)
{
        if (free_mode == m_free_mode)
                return;

        m_free_mode = free_mode;

        for (int i=0; i < ArraySize(m_array); i++)
        {
                CList *list = m_array[i];
                if (CheckPointer(list) == POINTER_INVALID)
                        continue;

                for (KeyValuePair* kvp = list.GetFirstNode(); kvp != NULL; kvp = list.GetNextNode())
                        kvp.FreeMode(m_free_mode);
        }
}

void CDictionary::Init(int capacity)
{
        m_array_size = ArrayResize(m_array,capacity);
        m_index = 0;
        m_hash  = 0;
        m_total = 0;
}

int CDictionary::FindNextLevel()
{
        double value=4;
        for (int i=2; i <= 31; i++)
        {
                value = MathPow(2.0,(double)i);
                if (value > m_total)
                        return (int)value;
        }
        
        return (int)value;
}

ulong CDictionary::Adler32(string line)
  {
        ulong s1 = 1;
        ulong s2 = 0;
        uint buflength = StringLen(line);
        uchar char_array[];
        ArrayResize(char_array, buflength, 0);
        StringToCharArray(line, char_array, 0, -1, CP_ACP);
        for (uint n=0; n < buflength; n++)
        {
                s1 = (s1 + char_array[n]) % 65521;
                s2 = (s2 + s1) % 65521;
        }
        return ((s2  <<  16) + s1);
}

template <typename T>
ulong CDictionary::GetHashByKey(T key)
{
        ulong ukey = 0;
        string name = typename(key);
        if (name == "string")
                return Adler32((string)key);
        if (name == "double" || name == "float")
        {
                casting.d_value = (double)key;
                ukey = casting.l_value;
        }
        else
                ukey = (ulong)key;
        return ukey;
}

template <typename T>
void CDictionary::GetCurrentKey(T &key)
{
        m_current_kvp.GetKey(key);
}

int CDictionary::GetIndexByHash(ulong key)
{
        return (int)(key % m_array_size);
}

void CDictionary::Clear(void)
{
        int size = ArraySize(m_array);
        for (int i=0; i < size; i++)
        {
                if (CheckPointer(m_array[i]) != POINTER_INVALID)
                {
                        m_array[i].FreeMode(true);
                        delete m_array[i];
                }
        }
        ArrayFree(m_array);
        if (m_auto_free)
                Init(3);
        else
                Init(size);
                
        m_first_kvp = m_last_kvp = m_current_kvp = NULL;
  }

void CDictionary::Resize(void)
  {
        int level = FindNextLevel();
        int n = level;
        CList* temp_array[];
        ArrayCopy(temp_array, m_array);
        ArrayFree(m_array);
        m_array_size = ArrayResize(m_array,n);
        int total = ArraySize(temp_array);
        KeyValuePair* kv = NULL;
        
        for (int i=0; i < total; i++)
        {
                if (temp_array[i] == NULL)
                        continue;

                CList* list = temp_array[i];
                int count = list.Total();
                list.FreeMode(false);
                kv = list.GetFirstNode();

                while (kv != NULL)
                {
                        int index = GetIndexByHash(kv.GetHash());
                        if (CheckPointer(m_array[index]) == POINTER_INVALID)
                        {
                                m_array[index] = new CList();
                                m_array[index].FreeMode(true);  // Элементы KeyValuePair удаляются всегда
                        }
                        list.DetachCurrent();
                        m_array[index].Add(kv);
                        kv = list.GetCurrentNode();
                }
                delete list;
        }
        int size = ArraySize(temp_array);
        ArrayFree(temp_array);
}

void CDictionary::Compress(void)
{
        if (!m_auto_free)
                return;
        
        double koeff = m_array_size / (double)(m_total+1);
        if (koeff < 2.0 || m_total <= 4)
                return;

        Resize();
}

template <typename T>
CObject* CDictionary::GetObjectByKey(T key)
{
        if (!ContainsKey(key))
                return NULL;
        CObject *obj = m_current_kvp.object;
        return obj;
}

template <typename T>
bool CDictionary::ContainsKey(T key)
{
        m_hash = GetHashByKey(key);
        m_index = GetIndexByHash(m_hash);
        
        if (CheckPointer(m_array[m_index]) == POINTER_INVALID)
                return false;
        
        CList* list = m_array[m_index];
        
        KeyValuePair* current_kvp = list.GetCurrentNode();
        
        if (current_kvp  ==  NULL)
                return false;
        
        if (current_kvp.EqualKey(key))
        {
                m_current_kvp = current_kvp;
                return true;
        }
        
        current_kvp = list.GetFirstNode();
        while (true)
        {
                if (current_kvp.EqualKey(key))
                {
                        m_current_kvp = current_kvp;
                        return true;
                }
                current_kvp = list.GetNextNode();
                if (current_kvp == NULL)
                        return false;
        }
        return false;
  }

template <typename T>
bool CDictionary::AddObject(T key, CObject *value)
{
        if (ContainsKey(key))
                return false;
        
        if (m_total == m_array_size)
        {
                Resize();
                ContainsKey(key);
        }
        
        if (CheckPointer(m_array[m_index]) == POINTER_INVALID)
        {
                m_array[m_index] = new CList();
                m_array[m_index].FreeMode(true);
        }
        
        KeyValuePair *kv = new KeyValuePair(key,m_hash,value);
        kv.FreeMode(m_free_mode);
        
        if (m_array[m_index].Add(kv) != -1)
                m_total++;
        
        if (CheckPointer(m_current_kvp) == POINTER_INVALID)
        {
                m_first_kvp = kv;
                m_current_kvp = kv;
                m_last_kvp = kv;
        }
        else
        {
                while (m_current_kvp.next_kvp != NULL)
                        m_current_kvp = m_current_kvp.next_kvp;
                        
                m_current_kvp.next_kvp = kv;
                kv.prev_kvp = m_current_kvp;
                m_current_kvp = kv;
                m_last_kvp = kv;
        }
        return true;
}


CObject* CDictionary::GetCurrentNode(void)
{
        if (m_current_kvp == NULL)
                return NULL;

        return m_current_kvp.object;
}

CObject* CDictionary:: GetPrevNode(void)
{
        if (m_current_kvp == NULL)
                return NULL;

        if (m_current_kvp.prev_kvp == NULL)
                return NULL;

        KeyValuePair *kvp = m_current_kvp.prev_kvp;
        m_current_kvp = kvp;

        return kvp.object;
}

CObject* CDictionary::GetNextNode(void)
{
        if (m_current_kvp == NULL)
                return NULL;
        
        if (m_current_kvp.next_kvp == NULL)
                return NULL;
        
        m_current_kvp = m_current_kvp.next_kvp;

        return m_current_kvp.object;
}

CObject* CDictionary::GetFirstNode(void)
{
        if (m_first_kvp == NULL)
                return NULL;

        m_current_kvp = m_first_kvp;
        return m_first_kvp.object;
}

CObject *CDictionary::GetLastNode(void)
{
        if (m_last_kvp == NULL)
                return NULL;

        m_current_kvp = m_last_kvp;
        return m_last_kvp.object;
}

bool CDictionary::DeleteCurrentNode(void)
{
        if (m_current_kvp == NULL)
                return false;

        KeyValuePair* p_kvp = m_current_kvp.prev_kvp;
        KeyValuePair* n_kvp = m_current_kvp.next_kvp;

        if (CheckPointer(p_kvp) != POINTER_INVALID)
                p_kvp.next_kvp = n_kvp;

        if (CheckPointer(n_kvp) != POINTER_INVALID)
                n_kvp.prev_kvp = p_kvp;

        m_array[m_index].FreeMode(m_free_mode);
        bool res = m_array[m_index].DeleteCurrent();

        if (res)
        {
                m_total--;
                Compress();
        }
        return res;
}

template <typename T>
bool CDictionary::DeleteObjectByKey(T key)
{
        if (!ContainsKey(key))
                return false;
        return DeleteCurrentNode();
}

 

Acho que encontrei um erro ao excluir um elemento e tentar chegar ao último elemento:

class CWord : CObject
{
        string m_Word;

        public:
                CWord(string word) : m_Word(word) {}
                ~CWord() {}
                
                string GetWord() { return m_Word; }
};
CDictionary* testDict = new CDictionary(10);

testDict.AddObject(0, (CObject*)new CWord("A"));
testDict.AddObject(100, (CObject*)new CWord("A"));
testDict.AddObject(200, (CObject*)new CWord("B"));
testDict.AddObject(300, (CObject*)new CWord("C"));

CWord* lastWord = (CWord*)testDict.GetLastNode();
Print(lastWord.GetWord());

CWord* firstWord = (CWord*)testDict.GetFirstNode();
Print(firstWord.GetWord());

testDict.DeleteCurrentNode();

lastWord = testDict.GetLastNode(); // resultará em um ponteiro inválido em CDictionary::GetLastNode(void) -> return m_last_kvp.object; -> m_last_kvp é um ponteiro inválido!
Print(lastWord.GetWord());

O erro no CDictionary.mqh será:

acesso deponteiro inválido em 'Dictionary.mqh' (463,9)

Alguém pode confirmar isso? Alguma ideia de como consertar?