Popularni Postovi

Izbor Urednika - 2019

MQL4: Ispravljanje pogrešaka i upozorenja tijekom kompilacije u MetaEditoru

Razvoj MQL4 trgovačkih stručnjaka nije lak zadatak. Prvo, algoritmizacija bilo kojeg složenog trgovačkog sustava već predstavlja problem jer trebate uzeti u obzir puno detalja, počevši od značajki TS-a i završivši sa specifičnostima okruženja MetaTrader 4. Drugo, čak i prisutnost detaljnog algoritma ne uklanja poteškoće koje nastaju prilikom prijenosa razvijenog algoritam za programski jezik MQL4.

Sastavljač pruža neku pomoć u pisanju ispravnih stručnjaka. Nakon pokretanja kompilacije, MetaEditor će prijaviti sve sintaksičke pogreške u vašem kodu. Nažalost, pored sintaksičkih pogrešaka, vaš savjetnik može sadržavati i logičke pogreške koje prevoditelj ne može uhvatiti. Stoga ćemo to morati sami. Kako to učiniti danas je u našem materijalu.

Najčešće pogreške u sastavljanju

Ako u kodu postoje pogreške, program se ne može sastaviti. Za potpunu kontrolu svih pogrešaka preporučuje se strogi način sastavljanja, koji je postavljen direktivom:

# vlasništvo strogo

Ovaj način rada uvelike pojednostavljuje pretraživanje pogrešaka. A sada prijeđimo na najčešće pogreške u sastavljanju.

Identifikator odgovara rezerviranoj riječi

Ako se ime varijable ili funkcije podudara s jednom od rezerviranih riječi:

int char; // krivo int char1; // ispravan int char () // krivo {return (0); }

tada prevoditelj prikazuje poruke o pogrešci:

Da biste popravili ovu pogrešku, morate popraviti ime varijable ili funkcije. Preporučujem pridržavanje sljedećeg sustava imenovanja:

Sve funkcije moraju naznačiti radnju. Odnosno, to mora biti glagol. Na primjer, OpenLongPosition () ili ModifyStopLoss (). Uostalom, funkcije uvijek nešto rade, zar ne?

Pored toga, preporučljivo je nazvati funkcije u tzv stilu CamelCase. A varijable su u stilu cebab_case. To je uobičajena praksa.

Govoreći o promjenjivim imenima. Varijable su imenice. Na primjer, my_stop_loss, day_of_week, current_month. Nije tako strašno imenovati varijablu dugačkim imenom; Što je minus, indeks Dow Jones? Ne, ispada da je dan u tjednu. Naravno, danas već razumijete šta je ta varijabla. Ali kad otvorite kod savjetnika mjesec dana kasnije, sve neće biti tako očito. A ovaj put izgubljeni na dekodiranju poruka iz prošlosti - trebate li?

Posebni znakovi u nazivima varijabli i funkcija

Samo naprijed. Ako imena varijabli ili funkcija sadrže posebne znakove ($, @, razdoblje):

int $ var1; // krivo int @ var2; // krivo int var.3; // kriva void f @ () // kriva {return; }

tada prevoditelj prikazuje poruke o pogrešci:

Da biste ispravili ovu pogrešku, ponovo morate prilagoditi imena varijabli ili funkcija, ili ih odmah na ljudski način nazvati. U idealnom slučaju, kod treba napisati tako da ga i osoba koja ne zna programirati samo pročita i shvati što se tamo događa.

Pogreške pri korištenju izjave o prebacivanju

Stara verzija prevoditelja dopuštena je korištenjem bilo koje vrijednosti u izrazima i konstantama prekidača:

void start () {dvostruki n = 3,14; sklopka (n) {slučaj 3.14: Ispis ("Pi"); razbiti; slučaj 2.7: Ispis ("E"); razbiti; }}

U novom sastavljaču izrazi i konstante prekidača moraju biti cjelobrojni, pa prilikom korištenja takvih konstrukcija dolazi do pogreške:

Stoga, kada razradite klasicni kôd, poput WallStreet-a, Ilan-a i ostalih nepristupačnih vrsta (što je vrlo korisno za samorazvoj), možete naići na ovu pogrešku. Na primjer, ako se ovdje koristi takav redak, to se tretira vrlo jednostavno:

sklopka (MathMod (dan_48, 10))

Ovako problem možete lako riješiti:

switch ((int) MathMod (dan_48, 10))

Funkcije povratne vrijednosti

Sve funkcije osim void moraju vratiti vrijednost deklariranog tipa. Na primjer:

int funkcija () {}

U strogom načinu kompilacije (strog) dolazi do pogreške:

U načinu kompilacije prevoditelj prema zadanim postavkama prikazuje upozorenje:

Ako povratna vrijednost funkcije ne odgovara deklaraciji:

int init () {povratak; }

Tada se u strogom načinu sastavljanja događa pogreška:

U načinu kompilacije prevoditelj prema zadanim postavkama prikazuje upozorenje:

Da biste popravili takve pogreške u funkcijskom kodu, samo trebate dodati povrat izvoda s povratnom vrijednošću odgovarajuće vrste.

Nizi u argumentima funkcije

Nizovi u funkcijskim argumentima prosljeđuju se samo kao referenca. Prije toga nije bilo tako, pa u starim savjetnicima možete pronaći ovu pogrešku. Evo primjera:

dvostruki ArrayAverage (dvostruki a) {return (0); }

Navedeni kôd u strogom načinu sastavljanja (strog) rezultirat će pogreškom:

U načinu kompilacije prevoditelj prema zadanim postavkama prikazuje upozorenje:

Da biste popravili takve pogreške, morate izričito navesti prijenos matrice referencom, dodajući & prefiks nazivu matrice:

dvostruki ArrayAverage (double & a) {return (0); }

Usput, konstantni nizovi (Time, Open, High, Low, Close, Volume) ne mogu se proslijediti referencama. Na primjer, poziv:

ArrayAverage (Otvoreno);

bez obzira na način sastavljanja vodi do pogreške:

Da biste uklonili takve pogreške, morate kopirati potrebne podatke iz konstantnog niza:

// --- niz za pohranjivanje vrijednosti otvorenih cijena double OpenPrices; // --- kopirajte vrijednosti početne cijene u polje OpenPrices ArrayCopy (OpenPrices, Open, 0,0, WHOLE_ARRAY); // --- nazovite funkciju ArrayAverage (OpenPrices);

Jedna od najčešćih pogrešaka je gubitak pokazatelja od strane savjetnika. U takvim slučajevima obično stručni korisnici na forumima bijesno napišu: "Savjetnik ne radi!" ili "Stavio sam savjetnika na kartu i ništa se ne događa!". Rješenje ovog pitanja je zapravo vrlo jednostavno. Kao i uvijek, samo pogledajte karticu "Dnevnik" terminala i tamo pronađite unos poput:

2018.07.08 09: 15: 44.957 2016.01.04 00:51 ne može otvoriti datoteku 'C: Users1AppDataRoamingMetaQuotesTerminal MQL4indicatorsKELTNER_F12.ex4' 2

To nam govori da su zaboravili staviti indikator u mapu, ili je to nazvano drugačije. Ako indikator nedostaje, morate ga dodati u mapu s pokazateljima. Ako jest, vrijedi provjeriti njegovo ime u šifri savjetnika - najvjerojatnije se tamo zove drugačije.

Upozorenja sastavljača

Upozorenja sastavljača su informativnog karaktera i nisu poruke o pogreškama, međutim ukazuju na moguće izvore grešaka i bolje ih je ispraviti. Čisti kod ne smije sadržavati upozorenja.

Presjeci globalnih i lokalnih imena varijabli

Ako na globalnoj i lokalnoj razini postoje varijable s istim nazivom:

int i; // globalna varijabla void OnStart () {int i = 0, j = 0; // lokalne varijable za (i = 0; i <5; i ++) {j + = i; } PrintFormat ("i =% d, j =% d", i, j); }

tada prevoditelj prikazuje upozorenje i pokazuje broj retka na kojem je deklarirana globalna varijabla:

Da biste ispravili takva upozorenja, morate prilagoditi imena globalnih varijabli.

Upišite neusklađenost

U sljedećem primjeru:

#programi stroga void OnStart () {double a = 7; plutati b = a; int c = b; string str = c; Ispis (c); }

u strogom načinu kompilacije s neusklađenošću tipa, prevoditelj prikazuje upozorenja:

U ovom primjeru prevoditelj upozorava na mogući gubitak preciznosti prilikom dodjeljivanja različitih vrsta podataka i implicitne pretvorbe vrste int u string.

Za ispravljanje morate koristiti eksplicitnu pretvorbu tipa:

#programi stroga void OnStart () {double a = 7; plutati b = (plutati) a; int c = (int) b; string str = (string) c; Ispis (c); }

Neiskorištene varijable

Prisutnost varijabli koje se ne koriste u programskom kodu (dodatni entiteti) nije dobar oblik.

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

Poruke o takvim varijablama prikazuju se bez obzira na način sastavljanja:

Da biste to riješili, samo trebate ukloniti neiskorištene varijable iz programskog koda.

Dijagnostika pogreške u sastavljanju

Često, nakon pisanja programa, nastaju problemi s kompilacijom zbog pogrešaka u kodu. To mogu biti najrazličitije pogreške, ali u svakom slučaju, treba brzo otkriti odjeljak koda gdje se napravi greška.

Često ljudima treba puno vremena i puno živaca u potrazi za dodatnim zagradom. No postoji način za brzo otkrivanje pogrešaka koji se temelji na korištenju komentiranja.

Pisanje dovoljno velikog koda bez ijedne pogreške vrlo je lijepo. Ali, nažalost, to se ne događa često. Ovdje ne smatram pogreške koje vode ka pogrešnom izvršavanju koda. Ovdje ćemo govoriti o pogreškama koje kompilaciju čine nemogućom.

Česte pogreške su umetanje dodatnog zagrade u teškom stanju, nedostatak zagrade, ne postavljanje dvotočke, zarez za deklariranje varijabli, pogreška u nazivu varijable i tako dalje. Često prilikom sastavljanja odmah možete vidjeti u kojem je retku napravljena slična pogreška. Ali postoje slučajevi kada pronalaženje takve pogreške nije tako jednostavno. Ni prevoditelj ni oštro oko ne mogu nam pomoći da odmah pronađemo pogrešku. U takvim slučajevima, u pravilu, početnici programeri počinju "zaobilaziti" sav kôd, pokušavajući vizualno prepoznati pogrešku. I opet i opet, dok živci izdrže.

Međutim, MQL, kao i drugi programski jezici, nudi odličan alat - komentiranje. Pomoću nje možete onemogućiti neke dijelove koda. Komentari se obično koriste za umetanje neke vrste komentara ili za onemogućavanje neiskorištenih dijelova koda. Komentiranje se također može uspješno primijeniti kada tražite pogreške.

