인기 게시물

에디터의 선택 - 2019

MQL4 : MetaEditor에서 컴파일 중 오류 및 경고 수정

MQL4 거래 전문가를 개발하는 것은 쉬운 일이 아닙니다. 첫째, TS의 기능부터 MetaTrader 4 환경의 세부 사항으로 끝나는 많은 세부 사항을 고려해야하기 때문에 복잡한 거래 시스템의 알고리즘 화는 이미 문제입니다. 두 번째로, 세부적인 알고리즘의 존재조차도 개발 된 데이터를 전송할 때 발생하는 어려움을 제거하지 않습니다 MQL4 프로그래밍 언어에 대한 알고리즘.

컴파일러는 올바른 전문가를 작성하는 데 도움을 제공합니다. 컴파일을 시작하면 MetaEditor가 코드의 모든 구문 오류를보고합니다. 그러나 불행히도 구문 오류 외에도 고문에는 컴파일러가 포착 할 수없는 논리적 오류도 포함될 수 있습니다. 그러므로 우리 스스로해야합니다. 이 작업을 수행하는 방법은 오늘날 우리 자료에 있습니다.

가장 일반적인 컴파일 오류

코드에 오류가 있으면 프로그램을 컴파일 할 수 없습니다. 모든 오류를 완전히 제어하려면 지시문에 의해 설정된 엄격한 컴파일 모드를 사용하는 것이 좋습니다.

#property strict

이 모드는 오류 검색을 크게 단순화합니다. 이제 가장 일반적인 컴파일 오류로 넘어 갑시다.

식별자는 예약어와 일치합니다.

변수 또는 함수의 이름이 예약어 중 하나와 일치하는 경우 :

int char; // 잘못된 int char1; // 올바른 int char () // 잘못된 {return (0); }

그런 다음 컴파일러는 오류 메시지를 표시합니다.

이 오류를 해결하려면 변수 또는 함수의 이름을 수정해야합니다. 다음 이름 지정 시스템을 사용하는 것이 좋습니다.

모든 기능은 조치를 나타내야합니다. 즉, 동사 여야합니다. 예를 들어 OpenLongPosition () 또는 ModifyStopLoss ()입니다. 결국 함수는 항상 무언가를합니까?

또한 소위 CamelCase 스타일로 함수를 호출하는 것이 좋습니다. 그리고 변수는 cebab_case 스타일입니다. 이것은 일반적인 관행입니다.

변수 이름 말하기. 변수는 명사입니다. 예를 들어, my_stop_loss, day_of_week, current_month입니다. 긴 이름으로 변수 이름을 지정하는 것은 그리 무섭지 않으며 이해할 수 없을 정도로 이름을 지정하는 것이 훨씬 더 나쁩니다. 다우 존스 지수 란 무엇인가? 아니요, 요일로 밝혀졌습니다. 물론 오늘날이 변수가 무엇인지 이미 이해하고 있습니다. 그러나 한 달 후 권고 자 코드를 열면 모든 것이 명확하지 않습니다. 그리고이 시간은 과거의 메시지를 디코딩 할 때 없어졌습니다. 필요합니까?

변수 및 함수 이름의 특수 문자

어서 변수 또는 함수 이름에 특수 문자 ($, @, 마침표)가 포함 된 경우 :

int $ var1; // 잘못된 int @ var2; // 잘못된 int var.3; // 잘못된 void f @ () // 잘못된 {return; }

그런 다음 컴파일러는 오류 메시지를 표시합니다.

이 오류를 수정하려면 변수 또는 함수의 이름을 다시 조정하거나 즉시 인간적으로 호출해야합니다. 프로그래밍을 모르는 사람이라도 코드를 읽고 무슨 일이 일어나고 있는지 이해할 수 있도록 코드를 작성하는 것이 이상적입니다.

Switch 문을 사용한 오류

이전 버전의 컴파일러에서는 switch 문의 표현식 및 상수에 값을 사용할 수있었습니다.

무효 시작 () {double n = 3.14; 스위치 (n) {case 3.14 : 인쇄 ( "Pi"); 휴식; 사례 2.7 : 인쇄 ( "E"); 휴식; }}

새 컴파일러에서 switch 문의 표현식과 상수는 정수 여야하므로 이러한 구문을 사용할 때 오류가 발생합니다.

따라서 WallStreet, Ilan 및 기타 손상되지 않는 (자체 개발에 매우 ​​유용한) 클래식 코드를 구문 분석 할 때이 오류가 발생할 수 있습니다. 예를 들어 여기에서 이러한 줄을 사용할 때 매우 간단하게 처리됩니다.

스위치 (MathMod (day_48, 10))

다음은 문제를 쉽게 해결할 수있는 방법입니다.

스위치 ((int) MathMod (day_48, 10))

함수 반환 값

void를 제외한 모든 함수는 선언 된 유형의 값을 반환해야합니다. 예를 들면 다음과 같습니다.

int 함수 () {}

엄격한 컴파일 모드 (strict)에서는 오류가 발생합니다.

컴파일 모드에서 컴파일러는 기본적으로 경고를 표시합니다.

함수의 반환 값이 선언과 일치하지 않는 경우 :

int init () {반환; }

그런 다음 엄격한 컴파일 모드에서 오류가 발생합니다.

컴파일 모드에서 컴파일러는 기본적으로 경고를 표시합니다.

함수 코드에서 이러한 오류를 수정하려면 해당 유형의 리턴 값으로 리턴 명령문 리턴을 추가하면됩니다.

함수 인수의 배열

함수 인수의 배열은 참조로만 전달됩니다. 이전에는 그렇지 않았으므로 이전 어드바이저에서는이 오류를 찾을 수 있습니다. 예를 들면 다음과 같습니다.

double ArrayAverage (더블 a) {반환 (0); }

