Forex programozás › Fórum › Kérdések az MQL4 programozási nyelvvel kapcsolatban › Új gyertyák azonosítása
Címkézve: gyertya
-
SzerzőBejegyzés
-
A stratégiámhoz szükségem van arra: meg tudjam állapítani, hogy az aktuális tick-nél melyik idősíkon kezdődött új gyertya.
Ehhez az alábbi kódot „kalapáltam” össze, amely az első H1-es gyertyát még jól jelzi, de ezután már folyamatosan 15 perces csúszásban van. Mi a búbánat hibádzik?Íme a kód:
int WhichNewBar2() { static datetime LastTime[]={0,0,0,0,0,0,0,0}; //0:M1, 1:M5, 2:M15, 3:M30, 4:H1, 5:H4, 6:D1, 7:W1 int periods[]={1,5,15,30,60,240,1440,10080}; //PERIOD_M1, PERIOD_M5, ... int z, biggestNewBar=0; if (LastTime[0]==0) //amennyiben a tömb első eleme nulla (akkor a többi is) { for (int i=0; i<=7; i++) { LastTime[i]=iTime(NULL,periods[i],0); //feltöltjük a tömböt időadatokkal } } else //viszont ha az inicializáló kör már lefutott, indulhat a vizsgálódás { z=0; while(z<8) //az alábbi logikából következően, max. csak "Hetes"-ídősíkig vizsgálódunk { if (iTime(NULL,periods[z],0)>LastTime[z]) //elsőként: van-e változás M1-en { LastTime[z]=iTime(NULL,periods[z],0); //ha van változás frissítjük a tömböt biggestNewBar=periods[z]; //megtaláltuk az eddigi legnagyobb-legújabb gyertyát z++; //jöhet az "eggyel fentebbi" idősík vizsgálata } else // ha még-már nincs változás... { return(biggestNewBar); //...nem vizsgálódunk tovább //visszatérés: pl. PERIOD_H4 azaz 240 vagy 0 (=nincs új gyertya) } } } return(0); }
A felhasználása pedig értelemszerűen ez lenne:
int NEWBAR=WichNewBar2(); if (NEWBAR>=30) { ... } //kódfuttatás új félórás gyertya esetén
Túlbonyolítod. A csatolt kódban nem kezdek hibát keresni, inkább leírom hogy én hogy csinálnám.
„A” megoldás: iBars() aktuális és legutóbbi mentett értékét összehasonlítod.
if (Bars > LastBar) { // Futtatni kívánt kód új gyertya esetén // [...] LastBar = Bars; }
„B” megoldás: én úgy hívom: NextRun. Minden tickben ellenőrzöd, hogy az egyes idősíkokon új gyertya jött-e létre. Ha igen, akkor a legfrissebb gyertya nyitóidejéhez képest beállítod a következő futási időpontot.
if (int(TimeCurrent()) >= NextRun) { // Futtatni kívánt kód új gyertya esetén // [...] NextRun = int(Time[0]) + Period() * 60; }
Persze nem muszáj az aktuális idősíkkal dolgozni, lehet az összessel egyszerre (a Time-ot iTime-ra cseréled, a Period() -ot meg az adott idősík konstansára).
Köszi a választ, de a csatolt kód egyáltalán nem bonyolult lényegében megegyezik a te „A” verzióddal csupán annyi a különbség, hogy nem a Bars* hanem a Time változó értékét figyelem.
Tulajdonképpen csak két vizsgálat fut le:
1. Inicializálva van-e az időadatok tömbje (hogy legyen mihez viszonyítani)
2. és ha igen akkor történt-e változás M1-en > és ha nem, akkor ezzel vége is> return(0);
Egyszerű mint a fakocka, csak jól megtűzdeltem kommentekkel, hogy más erre tévedő halandó is könnyen értelmezhesse. :)Mivel az expertem három-négy fő részre tagolódik (menedzsment, kereskedés, eseménykezelés, grafikus-szöveges visszajelzés-tájékoztatás) és a kód kölönböző pontjain szükségem van a gyertya adatokra (más-más feladatok futnak percenként, 5 percenként és óránként) ezért van szükségem arra, hogy lehetőleg csak egyetlen vizsgálat fusson le a kód elején és a rendelkezésemre álljon egy globális változó amit az adott pontokon vizsgálhatok, hiszen ha (esetemben) NEWBAR értéke >=30, akkor abból következik, hogy 1,5,15 és 30 perces idősíkon is új gyertya van.
(Így utóbb, most arra gyanakszom, hogy a referencia szerint az iTime() is futhat hibára és olyankor 0-t ad vissza)
Persze a B. verzó is teljesen logikus megoldás, de valahol zavar a dolog, hogy számításokat is végezetetek a programban amikor egy szimpla összehasonlítás
if (iTime(NULL,periods[z],0)>LastTime[z])
is elég lenne.
Azonkívül – bár még sosem irattam ki egy címkére a Time[0] értékét – de mi van, ha pl. egy egzotikus instrumentumnál (az M1 idősíkot figyelve) első 25 mp.-ben nem történik semmi. Akkor a NextRun 25 mp.-el eltolva indul a következő körben?
(* Az az igazság, hogy a Bars változó értékében nem bízom. A szemem előtt zajlott le olyan szituáció, hogy egyszercsak – napközben – eltűnt 4-5 gyertya a chart-ról, keletkezett egy hatalmas gap a robotom nyitott egy ‘értelmetlen’ pozíciót. Szerencsére csak demó számla volt és csak azért értettem meg (gyorsan), hogy nem piaci szituációról van szó, mert egy másik brókernél ugyanazon az instrumentumon minden ‘nyugodt volt és békés’
de a kettőt összevetve már látszott, hogy menetközben eltűnt néhány gyertya a chartról!!! Ilyen alapon néhyán „új” gyertya is lecsoroghat a chart „elejére” – mármint a legrégebbi gyertya elé – és akkor úgy vagyok átverve, hogy még ki se tudom deríteni mi történt. Szerintem a Bars csak arra jó, hogy lellenőrizzem van-e elegendő gyertyám pl. egy BrakeOut stratégia vizsgálatához.)A NextRun-os megoldást akárhányszor alkalmazhatod a kódban, én sem egy helyen használom nyilván. A legutolsó teljesülésnél jelölöm ki a következő futási időpontot.
Amit felvetsz, az pontosan így van: ha az első tick 25 másodperc múlva jön, akkor akkor fut le. Mivel a stratégiák 99%-a eleve a tickek beérkezésétől függ, így kvázi lényegtelen, hogy pár percig szünet van és utána fut le a program, vagy nagyon folyamatos a tickek áramlása és relatíve tényleg mindig másodpercre pontosan a gyertyák elején végezi a program az ellenőrzéseket.
A Bar-ban én sem bízom, ezért ajánlom a NextRun-t – én is hasonlók miatt nem alkalmaztam régebben.
A LastTime-os megoldás valóban hasonló, mint az enyém. Azt mondjuk nem értem, hogy miért jó mindent M1 alapján végezni, amikor eleve tudod hogy mely idősíkok adatai szükségesek és melyeken akarsz dolgozni. Természetesen ez is egy jó megoldás lehet, csak ennek a gyakorlati haszna a te stratégiádhoz kapcsolódik, nem a leggyakrabban előforduló elvárásokhoz.
Figyelembe véve az MT4 adatintegritását, legalább annyi problémát hozhat elő a megoldásod, mint amennyit megold. Főleg backtesztben érdekes ez a kérdés, amikor pl. M5-ön mész, és M1-es vagy H1-es adatokat akarsz elérni kódban, néha ezt egyáltalán nem hajlandó megtenni az MT4 :(
Igen, ezt jól telibetaláltad:
ennek a gyakorlati haszna a te stratégiádhoz kapcsolódik, nem a leggyakrabban előforduló elvárásokhoz.
Ezzel az expertel ugyanis nem szoktam backtesztelni mert több (ígértesnek tűnő) startégiát futtatok vele egyetlen programon belül. Ezért aztán teljesen igazad van: ez így backtesztre teljesen alkalmatlan lenne.
Azért kellett a fenti megoldás, hogy ha van egy újabb stratégia amit mondjuk M15-ön alapul akkor:if (NEWBAR>=15) { új stratégia }
‘és már kész is vagyok’.
De sajnos az alapproblémám nem változott. Én állítom, hogy a kód hibátlan, de mégsem működik jól.
Így lényegében arra keresem a választ, hogy én vagyok vak és nem látok valamilyen nyilvánvaló logikai bukfencet, vagy a MetaTrader szívat valamilyen bug-gal?Lévén a legutulsó javítások között is volt egy CopyTime()-al kapcsolatos hiba.
(Egyébként pedig azért fontos, hogy pontosan a gyertyák elején fusson egy-egy kódrész, mert mintázat alapú stratégia is van a repertoárban. De ez már tényleg nem MQL-hez kötődő kérdés.)
Nekem valós idejű futtatásnál – első ránézésre – jól működik a kódod, backtesztnél viszont abszolút nem. Ez utóbbi azért lehet, mert a választott idősíknál alacsonyabb idősík adatait nem mutatja a MT4. Ezt vedd figyelembe!
Illetve még amit jó tanácsként mondhatok: ellenőrizd, hogy az iTime visszatérési értéke nulla-e. Ha igen, akkor Sleep(50) és RefreshRates() kell, mert elképzelhető hogy pont abban a pillanatban frissíti a MT4 az adott idősík gyertyaadatait. Ha pedig ebbe M1-en futsz bele, akkor mész újra az inicializációs szakaszba.
Amúgy azt nem értem pontosan, hogy miért jobb tömbökkel szórakozni, amikor 7 nextrunnal nagyon egyszerűen meg lehet oldani a feladatot, a végeredmény pedig pontosan ugyanaz lesz, mint amit elvársz. Számolni idősíkonként egyszer csak akkor kell, amikor új gyertya képződik – a többi esetben az előre kikalkulált NextRun értékhez hasonlítgatod az aktuális brókeridőt.
A megoldásod ugyanúgy viselkedik majd az általad leírt esetben (ha pl. a 10:01-es gyertyában csak 10:01:25-kor jön tick), mint az enyém. Nem kötekszem, csak kíváncsiskodom!
Köszönöm a tanácsokat! A Sleep() és a RefreshRates()-t kifogom próbálni meg lekezelem ezt az iTime 0-t.
Mint írtam az hogy backtesztnél jól működjön jelen esetben nem szempont, de jó, hogy felhívtad rá a figyelmem.
A tömböket kifejezetten kedvelem. :)Viszont ez a NextRun nekem nem evidens.
Mondjuk H1 idősíkon vagyunk. (Most tekintsünk el a többi idősík vizsgálatától) Nyugodt periódus van és a Time[0] értéke pl. 05:00:25 lesz – merthogy a fenti példánál maradva az első 25mp-ben nem történik semmi – nem jön tick.
A NextRun_H1 értékét ugyebár így számolod:
NextRun_H1 = int(Time[0] + PERIOD_H1 * 60);
Ez esetben a NextRun_H1 értéke 06:00:25 lesz.
(Ha mondjuk H1-es gyertyák közötti Gap-et szeretnék elkapni ezt így nem lehetne.)Tehát egy óra múlva abban az első 25mp-ben sok minden történhet.
Avagy úgyis mondhatnám, hogy egy múltbeli adatból származtatod egy jövőbeli futtatás időpontját.
Amivel nincs is gond ha csak az a feladat, hogy időzítve fusson egy-egy funkció és nem pontosan egy esemény bekövetkeztekor – új gyertya képződésekor.Ha viszont nem fontos az esemény hanem csak az időzítés akkor meg miért ne így csinálnám:
static int NextRun_H1=0; OnInit() { NextRun_H1=Hour(); } OnTick() { if (NextRun_H1 != Hour()) { RunThis(); NextRun_H1=Hour(); } }
Nem jó a levezetésed! 25 másodpercről beszélsz az elején, a levezetésben meg ugyanez már percben van megadva.
Példa:
A felhasználó ráhelyezi a chartra a robotját, és óránkénti futtatást szeretne; a ráhelyezés mondjuk 00:22:16-kor történik meg. Ebben az esetben a következő futás időpontja 00:00:00 + 1 óra lesz, azaz 01:00:00. Amikor beérkezik a következő tick, az lehet 01:00:00, 01:00:25 és akár 01:15:06 is, lényegtelen – hiszen minden jóravaló belépési ellenőrzés egy gyertya első tickjéhez kötődik a stratégiák többségében, ezért ezzel semmiféle probléma nincs.
Gap-et is simán meg tudsz vele állapítani, csak akkor nyilván amúgy is több adattal kell hogy dolgozz. Amennyiben új gyertya jön létre, arról biztosan értesülök a következő futásos megoldásommal is – nem értem, hogy miért gondolod hogy ez nincs így. Az, hogy ez a gyertyát megelőzendő éppen mennyi gap van, az az esetek 99%-ban irreleváns, ha pedig mégis fontos, akkor az új gyertyában bekövetkező vizsgálattal egy pillanat alatt ki lehet deríteni, hogy mely gyertyák hiányoznak.
Amit utoljára írtál, az is jó megoldás.
Természetesen ha a gyertyaidőpontok kezdetével akarsz dolgozni függetlenül attól, hogy jön-e egy árva tick és épülnek-e gyertyák, akkor értem a célod, csak a megoldásod nem – hiszen te is ugyanúgy gyertyákra építesz, így a te tömbös megoldásod sem nyújt semmivel többet, mint a megfelelő idősíki Time gyertyaadatok használata. Éppen ezért nem értem, hogy miért gondolod, hogy az megfelelő. Ha gyertyák nélkül akarsz fizikai kezdőidőpontokkal dolgozni, akkor minimum TimeCurrent() vagy valamelyik Timer-es megoldás kell neked – minden másnál továbbra is a gyertyákra vagy utalva. Hiszen ha tick jön, akkor minden idősík frissül, míg ha egyáltalán nincs tick, akkor egyik sem fog.
A másodpercet elírtam. Már javítottam. Gyors voltál…. :)
Előrebocsátom, hogy én sem kötekedni szeretnék. Inkább tanulni.
De ezt nem értem:
A felhasználó ráhelyezi a chartra a robotját, és óránkénti futtatást szeretne; a ráhelyezés mondjuk 00:22:16-kor történik meg. Ebben az esetben a következő futás időpontja 00:00:00 + 1 óra lesz, azaz 01:00:00.
Hogy jön ide, hogy mikor helyezi rá a chart-ra a robotját?
Ez nem befolyásolja a Time[0] értékét!
A Time[0] értéke meg ugyebár egyáltalán nem biztos, hogy 00:00:00 lesz. Már miért lenne annyi? Lehet az 00:00:45 is. Mondjuk. (Vagy a Time[0] mindig kerek egész óra értéket vesz fel H1 idősíkon?)Ha ehhez hozzáadok 3600-at az pedig 01:00:45 lesz.
Tehát a NextRun futása nem az új gyertya kezdetéhez fog kötődni, hanem ehhez az időponthoz.
És persza ha aif (int(TimeCurrent()) >= NextRun)
feltétel már igaz lett, azonbelül már be tudod azonosítani, hogy igen, tényleg, ez egy új gyertya.
És szögezzük le: Most nem arról beszélünk, hogy mi értelme van pontosan azonosítani egy új gyertya első tickjét, hanem arról hogy hogyan lehetséges megoldani.
Az, hogy mikor helyezi rá, azért fontos mert a felhasználók – érthetően – össze-vissza indítanak robotokat. Erre próbáltam utalni.
Ez nem befolyásolja a Time[0] értékét! – persze, hogy nem – nem is írtam ilyet.
Már miért lenne annyi? Lehet az 00:00:45 is. Mondjuk. (Vagy a Time[0] mindig kerek egész óra értéket vesz fel H1 idősíkon?) Na, itt a probléma! A Time[0] értéke mindig szabályos gyertyaidőpont lesz! Azaz hiába jön be 00:00:25-kor a H1-es gyertya első tickje, a gyertya open time -ja mindenképpen 00:00:00 -nak megfelelő unix timestamp lesz.
Amit írsz az akkor lenne igaz, ha én a TimeCurrent() -hez adnám hozzá a 3600-at – de nem, épp ezért írtam a Time[0]-át, hiszen az mindig szabályos gyertyaidőpont, függetlenül attól hogy az első tick azon a gyertyán belül mikor érkezett meg.
Ha pedig nem volt egyáltalán tick, akkor az adott gyertya kompletten kimarad.
Az utolsó Time[] elmentése és az új gyertya Time[] értékének összehasonlítását kifejezetten speciális esetekben szoktam használni, például renko gyertyáknál, ahol a kezdőidőpontok teljesen össze-vissza alakulnak ki.
a gyertya open time -ja mindenképpen 00:00:00 -nak megfelelő unix timestamp lesz
Na ez az amit nem tudtam! Így már mindent értek. Kösz a türelmet.
Én erre úgy jöttem rá, hogy for ciklussal végigmentem 1000 darab gyertyán és kiolvastattam a másodperces pontosságra formázott időpontokat a Time[] tömbböl először az aktuális idősíkon, aztán pedig az összes többin. Sosem volt olyan, hogy ne nullára végződött volna a másodperc száma.
Dokumentálva szerintem egyébként ez sincs, bár lehet hogy azóta pótolták – a fentieket én 2009-ben próbáltam ki.
-
SzerzőBejegyzés
- Be kell jelentkezni a hozzászóláshoz.