Lemmik Postitused

Toimetaja Valik - 2020

MQL4: vigade ja hoiatuste parandamine kompileerimise ajal MetaEditoris

MQL4 kauplemisasjatundjate arendamine pole lihtne ülesanne. Esiteks on juba praegu probleemiks mis tahes keeruka kauplemissüsteemi algoritmimine, kuna peate arvestama paljude detailidega, alustades TS-i omadustest ja lõpetades MetaTrader 4 keskkonna spetsiifikaga. Teiseks ei kõrvalda isegi üksikasjaliku algoritmi olemasolu raskusi, mis tekivad väljatöötatud ülekandmisel. MQL4 programmeerimiskeele algoritm.

Koostaja pakub õigete ekspertide kirjutamisel teatavat abi. Pärast kompilatsiooni alustamist teatab MetaEditor kõigist teie koodi süntaksivigadest. Kuid kahjuks võib teie nõustaja lisaks süntaksivigadele sisaldada ka loogilisi vigu, mida kompilaator ei suuda tabada. Seetõttu peame seda ise tegema. Kuidas seda teha, on meie tänases materjalis.

Kõige tavalisemad kompimisvead

Kui koodis on vigu, ei saa programmi kompileerida. Kõigi vigade täielikuks kontrollimiseks on soovitatav kasutada ranget kompileerimisrežiimi, mille kehtestab direktiiv:

#property range

See režiim lihtsustab oluliselt vigade otsimist. Liigume nüüd kõige tavalisemate kompileerimisvigade juurde.

Identifikaator sobib reserveeritud sõnaga

Kui muutuja või funktsiooni nimi sobib ühega reserveeritud sõnadest:

int char; // vale int char1; // õige int char () // vale {return (0); }

siis kuvab kompilaator veateateid:

Selle vea parandamiseks peate parandama muutuja või funktsiooni nime. Soovitan jääda järgmise nimetamissüsteemi juurde:

Kõik funktsioonid peavad näitama toimingut. See tähendab, et see peab olema tegusõna. Näiteks OpenLongPosition () või ModifyStopLoss (). Lõppude lõpuks teevad funktsioonid alati midagi, eks?

Lisaks on soovitatav kutsuda funktsioone niinimetatud CamelCase'i stiilis. Ja muutujad on cebab_case stiilis. See on tavaline tava.

Muutujate nimedest rääkides. Muutujad on nimisõnad. Näiteks my_stop_loss, nädala_nädal, praegune_kuu. Muutujat pika nimega nimetada pole nii hirmutav, palju hullem on seda arusaamatult nimetada. Mis on Dow, Dow Jonesi indeks? Ei, see osutub nädalapäevaks. Muidugi, täna saate juba aru, mis see muutuja on. Kuid kui avate nõustaja koodi kuu aega hiljem, ei ole kõik enam nii ilmne. Ja see aeg kaotas mineviku sõnumite dekodeerimise - kas teil on seda vaja?

Erimärgid muutujate ja funktsioonide nimedes

Minge edasi. Kui muutujate või funktsioonide nimed sisaldavad erimärke ($, @, periood):

int $ var1; // vale int @ var2; // vale int var.3; // vale tühine f @ () // vale {tagasipöördumine; }

siis kuvab kompilaator veateateid:

Selle vea parandamiseks peate uuesti muutujate või funktsioonide nimesid kohandama, või nimetama need kohe inimlikult. Ideaalis peaks kood olema kirjutatud nii, et isegi inimene, kes programmeerimist ei oska, loeks selle lihtsalt läbi ja saaks aru, mis seal toimub.

Vigad lülitusavalduse kasutamisel

Kompilaatori vana versioon lubas lüliti avaldistes ja konstantides kasutada mis tahes väärtusi:

tühine algus () {kahekordne n = 3,14; lüliti (n) {juhtum 3.14: Prindi ("Pi"); vaheaeg; juhtum 2.7: print ("E"); vaheaeg; }}

Uues kompilatsioonis peavad lülituslause avaldised ja konstandid olema täisarvud, nii et selliste konstruktide kasutamisel ilmnevad vead:

Seega, klassifitseerides klassikoodi, näiteks WallStreet, Ilan ja muud katkematud elemendid (mis on enesearendamiseks väga kasulik) sõeludes, võite selle veaga kokku puutuda. Seda käsitletakse väga lihtsalt, näiteks siin sellise rea kasutamisel:

lüliti (MathMod (päev_48, 10))

Selle abil saate probleemi hõlpsalt lahendada:

lüliti ((int) MathMod (päev_48, 10))

Funktsiooni tagastamise väärtused

Kõik funktsioonid, välja arvatud tühine, peavad tagastama deklareeritud tüübi väärtuse. Näiteks:

int funktsioon () {}

Range kompileerimise režiimis (range) ilmneb tõrge:

Kompileerimisrežiimis kuvab kompilaator vaikimisi hoiatuse:

Kui funktsiooni tagastatav väärtus ei vasta deklaratsioonile:

int init () {tagasi; }

Seejärel ilmneb range kompileerimise režiimis tõrge:

Kompileerimisrežiimis kuvab kompilaator vaikimisi hoiatuse:

Selliste funktsioonikoodi vigade parandamiseks peate lihtsalt lisama tagastamisväljavõtte tagastamise vastava tüübi tagastamisväärtusega.

Funktsioonide argumentide massiivid

Funktsioonide argumentide massiive edastatakse ainult viitega. Varem see nii ei olnud, nii et vanadest nõustajatest leiate selle vea. Siin on näide:

kahekordne ArrayAverage (topelt a) {tagastamine (0); }