엄격한 컴파일 모드 (엄격)로 제공된 코드는 오류가 발생합니다.

컴파일 모드에서 컴파일러는 기본적으로 경고를 표시합니다.

이러한 오류를 해결하려면 배열 이름에 & 접두사를 추가하여 참조로 배열의 전송을 명시 적으로 표시해야합니다.

double ArrayAverage (double & a) {반환 (0); }

그런데 상수 배열 (Time, Open, High, Low, Close, Volume)은 참조로 전달할 수 없습니다. 예를 들어, 전화 :

ArrayAverage (열기);

컴파일 모드에 관계없이 오류가 발생합니다.

이러한 오류를 제거하려면 상수 배열에서 필요한 데이터를 복사해야합니다.

// --- 공개 가격 값을 저장하기위한 배열 double OpenPrices; // --- 개시 가격 값을 OpenPrices ArrayCopy 배열에 복사합니다 (OpenPrices, Open, 0,0, WHOLE_ARRAY); // --- 함수 호출 ArrayAverage (OpenPrices);

가장 흔한 실수 중 하나는 고문에 의한 지표의 상실입니다. 이러한 경우, 포럼의 전문가 사용자는 "고문이 작동하지 않습니다!"라고 씁니다. 또는 "고문을 차트에 올렸는데 아무 일도 일어나지 않습니다!". 이 문제에 대한 해결책은 실제로 매우 간단합니다. 항상 그렇듯이 터미널의 "로그"탭을보고 다음과 같은 항목을 찾으십시오.

2018.07.08 09 : 15 : 44.957 2016.01.04 00:51은 'C : Users1AppDataRoamingMetaQuotesTerminal MQL4indicatorsKELTNER_F12.ex4'파일을 열 수 없습니다 2

이것은 지시자가 폴더에 표시하는 것을 잊었거나 다르게 이름이 지정되었음을 알려줍니다. 표시기가 없으면 표시기가있는 폴더에 표시기를 추가해야합니다. 그렇다면 고문 코드에서 이름을 확인하는 것이 좋습니다. 대부분 다르게 호출됩니다.

컴파일러 경고

컴파일러 경고는 정보 제공 용이며 오류 메시지가 아니지만 가능한 오류 원인을 나타내므로 수정하는 것이 좋습니다. 깨끗한 코드에는 경고가 포함되어서는 안됩니다.

전역 및 지역 변수 이름의 교차점

글로벌 및 로컬 레벨에 동일한 이름의 변수가있는 경우 :

int i; // 전역 변수 void OnStart () {int i = 0, j = 0; // (i = 0; i <5; i ++)에 대한 지역 변수 {j + = i; } PrintFormat ( "i = % d, j = % d", i, j); }

컴파일러는 경고를 표시하고 전역 변수가 선언 된 행 번호를 나타냅니다.

이러한 경고를 수정하려면 전역 변수의 이름을 조정해야합니다.

유형 불일치

다음 예에서

#property strict void OnStart () {double a = 7; 플로트 b = a; int c = b; 문자열 str = c; 인쇄 (c); }

유형이 일치하지 않는 엄격한 컴파일 모드에서 컴파일러는 경고를 표시합니다.

이 예제에서 컴파일러는 다양한 데이터 유형을 할당하고 int 유형을 문자열로 암시 적으로 변환 할 때 가능한 정밀도 손실에 대해 경고합니다.

수정하려면 명시 적 유형 변환을 사용해야합니다.

#property strict void OnStart () {double a = 7; float b = (float) a; int c = (int) b; 문자열 str = (문자열) c; 인쇄 (c); }

사용하지 않은 변수

프로그램 코드에서 사용되지 않는 변수 (추가 엔터티)가 존재하는 것은 좋지 않습니다.

void OnStart () {int i, j = 10, k, l, m, n2 = 1; (i = 0; i <5; i ++) {j + = i;}}

이러한 변수에 대한 메시지는 컴파일 모드에 관계없이 표시됩니다.

수정하려면 프로그램 코드에서 사용하지 않는 변수를 제거하면됩니다.

컴파일 오류 진단

종종 프로그램을 작성한 후 코드 오류로 인해 컴파일 문제가 발생합니다. 이러한 오류는 가장 다양한 실수 일 수 있지만 어떤 경우에도 오류가 발생한 코드 섹션을 신속하게 감지해야합니다.

종종 사람들은 여분의 괄호를 찾기 위해 많은 시간과 신경이 필요합니다. 그러나 주석을 사용하여 오류를 신속하게 감지 할 수있는 방법이 있습니다.

한 번의 실수없이 충분히 큰 코드를 작성하는 것은 매우 좋습니다. 그러나 불행히도 이것은 자주 발생하지 않습니다. 잘못된 코드 실행으로 이어지는 오류는 고려하지 않습니다. 여기서는 컴파일을 불가능하게하는 오류에 대해 이야기 할 것입니다.

일반적인 실수는 어려운 조건, 대괄호 부족, 콜론 설정 안 함, 변수 선언시 쉼표, 변수 이름의 오타 등으로 추가 대괄호를 삽입하는 것입니다. 컴파일 할 때 비슷한 오류가 발생한 행을 즉시 확인할 수 있습니다. 그러나 그러한 오류를 찾는 것이 그렇게 간단하지 않은 경우가 있습니다. 컴파일러 나 예리한 눈은 즉시 오류를 찾는 데 도움이 될 수 없습니다. 이러한 경우, 일반적으로 초보자 프로그래머는 오류를 시각적으로 식별하려고 모든 코드를 "이동"하기 시작합니다. 그리고 신경이 견딜 동안 반복해서.

