고문 프로젝트 - 페이지 4

 
Vitaly Muzichenko :

저도 그렇지만 저는 오래전에 한 번도 본 적 없는 곳에서 코드를 압축해야 한다는 결론에 이르렀습니다.

포함된 사용자 정의 코드를 분산시키면 또 다른 골칫거리가 생깁니다 . 파일을 다른 터미널로 드래그 하거나 공유하려면 하나의 파일이 아니라 여러 파일을 드래그해야 합니다. 물론 내포물을 모든 단말로 옮길 수도 있지만, 하나의 단말에서 수정하거나 추가했다면 모두 새 단말로 교체해야 한다.

Expert Advisors와 지표는 너무 작아서 프로그램의 본체에서 무언가를 옮기는 것은 의미가 없습니다. 또는 오히려 작지 않고 단일 파일입니다. 이것은 클래스와 포함 없이는 할 수 없는 10,000페이지의 사이트가 아닙니다. 게다가, 이제 구조가 있고 100% 효율적인 간결한 코드를 작성하기에 충분합니다.

자, 우리는 도착했습니다 .... 폴더에 대한 심볼릭 링크에 대해 알고 있습니까? http://skesov.ru/sozdanie-simvolnoy-ssyilki-dlya-papki/

한 폴더에 모든 라이브러리가 있고 여러 터미널에 수십 개가 있습니다. mql*\includes 폴더에는 이 실제 폴더에 대한 심볼릭 링크가 있습니다. 아무것도 들고 다닐 필요가 없습니다.

저장소도 적극적으로 사용하고 있는데, 거기에 중요한 것은 모두 보관해 두면 5초 만에 다른 단말기에 다운로드할 수 있습니다. 그러나 어느 쪽이든 기호 링크가 더 편리하고 항상 전체 동기화입니다.

Создание символьной ссылки для папки в Windows 8.1, 8, 7, Vista
Создание символьной ссылки для папки в Windows 8.1, 8, 7, Vista
  • 2013.07.24
  • skesov.ru
Доброго времени суток! Сегодня рассмотрим интересную тему под названием «Символьные ссылки». Вариантов использования данного инструмента не так уж много. К примеру, если вы используете часть оперативной памяти как RAM-диск, можно перенести какую-либо игру или её часть (скажем папки с графикой) и создать символьную ссылку. Это значительно...
 
Alexey Navoykov :
MQL 폴더에 대한 심볼릭 링크 또는 접합 링크를 사용하는 것이 좋습니다. 모든 터미널은 하나의 폴더에서 찾습니다.

누군가와 공유해보는 것은 어떨까요?

 
Vitaly Muzichenko :

누군가와 공유해보는 것은 어떨까요?

글쎄요, 여기에서 체커들에게 무엇이 더 중요한지 결정해야 합니다. 아니면 다른 사람과 공유하는 과정의 단순함이 코딩의 편안함보다 더 중요합니까? 많은 조언자들이 사용하는 일부 기능에서 오류를 발견하면 각각의 코드에 들어가서 이 기능을 전달해야 합니다. 이것이 프로그래머로서 당신을 방해하지 않습니까?

 
내 문제를 논의해 주셔서 감사합니다.
내 (반복 가능한) 기능을 별도의 파일(파일)에 저장하기 위해 mqlx에서 OOP를 찾기 시작했습니다. 그리고 자유롭게 댓글을 달아주세요.

그리고 Windows의 심볼릭 링크의 경우 +! 어떻게든 Linux를 사용했지만 Windows는 잊어버렸습니다. 시도해야 할 것입니다..
 
Alexey Navoykov :

글쎄요, 여기에서 체커들에게 무엇이 더 중요한지 결정해야 합니다. 아니면 다른 사람과 공유하는 과정의 단순함이 코딩의 편안함보다 더 중요합니까? 예를 들어, 많은 조언자들이 사용하는 일부 기능에서 오류를 발견하면 각 조언자의 코드에 들어가서 이 기능을 전달해야 합니다. 이것이 프로그래머로서 당신을 괴롭히지 않습니까?