Kui kood antakse kompileerimise režiimis (range), kuvatakse tõrge:

Kompileerimisrežiimis kuvab kompilaator vaikimisi hoiatuse:

Selliste vigade parandamiseks peate massiivi ülekandmise selgesõnaliselt osutama viite abil, lisades massiivi nimele prefiksi & prefiksi:

kahekordne ArrayAverage (topelt ja a) {tagastamine (0); }

Muide, püsimassiive (aeg, avatud, kõrge, madal, suletud, maht) ei saa referentsiga mööda saata. Näiteks kõne:

ArrayAverage (avatud);

sõltumata kompileerimisrežiimist põhjustab vea:

Selliste vigade kõrvaldamiseks peate vajalikud andmed püsimassiivist kopeerima:

// --- massiiv avatud hinna väärtuste kahekordse OpenPricesi hoidmiseks; // --- kopeerige alghinna väärtused OpenPrices ArrayCopy massiivi (OpenPrices, Open, 0,0, WHOLE_ARRAY); // --- helistage funktsioonile ArrayAverage (OpenPrices);

Üks levinumaid vigu on näitaja kaotamine nõustaja poolt. Sellistel juhtudel kirjutavad foorumite asjatundjad tavaliselt vihaselt: "Nõustaja ei tööta!" või "Panen nõustaja edetabelisse ja midagi ei juhtu!". Selle küsimuse lahendus on tegelikult väga lihtne. Nagu alati, vaadake lihtsalt terminali vahekaarti "Logi" ja leidke sealt kirje:

2018.07.08 09: 15: 44.957 2016.01.04 00:51 ei saa avada faili 'C: Users1AppDataRoamingMetaQuotesTerminal MQL4indicatorsKELTNER_F12.ex4' 2

See ütleb meile, et nad unustasid indikaatori kausta panna või on selle nimi teisiti. Kui indikaator puudub, peate selle indikaatoritega kausta lisama. Kui on, siis tasub kontrollida selle nime nõustaja koodis - suure tõenäosusega kutsutakse seda seal teisiti.

Kompilaatori hoiatused

Kompilaatori hoiatused on informatiivsed ja ei ole tõrketeated, kuid need osutavad võimalikele vigade allikatele ja on parem need parandada. Puhas kood ei tohiks sisaldada hoiatusi.

Globaalsete ja kohalike muutujate nimede ristumised

Kui globaalsel ja kohalikul tasandil leidub samanimelisi muutujaid:

int i; // globaalne muutuja void OnStart () {int i = 0, j = 0; // kohalikud muutujad (i = 0; i <5; i ++) {j + = i; } PrintFormat ("i =% d, j =% d", i, j); }

siis kuvab kompilaator hoiatuse ja näitab reanumbrit, millel globaalne muutuja deklareeritakse:

Selliste hoiatuste parandamiseks peate kohandama globaalsete muutujate nimesid.

Tüübi mittevastavus

Järgmises näites:

#property range void OnStart () {double a = 7; ujuk b = a; int c = b; string str = c; Trükk (c); }

range kompileerimise režiimis tüübi mittevastavusega kuvab kompilaator hoiatused:

Selles näites hoiatab kompilaator võimaliku täpsuse kaotamise eest erinevate andmetüüpide määramisel ja tüübi kaudset teisendamist stringiks.

Parandamiseks peate kasutama selget tüüpi teisendust:

#property range void OnStart () {double a = 7; ujuk b = (ujuk) a; int c = (int) b; string str = (string) c; Trükk (c); }

Kasutamata muutujad

Muutujate olemasolu, mida programmikoodis ei kasutata (lisaüksused), ei ole hea vorm.

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

Selliste muutujate teated kuvatakse sõltumata kompileerimisrežiimist:

Selle parandamiseks peate lihtsalt eemaldama kasutamata muutujad programmikoodist.

Kompileerimisvigade diagnostika

Sageli tekivad pärast programmi kirjutamist kompileerimise probleemid koodi vigade tõttu. Need võivad olla kõige erinevamad vead, kuid igal juhul on vaja kiiresti tuvastada koodilõik, kus viga tehakse.

Sageli võtavad inimesed lisakinnituse otsimiseks palju aega ja palju närve. Siiski on olemas viis vigade kiireks avastamiseks, mis põhineb kommenteerimisel.

Piisavalt suure koodi kirjutamine ilma ühegi veata on väga tore. Kuid kahjuks ei juhtu seda sageli. Ma ei arvesta siin vigadega, mis viivad vale koodi täitmiseni. Siin räägime vigadest, mis muudavad kompileerimise võimatuks.

Levinumad vead on täiendava sulgu sisestamine raskes seisukorras, sulgu puudumine, kooloni mitte seadmine, muutujate deklareerimisel koma, muutuja nime trükiviga jne. Sageli näete kompileerimisel kohe, millises reas sarnane viga tehti. Kuid on aegu, kus sellise vea leidmine pole nii lihtne. Ei koostaja ega innukas silm aita meid kohe viga leida. Sellistel juhtudel hakkavad algajad programmeerijad reeglina kogu koodi "ringi käima", püüdes viga visuaalselt tuvastada. Ja ikka ja jälle, samal ajal kui närvid vastu peavad.

Kuid nagu teisedki programmeerimiskeeled, pakub MQL suurepärast tööriista - kommenteerimist. Seda kasutades saate mõne koodi osa keelata. Tavaliselt kasutatakse kommentaare mingite kommentaaride lisamiseks või kasutamata koodilõikude keelamiseks. Kommenteerimist saab edukalt rakendada ka vigade otsimisel.