그러나 다른 프로그래밍 언어와 마찬가지로 MQL은 훌륭한 도구 인 주석 작성 기능을 제공합니다. 이를 사용하면 코드의 일부를 비활성화 할 수 있습니다. 일반적으로 주석은 일종의 주석을 삽입하거나 사용하지 않는 코드 섹션을 비활성화하는 데 사용됩니다. 오류를 검색 할 때 주석을 적용 할 수도 있습니다.

오류에 대한 검색은 일반적으로 오류가 발생한 코드 섹션을 결정한 다음이 섹션에서 오류가 시각적으로 표시됩니다. 누구나 100 ~ 500 개, 심지어 수천 개보다 5 ~ 10 줄의 코드를 더 쉽고 빠르게 검사하는 것이 더 쉽고 빠르다는 것을 의심 할 것 같지 않습니다.

주석을 사용할 때 작업은 매우 간단합니다. 먼저 코드의 다양한 섹션 (때로는 거의 전체 코드)을 주석 처리하여 "비활성화"해야합니다. 그런 다음 코드의이 섹션에서 주석이 제거됩니다. 다음에 주석을 철회 한 후 컴파일을 시도합니다. 컴파일이 성공하면이 코드 섹션에 오류가 없습니다. 그런 다음 코드의 다음 섹션이 열립니다. 코드의 문제 부분이 있으면 오류를 시각적으로 검색 한 다음 수정됩니다. 다시, 컴파일을 시도한다. 모든 것이 잘 되었다면 오류가 해결됩니다.

주석을 달아야 할 코드 섹션을 올바르게 식별하는 것이 중요합니다. 이 조건 (또는 다른 논리적 구성) 인 경우 완전히 주석 처리해야합니다. 변수가 선언 된 코드 섹션에 대해 언급하는 경우 이러한 변수에 액세스하는 섹션을 열지 않는 것이 중요합니다. 즉, 프로그래밍 로직에 따라 주석을 달아야합니다. 이 방법을 따르지 않으면 새로운 오해의 소지가있는 컴파일 오류가 발생합니다.

어디에서 오류를 찾아야하는지 명확하지 않고 코드에 주석을 달면 도움이 될 수있는 오류의 좋은 예입니다.

런타임 오류

프로그램 코드 실행 중 발생하는 오류를 일반적으로 런타임 오류라고합니다. 이러한 오류는 일반적으로 프로그램 상태에 따라 다르며 잘못된 변수 값과 관련이 있습니다.

예를 들어, 변수가 배열 요소의 인덱스로 사용되면, 그 음의 값은 필연적으로 배열의 유출을 초래합니다.

범위를 벗어난 배열

이 오류는 종종 표시기 버퍼에 액세스 할 때 표시기에서 발생합니다. IndicatorCounted () 함수는 마지막 지표 호출 이후 변경되지 않은 막대 수를 반환합니다. 이전에 계산 된 막대의 지표 값을 다시 계산할 필요가 없으므로 계산 속도를 높이려면 마지막 몇 막대 만 처리하면 충분합니다.

이 계산 최적화 방법을 사용하는 대부분의 지표는 다음과 같은 형식을 갖습니다.

// + ----------------------------------------------- ------------------- + // | 사용자 정의 표시기 반복 기능 | // + ----------------------------------------------- ------------------- + int start () {// --- 때때로 계산에 적어도 N 개의 막대가 필요합니다 (예 : 100) // 차트에없는 경우 // (Bars <100) {return (-1) 인 경우 막대 수 (예 : MN 시간대). // 계산을 중지하고 일정보다 앞서 나가기} // --- 마지막 지표 호출 이후 변경되지 않은 막대 수 int counted_bars = IndicatorCounted (); // --- 오류가 발생하면 if (counted_bars0 // --- 반복 호출 중에 한계를 1 씩 증가시킵니다. // --- 마지막 막대 한계에 대한 지표 값을 업데이트하도록 보장합니다. ++;} // ---의 주 계산주기 (int i = limit; i> 0; i--) {// 5와 10까지 더 깊이 들어가는 막대의 값 사용 Buff1i = 0.5 * (Openi + 5 + Closei + 10)}}

counted_bars == 0을 잘못 처리하는 경우가 종종 있습니다 (한도의 초기 위치는 1 + 루프 변수에 대한 최대 색인과 같은 값으로 줄여야 함).

start () 함수가 실행될 때 0에서 Bars ()-1까지 인디케이터 버퍼 배열의 요소에 액세스 할 수 있음을 기억해야합니다. 인디케이터 버퍼가 아닌 어레이에 대한 작업이 필요한 경우 인디케이터 버퍼의 현재 크기에 따라 ArrayResize () 함수를 사용하여 크기를 늘려야합니다. 주소 지정을위한 요소의 최대 색인은 표시기 버퍼 중 하나를 인수로 사용하여 ArraySize ()를 호출하여 얻을 수도 있습니다.

0으로 나누기 (영점 나누기)

"제로 나누기"오류는 나누기 작업 중에 나누기가 0 인 경우 발생합니다.

void OnStart () {int a = 0, b = 0, c; c = a / b; 인쇄 ( "c =", c); }

이 스크립트가 실행되면 "전문가"탭에 오류 메시지가 표시되고 프로그램이 종료됩니다.

일반적으로 이러한 오류는 분배기의 값이 일부 외부 데이터의 값에 의해 결정될 때 발생합니다. 예를 들어, 거래 매개 변수가 분석되면 미결 주문이없는 경우 관련 마진의 값은 0이됩니다. 또 다른 예 : 분석 된 데이터를 파일에서 읽은 경우없는 경우 올바른 작동을 보장 할 수 없습니다. 따라서 이러한 경우를 고려하여 올바르게 처리하는 것이 좋습니다.

가장 쉬운 방법은 나누기 작업 전에 제수를 확인하고 잘못된 매개 변수 값에 대한 메시지를 표시하는 것입니다.