Potraga za pogreškama obično se svodi na određivanje odjeljka koda na kojem je napravljena pogreška, a zatim se u ovom odjeljku greška vizualno nalazi. Mislim da je malo vjerojatno da će netko sumnjati da je lakše i brže pregledati 5-10 redaka koda brže od 100-500 ili čak nekoliko tisuća.

Kada koristite komentare, zadatak je krajnje jednostavan. Prvo morate komentirati različite odjeljke koda (ponekad gotovo i cijeli kod) i tako ga „onesposobiti“. Potom se komentar uklanja iz ovih dijelova koda. Nakon sljedećeg povlačenja komentara, pokušava se sastaviti. Ako je kompilacija uspješna, pogreška nije u ovom odjeljku koda. Tada se otvara sljedeći odjeljak koda i tako dalje. Kada postoji problemski dio koda, greška se vizualno traži, zatim se ispravlja. Opet se pokušava sastaviti. Ako je sve prošlo dobro, greška je riješena.

Važno je pravilno odrediti odjeljke koda koje trebate komentirati. Ako je ovo stanje (ili druga logična konstrukcija), to bi trebalo u potpunosti prokomentirati. Ako komentirate odjeljak koda gdje su varijable deklarirane, važno je da se ne otvori odjeljak u kojem se pristupa tim varijablama. Drugim riječima, komentiranje treba primijeniti u skladu s programskom logikom. Nepoštivanje ovog pristupa dovodi do novih, zabludanih pogrešaka u sastavljanju.

Evo sjajnog primjera pogreške kada nam nije jasno gdje treba tražiti, a komentiranje koda može nam pomoći.

Pogreške tijekom rada

Pogreške koje nastaju tijekom izvršavanja programskog koda obično se nazivaju runtime pogreške. Takve pogreške obično ovise o stanju programa i povezane su s netočnim vrijednostima varijabli.

Na primjer, ako se varijabla koristi kao indeks elemenata niza, tada će njene negativne vrijednosti neizbježno dovesti do odljeva matrike.

Niz izvan dometa

Ova se pogreška često pojavljuje kod pokazatelja prilikom pristupa indikatorima. Funkcija IndicatorCount () vraća broj traka koje se nisu promijenile od zadnjeg poziva indikatora. Vrijednosti pokazatelja na prethodno izračunatim trakama ne moraju se preračunavati, stoga je za ubrzanje proračuna dovoljno obraditi samo posljednjih nekoliko traka.

Većina pokazatelja koji koriste ovu metodu optimizacije izračuna imaju sljedeći oblik:

// + ----------------------------------------------- ------------------- + // | Prilagođena funkcija ponavljanja indikatora | // + ----------------------------------------------- ------------------- + int start () {// --- ponekad je za proračun potreban najmanje N traka (na primjer, 100) // ako na grafikonu nema takvog broj traka (na primjer, u vremenskom okviru MN) ako (Bars <100) {return (-1); // zaustaviti izračunavanje i izaći unaprijed planirano} // --- broj traka koje se nisu promijenile od posljednjeg broja pokazatelja int count_bars = IndicatorCount (); // --- u slučaju pogreške, napustite ako (prebrojani_bar0 // --- tijekom ponovljenih poziva, povećajte ograničenje za 1 do // --- zajamčeno za ažuriranje vrijednosti indikatora za posljednju granicu bar ++;} // --- glavni ciklus izračuna za (int i = limit; i> 0; i--) {// koristeći vrijednosti traka koje idu dublje u povijest za 5 i 10 Buff1i = 0,5 * (Openi + 5 + Closei + 10)}}

Često postoji pogrešno rukovanje velikim brojem_broj = = 0 (početni položaj ograničenja mora se smanjiti za vrijednost jednaku 1 + maksimalni indeks u odnosu na varijablu petlje).

Također treba imati na umu da u vrijeme izvršenja funkcije start () možemo pristupiti elementima nizova indikatorskih međuspremnika od 0 do Bars () - 1. Ako treba raditi s nizovima koji nisu indikatori međuspremnici, tada bi se njihova veličina trebala povećati korištenjem funkcije ArrayResize () u skladu s trenutnom veličinom međuspremnika. Maksimalni indeks elementa za adresiranje može se dobiti i pozivom ArraySize () s jednim od međuspremnika pokazatelja kao argumentom.

Podjela po nuli (nulta podjela)

Pogreška „Nulta podijela“ nastaje ako je djelitelj jednak nuli tijekom rada podjele:

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

Kada se izvrši ova skripta, kartica "Stručnjaci" prikazuje poruku o pogrešci i program se prekida:

Obično se takva pogreška događa u slučajevima kada se vrijednost djelitelja određuje vrijednostima nekih vanjskih podataka. Na primjer, ako se analiziraju parametri trgovanja, tada će vrijednost uključene marže biti 0 ako nema otvorenih naloga. Drugi primjer: ako se analizirani podaci čitaju iz datoteke, tada, ako su odsutni, ne može se jamčiti ispravan rad. Iz tog razloga, preporučljivo je pokušati uzeti u obzir takve slučajeve i pravilno postupati s njima.

Najlakši način je provjeriti djelitelj prije operacije podjele i prikazati poruku o netočnoj vrijednosti parametra:

void OnStart () {int a = 0, b = 0, c; ako je (b! = 0) {c = a / b; Ispis (c); } else {Ispis ("Pogreška: b = 0"); povratak; }}

Kao rezultat, ne dolazi do kritične pogreške, ali se prikazuje poruka o pogrešnoj vrijednosti parametra i operacija se završava:

Koristite 0 umjesto NULL za trenutni znak