Vigade otsimine taandub tavaliselt koodiosa kindlaksmääramisele, kus viga tehti, ja seejärel selles jaotises asub viga visuaalselt. Arvan, et on ebatõenäoline, et keegi kahtleb, kas 5–10 koodirida on lihtsam ja kiirem uurida kiiremini kui 100–500 või isegi mitu tuhat.

Kommenteerimise kasutamisel on ülesanne äärmiselt lihtne. Esmalt peate kommenteerima koodi erinevaid sektsioone (mõnikord peaaegu kogu koodi), “keelates” selle. Seejärel eemaldatakse omakorda kommentaar nendest koodiosadest. Pärast järgmist kommentaaride tagasivõtmist üritatakse koostada. Kui kompileerimine õnnestub, siis viga selles koodiosas puudub. Siis avaneb järgmine koodiosa ja nii edasi. Kui koodil on probleemne osa, otsitakse viga visuaalselt ja see parandatakse. Jällegi üritatakse kompileerida. Kui kõik läks hästi, lahendatakse tõrge.

Oluline on õigesti tuvastada koodilõigud, mida peate kommenteerima. Kui see tingimus (või muu loogiline konstruktsioon), siis tuleks seda täielikult kommenteerida. Kui kommenteerite koodilõiku, kus muutujad deklareeritakse, on oluline, et sektsiooni, kuhu nende muutujatega tutvutakse, ei avataks. Teisisõnu, kommenteerimist tuleks rakendada vastavalt programmeerimisloogikale. Selle lähenemisviisi mittejärgimine toob kaasa uusi eksitavaid koostamisvigu.

Siin on suurepärane näide veast, kui pole selge, kust seda otsida ja koodi kommenteerimine võib meid aidata.

Kestusvead

Programmikoodi täitmisel ilmnevaid vigu nimetatakse tavaliselt käitustõrgeteks. Sellised vead sõltuvad tavaliselt programmi olekust ja on seotud muutujate valede väärtustega.

Näiteks kui muutujat kasutatakse massiivi elementide indeksina, siis põhjustab selle negatiivne väärtus paratamatult massiivi väljavoolu.

Massiivi levialast väljas

See tõrge ilmneb indikaatoripuhvritele juurdepääsu korral sageli indikaatorites. Funktsioon IndicatorCount () tagastab ribade arvu, mis pole pärast viimast indikaatorikõnet muutunud. Varem arvutatud ribade indikaatorite väärtusi ei ole vaja uuesti arvutada, seetõttu piisab arvutuste kiirendamiseks ainult paari viimase riba töötlemiseks.

Enamikul näitajatest, mis kasutavad seda arvutuste optimeerimise meetodit, on järgmine vorm:

// + ----------------------------------------------- ------------------- + // | Kohandatud indikaatori iteratsioonifunktsioon | // + ----------------------------------------------- ------------------- + int algus () {// --- mõnikord on arvutamiseks vaja vähemalt N riba (näiteks 100) // kui diagrammil sellist pole ribade arv (näiteks MN ajaraamil), kui (Baarid <100) {tagasipöördumine (-1); // peatage arvutamine ja väljuge graafikust ettepoole} // --- ribade arv, mis pole muutunud pärast viimast indikaatorikõnet int counted_bars = IndicatorCount (); // --- tõrke korral väljuge if (counted_bars0 // --- korduvate kõnede ajal suurendage limiiti 1 võrra // --- garanteeritud, et värskendatakse viimase riba riba ++ indikaatori väärtusi;} // --- peamine arvutustsükkel (int i = piir; i> 0; i--) {// kasutades tulpidega 5 ja 10 minevate ribade väärtusi Buff1i = 0,5 * (Openi + 5 + Closei + 10)}}

Sageli on juhtumite käsitlemine vale. Counted_bars == 0 (piiri algset positsiooni tuleb vähendada väärtusega, mis on võrdne 1 + maksimaalse indeksiga silmuse muutuja suhtes).

Samuti tuleks meeles pidada, et funktsiooni start () täitmise ajal pääseb juurde indikaatorpuhvrite massiivide elementidele vahemikus 0 kuni Baarid () - 1. Kui on vaja töötada massiividega, mis ei ole indikaatorpuhvrid, tuleks nende suurust suurendada funktsiooni ArrayResize () abil, vastavalt indikaatoripuhvrite praegusele suurusele. Elemendi maksimaalse indeksi adresseerimiseks saab ka ArraySize () kutsumisel, kasutades argumendina ühte indikaatoripuhvritest.

Jagage nulliga (nulljaotus)

Viga “Nulljaotus” ilmneb siis, kui jagaja on jagamistoimingu ajal võrdne nulliga:

tühine OnStart () {int a = 0, b = 0, c; c = a / b; Prindi ("c =", c); }

Kui see skript käivitatakse, kuvatakse vahekaardil Eksperdid tõrketeade ja programm lõpeb:

Tavaliselt ilmneb selline tõrge neil juhtudel, kui jagaja väärtus on määratud mõne välise teabe väärtustega. Näiteks kui analüüsitakse kauplemisparameetreid, on vastava marginaali väärtus 0, kui avatud tellimusi pole. Veel üks näide: kui analüüsitud andmeid loetakse failist, siis nende puudumisel ei saa korrektset toimimist tagada. Sel põhjusel on soovitatav proovida selliseid juhtumeid arvesse võtta ja neid õigesti käsitleda.

Lihtsaim viis on enne jagamist kontrollida jagajat ja kuvada teade vale parameetri väärtuse kohta:

tühine OnStart () {int a = 0, b = 0, c; if (b! = 0) {c = a / b; Trükk (c); } else {Prindi ("Viga: b = 0"); tagasi }}