void OnStart () {int a = 0, b = 0, c; if (b! = 0) {c = a / b; 인쇄 (c); } else {Print ( "오류 : b = 0"); 귀국 }}

결과적으로 심각한 오류가 발생하지 않지만 매개 변수의 잘못된 값에 대한 메시지가 표시되고 작업이 종료됩니다.

현재 문자에 ​​NULL 대신 0 사용

이전 버전의 컴파일러에서는 금융 상품이 필요한 함수에서 인수로 0을 사용할 수있었습니다.

예를 들어, 현재 심볼의 이동 평균 기술 지표 값은 다음과 같이 요청할 수 있습니다.

AlligatorJawsBufferi = iMA (0,0,13,8, MODE_SMMA, PRICE_MEDIAN, i); // 잘못

새 컴파일러에서 현재 문자를 나타내려면 명시 적으로 NULL을 지정해야합니다.

AlligatorJawsBufferi = iMA (NULL, 0.13.8, MODE_SMMA, PRICE_MEDIAN, i); // 맞다

또한 현재 기호 및 차트 기간은 기호 () 및 기간 () 기능을 사용하여 지정할 수 있습니다.

AlligatorJawsBufferi = iMA (기호 (),주기 (), 13.8, MODE_SMMA, PRICE_MEDIAN, i); // 맞다

미리 정의 된 변수 _Symbol 및 _Period를 사용하면 더욱 빠르게 처리됩니다.

AlligatorJawsBufferi = iMA (_Symbol, _Period, 13.8, MODE_SMMA, PRICE_MEDIAN, i); // 맞다

유니 코드 문자열과 DLL에서의 사용

문자열은 일련의 유니 코드 문자입니다. 이 사실을 명심하고 적절한 Windows 기능을 사용하십시오. 예를 들어, InternetOpenA () 및 InternetOpenUrlA () 대신 wininet.dll 라이브러리 함수를 사용하는 경우 InternetOpenW () 및 InternetOpenUrlW ()를 호출해야합니다. 문자열을 DLL로 전달할 때 MqlString 구조를 사용하십시오.

#pragma pack (push, 1) struct MqlString {int 크기; // 32 비트 정수. 문자열 LPWSTR 버퍼에 할당 된 버퍼 크기를 포함합니다. // 문자열을 포함하는 버퍼의 32 비트 주소 int reserved; // 32 비트 정수, 예약되어 있고 사용하지 않음}; #pragma pack (팝, 1)

파일 공유

파일을 열 때 공유 할 FILE_SHARE_WRITE 및 FILE_SHARE_READ 플래그를 명시 적으로 지정해야합니다.

파일이 없으면 독점 모드로 파일이 열리므로 독점자가 닫을 때까지 다른 사람이 파일을 열 수 없습니다.

예를 들어 오프라인 차트로 작업 할 때 공유 플래그를 명시 적으로 지정해야합니다.

// 1 차 변경-공유 플래그 추가 ExtHandle = FileOpenHistory (c_symbol + i_period + ". Hst", FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ);

날짜 / 시간 변환 기능

날짜 시간 유형을 문자열로 변환하는 것은 컴파일 모드에 따라 다릅니다.

날짜 시간 날짜 = D' 2014.03.05 15:46:58 '; 문자열 str = "mydate ="+ 날짜; // --- str = "mydate = 1394034418"-#property strict 지시문 없음 // --- str = "mydate = 2014.03.05 15:46:58"-#property strict 지시문

예를 들어, 이름에 콜론이 포함 된 파일을 사용하려고하면 오류가 발생합니다.

런타임 오류 처리

내장 된 사용자 정의 함수를 사용하지 않고는 거래 전문가가 할 수 없기 때문에, 우선 우리는 이러한 함수가 반환 한 오류를 분석 할 때 우리의 삶을 단순화하려고 노력할 것입니다.

오류에 대한 작업을위한 라이브러리를 포함하여 어드바이저 작성을 단순화하기 위해 일부 "라이브러리"세트로 일부 라이브러리를 사용할 수 있습니다. MQL4 / Include 폴더에 저장됩니다.

두 개의 라이브러리가 필요합니다 :

  • stderror.mqh-각 오류 수에 대한 상수를 포함합니다.
  • stdlib.mqh-오류 설명을 문자열로 리턴하는 기능을 포함하여 여러 보조 기능이 포함되어 있습니다.
문자열 ErrorDescription (int error_code)

따라서이 두 라이브러리를 모두 프로젝트에 연결합니다.

#include #include 

오류 설명 자체는 MQL4 / Library / stdlib.mql4 파일에 있으며 영어로되어 있습니다. 따라서 외국어에 반대하는 경우 언제든지 설명을 모국어로 다시 작성할 수 있습니다.

필요한 또 다른 내장 함수는 GetLastError ()입니다. 정수 (int) 형식으로 오류 코드를 반환하는 것은 바로 그녀입니다. 그러면 정수 코드가 처리됩니다. 러시아어로 된 오류 코드 및 설명은 MetaQuotes의 mql4 매뉴얼에서 찾을 수 있습니다. 여기에서 stdlib.mql4 파일을 러시아어로 번역하기위한 정보를 얻을 수 있습니다.

필요한 라이브러리를 연결 했으므로 거래 기능과 직접 관련된 기능의 결과를 고려할 것입니다. 이러한 기능의 오작동을 무시하면 봇에 중대한 결과를 초래할 수 있습니다.

불행하게도 MQL4를 사용하면 가능한 모든 오류 상황을 처리하기 위해 일반화 된 라이브러리를 작성할 수 없습니다. 각각의 경우, 오류를 별도로 처리해야합니다. 그러나 모든 것이 그렇게 나쁘지는 않습니다. 많은 오류를 처리 할 필요가 없습니다. 전문가의 개발 및 테스트 단계에서 오류를 제거하는 것으로 충분합니다.

