Proč jsem pro zobrazení obchodních hodin vybral zrovna indikátor? MetaTrader zpracovává obchodní strategie, skripty a indikátory. Obchodní strategie je pro tento účel nevhodná, jelikož můžu do grafu vložit pouze jednu strategii a tím bych sebral prostor pro smysluplnou strategii. Skript se spouští jenom jednou, což by mému záměru nevyhovovalo. Chci si zobrazit obchodní hodiny jednotlivých marketů pro aktuální den, takže očekávám, že příští den se zobrazení překreslí, tak jak má, nechci se o to starat. Z toho vyplývá, že indikátor je nejvhodnější.
Postup
Otevřete si editor jazyka MQL a založte nový souboru typu Custom indikator. V dalším kroku si pojmenujte indikátor např. MarketZones. Vyplňte následující vstupní parametry (Název, Typ, Hodnota), (viz obr):
London_Show, bool, true
London_Color, color, Blue
London_Text, string, London
Nyní pokračujte v průvodci a v dalším kroku ponechte vše, tak jak je a dokončete průvodce.
Průvodce vygeneroval kód skriptu, kód jsem lehce upravil (viz kód).
Nyní si v kódu za vstupní parametry přidáme následujcí proměnnou, kterou použijeme pro pojmenování grafických objektů (viz kód):
//---- základní názvy objektů
string London_BaseName = "MZLondon";
Dále si vytvoříme pomocné metody, které nám vytvoří grafické objekty, které se budou zobrazovat na time-framech od M1 až po H1. Pro náš účel použijeme vertikální čáru pro zobrazení otevírací a zavírací doby, a text pro popis otevírací doby (viz kód):
// vytvoří vertikální linii
// name = název linie
// c = barva linie
void createVLine(string name, color c)
{
// kontrola, zda objekt neexistuje
if(ObjectFind(name) < 0)
{
// pokud se podařilo objekt vytvořit, můžeme nastavit vlastnosti
if(ObjectCreate(name, OBJ_VLINE, 0, 0, 0))
{
ObjectSet(name, OBJPROP_COLOR, c);
ObjectSet(name, OBJPROP_STYLE, STYLE_DOT);
ObjectSet(name, OBJPROP_BACK, true);
ObjectSet(name, OBJPROP_TIMEFRAMES,
OBJ_PERIOD_M1|OBJ_PERIOD_M5|OBJ_PERIOD_M15|OBJ_PERIOD_M30|OBJ_PERIOD_H1);
}
}
}
// vytvoří textový objekt
// name = název textového objektu
// text = zobrazovaný text
// c = barva textu
void createText(string name, string text, color c)
{
// kontrola, zda objekt neexistuje
if(ObjectFind(name) < 0)
{
// pokud se podařilo objekt vytvořit, můžeme nastavit vlastnosti
if(ObjectCreate(name, OBJ_TEXT, 0, 0, 0))
{
ObjectSetText(name, text, 8, "Arial", c);
ObjectSet(name, OBJPROP_ANGLE, 90);
ObjectSet(name, OBJPROP_TIMEFRAMES,
OBJ_PERIOD_M1|OBJ_PERIOD_M5|OBJ_PERIOD_M15|OBJ_PERIOD_M30|OBJ_PERIOD_H1);
}
}
}
Když již máme napsané pomocné metody pro vytváření grafických objektů, můžeme si napsat metodu, která nám vytvoří komplet obchodních hodin daného marketu a rovnou si napíšeme ještě metodu, která po nás uklidí grafické objekty, pokud uživatel odebere tento indikátor ze svého grafu (viz kód):
// vytvoří MarketZone (MZ) linie
// baseName = základní název MZ
// c = barva MZ
// text = popisek MZ
void createMZ(string baseName, color c, string text)
{
// název linie zobrazující otevření marketu
string nameOpen = baseName + "Open";
// název linie zobrazující zavření marketu
string nameClose = baseName + "Close";
// název textu zobrazující popis marketu
string nameText = baseName + "Text";
createVLine(nameOpen, c);
createVLine(nameClose, c);
createText(nameText, text, c);
}
// odstraní MarketZone linie
// baseName = základní název MZ
void deleteMZ(string baseName)
{
ObjectDelete(baseName + "Open");
ObjectDelete(baseName + "Close");
ObjectDelete(baseName + "Text");
}
Nyní použijeme naše metody v kódu. Upravíme metody init() a deinit(). V metodě init() si vytvoříme MarketZone linii a v metodě deinit() provedeme smazání prvků (viz kód):
// inicializace
int init()
{
// pokud se má zobrazit London, vytvoříme MZ
if(London_Show)
{
createMZ(London_BaseName, London_Color, London_Text);
}
return(0);
}
// deinicializace
int deinit()
{
// smazání MZ pro London
deleteMZ(London_BaseName);
return(0);
}
Teď jsme ve fázi, kdy náš skript (indikátor) je použitelný, ale pokud se změní den, nepřekreslí se obchodní hodiny na nový den, ale zůstanou tam, kde se vytvořili poprvé. Stejně tak popisek otevírací doby se nepřekreslí správně, pokud si v grafu začneme přepínat jednotlivé time-frames. K pokynu překreslení dojde, pokud se změní aktuální cena, na to mi můžeme reagovat. Proto si vytvoříme metody, které nám překreslí naše grafické prvky. Upravíme metodu start() a zareagujeme na změnu ceny a provedeme překreslení. Následující kód lze optimalizovat, aby nedocházelo k překreslování pokaždé, ale pouze, když potřebujeme. Přesto jej ponechám tak, jak je, kvůli jednoduchosti ukázky kódu. Vzhledem k malému počtu použitých grafických prvků, nám to nebude vadit (viz kód):
// překreslí vertikální linii
// name = název linie
// dt = datum umístění linie
void redrawVLine(string name, datetime dt)
{
if(ObjectFind(name) > -1)
{
ObjectSet(name, OBJPROP_TIME1, dt);
}
}
// překreslí textový objekt
// name = název textového objektu
// dt = datum umístění textového objektu
void redrawText(string name, datetime dt)
{
if(ObjectFind(name) > -1)
{
ObjectSet(name, OBJPROP_TIME1, dt);
ObjectSet(name, OBJPROP_PRICE1, (WindowPriceMax() - WindowPriceMin()) / 2 + WindowPriceMin());
}
}
// překreslí MarketZone linii
// baseName = základní název MZ
// currentDate = řetězec aktuálního datumu (bez času)
// timeOpen = řetězec času otevření marketu
// timeClose = řetězec času zavření marketu
void redrawMZ(string baseName, string currentDate, string timeOpen, string timeClose)
{
// název linie zobrazující otevření marketu
string nameOpen = baseName + "Open";
// název linie zobrazující zavření marketu
string nameClose = baseName + "Close";
// název textu zobrazující popis marketu
string nameText = baseName + "Text";
// vytvoření datumu pro otevírací a zavírací dobu
datetime dtOpen = StrToTime(currentDate + " " + timeOpen);
datetime dtClose = StrToTime(currentDate + " " + timeClose);
redrawVLine(nameOpen, dtOpen);
redrawVLine(nameClose, dtClose);
redrawText(nameText, dtOpen);
WindowRedraw();
}
// běh indikátoru
int start()
{
string currentDate = TimeToStr(TimeCurrent(), TIME_DATE);
// pokud se má vykreslit London, překreslíme MZ
if(London_Show)
{
redrawMZ(London_BaseName, currentDate, "09:00", "17:59");
}
return(0);
}
Nyní, když zkompilujete bezchybný kód, můžete vyzkoušet indikátor v platformě. Měli byste vidět linie obchodních hodin londýnského marketu (viz obr); upozornění: na vyšších TF jak H1 se linie nezobrazují.
Samozřejmě, že se nabízí otázka, zda lze zobrazit obchodní hodiny jiného marketu? Ano, např. si přidáme MZ pro New York (viz obr). Stačí přidat nové vstupní parametry a proměnnou pro názvy grafických objektů:
extern bool NewYork_Show = true;
extern color NewYork_Color = Red;
extern string NewYork_Text = "New York";
//---- základní názvy objektů
string NewYork_BaseName = "MZNewYork";
Upravíme metody init(), deinit() a start():
// inicializace
int init()
{
// pokud se má zobrazit London, vytvoříme MZ
if(London_Show)
{
createMZ(London_BaseName, London_Color, London_Text);
}
// pokud se má zobrazit New York, vytvoříme MZ
if(NewYork_Show)
{
createMZ(NewYork_BaseName, NewYork_Color, NewYork_Text);
}
return(0);
}
// deinicializace
int deinit()
{
// smazání MZ pro London
deleteMZ(London_BaseName);
// smazání MZ pro New York
deleteMZ(NewYork_BaseName);
return(0);
}
// běh indikátoru
int start()
{
string currentDate = TimeToStr(TimeCurrent(), TIME_DATE);
// pokud se má vykreslit London, překreslíme MZ
if(London_Show)
{
redrawMZ(London_BaseName, currentDate, "09:00", "17:59");
}
// pokud se má vykreslit New York, překreslíme MZ
if(NewYork_Show)
{
redrawMZ(NewYork_BaseName, currentDate, "14:00", "22:59");
}
return(0);
}
Pokud chcete vykreslit i jiné obchodní hodiny, tak to už zbývá na vás, jako samostatné cvičení. Postup je stejný jako u New Yorku.
Zde je kompletní kód ke stažení (obsahuje obchodní hodiny pro Londýn, New York, Sydney a Tokio).