Selle tulemusel kriitilist tõrget ei teki, kuid kuvatakse teade parameetri vale väärtuse kohta ja toiming lõpeb:

Kasutades praeguse märgi jaoks NULLi asemel 0

Kompilaatori vanas versioonis oli lubatud kasutada finantsinstrumenti nõudvatel funktsioonidel argumendina 0 (null).

Näiteks võib praeguse sümboli tehnilise liikuva keskmise väärtuse küsida järgmiselt:

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

Uues kompilatsioonis peate praeguse märgi tähistamiseks selgelt määrama NULL:

AlligatorJawsBufferi = iMA (NULL, 0.13.8, MODE_SMMA, PRICE_MEDIAN, i); // õige

Lisaks saab praegust sümbolit ja diagrammi perioodi täpsustada funktsioonide Sümbol () ja Periood () abil.

AlligatorJawsBufferi = iMA (sümbol (), periood (), 13,8, MODE_SMMA, PRICE_MEDIAN, i); // õige

Veelgi parem, kui kasutate etteantud muutujaid _Symbol ja _Period - neid töödeldakse kiiremini:

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

Unicode-stringid ja nende kasutamine DLL-is

Stringid on Unicode-tähemärkide jada. Pidage seda fakti meeles ja kasutage sobivaid Windowsi funktsioone. Näiteks kui teegi funktsioonide Wininet.dll kasutamisel InternetOpenA () ja InternetOpenUrlA () asemel peaksite helistama InternetOpenW () ja InternetOpenUrlW (). Stringide DLL-ile ülekandmisel kasutage struktuuri MqlString:

#pragma pack (push, 1) struct MqlString {int size; // 32-bitine täisarv, sisaldab stringi LPWSTR puhvrile eraldatud puhvri suurust; // puhver 32-bitine aadress, mis sisaldab stringi int reserveeritud; // 32-bitine täisarv, reserveeritud, ärge kasutage}; #pragma pakk (pop, 1)

Failide jagamine

Failide avamisel peate jagamiseks selgelt määrama lipud FILE_SHARE_WRITE ja FILE_SHARE_READ.

Kui nad puuduvad, avatakse fail eksklusiivses režiimis, mis ei luba kellelgi teisel seda avada enne, kui monopolist selle suleb.

Näiteks peate võrguühenduseta diagrammidega töötades selgesõnaliselt määratlema jagatud lipud:

// Esimene muudatus - lisage jagamislipud ExtHandle = FileOpenHistory (c_symbol + i_period + ". Hst", FILE_BIN | FILE_WRITE | FILE_SHARE_WRITE | FILE_SHARE_READ);

Kuupäeva ja aja teisendamise funktsioon

Pidage meeles, et kuupäevaaja tüübi teisendamine stringiks sõltub kompileerimisrežiimist:

kuupäeva kuupäev = D'2014.03.05 15:46:58 '; string str = "mydate =" + kuupäev; // --- str = "mydate = 1394034418" - ilma #property range direktiivita // --- str = "mydate = 2014.03.05 15:46:58" - #property range direktiiviga

Näiteks katse töötada failidega, mille nimi sisaldab koolonit, põhjustab tõrke.

Runtime Error Handling

Kuna ükski kauplemisasjatundja ei saa hakkama ilma sisseehitatud kasutaja määratletud funktsioone kasutamata, proovime nende funktsioonide tagastatud vigade analüüsimisel kõigepealt oma elu lihtsustada.

Mõned raamatukogud on saadaval komplektis "karbist väljas", et lihtsustada nõustajate kirjutamist, sealhulgas ka vigadega töötamiseks. Neid hoitakse kaustas MQL4 / Include:

Vajame kahte raamatukogu:

  • stderror.mqh - sisaldab iga tõrke arvu konstante;
  • stdlib.mqh - sisaldab mitmeid abifunktsioone, sealhulgas veakirjelduse stringina tagastamise funktsioon:
string ErrorDescription (int viga_kood)

Seetõttu ühendame mõlemad need raamatukogud oma projektiga:

# lisan # lisan 

Veakirjeldused ise on MQL4 / Library / stdlib.mql4 failis ja need on inglise keeles. Seetõttu võite võõrkeelte vastu alati kirjeldused oma emakeeles ümber kirjutada.

Veel üks sisseehitatud funktsioon, mida vajame, on GetLastError (). See on tema, kes tagastab veakoodid täisarvu (int) kujul, mida me seejärel töötleme. Veakoodid ja nende kirjeldused vene keeles leiate MetaQuotes juhendist mql4. Sealt saate teavet stdlib.mql4 faili vene keelde tõlkimiseks.

Nüüd, kui oleme ühendanud vajalikud raamatukogud, kaalume vahetult kauplemistoimingutega seotud funktsioonide tulemusi, kuna nende funktsioonide rikete ignoreerimine võib robotile põhjustada kriitilisi tagajärgi.

Kahjuks ei saa MQL4 kasutades kirjutada üldistatud teeki kõigi võimalike tõrkesituatsioonide käsitlemiseks. Mõlemal juhul peate vead eraldi käsitlema. Kuid mitte kõik pole nii halb - paljusid vigu ei ole vaja töödelda, piisab nende kõrvaldamisest eksperdi väljatöötamise ja testimise etapis, kuigi selleks peate nende olemasolu kohta õigel ajal teadma.

Mõelge näiteks kahele MQL4 ekspertidele tüüpilisele veale:

  1. Viga 130 - ERR_INVALID_STOPS
  2. Viga 146 - ERR_TRADE_CONTEXT_BUSY