예를 들어, MQL4 전문가에게 일반적인 두 가지 오류를 고려하십시오.

  1. 오류 130-ERR_INVALID_STOPS
  2. 146 오류-ERR_TRADE_CONTEXT_BUSY

첫 번째 오류가 발생하는 경우 중 하나는 전문가가 보류중인 주문을 시장에 너무 가깝게 배치하려는 시도입니다. 경우에 따라 전문가 성능이 심각하게 손상 될 수 있습니다. 예를 들어, 수익성있는 포지션을 개설 한 전문가가 150 포인트마다 수익을 창출한다고 가정 해 보겠습니다. 다음 번 시도로 130의 오류가 발생하고 가격이 이전의 정지 수준으로 회복 될 수없는 경우 전문가가 귀하에게 합당한 이익을 박탈 할 수 있습니다. 이러한 결과의 가능성에도 불구하고이 오류는 전문가 코드를 마무리하여 가격과 정류장 사이의 최소 허용 거리를 고려하여 근본적으로 제거 할 수 있습니다.

터미널 거래 컨텍스트의 혼잡과 관련된 두 번째 오류는 완전히 제거 할 수 없습니다. 여러 전문가가 같은 터미널에서 일할 때 전문가 중 한 명이 직위를 열려고하면서 다른 전문가는 여전히 같은 일을 할 수 있습니다. 따라서 이러한 오류는 항상 처리해야합니다.

따라서 EA가 작동하는 동안 사용 된 내장 함수가 오류를 반환하는지 항상 알고 있어야합니다. 다음과 같은 간단한 도우미 기능을 사용하면됩니다.

void logError (string functionName, string msg, int errorCode = -1) {Print ( "ERROR : in"+ functionName + "()"); 인쇄 ( "ERROR :"+ msg); int err = GetLastError (); if (errorCode! = -1) {err = errorCode; } if (err! = ERR_NO_ERROR) {Print ( "ERROR : code ="+ err + "-"+ ErrorDescription (err)); }}

다음과 같이 사용합니다.

void openLongTrade () {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask + 5, 5, 0, 0); if (ticket == -1) {logError ( "openLongTrade", "주문을 열 수 없습니다"); }}

물론 이것은 간단한 예입니다. 주문 개설, 마감 및 수정에 대한보다 유능한 기능을 작성하려면이 학습을 참조하십시오.

logError () 함수의 첫 번째 매개 변수는 예제에서 openLongTrade () 함수에서 오류가 감지 된 함수의 이름입니다. 전문가가 여러 곳에서 OrderSend () 함수를 호출하면 오류가 발생한 위치를 정확하게 결정할 수 있습니다. 두 번째 매개 변수는 openLongTrade () 함수 내에서 오류가 감지 된 위치를 정확하게 이해할 수 있도록 오류 설명을 전달합니다. 이는 오류에 대한 간단한 설명이거나 내장 함수에 전달 된 모든 매개 변수의 값에 대한 자세한 설명 일 수 있습니다.

오류가 발생하면 분석에 필요한 모든 정보를 즉시 얻을 수 있기 때문에 후자의 옵션을 선호합니다. 예를 들어, OrderSend ()를 호출하기 전에 현재 가격이 마지막으로 알려진 가격에서 크게 벗어나야한다고 가정하십시오. 결과적으로이 예제를 실행하는 동안 오류가 발생하고 전문가 로그에 다음 줄이 나타납니다.

오류 : openLongTrade () 오류 : 주문을 열 수 없습니다 오류 : 코드 = 138-다시 인용

즉, 즉시 다음을 볼 수 있습니다.

  • 어떤 기능에서 오류가 발생했는지;
  • 그것이 참조하는 것 (이 경우, 위치를 열려고 시도);
  • 발생한 오류 (오류 코드 및 설명)

이제 logError () 함수에 대한 세 번째 선택적 매개 변수를 고려하십시오. 이러한 경우 특정 유형의 오류를 처리하려는 경우 이전과 같이 전문가의 작업 프로토콜에 나머지를보고합니다.

void updateStopLoss (double newStopLoss) {bool modified = OrderModify (OrderTicket (), OrderOpenPrice (), newStopLoss, OrderTakeProfit (), OrderExpiration ()); if (! 수정) {int errorCode = GetLastError (); if (errorCode! = ERR_NO_RESULT) {logError ( "updateStopLoss", "주문 수정 실패", errorCode); }}}

이것은 내장 OrderModify () 함수가 updateStopLoss () 함수에서 호출되는 곳입니다. 이 함수는 OrderSend ()의 오류 처리 측면에서 약간 다릅니다. 변경 될 순서의 매개 변수 중 현재 매개 변수와 다른 매개 변수가 없으면 함수는 오류 ERR_NO_RESULT를 리턴합니다. 전문가에게 그러한 상황이 허용되는 경우이 오류를 구체적으로 무시해야합니다. 이를 위해 GetLastError ()에서 반환 한 값을 분석합니다. ERR_NO_RESULT 코드에서 오류가 발생하면 프로토콜에 아무것도 출력하지 않습니다.

그러나 다른 오류가 발생하면 이전과 마찬가지로 오류를 완전히보고해야합니다. 그렇기 때문에 GetLastError () 함수의 결과를 중간 변수에 저장하고 세 번째 매개 변수를 logError () 함수에 전달합니다. 사실 내장 GetLastError () 함수는 호출 후 마지막 오류 코드를 자동으로 재설정합니다. 오류 코드를 명시 적으로 logError ()에 전달하지 않으면 코드 0의 오류와 "오류 없음"에 대한 설명이 프로토콜에 반영됩니다.

