기고글 토론 "MQL5 Cookbook: 빠른 데이터 액세스를 위한 연관 배열 또는 사전 구현" - 페이지 3

 
외환 금 기술 분석 거래소, 그룹 번호는 375124107, 그룹 확인 77, 협조 해 주셔서 감사합니다!
 

EA에서 이 클래스를 전략의 컨테이너로 사용하기로 결정했습니다 (StrategyGUID, Strategy). 여기서 StrategyGUID는 ulong 유형의 식별자이고 Strategy는 CObject에서 상속 된 클래스를 기반으로 생성 된 전략입니다.

따라서 활성 전략의 책인 CDictionary StrategyBook을 포함하여 필요한 변수를 선언하고, EA의 OnInit() 함수에서 고유 GUID를 할당하는 등 다양한 매개 변수를 시작하는 필요한 전략 Strategy01, Strategy02를 만듭니다. OnInit()의 맨 마지막에 다음 코드를 호출하여 전략을 StrategyBook에 저장하기로 결정했습니다.

StrategyBook.AddObject(Strategy01.strGUID,Strategy01);

StrategyBook.AddObject(Strategy02.strGUID,Strategy02); 

그런데 두 줄 모두에서 "StrategyXX - 매개변수 변환이 허용되지 않습니다"라는 오류가 발생합니다.

C#에 대한 제 경험에 따르면 모든 것이 올바르게 수행됩니다. 하지만 MQL5에서는 이 오류가 발생합니다.

무엇과 관련이 있을까요?

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

EA에서 이 클래스를 전략의 컨테이너로 사용하기로 결정했습니다 (StrategyGUID, Strategy). 여기서 StrategyGUID는 ulong 유형의 식별자이고 Strategy는 CObject에서 상속 된 클래스를 기반으로 생성 된 전략입니다.

따라서 활성 전략의 책인 CDictionary StrategyBook을 포함하여 필요한 변수를 선언하고, EA의 OnInit() 함수에서 고유 GUID를 할당하는 등 다양한 매개 변수를 시작하는 필요한 전략 Strategy01, Strategy02를 만듭니다. OnInit()의 맨 마지막에 다음 코드를 호출하여 전략을 StrategyBook에 저장하기로 결정했습니다.

StrategyBook.AddObject(Strategy01.strGUID,Strategy01);

StrategyBook.AddObject(Strategy02.strGUID,Strategy02); 

그런데 두 줄 모두에서 "StrategyXX - 매개변수 변환이 허용되지 않습니다"라는 오류가 발생합니다.

C#에 대한 제 경험에 따르면 모든 것이 올바르게 수행됩니다. 하지만 MQL5에서는 이 오류가 발생합니다.

무엇과 관련이 있을까요?

몇 가지 이유가 있을 수 있습니다. 대부분 유형 비호환성 또는 포인터를 사용한 잘못된 작업일 가능성이 큽니다. 또한 템플릿 메소드 작업의 특성을 배제 할 수 없습니다 (고유 한 뉘앙스도 있습니다).

일반적으로 기성품 거래 엔진을 사용하는 것이 더 좋으며 많은 시간과 신경을 절약 할 수 있습니다 : https://www.mql5.com/ko/articles/2166.

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

네, 결국 그렇게 하기로 결정했습니다.

 
MetaQuotes Software Corp.:

새 문서 MQL5 쿡북: 빠른 데이터 액세스를 위한 연관 배열 또는 사전 구현이 게시되었습니다:

작성자: Vasiliy Sokolov

모든 노력에 감사하지만 코드 예제 중 어떤 것도 작동하는 것 같지 않습니다.

사전 딕셔너리인 것 같은데 CDictionary 딕 셔너리여야 합니다;

간단한 작동 예제는 어떻습니까?

[삭제]  

새로운 MT4(빌드 1080, 2017년 5월 12일)의 경우 컴파일 중에 이러한 오류가 발생하여 실행을 방해합니다:

'm_array' - 객체를 포함하는 구조는 허용되지 않음 Dictionary.mqh 303 25

'DoubleValue'를 'ULongValue'로 형변환할 수 없음 Dictionary.mqh 252 14

 

안녕하세요,

이전에 다른 사람이 말했듯이 컴파일 가능한 예제는 없습니다.

러시아어로 된 주석이 있는 파일만 있습니다.

 
안녕하세요 바실리,

유용한 글을 작성해 주셔서 감사합니다. MQL5 빌드 2063으로 dictionary.mqh를 다운로드한 후 컴파일할 때 다음과 같은 오류가 발생합니다:

'GetKey' - 함수가 이미 정의되어 있고 유형이 다릅니다.
'Compress' - 함수가 이미 정의되어 있고 유형이 다릅니다.

왜 이런 오류가 발생하나요?

안부 인사
Gerik
 

바실리의 라이브러리를 성공적으로 사용하고 있어 감사하게 생각하고 있습니다. 정말 큰 도움이 되었어요!

저도 컴파일러 오류가 몇 개 있었는데 고칠 수 있었던 기억이 납니다. 하지만 어떤 오류였는지, 제가 무엇을 했는지는 정확히 기억나지 않습니다.

그리고 저는 MQL5 코드의 형식에 매우 짜증이 나고 항상 모든 것을 최신 C++ 형식(적절한 들여쓰기, 불필요한 대괄호 피하기, 주석 혼잡 없음 등)으로 다시 포맷하기 때문에 코드의 실제 변경 사항이 무엇인지 말하기는 불가능합니다. 제가 기억하는 것은 변경 사항이 작았다는 것뿐입니다.

적절한 형식의 라이브러리를 사용하고 싶으시다면 여기 있습니다:

(탭을 사용하고 있기 때문에 여기서는 서식이 깨진 것처럼 보이지만 메타에디터에서는 그렇지 않습니다!).

//+------------------------------------------------------------------+
//|CDictionary.mqh |
//|저작권 2015, 바실리 소콜로프. |
//| 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);  // 이 키값 쌍은 다음과 같습니다.
                        }
                        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();
}

 

요소를 삭제하고 마지막 요소로 이동하려고 할 때 버그를 발견한 것 같습니다:

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(); // CDictionary::GetLastNode(void) -> 반환 m_last_kvp.object; -> m_last_kvp가 잘못된 포인터가 됩니다!
Print(lastWord.GetWord());

CDictionary.mqh에 오류가 발생합니다:

'Dictionary.mqh'에서잘못된 포인터 액세스 (463,9)

누구든지 이것을 확인할 수 있습니까? 수정하는 방법에 대한 아이디어가 있습니까?