그런 경우가 한 달 정도 전에 딱 한 번 있었는데 거기에 시장개방 체크를 추가해야 했는데 이거 빼고 다 체크가 있는데 이게 전체 사용기간 중에 처음 나온거에요 .

추가해야 할 것이 있으면 현재 프로그램에 추가하고 그 후에 이미 파일을 다음 프로그램의 템플릿으로 사용합니다. 결과적으로 몇 년 안에 템플릿에 모든 것이 포함되거나 거의 모든 것이 포함되므로 복잡한 봇은 30분 만에 작성됩니다.

전체 실행 코드는 한 화면에 배치되지만 파일에는 4,000줄이 조금 넘지만 추가해야 할 경우에는 거의 보지 않습니다. 나는 순환 함수 사용을 거부했고 두 개만 사용되었습니다. 하나는 open에 대한 정보를 수집하고 두 번째는 history에 대한 정보를 수집하며 이 모든 것이 코드 맨 아래의 구조에 있습니다. 모든 것이 매우 간단하고 가깝습니다. 주요 코드가 주석 처리됩니다. 프로젝트 는 손실 없이 매우 간단하고 빠르게 확장됩니다.

 
Alexey Volchanskiy :

맛있어 보이는데 TRACE_***와 ASSERT도 볼 수 있나요?

음 ... 검은 부러워하는 여성을 유혹하는 마스터 클래스의 저자 에게는 항상 환영합니다.

해당 시스템 매크로가 정의되면 디버그 버전이 자동으로 활성화됩니다. 그러나 활성화되지 않은 경우 다음 정의를 사용하여 어설션 및 추적을 활성화할 수도 있습니다.

#define _FORCETRACE 1
#define _FORCEASSERT 1

이 경우 시스템 설정에 관계없이 디버그 추적 및 디버그 어설션이 생성됩니다.

이 매크로를 지시문과 연결합니다.

#include <MyLib\DebugOrRelease\DebugSupport.mqh>

이 지시문에는 필요한 모든 파일과 정의가 포함됩니다. 모두 별도의 DebugOrRelease 폴더에 있습니다. 나는 그것들을 붙이고 있다. (코드는 오래 전에 대부분 서둘러 작성되었으므로 인터페이스 및 히스토리 클래스만큼 아름답지 않습니다.) 디버그 버전에 대한 어설션 및 추적은 AssertD 및 TraceD 파일에 있으며 실제로는 PerformAssert() 및 PerformTrace() 함수입니다.

또한 이러한 파일과 매크로는 전역 로그 파일(로그 파일에 대한 출력이 설정된 경우)을 사용하므로 이미 한 번 게시했지만 다시 게시했습니다. 로그 파일은 내 "공통" 폴더에 있습니다.

파일:
 
Andrey Kisselyov :

잘했어, 나는 그것을 좋아하지만 나는 OOP를 좋아하지 않고 OOP 없이 하려고 노력한다. 스레드가 분리된 프로세서를 좋아하지 않는 것처럼(예: 4개 코어 및 8개 스레드). 커널의 스레드 분할이든 코드의 기능 가상화이든 분할 및 가상화는 성능 손실 및 구현을 위한 기계 시간 손실이라는 것이 분명해야 합니다.

간결함은 재능의 자매입니다. 그런 면에서 더 좋게 들립니다.

나는 오랫동안 유지보수의 편의성과 코드 재사용이 성능을 줄이는 것보다 훨씬 더 중요하다고 확신해 왔습니다.

OOP - 수정을 위해 잠시 후에 코드로 돌아갈 때 많은 도움이 됩니다. 재사용에 대해 말하는 것이 아닙니다.

그러나 OOP를 사용하는 것이 항상 필요한 것은 아니라는 점에 동의합니다.