다른 오류를 처리하는 동안 유사한 조치를 수행해야합니다 (예 : 다시 인용). 주요 아이디어는 처리해야하는 오류 만 처리하고 나머지는 logError () 함수에 전달하는 것입니다. 그러면 전문가의 작업 중에 예기치 않은 오류가 발생했는지 항상 알 수 있습니다. 로그를 분석 한 후이 오류가 별도의 처리가 필요한지 또는 전문가 코드를 마무리하여 제거 할 수 있는지 여부를 결정할 수 있습니다. 이 방법은 종종 수명을 크게 단순화하고 오류를 처리하는 데 걸리는 시간을 줄입니다.

논리적 오류 진단

전문가 코드의 논리적 오류는 많은 문제를 일으킬 수 있습니다. 전문가의 단계별 디버깅 가능성이 없기 때문에 이러한 오류와의 싸움은 매우 즐거운 일이 아닙니다. 현재이를 진단하기위한 주요 도구는 내장 인쇄 () 기능입니다. 이를 사용하여 중요한 변수의 현재 값을 인쇄 할 수있을뿐만 아니라 테스트 중에 전문가의 작업을 터미널에 직접 기록 할 수 있습니다. 시각화로 테스트하는 동안 전문가를 디버깅 할 때 내장 된 주석 () 함수가 도움이 될 수 있으며 차트에 메시지를 표시합니다. 일반적으로 전문가가 의도 한대로 작동하지 않도록하려면 Print () 함수에 임시 호출을 추가하고 오류가 발생한 것으로 의심되는 장소에 전문가의 내부 상태를 기록해야합니다.

그러나 복잡한 오류 상황을 감지하려면 때때로 Print () 함수에 수십 건의 이러한 호출을 추가해야하며, 문제점을 찾아서 수정 한 후에는 전문가 코드가 복잡해지지 않고 테스트 속도가 느려지지 않도록 해당 코드를 삭제하거나 주석을 달아야합니다. 전문가 코드에서 Print () 함수를 이미 사용하여 다양한 상태를 주기적으로 기록하면 상황이 악화됩니다. 그런 다음 전문가 코드에서 '인쇄'문구를 검색하여 인쇄 ()에 대한 임시 호출을 제거 할 수 없습니다. 이 함수에 대한 유용한 호출을 제거하지 않도록 고려해야합니다.

예를 들어, OrderSend (), OrderModify () 및 OrderClose () 함수의 오류를 로깅 할 때 Bid 및 Ask 변수의 현재 값을 프로토콜에 인쇄하는 것이 유용합니다. 이를 통해 ERR_INVALID_STOPS 및 ERR_OFF_QUOTES와 같은 오류의 원인을보다 쉽게 ​​인식 할 수 있습니다.

프로토콜에서 이러한 진단 결과를 강조 표시하려면 다음 보조 기능을 사용하는 것이 좋습니다.

void logInfo (string msg) {인쇄 ( "INFO :"+ msg); }

여러 가지 이유로 바람직합니다. 먼저, 전문가 코드에서 '인쇄'를 검색 할 때 이러한 호출이 발생하지 않습니다. logInfo를 검색하기 때문입니다. 둘째로,이 함수에는 또 다른 유용한 기능이 있습니다.

인쇄 () 기능에 대한 임시 진단 호출을 추가하고 제거하는 데 많은 시간이 걸립니다. 따라서 코드의 논리적 오류를 감지하는 데 효과적인 다른 방법을 고려하여 시간을 조금 절약 할 수 있습니다. 다음과 같은 간단한 기능을 고려하십시오.

void openLongTrade (double stopLoss) {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) {logError ( "openLongTrade", "주문을 열 수 없습니다"); }}

이 경우, 우리가 긴 포지션을 개설하고 있기 때문에 전문가의 정상적인 운영 중에 stopLoss 매개 변수의 값이 현재 입찰 가격보다 크거나 같지 않을 것입니다. 즉, openLongTrade () 함수가 호출되면 stopLoss <Bid 조건이 항상 충족됩니다. 문제의 함수를 작성하는 단계에서도 이에 대해 알고 있으므로 다음과 같이 즉시 사용할 수 있습니다.

void openLongTrade (double stopLoss) {assert ( "openLongTrade", stopLoss <Bid, "stopLoss <Bid"); int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) {logError ( "openLongTrade", "주문을 열 수 없습니다"); }}

즉, 새로운 헬퍼 함수 assert ()를 사용하여 코드에 명령문을 기록합니다. 함수 자체는 매우 단순 해 보입니다.

void assert (문자열 functionName, 부울 주장, 문자열 설명 = "") {if (! 주장) {Print ( "ASSERT : in"+ functionName + "()-"+ description); }}

함수의 첫 번째 매개 변수는 이름이며, logError () 함수와 유사하게 조건을 확인합니다. 두 번째 매개 변수는이 조건을 확인한 결과를 전달합니다. 그리고 세 번째 매개 변수는 설명입니다. 결과적으로 예상 조건이 충족되지 않으면 다음 정보가 프로토콜에 표시됩니다.

  • 조건을 위반 한 기능의 이름;
  • 위반 된 조건에 대한 설명.

설명으로서, 예를 들어 조건 자체를 전달하거나 조건 점검시 제어 된 변수의 값을 포함하는 더 자세한 설명을 표시 할 수 있습니다 (오류의 원인을 이해하는 데 도움이되는 경우).

물론 고려 된 예는 최대한 단순화됩니다. 그러나 주요 아이디어가 잘 반영되기를 바랍니다. 전문가의 기능을 구축하는 과정에서 우리는 어떻게 작동해야하며 어떤 기능의 상태 및 입력 매개 변수가 유효하고 어떤 매개 변수가 유효하지 않은지 알고 있습니다. assert () 함수를 사용하여 전문가 코드에서이 문제를 해결하여 전문가의 업무 논리가 위반되는 장소에 대한 유용한 정보를 얻습니다. 또한, assert () 함수는 예상 조건에서 불일치가 감지 될 때만 프로토콜에 진단 메시지를 발행하므로 Print () 함수에 임시 호출을 추가 및 제거 할 필요성을 부분적으로 완화합니다.