Üks juhtudest, kui ilmneb esimene viga, on eksperdi katse panna ootel tellimus turule liiga lähedale. Selle olemasolu võib mõnel juhul tõsiselt kahjustada ekspertide tulemusi. Oletagem näiteks, et pärast kasumliku positsiooni avanemist teenib ekspert kasumit iga 150 punkti järel. Kui järgmine katse põhjustab vea 130 ja hind naaseb pöördumatult eelmisele peatumistasandile, võib ekspert võtta sinult õigustatud kasumi. Vaatamata selliste tagajärgede võimalusele saab selle vea põhimõtteliselt kõrvaldada, viies ekspertkoodi lõpule nii, et see võtaks arvesse minimaalset lubatavat vahemaad hinna ja peatuste vahel.

Teist viga, mis on seotud terminali kauplemiskonteksti hõivamisega, ei saa täielikult kõrvaldada. Kui ühes ja samas terminalis töötab mitu eksperti, on alati võimalik, et üks ekspertidest üritab ametikohta avada, samas kui teine ​​töötab endiselt sama. Seetõttu tuleks sellist viga alati käsitleda.

Seega peaksime alati olema teadlikud, kui mõni kasutatav sisseehitatud funktsioon annab EA töötamise ajal tõrke. Seda saab saavutada kasutades järgmist lihtsat abistajafunktsiooni:

void logError (string functionName, string msg, int errorCode = -1) {Prindi ("VIGA: jaotises" + functionName + "()"); Prindi ("VIGA:" + msg); int err = GetLastError (); if (errorCode! = -1) {err = errorCode; } if (err! = ERR_NO_ERROR) {Prindi ("VIGA: kood =" + err + "-" + ErrorDescription (err)); }}

Kasutame seda järgmiselt:

void openLongTrade () {int pilet = OrderSend (sümbol (), OP_BUY, 1.0, Ask + 5, 5, 0, 0); if (pilet == -1) {logError ("openLongTrade", "ei saanud tellimust avada"); }}

Muidugi on see lihtsustatud näide. Tellimuste avamise, sulgemise ja muutmise pädevamate funktsioonide kirjutamiseks lugege seda õppetundi.

Funktsiooni logError () esimene parameeter on funktsiooni nimi, milles viga tuvastati, meie näites funktsioonis openLongTrade (). Kui meie ekspert kutsub funktsiooni OrderSend () mitmes kohas, võimaldab see meil täpselt kindlaks teha, milles neist viga ilmnes. Teine parameeter läbib vea kirjelduse, et saaksite täpselt aru saada, kus viga funktsiooni openLongTrade () sees tuvastati. See võib olla kas vea lühikirjeldus või kõigi sisseehitatud funktsioonile edastatud parameetrite väärtuste täpsem kirjeldus.

Ma eelistan viimast varianti, kuna kui ilmneb tõrge, saate kohe kogu analüüsi jaoks vajaliku teabe. Oletagem näiteks, et enne OrderSend () helistamist pidi praegune hind suuresti erinema viimasest teadaolevast hinnast. Selle näite täitmisel ilmneb viga ja ekspertlogis kuvatakse järgmised read:

VIGA: avatudLongTrade'is () VIGA: tellimust ei saanud avada VIGA: kood = 138 - ettekirjutus

See tähendab, et näete kohe:

  • millises funktsioonis viga ilmnes;
  • millele see viitab (antud juhul katse avada seisukoht);
  • milline viga ilmnes (veakood ja selle kirjeldus).

Nüüd kaaluge funktsiooni logError () kolmandat, valikulist parameetrit. See on vajalik nendel juhtudel, kui soovime töödelda teatud tüüpi tõrkeid, ja ülejäänu kohta kirjutame eksperdi töö protokollis, nagu varemgi:

tühine updateStopLoss (topelt newStopLoss) {bool muudetud = OrderModify (OrderTicket (), OrderOpenPrice (), newStopLoss, OrderTakeProfit (), OrderExpiration ()); if (! muudetud) {int errorCode = GetLastError (); if (errorCode! = ERR_NO_RESULT) {logError ("updateStopLoss", "tellimuse muutmine nurjus", errorCode); }}}

Siin kutsutakse funktsiooni updateStopLoss () sisseehitatud funktsiooni OrderModify (). See funktsioon erineb veidi tõrkekäsitluse poolest OrderSendist (). Kui ükski muudetava tellimuse parameetritest ei erine selle praegustest parameetritest, tagastab funktsioon vea ERR_NO_RESULT. Kui meie eksperdis on selline olukord lubatav, peaksime seda viga eriti eirama. Selleks analüüsime GetLastError () tagastatud väärtust. Kui koodiga ERR_NO_RESULT ilmneb tõrge, siis ei väljasta me protokollile midagi.

Kui ilmnes aga veel üks viga, tuleb sellest täielikult aru anda, nagu me varem tegime. Sellepärast salvestame funktsiooni GetLastError () tulemuse vahemuutujasse ja edastame selle kolmanda parameetri funktsioonile logError (). Fakt on see, et sisseehitatud funktsioon GetLastError () lähtestab automaatselt viimase kõne koodi pärast selle kõnet. Kui me ei edastanud veakoodi otse logError () -ile, kajastub protokollis viga koodiga 0 ja kirjeldusega „viga pole”.

Sarnaseid toiminguid tuleb teha ka muude vigade, näiteks rekvisiitide töötlemisel. Põhiidee on käsitleda ainult neid vigu, mida tuleb töödelda, ja üle anda ülejäänud osa logError () funktsioonile. Siis teame alati, kas eksperdi töö käigus ilmnes ootamatu tõrge. Pärast logide analüüsimist saame otsustada, kas see tõrge nõuab eraldi töötlemist või kas selle saab ekspertkoodi vormistamisega kõrvaldada. See lähenemisviis lihtsustab elu märkimisväärselt ja vähendab vigade lahendamiseks kuluvat aega.