CDataProvider:pulic 클래스가 있다고 가정해 보겠습니다. CDataProviderI는 시계열, 표시기, 터미널 및 환경 데이터를 EA에 제공하는 데이터 공급자입니다. Expert Advisor 내부에는 많은 TS가 있을 수 있습니다. 각 TS는 데이터 제공자로부터 시계열 및 표시기에 대한 포인터를 받습니다(결과적으로 각 TS는 이러한 시계열 생성을 처리할 필요가 없습니다. 데이터 제공자는 필요한 시계열, 이미 존재하는 경우 아직 생성되지 않은 시계열만 생성합니다.

데이터 제공자로부터 지표를 받아야 하는 경우 지표 설명 구조를 채운 다음 이 구조를 가리키는 제공자에게 지표를 요청해야 합니다.

따라서 데이터 제공자 내부의 각 표시기는 자체 구조를 인식할 수 있어야 하며(데이터 제공자는 구조의 추상 기본 클래스에만 "익숙함" 있음) 이를 사용하여 기성품 표시기 객체를 생성할 수 있어야 합니다. 데이터 제공자가 발행합니다.

그러나 일종의 지표에 대한 새로운 아이디어를 테스트하기 위해이 전체 정원을 펜싱하는 것은 물론 비합리적입니다. 결과적으로 이러한 새로운 지표의 경우 모든 것이 OOP 없이 "무릎에 조립"됩니다. 그러나 지표가 Expert Advisors에 유용하다는 것을 알면 "예상대로" 작성됩니다. 완전한 OOP 지원 및 데이터 제공자 내부 생성이 포함됩니다.

추신

그런데 지표와 데이터 공급자의 경우 상속 가상화의 이점이 분명히 보입니다. 기본 지표 매개변수 인터페이스 CIndicatorParametersI가 있으며 이 인터페이스의 후속 제품은 필수 지표의 실제 매개변수입니다. 표시기를 요청할 때 이러한 매개변수를 선언하고 추상 인터페이스에 대한 포인터를 데이터 제공자에게 전달합니다. 따라서 데이터 제공자 자체는 어떤 지표가 요청되었는지조차 알지 못합니다. 이는 필요한 유형의 새로운 지표가 생성되는 하나의 기능에서 결정됩니다. 그리고 정확히 어떤 매개변수가 전달되는지 - 이 생성된 표시기만 알고 전달된 객체에서 필요한 매개변수를 추출합니다.

트릭은 데이터 제공자 내부의 거의 모든 곳에서 매개변수(또는 표시기)의 간단한 기본 클래스로 작업이 수행되고 있다는 것입니다. 기본 인터페이스의 가장 단순하고 가장 일반적인 기능만 데이터 제공자가 사용할 수 있습니다. 이것은 코드 수정을 단순화하고(필요한 경우) 데이터 제공자의 표시기 코드에 "들어가는" 유혹을 만들지 않습니다. 지표를 변경해야 하는 경우 지표 자체 내에서만 수행되는 반면 데이터 공급자는 지표의 저장소일 뿐이므로 할 수 있는 최대치는 새 지표를 생성하는 것입니다.

 
George Merts :

그건 그렇고, 나는 중첩이 2 단계 이상일 때 매우 긴장합니다. 나는 절대로 이런 식으로 쓰지 않으려고 하고, 코드를 함수 위에 퍼뜨립니다.

그리고 두 수준의 중첩이 있는 경우에도(항상 각 닫는 대괄호 뒤에) 어떤 블록이 묻어 있는지에 대한 설명을 작성합니다(예: 순환 제목을 복제함).

스타일과 관련하여 다음은 MT5의 역사적 위치 를 선택하는 코드입니다(지정된 날짜 범위의 지정된 매직, 기호로).

동시에 히스토리 클래스 자체는 추상 인터페이스 CTradeHistoryI의 상속자입니다.

필요한 이력을 선택하면 해당 구성 요소(MT5의 경우 위치 또는 MT4의 경우 주문)를 다시 계산하고 추상 인터페이스 형태의 구성 요소에 대한 인터페이스를 얻을 수 있습니다.

MT4의 경우 - 이러한 인터페이스에서 상속되는 해당 히스토리 클래스가 있습니다. 따라서 크로스 플랫폼도 제공됩니다. 어드바이저는 작동 위치를 전혀 찾을 필요가 없으며, 히스토리에 대한 모든 작업은 추상 인터페이스를 통해 수행됩니다.


그다지 비판적이지 않다

 class CTradePosComponentI: public CMyObject
{
...
}

표준적이고 이해할 수 있는 CObject가 있는데 왜 CMyObject의 형태로 바퀴를 재발명합니까?

 class class CTradeHistoryI: public CMyObject
{
// Расширенный интерфейс
   virtual void Sort(ESortTPCMode stmMode = STM_BY_OPEN_TIME_A) = 0 ;
}

CObject 및 CArrayObj의 기능은 이미 여기에 명시적으로 복사되어 있습니다. 무엇 때문에? Quicksort는 표준 데이터 컨테이너에 내장되어 있습니다. 그것을 써.

 class CTradePosComponentI: public CMyObject
{
public :
   void CTradePosComponentI() {    SetMyObjectType(MOT_TRADEPOS_COMPONENT_I); };
   virtual void ~CTradePosComponentI() {};
}

클래스가 인터페이스인 경우 해당 생성자는 보호된 섹션에 숨겨져 있어야 합니다. 그러면 해당 개체를 직접 만들 수 없습니다.

빈 소멸자를 정의하시겠습니까? 글쎄, 나는 모른다. 나는 그렇게하지 않을 것입니다. 소멸자에 대해서는 필요하지 않은 경우 언급하지 않는 것이 좋습니다.

 for (iI= 0 ;iI<iHistoryDealsTotal; ++iI)
...

비표준 증분 iI, 비표준 반복 ++iI, iHistoryDealsTotal - 루프 이전 어딘가에 정의되어 있습니다. 더 간단하게:

 for ( int i = 0 ; i < HistoryDealsTotal ();i++)

이것은 이전 버전만큼 빠르지만 훨씬 더 명확합니다.

 virtual bool                IsTPCInUnloss() const { if (GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE ) return ( false ); if (GetTPCType() == POSITION_TYPE_BUY ) { if (GetTPCStopLoss() >= GetTPCOpenPrice()) return ( true ); } else { if (GetTPCStopLoss() <= GetTPCOpenPrice()) return ( true ); }; return ( false ); };

그들 자신은 그러한 시트에 반대하는 것처럼 보이지만 일부 장소에서는 스스로 이것을 씁니다. 아무도 그런 카누를 분해하고 싶어하지 않습니다. 내가 다음과 같이 글을 쓰지 못하게 한 이유는 무엇입니까?

 virtual bool IsTPCInUnloss() const
{
   if (GetTPCStopLoss() <= 0 || GetTPCStopLoss() == EMPTY_VALUE )
       return ( false );
   if (GetTPCType() == POSITION_TYPE_BUY )
   { 
       if (GetTPCStopLoss() >= GetTPCOpenPrice())
         return ( true );
   } 
   else
   {
     if (GetTPCStopLoss() <= GetTPCOpenPrice())
         return ( true );
   } ; 
   return ( false );
} ;

잘 ';' 중괄호 끝에 - 이것은 더 이상 사용되지 않습니다. 이제 더 이상 이 작업을 수행할 필요가 없습니다.

거대한 Select 메서드는 거대한 for 루프로 구성됩니다.

for(iI= 0 ;iI<iHistoryDealsTotal; ++iI)
      {
      ulCurTicket = HistoryDealGetTicket (iI);
      
       if (ulCurTicket == 0 )
         return ( WRONG_VALUE );
      
       // Получим направление сделки   
       if ( HistoryDealGetInteger (ulCurTicket, DEAL_ENTRY ,lCurEntry)!= true )
         {
         TRACE_INTEGER( "Не удалось получить направление сделки ! Тикет: " ,ulCurTicket);
         continue ;
         };
      
       // Проверим направление сделки
       if (lCurEntry != DEAL_ENTRY_OUT )
         continue ;
      
       // Получим магик сделки
       if ( HistoryDealGetInteger (ulCurTicket, DEAL_MAGIC ,lCurMagic)!= true )
         {
         TRACE_INTEGER( "Не удалось получить магик сделки ! Тикет: " ,ulCurTicket);
         continue ;
         };
         
       // Проверим магик
       if (ulMagic != NULL && lCurMagic != ulMagic)
         {
         //TRACE_INTEGER("Сделка не подходит ! Имеет неверный магик ! Magic сделки: ",lCurMagic);
         //TRACE_INTEGER("Требуемый Magic : ",ulMagic);
         continue ;
         };
      ...
}

현재 Expert Advisor에 대한 거래 준수에 대한 모든 확인을 별도의 방법으로 옮기는 것이 더 나은 것은 분명합니다. 예를 들면 다음과 같습니다.

 for (iI= 0 ;iI<iHistoryDealsTotal; ++iI)
{
   if (!CheckDeal(iI))
       continue ;
   ...
}

그리고 일반적으로 선택은 3-4 가지 방법으로 더 나누어야 무슨 일이 일어나고 있는지 명확하게 알 수 있습니다.

조지 머츠
동시에 Advisor 파일 자체는 5줄로 구성됩니다. 이 파일은 전문가의 부품 공장 개체 자체를 선언하고 포함을 포함합니다.

공장은 매우 논란의 여지가 있는 패턴입니다. 사용 - 양호하지만 공장에서 모든 작업을 수행하는 것은 권장하지 않습니다.

조지 머츠
그리고 두 가지 수준의 중첩이 있는 경우에도( 항상 각 닫는 대괄호 뒤에) 어떤 블록이 묻혀 있는지에 대한 설명을 작성합니다 (예: 순환 제목을 복제함).

그래서 MQL에서 역겨운 방식으로 괄호를 배치한다고 작성하는 것입니다. 다음과 같이 작성했다면:

 if ( OrderSelect ())
{
   ...
}

어떤 대괄호가 어떤 코드 블록을 닫는지 항상 볼 수 있습니다.

코드에서 더 많은 경고를 찾을 수 있습니다. 물론 코드가 완벽하진 않지만 작가님의 아름다움에 대한 갈망은 이미 느껴져요 :))

 
Vasiliy Sokolov :