또 다른 유용한 트릭은 각 나누기 작업 전에이 기능을 사용하는 것입니다. 사실 때때로 하나 또는 다른 논리적 오류의 결과로 때로는 0으로 나누기가 발생합니다. 이 경우 전문가의 작업이 종료되고 프로토콜에 슬픈 진단으로 '제로 나누기'라는 한 줄만 나타납니다. 코드에서 나누기 연산을 반복적으로 사용하는 경우이 오류가 발생한 위치를 정확히 찾는 것은 매우 어렵습니다. assert () 함수가 도움이 될 것입니다. 각 분할 작업 전에 해당 검사를 삽입합니다.

주장 ( "buildChannel", 거리> 0, "거리> 0"); 이중 경사 = 델타 / 거리;

이제 0으로 나누는 경우 로그에서 오류가 발생한 정확한 위치를 찾는 것으로 충분합니다.

상태 처리

전문가가 귀하의 계정에서 작업하는 동안 오류가 아닌 상황 (소위 전문가 상태)이 발생할 수 있습니다. 이러한 상태는 오류는 아니지만 여전히 기록해야합니다. mql4 언어의 특수 기능이 도움이됩니다.

IsExpertEnabled () 함수는 전문가를 실행할 수있는 기능에 대한 정보를 반환합니다. 이 기능은 전문가가 클라이언트 터미널에서 실행할 수 있으면 true를, 그렇지 않으면 false를 반환합니다. false가 반환되면 사용자에게 적절한 설정을 사용하라는 요청을 알리는 것이 좋습니다. 예를 들면 :