U staroj verziji prevodioca dopušteno je koristiti 0 (nula) kao argument u funkcijama koje zahtijevaju financijski instrument.

Na primjer, vrijednost tehničkog pokazatelja Pomični prosjek za trenutni simbol može se zatražiti na sljedeći način:

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

U novom sastavljaču, da biste naznačili trenutni znak, morate izričito navesti NULL:

AlligatorJawsBufferi = iMA (NULL, 0,13,8, MODE_SMMA, PRICE_MEDIAN, i); // ispraviti

Uz to se trenutni simbol i razdoblje grafikona mogu odrediti funkcijama Symbol () i Period ().

AlligatorJawsBufferi = iMA (Symbol (), Period (), 13.8, MODE_SMMA, PRICE_MEDIAN, i); // ispraviti

Još bolje, ako koristite unaprijed definirane varijable _Symbol i _Period - one se brže obrađuju:

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

Unicode nizovi i njihova upotreba u DLL-u

Nizovi su niz Unicode znakova. Imajte to na umu i koristite odgovarajuće značajke sustava Windows. Na primjer, kada koristite funkcije knjižnice wininet.dll umjesto InternetOpenA () i InternetOpenUrlA (), trebali biste nazvati InternetOpenW () i InternetOpenUrlW (). Pri prosljeđivanju nizova na DLL koristite MqlString strukturu:

#pragma paket (push, 1) struct MqlString {int size; // 32-bitni cijeli broj, sadrži veličinu međuspremnika dodijeljenog nizu LPWSTR međuspremnika; // 32-bitna adresa međuspremnika koji sadrži rezervirani niz int; // 32-bitni cijeli broj, rezervirano, ne koristi}; #pragma paket (pop, 1)

Dijeljenje datoteka

Prilikom otvaranja datoteka morate eksplicitno navesti FILE_SHARE_WRITE i FILE_SHARE_READ zastave za dijeljenje.

Ako su odsutni, datoteka će se otvoriti u ekskluzivnom načinu rada, što nikome drugom neće dopustiti da je otvori dok je monopolist ne zatvori.

Na primjer, kada radite s offline ljestvicama, morate izričito navesti zajedničke zastave:

// 1. promjena - dodajte zajedničke zastave ExtHandle = FileOpenHistory (c_symbol + i_period + ". Hst", FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ);

Značajka pretvorbe datuma

Imajte na umu da pretvaranje vrste datuma u niz ovisi o načinu kompilacije:

datetime date = D'2014.03.05 15:46:58 '; string str = "mydate =" + datum; // --- str = "mydate = 1394034418" - bez stroge direktive #property // --- str = "mydate = 2014.03.05 15:46:58" - s strogom direktivom #property

Na primjer, pokušaj rada s datotekama čije ime sadrži dvotočka rezultiraće pogreškom.

Rukovanje pogreškama

Budući da nijedan trgovački stručnjak ne može bez upotrebe ugrađenih korisnički definiranih funkcija, prvo ćemo pokušati pojednostaviti svoj život analizirajući pogreške vraćene tim funkcijama.

Neke su knjižnice dostupne u setu „out of the box“ kako bi se pojednostavilo pisanje savjetnika, uključujući i one za rad s pogreškama. Spremljeni su u mapu MQL4 / Uključi:

Trebat će nam dvije knjižnice:

  • stderror.mqh - sadrži konstante za broj svake pogreške;
  • stdlib.mqh - sadrži nekoliko pomoćnih funkcija, uključujući funkciju vraćanja opisa pogreške kao niza:
string ErrorDescription (int error_code)

Stoga ćemo obje naše knjižnice povezati s našim projektom:

#include #include 

Sami opisi pogrešaka nalaze se u datoteci MQL4 / Library / stdlib.mql4 i nalaze se na engleskom jeziku. Stoga, ako se protivite stranim jezicima, opise možete prepisati na svom materinjem jeziku.

Još jedna ugrađena funkcija koja nam treba je GetLastError (). Ona je ona koja vraća kodove pogrešaka u obliku cijelog broja (int) koji ćemo potom obraditi. Kodovi pogrešaka i njihovi opisi na ruskom mogu se naći u mql4 priručniku iz MetaQuotesa. Odatle možete preuzeti informacije za prevođenje datoteke stdlib.mql4 na ruski.

Sada kada smo povezali potrebne knjižnice, razmotrit ćemo rezultate funkcija izravno povezanih s trgovinskim operacijama, jer ignoriranje kvarova u tim funkcijama može dovesti do kritičnih posljedica za robota.

Nažalost, koristeći MQL4, ne možete napisati generaliziranu biblioteku za obradu svih mogućih situacija s pogreškama. U svakom ćete slučaju morati odvojeno obraditi pogreške. No nije sve tako loše - mnoge pogreške ne trebaju se obrađivati, dovoljno je da ih otklonite u fazi razvoja i testiranja stručnjaka, iako za to morate znati na vrijeme o njihovoj prisutnosti.

Na primjer, razmotrite dvije pogreške tipične za stručnjake MQL4:

  1. Pogreška 130 - ERR_INVALID_STOPS
  2. Pogreška 146 - ERR_TRADE_CONTEXT_BUSY

Jedan od slučajeva kada se dogodi prva pogreška je pokušaj stručnjaka da donese nalog za čekanje preblizu tržištu. Njegova prisutnost može ozbiljno ugroziti rad stručnjaka u nekim slučajevima. Na primjer, recimo da stručnjak, otvarajući profitabilnu poziciju, donosi zaradu na svakih 150 bodova. Ako sljedeći takav pokušaj uzrokuje pogrešku od 130, a cijena nepovratno vrati na prethodnu stopu, stručnjak vas može lišiti legitimne dobiti. Unatoč mogućnosti takvih posljedica, ovu se pogrešku u osnovi može otkloniti dovršetkom stručnog koda tako da se uzme u obzir minimalna dopuštena udaljenost između cijene i zaustavljanja.