약간의 비판:

A. 제가 좋아하는 토론입니다. 그래서.

표준적이고 이해할 수 있는 CObject가 있는데 왜 CMyObject의 형태로 바퀴를 재발명합니까?

CObject 및 CArrayObj의 기능은 이미 여기에 명시적으로 복사되어 있습니다. 무엇 때문에? Quicksort는 표준 데이터 컨테이너에 내장되어 있습니다. 그것을 써.

CMyObject - 표준 CObject의 상속인이 있고 내 코드의 모든 목록과 배열은 CArray(및 표준 라이브러리의 다른 배열)의 상속인입니다. 나는 표준 array[] 배열을 거의 사용하지 않습니다.

물론 목록을 정렬하고 사용하는 작업은 CObject의 기본 기능을 사용합니다.

차이점은 다음과 같습니다. 표준 CObject는 "목록 또는 정렬된 배열의 개체"입니다. CMyObject는 특정 유형을 갖고 생성될 때 제공된 일부 값을 포함하는 CObject입니다. 객체가 "실제로" 가리키는 포인터를 이해하기 위해 기본 추상 클래스에 대한 객체의 광범위한 캐스팅과 관련하여 이 객체가 필요했습니다. CMyObject 유형은 동일한 SetMyObjectType() 함수에 의해 설정됩니다. 이 함수는 생성되는 개체가 속한 클래스의 식별자를 할당하기 위해 CMyObject의 모든 자손의 생성자에서 호출되어야 합니다.