void OnStart () {if (! IsExpertEnabled () {// 고문은 경고를 교환 할 수 없습니다 ( "주의! MT4의 전문가 고문"버튼을 누르십시오 ");} // 고문의 작동 알고리즘 리턴};

전문가가 외부 라이브러리를 사용하는 경우 IsLibrariesAllowed () 함수가 유용합니다. 전문가가 라이브러리 함수를 호출 할 수 있으면 true를, 그렇지 않으면 false를 반환합니다.

라이브러리가 dll 파일 형식 인 경우 IsDllsAllowed () 함수가 유용합니다. IsTradeAllowed () 함수를 사용하여 전문가의 도움으로 거래 할 수 있는지 여부를 확인하는 것도 유용합니다.

계정이 데모인지 실제인지 확인하려면 IsDemo () 함수를 사용할 수 있습니다.

위의 모든 검사는 OnInit () 함수에서 수행해야합니다.

물론 서버와의 연결을 주기적으로 확인하는 것이 좋습니다. IsConnected () 함수가 도움이됩니다.

다음 세 가지 기능은 EA가 어떤 모드에 있는지 결정하는 데 도움이됩니다. IsOptimisation ()이 true를 반환하면 IsTesting (), 테스트, IsVisualMode ()-시각화 모드에서 테스트하는 경우 최적화가 수행됩니다. 이러한 각 옵션에 대해 어드바이저는 고유 한 논리를 가질 수 있습니다. 예를 들어, 시각화 모드의 경우 차트에 무언가를 표시 할 수 있습니다 (자원 절약을 위해 다른 모드에서는 표시하지 않음). 테스트 모드에서는 디버깅 정보를 표시 할 수 있으며 최적화 모드에서는 시간을 절약하기 위해 코드를 최대한 밝게합니다.

그리고 마지막 함수는 IsTradeContextBusy ()입니다. 거래 작업을 수행하기위한 스레드가 사용중인 경우 true를 리턴합니다. 이는 전문가가 거래 작업을 수행 할 때 유용 할 수 있습니다. 잠자기 기능을 사용하여 잠시 기다렸다가 다시 시도 할 수 있습니다.

또 다른 유용한 기능은 UninitializeReason ()입니다.

int deinit () {switch (UninitializeReason ()) {case REASON_CHARTCLOSE : 사례 REASON_REMOVE : 정리 (); 휴식; // 깨끗하고 자유로운 자원. 사례 REASON_RECOMPILE : 사례 REASON_CHARTCHANGE : 사례 REASON_PARAMETERS : 사례 REASON_ACCOUNT : StoreData (); 휴식; // 재시작 준비. } // ...}

어드바이저가 종료 된 이유를 기록 할 수도 있습니다.

가장 일반적인 오류 코드 및 가능한 해결책

오류 번호가치문제해결책
4, 146바쁜 거래 서버어드바이저가 작업 중 서버의 응답을 기다리거나 기다리지 않고 너무 많은 명령을 내 렸습니다. 어드바이저는 새 주문을 보내려고합니다.오류 처리 기능을 사용하여 터미널 재부팅 또는 권고 자 코드 최적화
8, 141너무 자주 요청매우 빈번한 요청의 이전 오류 이유비슷한 솔루션
129잘못된 가격포지션을 개설하려는 가격 (BUY 또는 SELL)이 잘못되었습니다BUY는 Ask에 의해 개설되고 BID에 의해 개설되어야합니다.
매도는 BID에 의해 개설되고 ASK에 의해 개설되어야합니다.
130, 145잘못된 발손실을 중지하거나 이익을 얻거나 보류 중이거나 리미터의 개시 수준이 올바르지 않습니다.
정류장이 가격에 너무 가깝습니다.
귀하의 계정이 ECN (ETSN) 또는 NDD (NDD) 그룹에서 열리므로 즉시 정차 할 수 없습니다
정지를 설정할 때 정지 손실의 값을 확인하고, 이익을 취하고, 브로커와 함께 계측기의 최소 정지 레벨을 확인하십시오-최소 거리 레벨을 관찰하십시오. 잘 작성된 고문은 ECN 및 NDD 계정 작업을위한 기능을 가지고 있어야합니다. 이것은 주문을 연 후 주문을 수정하여 이루어집니다
131잘못된 음량거래를 개설 할 때 잘못된 로트 또는 최소값보다 적습니다 (최대 값보다 큼). 로트의 비트 심도는 브로커 비트와 다를 수 있습니다로트의 올바른 개통을 확인하고, 계약의 사양을 연구하고, DC의 거래 조건을 읽고, DC와 계정에서 최소 및 최대 로트를 확인하십시오
132시장은 문을 닫았다주말에는 시장이 문을 닫습니다주말 후에 시장에 연락하십시오
133거래 없음현재 거래가 없습니다특정 시점 또는 일반적으로이 통화 쌍으로 거래하는 것은 금지되어 있습니다. 종종 브로커는 자정에 몇 분의 휴식을 취합니다.
134작업을 완료하기에 돈이 충분하지 않습니다열려고하는 로트가 너무 커서 여백이 충분하지 않습니다사용 가능한 자금의 수준을 확인하고 많이 열어야하는 자금을 계산하고 사용 가능한 자금의 수준을 모니터링하십시오
135-138가격이 변경되었습니다너무 빠른 시장 재판매 (뉴스), 브로커 또는 DC는 신고 가격에 입장을 허용하지 않습니다.그러한 순간에 거래하지 말고 미끄러짐 수준을 높이십시오. 그러나 이것은 명시된 가격이 아닌 포지션의 개설을 수반한다는 것을 기억하십시오. EA에서 오류 처리 기능 및 위치를 열려고 시도하는 횟수 제공
147브로커에서 주문 만료 날짜 사용을 금지합니다.조언자 또는 보류중인 주문의 만료 날짜를 설정하려고합니다Expert Advisor의 OrderSend 함수에서 만기 매개 변수를 0으로 설정하십시오. 만료 날짜를 설정하지 마십시오
148미결 주문 및 보류 주문 수가 브로커가 설정 한 한도에 도달했습니다.최대 주문 및 포지션 수가 브로커가 설정 한 한도에 도달했습니다.위치의 일부를 삭제하거나 닫습니다. 새로운 직책을 여는 과정을 중단
4012, 40130으로 나눈 나머지숫자를 0으로 나누려고합니다.고문 코드에서 오류를 확인하거나 0을 리턴 할 때 MarketInfo 함수의 모든 값을 확인하십시오. 때로는 MarketInfo (Symbol (), MODE_SPREAD)가 스프레드가 아닌 0이 0 인 경우 (유동 스프레드가있는 브로커의 경우)
4017DLL 호출은 허용되지 않습니다터미널에서 DLL 호출 금지메뉴를 통한 DLL 호출 허용-서비스-설정-관리자-DLL 호출 허용
4018, 4019라이브러리를로드 할 수 없습니다라이브러리가 손상되었거나 호출이 실패했을 수 있습니다.DLL 확인
4020외부 라이브러리 함수에 대한 호출은 허용되지 않습니다터미널에서 외부 전문가의 기능을 호출 할 수 없습니다메뉴를 통한 통화 기능 허용-서비스-설정-관리자-외부 전문가에게 전화 허용
4103파일을 열 수 없습니다이 파일이 존재하지 않거나 다른 프로세스에 의해 잠겨 있습니다.지정된 파일을 확인하십시오. 안티 바이러스 시스템에 의해 파일이 잠겨 있는지, 파일의 쓰기-읽기 모드가 허용되는지 확인하십시오
4106알 수없는 캐릭터시장 개요에 상징이 없음시장 개요에서 마우스 오른쪽 버튼을 클릭하면 모든 기호가 표시됩니다. 어드바이저의 기호 이름과 시장 개요에 해당 기호가 있는지 확인하십시오. 일부 어드바이저는 접미사없이 명확한 이름을 사용하고 브로커는 의도적으로 접미사를 설정합니다 (예 : EURUSDx, 여기서 x는 접미사 임)
4108유효하지 않은 티켓 번호전문가가 선택한 주문 티켓이 없습니다. 전문가가 티켓을 선택하려고하는데이 명령은 다른 고문이나 손에 의해 마감되었습니다. 주문에 대해 주문을 수행하려고 할 때 브로커가 티켓을 실행하고 닫았습니다.이 오류가 분당 100-1000 회 매우 자주 나타나는 경우 조언자의 기능을 확인하십시오. 다른 어드바이저를 비활성화하거나 충돌하지 않도록 구성하십시오. 전문가가 작업을 수행 할 때 손으로 주문을 닫지 마십시오. 때로는 여러 고문이 동일한 MagicNumber를 사용할 때 이런 일이 발생합니다.
4109거래 불가고문은 슬픈 미소 나 십자가 차트에서 거래 금지어드바이저를 설치할 때 예금 또는 메뉴-서비스-설정-어드바이저에서 "Advisor to Trade 허용"체크 상자를 선택하십시오.
4110, 4111길고 짧은 위치는 허용되지 않습니다권고 자 설정의 일반 탭에서 위치 유형이 허용되지 않습니다.일반 탭에서 어드바이저를 설치할 때 열 수있는 위치를 선택할 수 있습니다

결론

고려 된 보조 기능과 간단한 트릭은 MQL4 프로그래밍 언어로 작성된 거래 전문가 코드에서 오류를 감지하고 수정하는 프로세스를 크게 단순화하고 가속화 할 수 있습니다. 어드바이저의 작업을 기록하고 추적하기위한 코드와 함수를 올바르게 작성하면 개발 프로세스 속도가 크게 향상됩니다.

비디오 시청: Robot Building Tutorials #6 - Intro to MQL4 (12 월 2019).

귀하의 코멘트를 남겨