Loogiliste vigade diagnostika

Loogilised vead ekspertkoodis võivad põhjustada palju probleeme. Ekspertide sammhaaval silumise võimaluse puudumine muudab selliste vigade vastu võitlemise mitte eriti nauditavaks ülesandeks. Peamine vahend selle diagnoosimiseks on sisseehitatud funktsioon Print (). Seda kasutades saate printida oluliste muutujate praegused väärtused ja logida eksperdi töö otse testi ajal terminali. Asjatundja silumisel visualiseerimisega testimise ajal võib abi olla ka sisseehitatud kommentaarist (), mis kuvab diagrammil teateid. Reeglina veendudes, et ekspert ei tööta ettenähtud viisil, peate printimise () funktsiooni lisama ajutised kõned ja registreerima eksperdi sisemise oleku väidetavates kohtades, kus tõrge ilmnes.

Kuid keerukate veaolukordade tuvastamiseks peate mõnikord funktsiooni Prindi () lisama kümneid selliseid kõnesid ja pärast probleemi leidmist ja parandamist peate need kustutama või kommenteerima, et ekspertkood ei oleks risustatud ja selle testimist ei aeglustata. Olukord halveneb, kui funktsiooni Prindi () kasutatakse ekspertkoodis juba erinevate olekute perioodiliseks logimiseks. Siis ei saa ajutisi kõnesid printimisele () eemaldada, otsides lihtsalt ekspertkoodist fraasi „Prindi”. Peate selle läbi mõtlema, et mitte eemaldada selle funktsiooni kasulikke kõnesid.

Näiteks funktsioonide OrderSend (), OrderModify () ja OrderClose () vigade logimisel on kasulik printida muutujate Bid ja Ask praegune väärtus protokollis. Nii on lihtsam tuvastada selliste vigade põhjuseid nagu ERR_INVALID_STOPS ja ERR_OFF_QUOTES.

Selliste diagnostiliste leidude esiletõstmiseks protokollis soovitan kasutada järgmist abifunktsiooni:

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

See on soovitav mitmel põhjusel. Esiteks: nüüd ei tule selliseid kõnesid ekspertkoodis otsimisel nuppu „Prindi”, kuna me otsime logInfo. Teiseks on sellel funktsioonil veel üks kasulik funktsioon, millest räägime veidi hiljem.

Ajutiste diagnostiliste kõnede lisamine ja eemaldamine funktsioonile Printimine () võtab palju aega. Seetõttu teen ettepaneku kaaluda teist lähenemisviisi, mis on koodis loogiliste vigade tuvastamisel tõhus ja võimaldab meil oma aega pisut kokku hoida. Mõelge järgmisele lihtsale funktsioonile:

tühine openLongTrade (topelt stopLoss) {int ticket = OrderSend (Symbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (pilet == -1) {logError ("openLongTrade", "ei saanud tellimust avada"); }}

Kuna me avame pika positsiooni, on üsna ilmne, et eksperdi tavapärase töö ajal ei ole stopLoss parameetri väärtus kunagi suurem või võrdne praeguse Bid hinnaga. See tähendab, et kui funktsiooni openLongTrade () kutsutakse, on stopLoss <Bid tingimus alati täidetud. Kuna me teame sellest isegi kõnealuse funktsiooni kirjutamise etapis, saame seda kohe kasutada järgmiselt:

void openLongTrade (double stopLoss) {assert ("openLongTrade", stopLoss <Bid, "stopLoss <Bid"); int pilet = OrderSend (sümbol (), OP_BUY, 1.0, Ask, 5, stopLoss, 0); if (pilet == -1) {logError ("openLongTrade", "ei saanud tellimust avada"); }}

See tähendab, et logime oma avalduse koodi, kasutades uut abistajafunktsiooni assert (). Funktsioon ise näeb üsna lihtne välja:

void assert (string functionName, bool assertion, stringi kirjeldus = "") {if (! väide) {Print ("ASSERT: in" + functionName + "() -" + description); }}

Funktsiooni esimene parameeter on selle nimi, milles meie seisundit kontrollitakse (analoogselt funktsiooniga logError ()). Teine parameeter läbib selle tingimuse kontrollimise tulemuse. Ja kolmas parameeter on selle kirjeldus. Selle tulemusel kuvatakse protokollis järgmine teave, kui eeldatav tingimus ei ole täidetud:

  • selle funktsiooni nimi, milles tingimust rikuti;
  • rikutud seisundi kirjeldus.

Kirjeldusena võite edastada näiteks tingimuse ise või kuvada üksikasjalikuma kirjelduse, mis sisaldab kontrollitavate muutujate väärtusi tingimuse kontrollimise ajal, kui see aitab vea põhjuseid mõista.

Muidugi on vaadeldav näide maksimaalselt lihtsustatud. Kuid loodan, et põhiidee kajastub üsna hästi. Eksperdi funktsionaalsuse ülesehitamisel oleme teadlikud, kuidas see peaks toimima ning millised olekud ja funktsioonide sisendparameetrid kehtivad ja millised mitte. Fikseerides selle eksperdikoodis funktsiooni assert () abil, saame väärtuslikku teavet koha kohta, kus eksperdi töö loogikat rikutakse. Lisaks vabastame end osaliselt vajadusest lisada ja eemaldada ajutisi kõnesid funktsioonile Print (), kuna funktsioon assert () väljastab protokolli diagnostilisi teateid ainult siis, kui eeldatavates tingimustes tuvastatakse vastuolud.

Veel üks kasulik trikk on selle funktsiooni kasutamine enne iga jagamist. Fakt on see, et mõnikord toimub ühe või teise loogilise vea tagajärjel jagamine nulliga. Eksperdi töö sel juhul lõpetatakse ja protokolli ilmub kurbliku diagnoosiga ainult üks rida: nulljaotus. Täpselt välja selgitada, kus see tõrge tekkis, kui koodis korduvalt kasutatakse jagamistoimingut, on üsna keeruline. Siin aitab funktsioon assert (). Enne iga jagamistoimingut sisestame vastavad kontrollid:

kinnitama ("buildChannel", vahemaa> 0, "kaugus> 0"); topeltkalle = delta / vahemaa;

Ja nüüd nulliga jagamise korral piisab lihtsalt logide otsimisest, et teada saada, milles täpselt viga ilmnes.

Riigi käitlemine

Sel ajal kui ekspert töötab teie kontoga, võib tekkida mõni olukord, mis pole vead - nn ekspertiigid. Sellised olekud pole vead, kuid siiski tuleks need logida. Selles aitavad mql4 keele erifunktsioonid.

Funktsioon IsExpertEnabled () tagastab teabe ekspertide käitamise võime kohta. Funktsioon naaseb tõeseks, kui ekspertidel lubatakse klienditerminalis joosta, tagastab vastasel juhul vale. Vale tagastamise korral on kasulik teavitada kasutajat vastava sätte lubamiseks. Näide:

void OnStart () {if (! IsExpertEnabled () {// nõustajatel ei ole lubatud hoiatust vahetada ("Tähelepanu! Palun vajutage MT4 nuppu" Ekspertnõustajad ");} // Nõustaja tagastamise tööalgoritm;}

Kui ekspert kasutab väliseid teeke, on kasulik funktsioon IsLibrariesAllowed (). Kui ekspert saab raamatukogu funktsiooni kutsuda, tagastab see tõese väärtuse, vastasel juhul tagastab väärtuse vale.

Kui teek on dll-faili kujul, on kasulik funktsioon IsDllsAllowed (). Samuti on kasulik kontrollida, kas funktsiooni IsTradeAllowed () abil on üldiselt võimalik ekspertide abiga kaubelda.

Kui soovite teada saada, kas konto on demo või päris, võite kasutada funktsiooni IsDemo ().

Kõik ülaltoodud kontrollid tuleks teha funktsioonis OnInit ().

Muidugi tasub perioodiliselt kontrollida ühendust serveriga. Funktsioon IsConnected () aitab.

Järgmised kolm funktsiooni aitavad kindlaks teha, millises režiimis EA töötab. Kui IsOptimisation () vastab tõele, viiakse optimeerimine läbi, kui IsTesting (), siis testimine, IsVisualMode () - testimine visualiseerimisrežiimis. Kõigi nende võimaluste jaoks võib nõustajal olla oma loogika. Näiteks saate visualiseerimisrežiimis kuvada diagrammil midagi (ja ressursside kokkuhoiu huvides mitte kuvada teistes režiimides). Testimisrežiimis saate silumisteavet kuvada, optimeerimisrežiimis aja säästmiseks kergendada koodi nii palju kui võimalik.

Ja viimane funktsioon on IsTradeContextBusy (). See vastab tõele, kui kauplemistoimingute lõim on kinni. See võib olla kasulik, kui ekspert viib läbi kauplemistehinguid. Unerežiimi abil saate hetke oodata ja uuesti proovida.

Veel üks kasulik funktsioon on UninitializeReason ()

int deinit () {lüliti (UninitializeReason ()) {juhtum REASON_CHARTCLOSE: juhtum REASON_REMOVE: CleanUp (); vaheaeg; // puhtad ja tasuta ressursid. juhtum REASON_RECOMPILE: juhtum REASON_CHARTCHANGE: juhtum REASON_PARAMETERS: juhtum REASON_ACCOUNT: StoreData (); vaheaeg; // taaskäivituse ettevalmistamine. } // ...}

Samuti saate sisse logida nõustaja lahkumise põhjuse.

Kõige tavalisemate vigade koodid ja nende tõenäoline lahendus

Vea numberVäärtusProbleemLahendus
4, 146Kauplemisserver on hõivatudNõustaja andis operatsiooni ajal korraga liiga palju tellimusi või serverist vastust ootamata - nõustaja proovib saata uue tellimuseTerminali taaskäivitamine või nõustaja koodi optimeerimine veakäsitlusfunktsioonide abil
8, 141Liiga sagedased taotlusedVarasema vea põhjused väga sagedase päringu korralSarnane lahendus
129Vale hindHind, millega proovite positsiooni avada (OSTA või MÜÜA), on valeOstu peab avama Ask ja sulgema BID;
Müügi peab avama BID ja sulgema ASK
130, 145Valed jaladLõpetage kahjum, võtke kasumit või ootel või piiraja avanemistase on vale.
Peatused on hinnale liiga lähedal.
Teie konto avatakse rühmas ECN (ETSN) või NDD (NDD), mis takistab teil viivitamatult peatusi teha
Kontrollige peatumiskadude väärtusi, võtke kasumit, kontrollige vahendaja juures oma instrumendi minimaalset peatustaset, peatuste seadmisel - jälgige minimaalset kauguse taset. Hästi kirjutatud nõustajal peaksid olema funktsioonid ECN- ja NDD-kontodega töötamiseks - see toimub tellimuse muutmisega pärast selle avamist
131Vale helitugevusTehingu avamisel vale partii või minimaalsest väiksem (rohkem kui maksimaalne). Samuti võib partii bitti sügavus erineda maakleri bitistKontrollige partii korrektset avamist, uurige lepingu spetsifikatsiooni ja lugege oma DC-s kaubandustingimusi, kontrollige alalist alampiiri ja teie kontol olevat minimaalset ja maksimaalset partiid
132Turg on suletudTurg on nädalavahetustel suletudProovige pärast nädalavahetust turuga ühendust võtta
133Ei mingit kaubandustPraegu ei kaubeldaSelle valuutapaari peal on keelatud kaubelda - kindlal ajahetkel või üldiselt. Sageli on maakleritel südaööl mõneminutiline paus
134Operatsiooni lõpuleviimiseks pole piisavalt rahaPartii, mida proovite avada, on liiga suur, sellel pole piisavalt varuKontrollige saadaolevate vahendite taset ja arvutage välja palju vahendeid, mida peate palju avama, jälgige saadaolevate rahaliste vahendite taset
135-138Hind on muutunudNõuda, liiga kiire turg (uudised), maakler või DC ei võimalda teil positsiooni deklareeritud hinnaga pannaÄrge kaubelge sellistel hetkedel, suurendage libeduse taset, kuid pidage meeles, et see tähendab, et positsioonide avamine toimub mitte teie nimetatud hinnaga. Esitage tõrkekäsitlusfunktsioon ja EA-s positsioonide avamise katsete arv
147Maakler on tellimuse aegumiskuupäeva kasutamise keelanudTeie nõustaja või proovite määrata ootel tellimuse aegumiskuupäevaSeadke ekspertnõustaja funktsioonis OrderSend aegumisparameeter väärtusele 0 (null). Ärge määrake aegumiskuupäeva
148Avatud ja menetluses olevate tellimuste arv on jõudnud maakleri seatud piiriniMaksimaalne avatud tellimuste ja positsioonide arv on jõudnud maakleri seatud piiriniKustutage või sulgege osa positsioonidest. Peatage uute positsioonide avamise protsess
4012, 4013Ülejäänud jaotus nulligaÜritate arvu jagada nulliga (0)Kontrollige, kas nõustaja koodil pole tõrkeid, või kontrollige kõiki MarketInfo funktsioonide väärtusi 0 tagastamise ajal, mõnikord kui MarketInfo (Symbol (), MODE_SPREAD) ei tagastata levikut, vaid 0 (ujuva väärtusega maaklerite puhul)
4017DLL-kõned pole lubatudTeie terminalis on DLL-helistamine keelatudLuba DLL-i kõne kaudu läbi Menüü - Teenus - Seaded - Nõustaja - Luba DLL-kõne
4018, 4019Raamatukogu ei saa laadidaTeek on kahjustatud või selle kõne ebaõnnestub, võib-olla on see üldse puuduKontrollige DLL-i
4020Kõned väliste raamatukogu funktsioonide juurde pole lubatudVälisekspertide kutsumisfunktsioonid on teie terminalis keelatudHelistamisfunktsioonide lubamine menüü kaudu - Teenus - Seaded - Nõustaja - Välisekspertidele helistamise lubamine
4103Faili ei saa avadaSeda faili ei eksisteeri või on lukustatud mõne muu protsessiga.Kontrollige määratud faili. Kontrollige, kas viirusetõrjesüsteem on faili lukustanud, kas faili kirjutus- ja lugemisrežiim on lubatud
4106Tundmatu tegelaneTuruülevaates pole sümbolitTuruülevaates - paremklõpsake - näidake kõiki sümboleid. Kontrollige sümboli nime nõustajas ja selle olemasolu turuülevaates. Mõned nõustajad kasutavad selgeid nimesid ilma järelliideteta ja maaklerid määravad järelliiteid tahtlikult, näiteks EURUSDx, kus x on järelliide
4108Vale piletinumberEksperdi valitud tellimispiletit ei eksisteeri. Ekspert proovib piletit valida, kuid selle tellimuse sulges teine ​​nõustaja või käed. Üritades tellimust täita, pidas pilet maakleri kinni ja sulges selleKui see tõrge ilmub väga sageli, 100–1000 korda minutis, kontrollige oma nõustaja funktsioone. Keelake teised nõustajad või konfigureerige neid nii, et need ei läheks konflikti, ärge sulgege tellimust kätega, kui ekspert teostab toimingu. Mõnikord juhtub see siis, kui mitu nõustajat kasutavad sama MagicNumberi.
4109Kauplemine pole lubatudNõustajal on keelatud kaubelda, graafikul on näha kurb naeratus või ristLülitage sisse nõustaja installimisel sissemakse ruut „Luba nõustajal kaubelda” või menüüs - teenus - seaded - nõustajad
4110, 4111Pikad / lühikesed positsioonid pole lubatudNõustaja sätete vahekaardil Üldine pole positsioonide tüüp lubatudVahekaardil Üldine on nõustaja installimisel saadaval valik kohti, mida lubada avada

Järeldus

Vaatletud abifunktsioonid ja lihtsad nipid võivad MQL4 programmeerimiskeeles kirjutatud kauplemisasjatundjate koodide vigade tuvastamise ja parandamise protsessi oluliselt lihtsustada ja kiirendada. Koodide ja funktsioonide õige kirjutamine nõustaja töö logimiseks ja jälgimiseks kiirendab oluliselt selle väljatöötamise protsessi.

Vaata videot: Robot Building Tutorials #6 - Intro to MQL4 (Veebruar 2020).

Jäta Oma Kommentaar