또한 SetUDCreationValue() 함수가 있습니다 - 생성하는 동안 사용자가 정의한 값을 설정합니다. 드물게 사용되는. 같은 클래스의 다른 객체를 구별하기 위해 필요합니다.

클래스가 인터페이스인 경우 해당 생성자는 보호된 섹션에 숨겨져 있어야 합니다. 그러면 해당 개체를 직접 만들 수 없습니다.

보호된 생성자??? 음... 예, 아마도 인터페이스에 대해 합리적일 것입니다. 그렇게 할 수 있는지 몰랐습니다.

빈 소멸자를 정의하시겠습니까? 잘 모르겠어. 나는 그렇게하지 않을 것입니다. 소멸자에 대해서는 필요하지 않은 경우 언급하지 않는 것이 좋습니다.

이것이 "과거의 저주받은 유산"이다. 일단 그들이 상당히 큰 프로젝트를 작성하고 거기에서 빈 소멸자를 정의하지 않으면 어떤 이유로 개체를 삭제하는 데 오랜 시간이 걸립니다. 그래서 저는 이 일을 오랫동안 해왔습니다. 소멸자는 일반적으로 가상이어야 합니다.

비표준 증분 iI, 비표준 반복 ++iI, iHistoryDealsTotal - 루프 이전 어딘가에 정의되어 있습니다. 더 간단하게:

동의하지 않는다. 증분은 아주 정상적입니다. - i, 그냥 표준화된 표기법 - 먼저 정수 유형의 소문자로, 다음으로 - 명명 I의 대문자로 표시됩니다.

그들 자신은 그러한 시트에 반대하는 것처럼 보이지만 어떤 곳에서는 스스로 이것을 씁니다. 아무도 그런 카누를 분해하고 싶어하지 않습니다. 내가 다음과 같이 글을 쓰지 못하게 한 이유는 무엇입니까?

이 경우 클래스의 "가시성"과 이 기능의 아름다움 사이에서 선택해야 했습니다. "가시성"을 선택했습니다. 아름다움은 고통을 겪었습니다.

거대한 Select 메서드는 거대한 for 루프로 구성됩니다.

현재 Expert Advisor에 대한 거래 준수에 대한 모든 확인을 별도의 방법으로 옮기는 것이 더 나은 것은 분명합니다. 예를 들면 다음과 같습니다.

그리고 일반적으로 선택은 3-4 가지 방법으로 더 나누어야 무슨 일이 일어나고 있는지 명확하게 알 수 있습니다.

동의한다. 여기에서 원칙적으로이 동일한주기가 "확장"되었지만 처음에는 그렇게 크지 않았습니다.

작은 검사를 private 함수로 옮기는 것이 항상 편리한 것은 아니지만, 나중에 코드에서 이러한 검사를 항상 추적할 수는 없습니다.

공장은 매우 논란의 여지가 있는 패턴입니다. 사용 - 양호하지만 공장에서 모든 작업을 수행하는 것은 권장하지 않습니다.

지금은 기억나지 않습니다. 고문을 만드는 데에는 몇 가지 옵션이 있었습니다. "전문 부품 공장"에서 멈췄습니다. 원칙적으로 이제는 더 이상 순수한 고전적인 "공장" 패턴이 아닙니다. 처음에는 "클래식"으로 계획되었지만 이제는 Expert Advisor 일부의 "생성자 집중 장치"에 불과합니다. 그리고 그는 공장에서 보기 드문 이러한 부품의 제거도 담당합니다. 글쎄, 이름은 남아있다.

그래서 MQL에서 역겨운 방식으로 괄호를 배치한다고 작성하는 것입니다. 다음과 같이 작성했다면:

어떤 대괄호가 어떤 코드 블록을 닫는지 항상 볼 수 있습니다.

왜 "나쁜"?

루프의 제목, 들여쓰기가 있는 여는 중괄호, 같은 들여쓰기가 있는 전체 블록, 마지막으로 닫는 중괄호 - 역시 들여쓰기됩니다.

뭐가 더 낫다고 생각하세요?

 
Gregory Kovalenko :

나는 2개의 미결 주문에 대해 이익을 얻어야 합니다. 마지막으로 열린 주문인 OrderProfit2와 다음 주문인 OrderProfit1을 호출 합니다.

먼저 1개 오픈하고 2차 주문해서 1개는 싸이클에 걸려서 2)

실수는 어디에 있습니까?

당신은 단지 주문을 정렬하고 있습니다. 어느 것이 첫 번째이고 어느 것이 두 번째인지에 대한 확인은 어디에도 없습니다.

개장 시간 에 대한 수표 를 입력 해야 합니다 . 그러면 이전에 열린 주문과 나중에 열린 주문을 구분할 수 있습니다. 아니면 동시에 열릴 수도 있습니다.