Druga greška koja se odnosi na zauzetost trgovinskog konteksta terminala ne može se u potpunosti otkloniti. Kada nekoliko stručnjaka radi na istom terminalu, uvijek je moguće da će jedan od stručnjaka pokušati otvoriti radno mjesto, dok drugi još uvijek radi isto. Stoga se s takvom pogreškom treba uvijek postupati.

Stoga bismo uvijek trebali biti svjesni hoće li neka od ugrađenih funkcija vratiti grešku dok EA radi. To se može postići pomoću sljedeće jednostavne pomoćne funkcije:

void logError (string functionName, string msg, int errorCode = -1) {Print ("GREŠKA: u" + functionName + "()"); Ispis ("GREŠKA:" + msg); int err = GetLastError (); ako (errorCode! = -1) {err = errorCode; } if (err! = ERR_NO_ERROR) {Print ("ERROR: code =" + err + "-" + ErrorDescription (err)); }}

Koristit ćemo ga na sljedeći način:

void openLongTrade () {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask + 5, 5, 0, 0); if (ticket == -1) {logError ("openLongTrade", "nije mogao otvoriti nalog"); }}

Naravno, ovo je pojednostavljeni primjer. Za pisanje kompetentnijih funkcija otvaranja, zatvaranja i izmjene naloga, pogledajte ovu lekciju.

Prvi parametar funkcije logError () naziv je funkcije u kojoj je greška otkrivena, u našem primjeru, u funkciji openLongTrade (). Ako naš stručnjak na nekoliko mjesta nazove funkciju OrderSend (), to će nam omogućiti da točno utvrdimo u kojem je od njih došlo do pogreške. Drugi parametar prolazi opis pogreške tako da možete točno shvatiti gdje je pogreška otkrivena unutar funkcije openLongTrade (). To može biti ili kratki opis pogreške ili detaljniji opis vrijednosti svih parametara prenesenih na ugrađenu funkciju.

Preferiram potonju opciju, jer ako se dogodi pogreška, možete odmah dobiti sve informacije potrebne za analizu. Na primjer, pretpostavimo da je trenutna cijena prije nego što nazovete OrderSend () morala znatno odstupati od posljednje poznate cijene. Zbog toga će se dogoditi pogreška tijekom izvršavanja ovog primjera, a sljedeći se redovi pojavljuju u stručnom dnevniku:

POGREŠKA: in openLongTrade () POGREŠKA: nije se moglo otvoriti red GREŠKA: code = 138 - zahtjev

Odnosno, odmah ćete vidjeti:

  • u kojoj se funkciji dogodila greška;
  • na što se odnosi (u ovom slučaju pokušaj otvaranja položaja);
  • koja je greška nastala (kod pogreške i njezin opis).

Sada razmotrite treći, neobavezni parametar, funkcije logError (). To je potrebno u onim slučajevima kada želimo obraditi određenu vrstu pogreške, a o ostalom ćemo izvijestiti u protokolu stručnog rada, kao i prije:

void updateStopLoss (dvostruko newStopLoss) {bool modificiran = OrderModify (OrderTicket (), OrderOpenPrice (), newStopLoss, OrderTakeProfit (), OrderExpiration ()); if (! izmijenjeno) {int errorCode = GetLastError (); ako (errorCode! = ERR_NO_RESULT) {logError ("updateStopLoss", "nije uspio izmijeniti redoslijed", errorCode); }}}

Ovdje se u funkciji updateStopLoss () poziva ugrađena funkcija OrderModify (). Ova se funkcija malo razlikuje u pogledu upravljanja pogreškama od OrderSend (). Ako se nijedan od parametara naloga koji se mijenja ne razlikuje se od njegovih trenutnih parametara, funkcija će vratiti pogrešku ERR_NO_RESULT. Ako je u našem stručnjaku takva situacija dopuštena, onda bismo trebali posebno zanemariti ovu pogrešku. Da bismo to učinili, analiziramo vrijednost koju je vratio GetLastError (). Ako se dogodi pogreška s kodom ERR_NO_RESULT, tada ništa ne šaljemo u protokol.

No, ako se dogodila još jedna greška, potrebno je u potpunosti izvijestiti o njoj, kao što smo to radili ranije. Zato spremamo rezultat funkcije GetLastError () u intermedijarnu varijablu i treći parametar prosljeđujemo u funkciju logError (). Činjenica je da ugrađena funkcija GetLastError () automatski resetira kod zadnje pogreške nakon poziva. Ako kod pogreške nismo izričito proslijedili logError (), tada će se greška s kodom 0 i opisom „bez pogreške“ odražavati u protokolu.

Slične radnje moraju se provesti tijekom obrade drugih pogrešaka, na primjer, rekvizita. Glavna ideja je rukovati samo greškama koje je potrebno obraditi, a ostatak proslijediti funkciji logError (). Tada ćemo uvijek biti svjesni je li tijekom rada stručnjaka došlo do neočekivane pogreške. Nakon analize zapisnika, možemo utvrditi da li je za ovu pogrešku potrebna posebna obrada ili se može eliminirati finaliziranjem ekspertnog koda. Ovakav pristup često značajno pojednostavljuje život i smanjuje vrijeme potrebno za suočavanje s pogreškama.

Dijagnostika logičkih pogrešaka

Logičke pogreške u stručnom kodu mogu uzrokovati mnoge probleme. Nepostojanje mogućnosti postupnog uklanjanja pogrešaka stručnjaka čini borbu protiv takvih pogrešaka ne baš ugodan zadatak. Trenutno glavni alat za dijagnosticiranje ovog problema je ugrađena funkcija Print (). Pomoću nje možete ispisati trenutne vrijednosti važnih varijabli, kao i evidentirati rad stručnjaka izravno u terminalu tijekom testiranja. Pri uklanjanju pogrešaka stručnjaka tijekom testiranja s vizualizacijom može vam pomoći i ugrađena funkcija Comment () koja prikazuje poruke na grafikonu. U pravilu, kako biste bili sigurni da stručnjak ne radi kako treba, morate dodati privremene pozive u funkciju Print () i zabilježiti interno stanje stručnjaka na navodnim mjestima na kojima je došlo do pogreške.

Međutim, da biste otkrili složene pogreške, ponekad morate dodati desetine takvih poziva na funkciju Print (), a nakon što pronađete i riješite problem, morate ih izbrisati ili komentirati kako se stručni kôd ne bi zatrpao i njegovo testiranje ne bi usporilo. Situacija se pogoršava ako se u stručnom kodu već koristi funkcija Print () za periodičko bilježenje različitih stanja. Tada se uklanjanje privremenih poziva na Print () ne može obaviti jednostavnim traženjem fraze 'Print' u stručnom kodu. Morate razmišljati o tome kako ne biste uklonili korisne pozive u ovu funkciju.

Na primjer, prilikom evidentiranja pogrešaka funkcija OrderSend (), OrderModify () i OrderClose () korisno je ispisati trenutnu vrijednost varijabli Bid and Ask u protokol. To olakšava prepoznavanje uzroka pogrešaka poput ERR_INVALID_STOPS i ERR_OFF_QUOTES.

Kako biste istaknuli takve dijagnostičke nalaze u protokolu, preporučujem uporabu sljedeće pomoćne funkcije:

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

To je poželjno iz nekoliko razloga. Prvo, sada se takvi pozivi neće pojaviti kada u ekspertnom kodu potražite „Ispis“, jer ćemo pretraživati ​​logInfo. Drugo, ova funkcija ima još jednu korisnu značajku, o kojoj ćemo govoriti malo kasnije.

Dodavanje i uklanjanje privremenih dijagnostičkih poziva funkciji Print () oduzima nam dragocjeno vrijeme. Stoga predlažem da razmotrimo još jedan pristup koji je učinkovit u otkrivanju logičkih pogrešaka u kodu i omogućava nam malo uštede vremena. Razmotrite sljedeću jednostavnu funkciju:

void openLongTrade (dvostruki stopLoss) {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (ticket == -1) {logError ("openLongTrade", "nije mogao otvoriti nalog"); }}

U ovom slučaju, budući da otvaramo dugu poziciju, sasvim je očito da za vrijeme normalnog rada stručnjaka vrijednost parametra stopLoss nikada neće biti veća ili jednaka trenutnoj cijeni ponude. To jest, kad se poziva funkcija openLongTrade (), zaustavni uvjet <Ponuda je uvijek zadovoljen. Budući da za to znamo već u fazi pisanja dotične funkcije, možemo je odmah koristiti na sljedeći način:

void openLongTrade (dvostruki stopLoss) {assert ("openLongTrade", stopLoss <Ponuda, "stopLoss <Ponuda"); int ticket = OrderSend (Simbol (), OP_BUY, 1.0, Pitaj, 5, stopLoss, 0); if (ticket == -1) {logError ("openLongTrade", "nije mogao otvoriti nalog"); }}

Odnosno, svoju izjavu zabilježimo u kodu pomoću nove assrt funkcije (). Sama funkcija izgleda prilično jednostavno:

poništavanje tvrdnje (string functionName, tvrdnja bool, string opis = "") {if (! tvrdnja) {Print ("ASSERT: u" + functionName + "() -" + opis); }}

Prvi parametar funkcije je njezin naziv u kojem se provjerava naše stanje (analogno funkciji logError ()). Drugi parametar prolazi rezultat provjere ovog stanja. I treći parametar je njegov opis. Kao rezultat, ako očekivani uvjet nije ispunjen, u protokolu će se prikazati sljedeće informacije:

  • naziv funkcije u kojoj je uvjet povrijeđen;
  • opis narušenog stanja.

Kao opis možete prenijeti, na primjer, sam uvjet ili možete prikazati detaljniji opis koji sadrži vrijednosti kontroliranih varijabli u vrijeme provjere stanja, ako to pomaže razumjeti uzroke pogreške.

Naravno, razmatrani primjer je maksimalno pojednostavljen. No, nadam se da se glavna ideja prilično dobro odražava. U procesu izgradnje funkcionalnosti stručnjaka, svjesni smo kako to treba raditi i koja stanja i ulazni parametri funkcija su valjani, a koji nisu. Ispravljajući to u ekspertnom kodu pomoću funkcije assrt (), dobivamo vrijedne informacije o mjestu na kojem je kršena logika rada stručnjaka. Nadalje, djelomično se oslobađamo potrebe dodavanja i uklanjanja privremenih poziva funkciji Print (), budući da funkcija assert () šalje dijagnostičke poruke protokolu samo kad se otkriju nedosljednosti pod očekivanim uvjetima.

Još jedan koristan trik je korištenje ove funkcije prije svake operacije podjele. Činjenica je da se ponekad, kao rezultat jedne ili druge logičke pogreške, ponekad dogodi podjela prema nuli. Rad stručnjaka u ovom slučaju prestaje, a samo se jedan redak pojavljuje u protokolu s tužnom dijagnozom: "nulta podjela". Dovoljno je teško otkriti gdje se ta pogreška dogodila ako se operacija podjele više puta koristi u kodu. Ovdje će vam pomoći funkcija assert (). Prije svake podjele umetamo odgovarajuće provjere:

assert ("buildChannel", udaljenost> 0, "udaljenost> 0"); dvostruki nagib = delta / udaljenost;

A sada, u slučaju podjele na nulu, dovoljno će biti samo pogledati u zapisnike kako bi se utvrdilo na kojem je točno mjestu nastala greška.

Državno postupanje

Dok stručnjak radi na vašem računu, mogu se pojaviti neke situacije koje nisu pogreške - navode stručnjaci. Takva stanja nisu pogreške, ali svejedno treba ih zabilježiti. U tome pomažu posebne funkcije jezika mql4.

IsExpertEnabled () funkcija vraća informacije o sposobnosti pokretanja stručnjaka. Funkcija će se vratiti true ako se stručnjacima dozvoli pokretanje u klijentskom terminalu, u protivnom vraća false. Ako se pogrešno vrati, korisno će biti obavijestiti korisnika sa zahtjevom za omogućavanje odgovarajuće postavke. Primjer:

void OnStart () {if (! IsExpertEnabled () {// savjetnicima nije dopušteno trgovanje upozorenjem ("Pažnja! Molimo pritisnite gumb" Stručni savjetnici "u MT4");} // algoritam rada savjetnika povratak;}

Ako stručnjak koristi vanjske biblioteke, korisna je funkcija IsLibrariesAllowed (). Vraća se true ako stručnjak može nazvati funkciju knjižnice, u protivnom vraća false.

Ako je knjižnica u obliku dll datoteke, korisna je funkcija IsDllsAllowed (). Također će biti korisno provjeriti je li općenito moguće trgovati uz pomoć stručnjaka koji koriste funkciju IsTradeAllowed ().

Ako želite saznati je li račun demo ili stvaran, možete koristiti funkciju IsDemo ().

Sve gore provjere treba obaviti u funkciji OnInit ().

Naravno, vrijedi povremeno provjeriti vezu s poslužiteljem. IsConnected () funkcija će vam pomoći.

Sljedeće tri funkcije pomoći će vam u određivanju u kojem je režimu EA. Ako se IsOptimisation () vrati istinito, provodi se optimizacija, ako IsTesting (), zatim testiranje, IsVisualMode () - testiranje u načinu vizualizacije. Za svaku od tih opcija, savjetnik može imati svoju logiku. Na primjer, za način vizualizacije možete prikazati nešto na grafikonu (a ne prikazivati ​​ga u drugim modusima radi štednje resursa). U testnom načinu možete prikazati podatke o ispravljanju pogrešaka, u načinu optimizacije osvijetlite kod što je više moguće kako biste uštedjeli vrijeme.

I zadnja funkcija je IsTradeContextBusy (). Vratit će se ako je nit za obavljanje trgovačkih operacija zauzeta. To može biti korisno kad stručnjak obavlja trgovinske radnje. Pomoću funkcije mirovanja možete pričekati trenutak i pokušati ponovo.

Još jedna korisna značajka je UninitializeReason ()

int deinit () {switch (UninitializeReason ()) {case REASON_CHARTCLOSE: case REASON_REMOVE: CleanUp (); razbiti; // čisti i besplatni resursi. slučaj REASON_RECOMPILE: slučaj REASON_CHARTCHANGE: slučaj REASON_PARAMETERS: slučaj REASON_ACCOUNT: StoreData (); razbiti; // priprema za ponovno pokretanje. } // ...}

Možete i prijaviti razlog odlaska savjetnika.

Kodovi najčešće pogreške i njihovo vjerojatno rješenje

Broj pogreškevrijednostProblemodluka
4, 146Poslužitelj za trgovanje je zauzetSavjetnik je dao previše naloga istovremeno ili bez čekanja na odgovor poslužitelja, tijekom operacije - savjetnik pokušava poslati novu narudžbuPonovno pokretanje terminala ili optimizacija savjetodavnog koda korištenjem funkcija rukovanja pogreškama
8, 141Prečesto traženi zahtjeviPrethodni razlozi pogreške u vrlo čestom zahtjevuSlično rješenje
129Pogrešna cijenaCijena po kojoj pokušavate otvoriti poziciju (KUPITE ili PRODAJEM) je netočnaKUPUJEM treba otvoriti Pitaj i zatvoriti BID;
PRODAJU treba otvoriti BID, a zatvoriti ASK
130, 145Pogrešna stopalaZaustavi gubitak, uzmi profit ili otvorni nivo na čekanju ili ograničenju nije ispravan.
Zaustavljanja su preblizu cijeni.
Vaš je račun otvoren u grupi ECN (ETSN) ili NDD (NDD), što vam onemogućuje da odmah postavite zaustavljanja
Provjerite vrijednosti vaših zaustavnih gubitaka, uzmite profit, s brokerom provjerite minimalnu razinu zaustavljanja vašeg instrumenta, kad postavljate zaporke - pridržavajte se minimalne razine udaljenosti. Dobro napisani savjetnik trebao bi imati funkcije za rad na ECN i NDD računima - to se događa izmjenom naloga nakon otvaranja
131Pogrešan volumenPogrešno lot pri otvaranju posla, ili manji od minimalnog (više od maksimalnog). Dubina bita puno može se razlikovati od bitovaProvjerite ispravno otvaranje partije, proučite specifikacije ugovora i pročitajte uvjete trgovine u vašem DC-u, provjerite minimalnu i maksimalnu partiju u vašem DC-u i na svom računu
132Tržište je zatvorenoTržište je zatvoreno vikendomPokušajte kontaktirati tržnicu nakon vikenda
133Nema trgovineTrenutno nema trgovanjaTrgovanje ovim valutnim parom zabranjeno je - u određeno vrijeme ili općenito. Često posrednici imaju pauzu od nekoliko minuta u ponoć
134Nema dovoljno novca za dovršenje operacijeMnoga koju pokušavate otvoriti prevelika je i nema dovoljno maržeProvjerite razinu raspoloživih sredstava i izračunajte sredstva koja trebate puno otvoriti, pratite razinu raspoloživih sredstava
135-138Cijena se promijenilaPredložiti, prebrzo tržište (vijesti), Broker ili DC ne dopušta vam da stavite poziciju po deklariranoj cijeniNe trgujte u takvim trenucima, povećajte razinu proklizavanja, ali imajte na umu da to podrazumijeva otvaranje pozicija ne po cijeni koju ste naveli. Navedite funkciju rukovanja pogreškama i broj pokušaja otvaranja pozicija u EA
147Korištenje datuma isteka narudžbe za brokera je zabranjenoVaš savjetnik ili pokušavate odrediti datum isteka naloga na čekanjuU Stručnom savjetniku, u funkciji OrderSend, postavite parametar istjecanja na 0 (nula). Ne postavljajte datum isteka
148Broj otvorenih i neriješenih naloga dosegao je ograničenje koje je postavio brokerMaksimalan broj otvorenih naloga i pozicija dosegao je ograničenje koje je postavio brokerIzbrišite ili zatvorite dio pozicija. Zaustavite proces otvaranja novih radnih mjesta
4012, 4013Ostatak podjele prema nuliPokušavate podijeliti broj s 0 (nula)Provjerite kod savjetnika da li postoji pogreška ili provjerite sve vrijednosti iz funkcije MarketInfo u trenutku vraćanja 0, ponekad kada se MarketInfo (Symbol (), MODE_SPREAD) ne vraća namaz, već 0 (za posrednike s plutajućim širenjem)
4017DLL pozivi nisu dopušteniDLL pozivi su zabranjeni na vašem terminaluDopusti DLL poziv putem izbornika - Usluga - Postavke - Savjetnik - Dopusti DLL poziv
4018, 4019Nije moguće učitati bibliotekuBiblioteka je oštećena ili je poziv propao, možda uopće nedostajeProvjerite DLL
4020Pozivi na funkcije vanjske biblioteke nisu dopušteniPozivanje funkcija vanjskih stručnjaka zabranjeno je na vašem terminaluDopustite pozivanje funkcija putem Izbornika - Usluga - Postavke - Savjetnik - Dopustite pozivanje vanjskih stručnjaka
4103Datoteku nije moguće otvoritiOva datoteka ne postoji ili je zaključana nekim drugim postupkom.Provjerite za navedenu datoteku. Provjerite je li datoteka zaključana antivirusnim sustavom, je li dopušten način čitanja datoteke za čitanje
4106Nepoznati likNema simbola u pregledu tržištaU pregledu tržišta - desnom tipkom miša - prikazujte sve simbole. Provjerite naziv simbola u savjetniku i njegovu prisutnost u pregledu tržišta. Neki savjetnici koriste jasna imena bez sufiksa, a brokeri namjerno postavljaju sufikse, na primjer EURUSDx, gdje je x sufiks
4108Nevažeći broj ulazniceKarta za narudžbu koju je stručnjak odabrao ne postoji. Stručnjak pokušava odabrati kartu, ali ovaj je nalog zatvorio drugi savjetnik ili rukom. Kada pokušavate izvršiti nalog preko naloga, broker je izvršio i zatvorio brokerAko se ova greška pojavljuje vrlo često, 100-1000 puta u minuti, provjerite funkcije svog savjetnika. Onemogućite druge savjetnike ili ih konfigurirajte tako da se ne sukobljavaju, ne zatvarajte narudžbu rukama kad stručnjak obavlja operaciju. Ponekad se to događa kada nekoliko savjetnika koristi isti MagicNumber.
4109Trgovina nije dopuštenaSavjetnicima je zabranjeno trgovati, na grafikonu je tužan osmijeh ili križUključite potvrdni okvir "Dopusti savjetniku da trguje" na depozitu prilikom instaliranja savjetnika ili u izborniku - usluga - postavke - savjetnici
4110, 4111Dugi / kratki položaji nisu dopušteniU postavkama savjetnika, na kartici Općenito, nije dopuštena vrsta položajaNa kartici Općenito, prilikom instaliranja savjetnika postoji izbor mjesta koje se mogu otvoriti

Zaključak

Razmatrane pomoćne funkcije i jednostavni trikovi mogu značajno pojednostaviti i ubrzati proces otkrivanja i ispravljanja pogrešaka u kodu trgovačkih stručnjaka napisanom na programskom jeziku MQL4. Pravilno pisanje koda i funkcija za evidentiranje i praćenje rada savjetnika znatno ubrzava proces njegovog razvoja.

Pogledajte video: Robot Building Tutorials #6 - Intro to MQL4 (Listopad 2019).

Ostavite Komentar