MetaTrader 5 ve MQL5 Ekonomik Takvim: Haberler Nasıl Tekrarlanabilir Bir Alım-Satım Sistemine Dönüştürülür?
Giriş
Haberlere dayalı işlem yapan yatırımcıların temel sorunları, dağınık araç seti ve sistematik, algoritmik bir alım-satım iş akışının olmamasıdır. İşlem yaparken dikkatinizi internet tarayıcınız (haber sitelerinde gezinmek) ve işlem terminaliniz arasında bölmek oldukça zordur.
Haber tabanlı işlem yapan bir yatırımcının iş akışı şuna benzer: Web tarayıcınızda haber takvimini hızlıca açma ve olaylardaki değişiklikleri kontrol etme → Yaklaşan olayları hızlıca değerlendirme ve ne ve nasıl işlem yapacağınıza karar verme → MetaTrader 5 terminaline gitme - bekleyen emirler yerleştirme veya terminal başında oturup karar vermek için haberlerin yayınlanmasını bekleme. Bu senaryoda, yatırımcı genellikle bağlam kaybı yaşar, bu da haberlere tepki vermede gecikmelere yol açar ve bu da kayıplara neden olur.
Haberlere dayalı alım-satımın net kurallar, tekrarlanabilir sonuçlar ve otomatik testlerle bir mühendislik problemi gibi çalışmasını ister misiniz? Bu makalenin amacı, MetaTrader 5 için bir haber katmanının çalışma mimarisini göstermektir: tek bir veri kaynağı, takvim API'sinin uygun kullanımı, bir filtreleme ve önbelleğe alma mekanizması, geçmiş olayların sınayıcı için bir kaynağa aktarılması ve Canlı ve Sınayıcı arasında otomatik geçiş - böylece aynı kod hem gerçek zamanlı hem de geçmiş verilerde deterministik sonuçlar üretir.
Şekil 1. Manuel bir yatırımcının temel sorunu araçların dağınık olmasıdır
Haberlere dayalı manuel alım-satımın artık modası geçti
Öncelikle, dış faktörlere bağlı bir haber stratejisi test edilemez. Alım-satımda başarının yarısı, stratejinin geçmişteki performansını test etmekle ilgilidir. Bir stratejinin test edilememesi, alınan kararlarda öznelliğe yol açar. Strateji bir hipotez olarak kalacak ve onu test etmek için aylar hatta yıllar boyunca çok zaman harcayacaksınız.
İkinci olarak, manuel alım-satım ölçeklendirilmesi çok zordur. Düzensiz kar getiren ve istikrarsız bir işletmeyi ölçeklendirmeye çalışın. Onu genişletmek sorunları daha da kötüleştirebilir. Net bir yapı, sistematikleştirme ve optimizasyon yoksa, ölçeklendirme hakkında düşünmek faydasızdır.
Üçüncüsü, haberlere verilen tepkilerdeki gecikmeler manuel alım-satımın en büyük sorunlarından biridir. Bir FOREX yatırımcısı olduğunuzu ve Tarım Dışı İstihdam (Non Farm Payrolls, NFP) verisine dayalı işlem yaptığınızı hayal edin. NFP verileri genellikle ayda bir kez açıklanmaktadır. Dikkatiniz dağıldı ve NFP'yi kaçırdınız, para kazanma fırsatını kaybettiniz. Bu, birçok yatırımcı için tanıdık bir durumdur.
Sonuç: Otomasyon, haberlere dayalı tekrarlanabilir alım-satımın tek yoludur.

Şekil 2. Bir robot her zaman daha hızlıdır
MetaTrader 5'te yerleşik ekonomik takvim: Tek bir bilgi kaynağı
Haber tabanlı alım-satımı algoritmik hale getirmek ve dolayısıyla geçmiş testlerini mümkün kılmak için şirketimizin benzersiz ürününü kullanın - MQL5 API aracılığıyla haberlere erişim sağlayan, MetaTrader 5'te yerleşik bir ekonomik takvim. Haberlere dayalı alım-satımınızı doğaçlamadan, doğrulanabilir algoritmik bir sürece dönüştürecek olan şey budur. Çevrimdışı testler için hem gerçek zamanlı güncel olaylar hem de geçmiş olaylar mevcuttur.
Tablo 1:
MetaTrader 5'te yerleşik takvimi benzersiz kılan özellikler nelerdir?
| Parametre | |
|---|---|
| Erişim hızı | <100 ms - haberleri terminale yükledikten sonra |
| Entegrasyon | Yerel - terminal çekirdek seviyesinde + MQL-API |
| Testler | Tam destek - haberleri terminale indirdikten sonra (sınayıcıda dosyalar, kaynaklar veya SQLite üzerinden erişim) |
| Güvenilirlik | Yüksek |
MetaTrader 5 mükemmel bir strateji sınayıcıya sahiptir - hızlı, çok varlıklı ve test ve optimizasyon için yerel ve küresel ağlardaki bilgisayarları kullanabilir. Haber tabanlı alım-satım sisteminizi geçmiş veriler üzerinde çalıştırmayı deneyin. Bu, alım-satım yaklaşımınızı daha iyi hale getirebilir.
MetaTrader 5 ekonomik takvim fonksiyonları: MQL5 API'ye genel bakış
Manuel analizden algoritmik analize geçiş, veri mimarisini anlamakla başlar. MQL5'te ekonomik takvim sadece bir tablo değil, yerel bir API aracılığıyla erişilebilen yapılandırılmış bir veritabanıdır. Olayları doğru bir şekilde nasıl sorgulayacağımızı, Olay ve Değer arasındaki farkı ve başarılı bir strateji için zaman senkronizasyonunun neden gerekli olduğunu keşfedeceğiz.
MQL5 takviminin çekirdeği, her biri kendi görevini çözen birkaç temel fonksiyondan oluşur. Tüm Ekonomik Takvim verilerini aynı anda sağlayan evrensel bir fonksiyon olmadığını anlamak önemlidir. Kombine bir yaklaşım gerekmektedir.
- CalendarValueHistory - ilk yükleme için ana araç. Belirli bir zaman aralığı için bir olay değerleri dizisi almayı sağlar. Bu, Uzman Danışmanın başlatılması sırasında önbelleği geçmiş verilerle veya önümüzdeki haftanın verileriyle doldurmak için kullanılan "ağır toplardır".
- CalendarValueLast - gerçek zamanlı çalışan Uzman Danışmanlar için ana fonksiyon. Son talepten bu yana yalnızca değişen veya yeni değerleri geri döndürür (change_id mekanizması aracılığıyla). Bu, her tikte tüm veri dizisini talep etmeyerek trafikten ve sunucu kaynaklarından tasarruf edilmesini sağlar.
- CalendarEventByCountry - ülkedeki tüm olayların açıklamalarını alır. ISO 3166-1 alpha-2 standardına göre kodla belirtilen belirli bir ülke için olay açıklamalarının bir listesini geri döndürür. Filtreler oluşturmak için gereklidir (örneğin, yalnızca "US" (ABD), "RU" (Rusya), "CA" (Kanada) vb. için olayları göstermek).
- CalendarEventByCurrency - para birimine göre tüm olayların açıklamalarını alır. Kodla ("USD", "EUR" vb.) belirtilen belirli bir para birimi için olay açıklamalarının bir listesini geri döndürür.
- CalendarCountryById - ID'ye göre ülke özelliklerini alır.
- CalendarEventById - ID'ye göre olay özelliklerini alır.
- CalendarValueById - ID'ye göre belirli bir değer alır.
Veri yapıları: Takvim MQL5 API'si ne geri döndürür?
Tüm ekonomik takvim API fonksiyonları ya bir yapı dizisi ya da tek bir yapı içeren bir değişken geri döndürür. Yapıları ve alanlarını tam olarak listeleyelim.
Olay açıklamaları - CalendarEventById, CalendarEventByCountry ve CalendarEventByCurrency fonksiyonlarında kullanılır:
struct MqlCalendarEvent { ulong id; // event ID ENUM_CALENDAR_EVENT_TYPE type; // event type from the ENUM_CALENDAR_EVENT_TYPE enumeration ENUM_CALENDAR_EVENT_SECTOR sector; // sector an event is related to ENUM_CALENDAR_EVENT_FREQUENCY frequency; // event frequency (periodicity) ENUM_CALENDAR_EVENT_TIMEMODE time_mode; // event time mode ulong country_id; // country ID ENUM_CALENDAR_EVENT_UNIT unit; // economic indicator value's unit of measure ENUM_CALENDAR_EVENT_IMPORTANCE importance; // event importance ENUM_CALENDAR_EVENT_MULTIPLIER multiplier; // economic indicator value multiplier uint digits; // number of decimal places string source_url; // URL of a source where an event is published string event_code; // event code string name; // event text name in the terminal language (in the current terminal encoding) };
Ülke açıklamaları - CalendarCountryById ve CalendarCountries fonksiyonlarında kullanılır:
struct MqlCalendarCountry { ulong id; // country ID (ISO 3166-1) string name; // country text name (in the current terminal encoding) string code; // country code name (ISO 3166-1 alpha-2) string currency; // country currency code string currency_symbol; // country currency symbol string url_name; // country name used in the mql5.com website URL };
Olay değerleri - CalendarValueById, CalendarValueHistoryByEvent, CalendarValueHistory, CalendarValueLastByEvent ve CalendarValueLast fonksiyonlarında kullanılır.
struct MqlCalendarValue { ulong id; // value ID ulong event_id; // event ID datetime time; // event date and time datetime period; // event reporting period int revision; // revision of the published indicator relative to the reporting period long actual_value; // actual value in ppm or LONG_MIN if the value is not set long prev_value; // previous value in ppm or LONG_MIN if the value is not set long revised_prev_value; // revised previous value in ppm or LONG_MIN if the value is not set long forecast_value; // forecast value in ppm or LONG_MIN if the value is not set ENUM_CALENDAR_EVENT_IMPACT impact_type; // potential impact on the currency rate //--- functions for checking the values bool HasActualValue(void) const; // returns 'true' if actual_value is set bool HasPreviousValue(void) const; // returns 'true' if prev_value is set bool HasRevisedValue(void) const; // returns 'true' if revised_prev_value is set bool HasForecastValue(void) const; // returns 'true' if forecast_value is set //--- functions for getting values double GetActualValue(void) const; // return actual_value or nan if the value is not set double GetPreviousValue(void) const; // return prev_value or nan if the value is not set double GetRevisedValue(void) const; // returns revised_prev_value or nan if the value is not set double GetForecastValue(void) const; // returns forecast_value or nan if the value is not set };
Not:
MqlCalendarValue yapısının actual_value, forecast_value, prev_value ve revised_prev_value alanlarını kontrol etmek ve bu alanlardan değerler almak için metotlar sağladığını unutmayın. Listelenen alanların değerleri olmayabilir - örneğin, haber öğesi henüz yayınlanmadığı için actual_value alanı boş olabilir. Değerleri almanın en iyi yolu, kontrolü yapmak ve değerleri yapının kendi metotlarını kullanarak almaktır.
Yapılar birbirleriyle aşağıdaki ilişkilerle bağlantılıdır:

Şekil 3. Takvim yapısı ilişkileri
MqlCalendarCountry yapısı, bir ülke ID'si aracılığıyla MqlCalendarEvent ile bağlantılıdır. İlişki biçimi "bire-çok" (1..*) şeklindedir.
MqlCalendarEvent yapısı, bir olay ID'si aracılığıyla MqlCalendarValue ile bağlantılıdır. İlişki biçimi "bire-çok" (1..*) şeklindedir.
Haber yayınlanma zamanı ve sunucu zamanı
Ekonomik takvimle çalışmaya yönelik tüm fonksiyonlar TimeTradeServer() işlem sunucusu zamanını kullanır. Bu, MqlCalendarValue yapısındaki zamanın ve CalendarValueHistoryByEvent() ve CalendarValueHistory() fonksiyonlarındaki zaman girdilerinin kullanıcının yerel zamanı yerine işlem sunucu saat dilimine ayarlandığı anlamına gelir.
Dönüştürmeye gerek yoktur: MqlCalendarValue::period olay zamanı, TimeCurrent() veya TimeTradeServer() fonksiyonları çağrıldığında elde edilen zamanla doğrudan karşılaştırılabilir. Sınayıcıda, TimeTradeServer() fonksiyonu geçmiş verilerdeki zamanla aynı olan bir model zamanı geri döndürür. Zaman pencereleriyle çalışma mantığı ("haberlerden 30 dakika önce") gerçek zamanda ve geçmişte aynı şekilde çalışır. Aracı kurum yaz/kış saati geçişini dikkate alırsa, takvim otomatik olarak bu geçişe göre ayarlanır.
Pratik örnek - bugün (geçerli gün) için olayların bir listesini alma:
//+------------------------------------------------------------------+ //| Get calendar values for the current day | //+------------------------------------------------------------------+ void GetTodayUSD_Events() { //--- define the period boundaries in server time datetime server_now = TimeTradeServer(); datetime day_start = server_now - (server_now % 86400); datetime day_end = day_start + 86400; MqlCalendarValue values[]; MqlCalendarEvent event; MqlCalendarCountry country; //--- request values only for USD if(CalendarValueHistory(values, day_start, day_end, NULL, "USD")) { Print(" Events received for USD: ", ArraySize(values)); //--- iterate over the array of values for(int i = 0; i < ArraySize(values); i++) { //--- get event description if(CalendarEventById(values[i].event_id, event)) { //--- get country description if(CalendarCountryById(event.country_id, country)) { Print("✅ Event #", i); Print("Event ID: ", values[i].event_id); Print("Event name: ", event.name); Print("Sector: ", event.sector); Print("Source: ", event.source_url); Print("Country name: ", country.name); Print("Country URL: ", country.url_name); Print("Time: ", TimeToString(values[i].time, TIME_DATE | TIME_SECONDS)); Print("Impact: ", values[i].impact_type); // CHECK AND OUTPUT VALUES if(values[i].HasActualValue()) Print("Actual: ", values[i].GetActualValue()); if(values[i].HasRevisedValue()) Print("Revised: ", values[i].GetRevisedValue()); if(values[i].HasForecastValue()) Print("Forecast: ", values[i].GetForecastValue()); if(values[i].HasPreviousValue()) Print("Previous: ", values[i].GetPreviousValue()); } } } } else { int error = GetLastError(); if(error == 0) { Print("❌ CalendarValueHistory: No Events"); } else { Print("❌ Error CalendarValueHistory: ", error); } } } //+------------------------------------------------------------------+
Fonksiyon, geçerli gün için USD para birimine ait olayların bir listesini ve takvimin MQL API'si aracılığıyla alınan yapıların ana alanlarının içeriğini görüntüler. Kodun tamamı makaleye ekli GetTodayEvents-S.mq5 dosyasında yer almaktadır.
Fonksiyonun çalışma sonuçları MetaTrader 5 terminalinin Araç Kutusu\Uzmanlar sekmesinde görülebilir. USD için iki olay alındığını görüyoruz. Talebin yapıldığı zamanda bu olaylar henüz gerçekleşmemişti (haberler yayınlanmamıştı). Bu nedenle, MqlCalendarValue::actual_value alanı bir değer içermez - HasActualValue() fonksiyonu 'false' geri döndürür.
Bu olay türleri için HasForecastValue() tarafından kontrol edilen MqlCalendarValue::forecast_value alanı yoktur (değer içermez). Diğer olaylar için dört alanın tümü (prev_value, actual_value, forecast_value ve revised_prev_value) eksik olabilir.
Received events for USD: 2
✅ Event #0
Event ID: 840220005
Event name: 3-month treasury bills auction
Sector: 1
Source: https://home.treasury.gov/
Country name: USA
Country URL: united-states
Time: 2026.04.20 18:30:00
Impact: 0
Previous: 3.62
✅ Event #1
Event ID: 840220006
Event name: 6-month treasury bills auction
Sector: 1
Source: https://home.treasury.gov/
Country name: USA
Country URL: united-states
Time: 2026.04.20 18:30:00
Impact: 0
Previous: 3.61
Sağlanan kod için açıklamalar:
İlk olarak, "USD" para birimi filtresi ile belirli bir zaman aralığındaki tüm olaylar için bir değer dizisi elde ediyoruz. Bir döngü içinde, değer dizisi üzerinden geçiyoruz ve CalendarEventById() fonksiyonunu kullanarak MqlCalendarValue::event_id olay ID'sine göre olay açıklamasını talep ediyoruz. Ardından CalendarCountryById() fonksiyonunu kullanarak MqlCalendarEvent::country_id ID'sine göre bir ülke açıklaması talep ediyoruz.
CalendarValueHistory() fonksiyonu 'false' geri döndürür, ancak GetLastError() sıfır (hata yok) geri döndürürse, bu istenen ayarlara sahip hiçbir olay olmadığını gösterir.
Takvimle çalışırken hata işleme ve sınırlar
Uzak verilerle çalışmak her zaman bağlantı kesintileri veya erişim kısıtlamaları riski taşır. Takvim fonksiyonları başarısızlık durumunda false veya 0 geri döndürür. Nedenini anlamak için GetLastError() fonksiyonunu kullanmak gerekir. Dokümantasyonda takvim modülü için ayrı bir hata grubu vurgulanmaktadır.
Hata kodları:
- ERR_CALENDAR_TIMEOUT (kod 5200) - sunucu yanıtı bekleme süresi doldu. Ağ arızası veya sunucu aşırı yüklenmesi. Çözüm: Talebi 5...10 saniyelik bir aradan sonra tekrarlayın.
- ERR_CALENDAR_NO_DATA (kod 5201) - takvim verileri henüz yüklenmedi. Takvim eşzamansız olarak başlatılmıştır. Çözüm: 1...2 saniye bekleyin ve tekrarlayın.
- ERR_CALENDAR_INVALID_DATE (kod 5202) - geçersiz tarih aralığı. Kod hatası (örneğin, başlangıç tarihi bitiş tarihinden daha ileridir). Çözüm: Mantığı düzeltin, talebi tekrarlamak işe yaramaz.
- ERR_CALENDAR_INVALID_COUNTRY (kod 5203) - bilinmeyen ülke/para birimi kodu. Talep parametrelerinde hata. Çözüm: Kodu kontrol edin (örneğin, "USA" yerine "US").
- ERR_CALENDAR_TOO_MANY_REQUESTS (kod 5204) - talep sınırı aşıldı. Kritik hata. Çözüm: Talepler arasındaki aralığı artırın.
Talep hızı sınırlaması:
MetaTrader 5 terminalinin bağlandığı sunucular, altyapıyı aşırı yükten korur. Uzman Danışman, CalendarValueHistory() fonksiyonunu her tikte veya gecikme olmaksızın bir döngü içinde çağırırsa, sunucu 5204 hatasını geri döndürür ve terminaliniz için takvime erişimi geçici olarak engeller. En iyi uygulama: başlangıçta OnInit() içinde gerekli aralık için verileri bir kez yükleyin.
Gerçek zamanlı güncellemeler için, geri döndürülen change_id değişkenini saklayarak CalendarValueLast() fonksiyonunu kullanın - bu, tüm veri dizisi yerine yalnızca değişikliklerin alınmasını sağlar. OnTimer() içindeki bir zamanlayıcıdaki verileri 5-10 dakikadan fazla olmayan aralıklarla güncelleyin.
Bir takvimi yüklerken ortaya çıkabilecek sorunlara yönelik bazı çözüm örneklerine bakalım:
Terminali ilk kez başlattığınızda ve Uzman Danışmanı çalıştırdığınızda takvim hemen hazır olmaz. Veriler arka planda sunucudan yüklenir. OnInit() fonksiyonunun ilk satırında CalendarValueHistory() fonksiyonunu çağırırsak, büyük olasılıkla 5201 - veri yok hatası alırız. Üstel veya sabit bir zaman aşımı ile bir durum sorgulama mekanizması uygulamak gerekir.
Pratik örnek - hata işleme ile takvim veri yükleme fonksiyonu:
//+------------------------------------------------------------------+ //| Calendar loading function | //+------------------------------------------------------------------+ bool LoadCalendar(MqlCalendarValue& values[], const datetime from, const datetime to, const string country_code = NULL, const string currency = NULL, const int max_retries = 5) { int retry_count = 0; while(retry_count < max_retries) { ResetLastError(); //--- download attempt if(CalendarValueHistory(values, from, to, country_code, currency)) return true; // Success int error = GetLastError(); //--- in case of "No data" (5201) or "Timeout" (5200) error — wait and repeat if(error == 5201 || error == 5200) { retry_count++; Sleep(1000); // 1 second pause before repeating continue; } //--- if the error is critical (for example, an invalid date), interrupt the download immediately Print("❌ Critical Calendar Error: ", error); return false; } Print("❌ Failed to load calendar after ", max_retries, " attempts."); return false; } //+------------------------------------------------------------------+
Sağlanan kod için açıklamalar:
"Veri yok" (5201) ve "Zaman aşımı" (5200) hataları olasılığını göz önünde bulundurun. Bunlar düzeltilebilir hatalardır. 1...5 saniye duraklama yaparak ve verileri tekrar talep ederek bu hataları yönetin. Düzeltilemeyen herhangi bir hata oluşursa, indirmeyi derhal durdurun. Düzeltilemeyen hatalar arasında geçersiz tarihler, yanlış para birimi veya ülke kodları vb. yer alır. Kodun tamamını bu makaleye ekli GetTodayEvents-S.mq5 dosyasında bulabilirsiniz.
Sınırlamalardan kaçınmak ve maksimum tepki hızını sağlamak için, OnTimer() içinde change_id mekanizmasını kullanmalıyız. Başlangıçta, tüm olay geçmişini yükleyin ve son change_id'yi hatırlayın. Zamanlayıcıda, CalendarValueLast() fonksiyonunu kullanarak yalnızca yeni verileri talep edin. Sunucu, eski verileri iletmek için kaynakları boşa harcamadan yalnızca değişenleri (veya herhangi bir değişiklik yoksa ‘false’) geri döndürecektir.
Pratik örnek - hata işleme ile takvim veri güncelleme fonksiyonu:
//+------------------------------------------------------------------+ //| Timer: incremental update | //+------------------------------------------------------------------+ void OnTimer() { if(!is_initialized) return; MqlCalendarValue updates[]; ResetLastError(); //--- API automatically updates last_change_id by reference if(!CalendarValueLast(last_change_id, updates, (InpCountryCode == "") ? NULL : InpCountryCode, (InpCurrency == "") ? NULL : InpCurrency)) { int err = GetLastError(); // 0 = SUCCESS/NO_NEW_DATA, 5402 = ERR_CALENDAR_NO_CHANGES if(err != 0 && err != 5402) Print("🔴️ CalendarValueLast error: ", err); return; } int cnt = ArraySize(updates); if(cnt == 0) return; Print("🟢 Received ", cnt, " updates. New change_id: ", last_change_id); if(InpPrintChanges) ArrayPrint(updates); SyncCache(updates); } //+------------------------------------------------------------------+ //| Cache synchronization | //+------------------------------------------------------------------+ void SyncCache(const MqlCalendarValue &updates[]) { int upd_cnt = ArraySize(updates); int cache_sz = ArraySize(calendar_cache); for(int u = 0; u < upd_cnt; u++) { bool found = false; for(int c = 0; c < cache_sz; c++) { if(calendar_cache[c].id == updates[u].id) { calendar_cache[c] = updates[u]; found = true; break; } } if(!found) { ArrayResize(calendar_cache, cache_sz + 1); calendar_cache[cache_sz] = updates[u]; cache_sz++; total_events++; } } } //+------------------------------------------------------------------+
Sağlanan kod için açıklamalar:
Olayların aşamalı güncellenmesi, OnTimer() zamanlayıcısındaki olay işleyicisi aracılığıyla gerçekleşir. Takvim API'si CalendarValueLast() fonksiyonu çağrılır - yeni olaylar ortaya çıkarsa, önceden yüklenmiş MqlCalendarValue yapı dizisindeki uygun öğeleri günceller ve terminal günlüğüne verileri yazdırır. Yüklenen dizide böyle bir olay bulunmazsa, diziye eklenir.
Kodun tamamı makaleye eklenmiş olan CalendarEventMonitor-EA.mq5 dosyasında yer almaktadır.
Olayları filtreleme: Genelden özele
Neden filtreleme:
Ekonomik takvim günlük 60-90 olay yayınlamaktadır. Bu, piyasa üzerinde hemen hiçbir etkisi olmayan yüzlerce küçük gösterge, tatil ve resmi konuşmanın sürekli akışını dinlemek gibidir. Her biri üzerinde işlem yapmak, aşırı işlem yapmanın ve bakiyenizi kaybetmenin kesin bir yoludur. Haberlere dayalı işlem yapan algoritmik bir yatırımcının görevi, piyasayı gerçekten hareket ettiren 3-5 olay bırakmaktır.
Haberlere dayalı algoritmik alım-satımda filtreleme, sinyal-gürültü oranını otomatik karar verme için uygun bir seviyeye çıkarmakla eşdeğerdir. MQL5 takvim API'sinde bu süreç, MqlCalendarEvent ve MqlCalendarValue yapı dizilerinin geçtiği çok seviyeli bir elek sistemi olarak uygulanır.
Filtreleme kriterleri:
Piyasa, haberlerin yayınlanmasının kendisine değil, açıklanan verilerin beklentilerden sapmasına ve makroekonomik etki düzeyine tepki verir. Düşük etkili olaylar (MqlCalendarValue::impact_type < 3) genellikle alım-satım algoritmaları ve piyasa yapıcılar tarafından göz ardı edilir.
Filtreleme olmadan şunları elde edersiniz:
- Stratejinin ikincil istatistiklere dayalı yanlış tetiklemeleri;
- Volatilite olmadan geniş makas dönemlerinde işlem;
- Uzman Danışmanın mantığını gereksiz kontrollerle aşırı yükleme.
Filtrelemenin amacı, veri akışını %90 oranında azaltmak ve belirli bir zaman penceresinde yatırımcı tarafından seçilen hedef para birimi için yalnızca yüksek etkili olayları (ENUM_CALENDAR_EVENT_IMPORTANCE::CALENDAR_IMPORTANCE_HIGH) bırakmaktır.
Hem gerçek zamanlı hem de test modunda eşit derecede güvenilir şekilde çalışacak güvenilir bir filtrenin nasıl oluşturulacağına bakalım.
Çok seviyeli filtreleme sistemi:
Terminalden indirilen "ham" olay verileri işlenmemiş cevher gibidir: önemsiz istatistiksel raporlardan algoritmik stratejiye hiçbir fayda sağlamayan tatil günlerine kadar binlerce girdi içerir.
Bu veri akışını temiz bir sinyale dönüştürmek için çok seviyeli bir filtreleme sistemine ihtiyacımız var. Olay filtreleme, ham verilerin içinden geçtiği bir "elek" görevi görür ve çıktıda yalnızca belirtilen kriterleri karşılayan olayları bırakır: para birimi, önem, kod ve zaman penceresi.
Etkili bir filtre hiyerarşik bir yapıya sahip olmalıdır: başlangıçta coğrafyaya göre kaba bir eleme işlemiyle başlar ve zaman penceresine göre ince ayar ile sona erer.
MQL5-API haberlerinin önemli bir özelliği - MqlCalendarValue yapısı currency_id ve country_id alanlarını içermez. Yalnızca event_id, zaman, gösterge değerleri ve etki türünü depolar. Bu filtrasyonu nasıl etkiler?
Para birimi filtreleme API talebi düzeyinde gerçekleştirilir. CalendarValueHistory(..., NULL, "USD") çağırdığınızda, terminalin kendisi USD dışındaki her şeyi göz ardı eder. Elde ettiğiniz dizi zaten para birimine göre filtrelenmiştir. Bu nedenle, currency_id'yi gerçek zamanlı olarak kontrol etmeye gerek yoktur - zamana, öneme ve beklenti varlığına/önemine göre filtrelemek yeterlidir.
Seviye 1: Para birimi filtresi
İlk bariyer olay coğrafyasıdır. EURUSD alım-satımı yaparken, Uzman Danışman yalnızca Euro Bölgesi (EUR) ve ABD'yi (USD) etkileyen olaylara tepki vermelidir. Filtreleme, işlem gören enstrümanın para birimi kodlarıyla olayların talep edilmesiyle gerçekleşir. Çapraz kurlar için (örneğin "GBPJPY"), her iki para birimi ("GBP" ve "JPY") ve "USD" için olayları talep etmemiz gerekir.
Seviye 2: Olayın önemi
Tüm haberler, ekonomi -aslında fiyatlar- üzerindeki etkileri bakımından farklı önemlere sahiptir. Tüketici Fiyat Endeksi (TÜFE) piyasayı 100 puan hareket ettirebilirken, ZEW Tüketici Güven Endeksi sadece 10 puan hareket ettirebilmektedir.
MQL5-API, önem derecesini ayarlamak için ENUM_CALENDAR_EVENT_IMPORTANCE numaralandırmasını kullanır:
enum ENUM_CALENDAR_EVENT_IMPORTANCE { CALENDAR_IMPORTANCE_NONE, // importance level is not set CALENDAR_IMPORTANCE_LOW, // low importance CALENDAR_IMPORTANCE_MODERATE, // medium importance CALENDAR_IMPORTANCE_HIGH // high importance };
Haber tabanlı Uzman Danışmanlar, likiditesi düşük haberlerde yanlış pozitifleri önlemek için YÜKSEK öneme sahip haberlerin altındaki her şeyi göz ardı etmelidir.
Seviye 3: Olay kodu
Yüksek öneme sahip olaylar arasında bile istisnalar vardır. Örneğin, bir ECB veya IMF konuşması önemli olarak işaretlenebilir, ancak algoritmik olarak işlenmesi belirli sayıların yayınlanmasından daha zordur. Bu nedenle, olay koduna göre filtrelemeye ihtiyacımız var: MqlCalendarEvent::event_code alanı benzersiz bir kimlik içerir (örneğin, "NONFARM", "CPI", "GDP"). Anketleri ve konuşmaları değil, yalnızca ekonomik sayıların yer aldığı olayları seçiyoruz.
Sadece ilk üç doğrulama seviyesini geçtikten sonra olay sonuç dizisine kopyalanır ve alım-satımda kullanılır.

Şekil 4. Çok seviyeli filtreleme, haberlere dayalı alım-satımda başarının anahtarıdır
İlk üç filtreleme seviyesinden sonra Uzman Danışman, olayın yapılandırılan zaman penceresine denk gelip gelmediğini kontrol eder. Bu, Uzman Danışman çalışırken gerçekleşir.
Seviye 4: Zaman penceresi
Son aşama alaka düzeyinin kontrol edilmesidir. Bir ay sonra çıkacak haberlere ihtiyacımız yok. Dün çıkan haberler piyasa tarafından çoktan işlendi. Bu nedenle, TimeCurrent(), haberin yayınlanmasından önceki belirtilen süre ile haberin yayınlanmasından sonraki belirtilen süre arasındaki aralığa denk geliyorsa bir olay aktif olarak kabul edilir. Tipik olarak aşağıdaki ayarlar kullanılır: Pozisyonları kapatmak için haberden 15-30 dakika öncesi ve volatilite ve fiyat hareket yönünü analiz etmek için haberden 60 dakika sonrası.
MQL5 ikili kaynakları: Verimli önbelleğe alma için olayları çevrimdışı teste taşıma
Haber tabanlı algoritmik alım-satımda test yaparken karşılaşılan bir sorun, strateji sınayıcının internet erişimine sahip olmamasıdır. Bu çözüm testi hızlandırır ve deterministik olmayan faktörlere karşı koruma sağlar, ancak haber tabanlı stratejileri test etmek için bir sorun yaratır.
Sınayıcıdaki Uzman Danışman, CalendarValueHistory() fonksiyonunu çağırırsa bir hata ve boş bir dizi alır. Stratejiyi test etmek için, geçmiş haber verilerini .ex5 yürütülebilir dosyasına yerleştirmemiz gerekir. Bunun için MQL5 ikili kaynakları seçeneğini kullanıyoruz. Neden özellikle bu seçenek? Bu, yapılandırılmış verilere erişmenin en hızlı yoludur - erişim hızı yalnızca bilgisayarın dosya sisteminin performansı ile sınırlıdır.
MqlCalendarValue[] dizisinin kompakt bir ikili dosyaya nasıl dönüştürüleceğine ve sınayıcının RAM'den yıldırım hızında veri okuması için koda nasıl yerleştirileceğine bakalım. İlk adım, mevcut verileri takvimden indirecek ve ikili bir dosyaya kaydedecek bir dışa aktarıcı komut dosyası oluşturmaktır.
Pratik örnek - olayları ikili bir dosyaya aktarmak için bir komut dosyası:
Kodun tamamı makaleye ekli ExportCalendarForTester.mq5 dosyasında yer almaktadır.
1. Adım: Dizinin oluşturulması ve filtrelenmesi
Tüm küresel olayları kaynakta saklamayacağız. İkili bir dosyaya aktarma aşamasında, Uzman Danışmanda olduğu gibi aynı filtreleri uygularız: para birimi, önem ve olay türü. Komut dosyası girdileri para birimlerinin listesini, olayların yüklenmesi için zaman aralığını, olay kodlarını ve minimum önemi belirtir.
Olay kodları listesi (InpEventCodes parametresi) varsayılan olarak boştur - bu, tüm olay türlerinin yüklendiği anlamına gelir. Bu filtreyi daraltabiliriz. Örneğin, sadece Tarım Dışı İstihdam verileri - o zaman kod listesi "NONFARM" olacaktır.
InpUseCommonDir bayrağı ikili dosyanın nereye kaydedileceğini belirtir: true - tüm müşteri terminalleri için paylaşılan klasöre (\Terminal\Common\Files) kaydedilir.
//--- input parameters input string InpCurrencies = "USD"; input datetime InpDateFrom = D'2025.01.01'; input datetime InpDateTo = 0; input string InpEventCodes = ""; input ENUM_CALENDAR_EVENT_IMPORTANCE InpMinImportance = CALENDAR_IMPORTANCE_HIGH; input string InpOutputFile = "calendar_test_res.bin"; input bool InpUseCommonDir = true;
Komut dosyasının, girdilerde belirtilen değerlerle olayları yükleyen ve filtreleyen kısmı aşağıda gösterilmiştir:
Print("🔄 Calendar export:"); Print("----------------------------------"); Print("Filtering options:"); Print(" 🟨 Interval = ", InpDateFrom, " — ", InpDateTo); Print(" 🟨 Currencies = ", InpCurrencies, "\n 🟨 Event Codes = ", InpEventCodes, "\n 🟨 Min Importance = ", EnumToString(InpMinImportance)); Print("----------------------------------"); //--- initialize filter by currencies ArrayResize(currencies, 0); if(InpCurrencies == "") return; StringSplit(InpCurrencies, ',', currencies); currencies_size = ArraySize(currencies); for(int i = 0; i < currencies_size; i++) StringToUpper(currencies[i]); //--- initialize the filter by event codes ArrayResize(event_codes, 0); if(InpEventCodes != "") StringSplit(InpEventCodes, ',', event_codes); event_codes_Size = ArraySize(event_codes); //--- load calendar values with the CURRENCY FILTER (if specified) if(currencies_size > 0) { ArrayResize(values_size, currencies_size); ArrayFill(values_size, 0, currencies_size, 0); for(int i = 0; i < currencies_size; i++) { if(LoadCalendar(raw_values, InpDateFrom, InpDateTo, "", currencies[i])) { raw_values_size = ArraySize(raw_values); //--- load events with an IMPORTANCE AND EVENT CODE FILTER for(int k = 0; k < raw_values_size; k++) { //--- get event description if(CalendarEventById(raw_values[k].event_id, event)) { //--- take indicators only if(event.type != CALENDAR_TYPE_INDICATOR) continue; // nothing else to filter //--- check by IMPORTANCE if(event.importance < InpMinImportance) continue; // nothing else to filter //--- check by EVENT CODE (if specified) if(event_codes_Size > 0) { bool code_allowed = false; for(int c = 0; c < event_codes_Size; c++) { StringToUpper(event.event_code); if(StringFind(event.event_code, event_codes[c]) >= 0) { code_allowed = true; break; } } if(code_allowed == false) continue; } //--- replenish the array of filtered events int event_index = ArraySize(values); ArrayResize(values, event_index + 1); values[event_index] = raw_values[k]; values_size[i]++; } } Print("✅ Received values BY CURRENCY \"", currencies[i], "\": ", raw_values_size, " → Of these, filtered: ", values_size[i]); } else { int error = GetLastError(); if(error == 0) Print("⚠ LoadCalendar Info: No Events for ", currencies[i]); else Print("❌ LoadCalendar Error: ", error, " for ", currencies[i]); return; // nothing else to filter } } }
Sağlanan kod için açıklamalar:
- values_size[] dizisi, girdilerde belirtilen her bir para birimi kodu için filtrelenen olay sayısını saklar.
- MQL5 datetime türünün sıfır değeri 1970.01.01 00:00:00 tarihine karşılık gelir.
- Olay türüne göre ek filtreleme gerçekleşir. Sadece ENUM_CALENDAR_EVENT_TYPE::CALENDAR_TYPE_INDICATOR türündeki olaylar ayrıştırılır - bunlar ekonomik olaylardır (konuşmalar değil, sayılar). Diğer tüm haberler göz ardı edilir. Bu, filtrelemenin en başında doğrulama ile yapılır:
//--- take only indicators if(event.type != CALENDAR_TYPE_INDICATOR) continue; // Nothing else to filter
Komut dosyasını farklı filtreleme parametreleriyle çalıştıralım ve olay yükleme/filtreleme komut dosyasının ne kadar hızlı çalıştığını görelim. Hızın bilgisayarın gücüne ve internet üzerinden veri sunucularına bağlantı hızına bağlı olduğu açıktır. Bununla birlikte, bir stres testi gerçekleştireceğiz. Sonuçlar aşağıda sunulmuştur.
Mevcut tüm tarih boyunca yüksek öneme sahip tüm USD olayları:
13:59:43.724 🔄 Calendar export:
13:59:43.724 ----------------------------------
13:59:43.724 Filtering options:
13:59:43.724 🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
13:59:43.724 🟨 Currencies = USD
13:59:43.724 🟨 Event Codes =
13:59:43.724 🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
13:59:43.724 ----------------------------------
13:59:45.511 ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 9009
13:59:45.511 ----------------------------------
13:59:45.513 ✅ Saved: USD_calendar_test_res.bin Size: 1153152 bytes (9009 events)
Filtrelenmiş değerler (MqlCalendarValue yapıları) dizisinin elde edilme zamanı 1.80 sn (0.20 ms / filtreleme başına).
Mevcut tüm tarih boyunca yüksek öneme sahip tüm USD, EUR ve JPY olayları:
14:03:08.724 🔄 Calendar export:
14:03:08.724 ----------------------------------
14:03:08.724 Filtering options:
14:03:08.724 🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:03:08.724 🟨 Currencies = USD,EUR,JPY
14:03:08.724 🟨 Event Codes =
14:03:08.724 🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:03:08.724 ----------------------------------
14:03:10.488 ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 9009
14:03:10.947 ✅ Received values BY CURRENCY "EUR": 45139 → Of these, filtered: 1102
14:03:11.404 ✅ Received values BY CURRENCY "JPY": 18907 → Of these, filtered: 937
14:03:11.404 ----------------------------------
14:03:11.406 ✅ Saved: USD_calendar_test_res.bin Size: 1153152 bytes (9009 events)
14:03:11.407 ✅ Saved: EUR_calendar_test_res.bin Size: 141056 bytes (1102 events)
14:03:11.408 ✅ Saved: JPY_calendar_test_res.bin Size: 119936 bytes (937 events)
Filtrelenmiş değerler (MqlCalendarValue yapıları) dizisinin elde edilme zamanı 2.68 sn (0.24 ms / filtreleme başına).
Mevcut tüm tarih boyunca yüksek öneme sahip tüm USD - NFP (Tarım Dışı İstihdam) olayları:
14:07:22.203 ----------------------------------
14:07:22.203 Filtering options:
14:07:22.203 🟨 Interval = 1970.01.01 00:00:00 — 1970.01.01 00:00:00
14:07:22.203 🟨 Currencies = USD
14:07:22.203 🟨 Event Codes = NONFARM
14:07:22.203 🟨 Min Importance = CALENDAR_IMPORTANCE_HIGH
14:07:22.203 ----------------------------------
14:07:22.290 ✅ Received values BY CURRENCY "USD": 53346 → Of these, filtered: 473
14:07:22.290 ----------------------------------
14:07:22.291 ✅ Saved: USD_calendar_test_res.bin Size: 60544 bytes (473 events)
Filtrelenmiş değerler (MqlCalendarValue yapıları) dizisinin elde edilme zamanı 0.09 sn (0.18 ms / filtreleme başına).
Notlar:
- Filtrede olay kodunun tamamının belirtilmesi gerekli değildir. Kodu içeren dizgenin benzersiz bir bölümünü belirtmek yeterlidir. Örneğin, Tarım Dışı İstihdam verileri için tam kod "NONFARM-PAYROLLS" şeklindedir - ancak "NONFARM" belirtilmesi yeterlidir.
- MetaTrader 5 terminalinde gerçek zamanlı bir alım-satım sistemi çalıştırırken, tüm dönem için tüm olayları indirmemiz gerekmeyecektir. Tipik olarak, o gün ve gelecek hafta için güncel haberler indirilir. Bu nedenle, haber tabanlı Uzman Danışman algoritmasındaki yükleme süresi ihmal edilebilir.
2. Adım: Olay dizisini ikili bir dosyaya aktarma
SaveToBinary fonksiyonu filtrelenmiş olayları bir ikili dosyaya kaydeder. Dosya sayısı, girdilerde belirtilen para birimi kodlarının sayısına eşittir - her para birimi kendi ikili dosyasına aktarılır. Dosya adı para birimi kodu önekiyle başlar. Örneğin, "USD_calendar_test_res.bin". Bu şekilde, para birimi kodu ile buna ilişkin olayların listesi arasında bire bir eşleşme elde ederiz.
//+------------------------------------------------------------------+ //| Save an array to a binary file | //+------------------------------------------------------------------+ void SaveToBinary(MqlCalendarValue &values[], const int &vls_size[], const string filename, const string ¤cies[]) { if(ArraySize(values) == 0) { Print("⚠️ Nothing to save"); return; } Print("----------------------------------"); int offset = 0; for(int i = 0; i < ArraySize(vls_size); i++) { int file_handle = FileOpen(currencies[i] + "_" + filename, FILE_WRITE | FILE_BIN | (InpUseCommonDir ? FILE_COMMON : 0)); if(file_handle == INVALID_HANDLE) { Print("❌ FileSave failed: ", GetLastError()); return; } FileWriteArray(file_handle, values, offset, vls_size[i]); FileFlush(file_handle); FileClose(file_handle); Print("✅ Saved: ", currencies[i] + "_" + filename, " Size: ", vls_size[i] * sizeof(MqlCalendarValue), " bytes", " (", vls_size[i], " events)"); offset += vls_size[i]; } }
Olayları ikili dosyalara aktarmak için komut dosyasını başarıyla çalıştırdıktan sonra, MetaTrader 5'in Uzmanlar sekmesinde aşağıdakine benzer mesajlar görünür:
14:28:42.077 ----------------------------------
14:28:42.078 ✅ Saved: USD_calendar_test_res.bin Size: 58240 bytes (455 events)
14:28:42.079 ✅ Saved: EUR_calendar_test_res.bin Size: 7680 bytes (60 events)
3. Adım: Kaynağın Uzman Danışmana derlenmesi
ExportCalendarForTester.mq5 komut dosyasını MQL5/Files/ içinde başlattıktan sonra, USD_calendar_test_res.bin ve EUR_calendar_test_res.bin dosyaları görünür. Şimdi bunların Uzman Danışmana "yerleştirilmesi" gerekiyor. Uzman Danışman dosyasının başına (#property yönergelerinden sonra), aşağıdaki şekilde bir (tek bir para birimi için bir dosya kullanıyorsanız) veya birkaç satır ekleyin:
// Embed the binary file as a static resource at the compilation stage #resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[] #resource "\\Files\\EUR_calendar_test_res.bin" as MqlCalendarValue EUR_res_calendar_data[]
Not:
- #resource yolu MQL5/Files/ klasörüne göre belirtilir. \\Files\\ ön eki zorunludur.
- Uzman Danışman derlenirken, MetaEditor'ın Hatalar sekmesinde aşağıdaki gibi mesajlar görünmelidir:
- 'USD_calendar_test_res.bin' as 'const MqlCalendarValue USD_res_calendar_data[455]'
- 'EUR_calendar_test_res.bin' as 'const MqlCalendarValue EUR_res_calendar_data[60]'
Uzman Danışman başlatılırken, dışa aktarma aşamasında kaydedilen olayların yapıları USD_res_calendar_data[] ve EUR_res_calendar_data[] dizilerinde saklanır.
Uzman Danışmana entegrasyon: Otomatik mod değiştirme
Amaç, aynı Uzman Danışman kodunun hem gerçek zamanlı olarak hem de sınayıcıda veri kaynağını otomatik olarak seçerek çalışmasını sağlamaktır. MQLInfoInteger(MQL_TESTER) fonksiyonu, Uzman Danışman strateji sınayıcı veya optimize edicide çalışıyorsa 'true' geri döndürür.
//+------------------------------------------------------------------+ //| Initialization: select a data source | //+------------------------------------------------------------------+ int OnInit() { Print("🔄 Initializing the news module:"); //--- initialize filter by currencies ArrayResize(currencies, 0); if(InpCurrencies == "") return INIT_FAILED; StringSplit(InpCurrencies, ',', currencies); currencies_size = ArraySize(currencies); for(int i = 0; i < currencies_size; i++) StringToUpper(currencies[i]); //--- initialize the filter by event codes ArrayResize(event_codes, 0); if(InpEventCodes != "") StringSplit(InpEventCodes, ',', event_codes); event_codes_Size = ArraySize(event_codes); //--- define the execution environment bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE); if(is_tester) { //--- TESTER MODE: Load from resource if(!LoadFromResource()) { Print("❌ ERROR: Failed to load calendar from resource"); return INIT_FAILED; } is_live_mode = false; Print("⚠️ Mode: TESTER (data from resource)"); } else { //--- LIVE MODE: Load from API if(!LoadFromCalendarAPI()) { int error = GetLastError(); Print("❌ ERROR: Failed to load calendar from API - ", error); return INIT_FAILED; } is_live_mode = true; Print("⚠️ Mode: LIVE (data from API)"); } return INIT_SUCCEEDED; }
Sağlanan kod için açıklamalar:
Ana kontrol OnInit() Uzman Danışman başlatma olay işleyicisinde yapılır:
//--- define the execution environment bool is_tester = MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_OPTIMIZATION) || MQLInfoInteger(MQL_VISUAL_MODE); if(is_tester) { //--- TESTER MODE: Load from resource if(!LoadFromResource()) { ... } } else { //--- LIVE MODE: Load from API if(!LoadFromCalendarAPI()) { ... } }
Sağlanan kod için açıklamalar:
Çalışan MQL5 programının (burada bizim Uzman Danışmanımızdır) hangi modda çalıştığını belirleriz. Aşağıdaki bayraklarla ilgileniyoruz:
- MQL_TESTER - sınayıcıda başlatılan programın bayrağı;
- MQL_OPTIMIZATION - optimizasyonda başlatılan programın bayrağı;
- MQL_VISUAL_MODE - görsel test modunda başlatılan programın bayrağı.
14:42:18.894 🔄 Initializing news module:
14:42:18.905 ✅ Events from Server Loaded: 455 events for: USD
14:42:18.914 ✅ Events from Server Loaded: 60 events for: EUR
14:42:18.914 ⚠️ Mode: LIVE (data from API)
Veri dönüştürme zincirinin doğrulanması: Olaylar → İkili dosya → Kaynağa derleme → Kaynaktan olayları alma
Geriye kalan tek şey, sınayıcıda olayların alınmasını kontrol etmek ve bunların gerçek zamanlı olarak alınan listeyle tamamen eşleştiğinden emin olmaktır. Bu, haberlere dayalı alım-satım algoritmalarını otomatik olarak test etme ve optimize etme olanağını doğrulayacaktır.
Bunu yapmak için, sunucudan alınan/kaynaktan indirilen olayların çıktısını terminal/strateji sınayıcı günlüğüne ekleriz. Sınayıcı çalıştırma sonuçlarını içeren ImportTesterLog.txt tam metin dosyası aşağıya eklenmiştir. Aşağıda günlük dosyasının bir parçası yer almaktadır - her bir para birimi kodu için olay dizisinin başlangıcı ve sonu.
Strateji sınayıcıda görsel modda tek test sonucu:
16:48:22.527 InpCurrencies=USD,EUR
16:48:22.527 InpDateFrom=1735689600
16:48:22.527 InpDateTo=1767225600
16:48:22.527 InpEventCodes=
16:48:22.527 InpMinImportance=3
16:48:22.546 🔄 Initializing news module:
16:48:22.546 ✅ Events from Resource Loaded: 455 events for: USD
16:48:22.546 ✅ Event #0
16:48:22.546 ID: 230215
16:48:22.546 Event ID: 840140001
16:48:22.546 Time: 2025.01.02 16:30:00
16:48:22.546 Impact: CALENDAR_IMPACT_POSITIVE
16:48:22.546 Revision: 0
16:48:22.546 Actual: 211.0
16:48:22.546 Revised: 220.0
16:48:22.546 Forecast: 219.0
16:48:22.546 Previous: 219.0
16:48:22.546 ✅ Event #1
16:48:22.546 ID: 230641
16:48:22.546 Event ID: 840500001
16:48:22.546 Time: 2025.01.02 17:45:00
16:48:22.546 Impact: CALENDAR_IMPACT_NEGATIVE
16:48:22.546 Revision: 3
16:48:22.546 Actual: 49.4
16:48:22.546 Forecast: 50.5
16:48:22.546 Previous: 49.7
...
16:48:22.553 ✅ Event #453
16:48:22.553 ID: 274419
16:48:22.553 Event ID: 840510001
16:48:22.553 Time: 2025.12.30 17:45:00
16:48:22.553 Impact: CALENDAR_IMPACT_POSITIVE
16:48:22.553 Revision: 0
16:48:22.553 Actual: 43.5
16:48:22.553 Forecast: 42.4
16:48:22.553 Previous: 36.3
16:48:22.553 ✅ Event #454
16:48:22.553 ID: 274484
16:48:22.553 Event ID: 840140001
16:48:22.553 Time: 2025.12.31 16:30:00
16:48:22.553 Impact: CALENDAR_IMPACT_POSITIVE
16:48:22.553 Revision: 0
16:48:22.553 Actual: 199.0
16:48:22.553 Revised: 215.0
16:48:22.553 Forecast: 227.0
16:48:22.553 Previous: 214.0
...
16:48:22.553 ✅ Events from Resource Loaded: 60 events for: EUR
16:48:22.553 ✅ Event #0
16:48:22.553 ID: 231322
16:48:22.553 Event ID: 999030013
16:48:22.553 Time: 2025.01.07 13:00:00
16:48:22.553 Impact: CALENDAR_IMPACT_NA
16:48:22.553 Revision: 1
16:48:22.553 Actual: 2.4
16:48:22.553 Forecast: 2.4
16:48:22.553 Previous: 2.2
16:48:22.553 ✅ Event #1
16:48:22.553 ID: 187384
16:48:22.553 Event ID: 999040007
16:48:22.553 Time: 2025.01.08 13:00:00
16:48:22.553 Impact: CALENDAR_IMPACT_POSITIVE
16:48:22.553 Revision: 0
16:48:22.553 Actual: 21.0
16:48:22.553 Revised: 17.8
16:48:22.553 Forecast: 15.7
16:48:22.553 Previous: 17.7
...
16:48:22.555 ✅ Event #58
16:48:22.555 ID: 204746
16:48:22.555 Event ID: 999010006
16:48:22.555 Time: 2025.12.18 16:15:00
16:48:22.555 Impact: CALENDAR_IMPACT_NA
16:48:22.555 Revision: 0
16:48:22.555 Actual: 2.0
16:48:22.555 Previous: 2.0
16:48:22.555 ✅ Event #59
16:48:22.555 ID: 204762
16:48:22.555 Event ID: 999010007
16:48:22.555 Time: 2025.12.18 16:15:00
16:48:22.555 Impact: CALENDAR_IMPACT_NA
16:48:22.555 Revision: 0
16:48:22.555 Actual: 2.15
16:48:22.555 Previous: 2.15
16:48:22.555 ⚠️ Mode: TESTER (data from resource)
Tüm olay dizilerinin kaynaktan yaklaşık 10 ms içinde yüklendiği görülüyor, bu şaşırtıcı değildir - kaynak Uzman Danışmanın koduna yerleştirilmiştir ve test başladığında onunla birlikte yüklenir.
MetaTrader 5 terminalinde Canlı modda bir Uzman Danışmanın aynı şekilde çalıştırılması (başlatılması), yüklenen olayların bir listesini içeren benzer bir günlük dosyası oluşturur. Canlı yükleme sonuçlarını içeren LoadLiveLog.txt dosyasının tamamı makaleye eklenmiştir. Aşağıda günlük dosyasının bir parçası yer almaktadır - her bir para birimi kodu için olay dizisinin başlangıcı ve sonu.
Olayların sunucudan canlı olarak indirilmesinin sonuçları:
17:27:25.250 🔄 Initializing news module:
17:27:25.258 ✅ Received values BY CURRENCY "USD": 3589 → Of these, filtered: 455
17:27:25.258 ✅ Events from Server Loaded: 455 events for: USD
17:27:25.258 ✅ Event #0
17:27:25.258 ID: 230215
17:27:25.258 Event ID: 840140001
17:27:25.258 Time: 2025.01.02 16:30:00
17:27:25.258 Impact: CALENDAR_IMPACT_POSITIVE
17:27:25.258 Revision: 0
17:27:25.258 Actual: 211.0
17:27:25.258 Revised: 220.0
17:27:25.258 Forecast: 219.0
17:27:25.258 Previous: 219.0
17:27:25.258 ✅ Event #1
17:27:25.258 ID: 230641
17:27:25.258 Event ID: 840500001
17:27:25.258 Time: 2025.01.02 17:45:00
17:27:25.258 Impact: CALENDAR_IMPACT_NEGATIVE
17:27:25.258 Revision: 3
17:27:25.258 Actual: 49.4
17:27:25.258 Forecast: 50.5
17:27:25.258 Previous: 49.7
...
17:27:25.288 ✅ Event #453
17:27:25.288 ID: 274419
17:27:25.288 Event ID: 840510001
17:27:25.288 Time: 2025.12.30 17:45:00
17:27:25.288 Impact: CALENDAR_IMPACT_POSITIVE
17:27:25.288 Revision: 0
17:27:25.288 Actual: 43.5
17:27:25.288 Forecast: 42.4
17:27:25.288 Previous: 36.3
17:27:25.288 ✅ Event #454
17:27:25.288 ID: 274484
17:27:25.288 Event ID: 840140001
17:27:25.288 Time: 2025.12.31 16:30:00
17:27:25.288 Impact: CALENDAR_IMPACT_POSITIVE
17:27:25.288 Revision: 0
17:27:25.288 Actual: 199.0
17:27:25.288 Revised: 215.0
17:27:25.288 Forecast: 227.0
17:27:25.288 Previous: 214.0
17:27:25.301 ✅ Received values BY CURRENCY "EUR": 3116 → Of these, filtered: 0
17:27:25.301 ✅ Events from Server Loaded: 60 events for: EUR
17:27:25.301 ✅ Event #0
17:27:25.301 ID: 231322
17:27:25.301 Event ID: 999030013
17:27:25.301 Time: 2025.01.07 13:00:00
17:27:25.301 Impact: CALENDAR_IMPACT_NA
17:27:25.301 Revision: 1
17:27:25.301 Actual: 2.4
17:27:25.301 Forecast: 2.4
17:27:25.301 Previous: 2.2
17:27:25.301 ✅ Event #1
17:27:25.301 ID: 187384
17:27:25.301 Event ID: 999040007
17:27:25.301 Time: 2025.01.08 13:00:00
17:27:25.301 Impact: CALENDAR_IMPACT_POSITIVE
17:27:25.301 Revision: 0
17:27:25.301 Actual: 21.0
17:27:25.301 Revised: 17.8
17:27:25.301 Forecast: 15.7
17:27:25.301 Previous: 17.7
...
17:27:25.303 ✅ Event #58
17:27:25.303 ID: 204746
17:27:25.303 Event ID: 999010006
17:27:25.303 Time: 2025.12.18 16:15:00
17:27:25.303 Impact: CALENDAR_IMPACT_NA
17:27:25.303 Revision: 0
17:27:25.303 Actual: 2.0
17:27:25.303 Previous: 2.0
17:27:25.303 ✅ Event #59
17:27:25.303 ID: 204762
17:27:25.303 Event ID: 999010007
17:27:25.303 Time: 2025.12.18 16:15:00
17:27:25.303 Impact: CALENDAR_IMPACT_NA
17:27:25.303 Revision: 0
17:27:25.303 Actual: 2.15
17:27:25.303 Previous: 2.15
17:27:25.303 ⚠️ Mode: LIVE (data from API)
Filtreleme ve günlük kaydı ile tam bir indirme yaklaşık 50 ms sürer - hala olayların indirilme/filtrelenme süresini göz ardı edecek kadar hızlıdır. İki günlük dosyasını karşılaştırdığımızda, olay listesinin hem olay sayısı hem de alanların değerleri açısından tamamen aynı olduğunu görüyoruz. Veri dönüştürme zinciri doğrulaması başarıyla tamamlandı.
Tipik hataların ve yanlış beklentilerin analizi
Geliştiricilerin MQL5 ekonomik takvimini entegre ederken yaptıkları en yaygın altı hataya bakalım. Bunların her biri gerçek hayatta test edilmiştir ve bir kişinin bakiyesini kaybetmesine neden olabilir.
1. "Takvim hareketi tahmin eder"
Yanlış beklenti:
YÜKSEK öneme sahip bir haber yayınlanırsa ve açıklanan veri beklentiden önemli ölçüde farklı olursa, fiyatın sapma yönünde hareket etmesi garantidir. Baz para birimi için açıklanan > beklenti ise basitçe alış yapılır.
Gerçek:
Ekonomik takvim bir veri kaynağıdır, işlem sinyali oluşturucu değildir. Size ne olduğunu söyler, ancak piyasanın nasıl tepki vereceğini söylemez. Fiyat neden "bariz" mantığa aykırı bir şekilde hareket edebilir?
- Piyasa, haberin yayınlanmasından günler önce beklentileri fiyatlamıştır. Haberin yayınlandığı anda "haberin satılması" gerçekleşir.
- Merkez bankası politikasının sıkılaştırıldığı bir dönemde güçlü enflasyon verileri para birimini güçlendirebilir, ancak gevşeme döneminde aşırı ısınma korkusu nedeniyle satışları tetikleyebilir.
- Haber iyi olabilir, ancak önceki değer aşağı doğru revize edilirse, genel sinyal belirsizleşir.
- Birden fazla para birimine ait verilerin aynı anda açıklanması, doğrusal olarak yorumlanamayacak çapraz etkiler yaratır.
Doğru yaklaşım, takvimi bir giriş tetikleyicisi olarak değil, bir volatilite filtresi olarak kullanmaktır:
//--- instead of if(actual > forecast) OrderSend(...); //--- use: if(IsHighImpactNewsComingSoon(30)) { //--- reduce the position size or temporarily suspend trading ReduceRiskExposure(); }
2. "Tüm YÜKSEK öneme sahip olaylar eşit derecede önemlidir"
Yanlış beklenti:
Önem == CALENDAR_IMPORTANCE_HIGH alanı, olayın piyasayı 50+ pip hareket ettireceğinin garanti olduğu anlamına gelir. Tüm bu haberlerde aynı algoritmayı kullanarak işlem yapabiliriz.
Gerçek:
ENUM_CALENDAR_EVENT_IMPORTANCE numaralandırmasındaki belirli değerler, takvim editörleri tarafından yapılan öznel bir değerlendirmedir, piyasa etkisinin nicel bir ölçütü değildir. Örneğin, YÜKSEK olarak etiketlenmiş, ancak farklı piyasa önemine sahip iki olayı ele alalım.
İlk olay olan Tarım Dışı İstihdam (ABD), kilit bir istihdam göstergesi olduğu ve Fed politikasını etkilediği için 80-150 puanlık bir volatilite tepkisi üretir. İkinci olay olan İmalat PMI (Euro Bölgesi), dar sektörlü bir gösterge olduğu ve ECB için ikincil olduğu için 10-30 puanlık bir tepki oluşturur.
Doğru yaklaşım, önem filtrelemesini bir öncelikli olay kodları listesiyle desteklemektir:
//--- a list of events that are really worth reacting to bool IsGoodEvent(const string event_code) { static const string tier1_codes[] = { "NONFARM", "CPI", "GDP", "RATE", "FOMC", "ECB_RATE", "RETAIL_SALES", "UNEMPLOYMENT", "PMI_MANUFACTURING" }; for(int i = 0; i < ArraySize(tier1_codes); i++) if(StringFind(event_code, tier1_codes[i]) != -1) return true; return false; } //--- use in filter if(event.importance == CALENDAR_IMPORTANCE_HIGH && IsGoodEvent(event.event_code)) { //--- handle only truly significant news }
Öneri:
Geçmiş volatilite analizine dayalı olarak kendi olay sıralamanızı oluşturun - önceden ayarlanmış herhangi bir etiketten daha güvenilirdir.
3. "TimeTradeServer() yerine TimeLocal() kullandım"
Yanlış beklenti:
MqlCalendarValue::time yapısındaki olay zamanı benim yerel saat dilimimde (veya UTC) belirtiliyor, dolayısıyla TimeLocal() veya TimeGMT() ile karşılaştırabilirim.
Gerçek:
Tüm ekonomik takvim fonksiyonları işlem sunucusunun saat dilimindeki zamanı geri döndürür (TimeTradeServer()). Bu, manuel dönüştürme ihtiyacını ortadan kaldıran ancak geliştiricinin disiplinli olmasını gerektiren mimari bir karardır.
Bu hatanın sonuçları ciddidir - sunucunuz EET zaman dilimindeyse (UTC+2) ve TimeLocal() kullanıyorsanız (örneğin MSK, UTC+3), olayları 1 saatlik bir sapmayla kontrol edersiniz. Uzman Danışman haberleri kaçırabilir veya tam tersine, haberlere sonradan tepki verebilir.
Doğru yaklaşım, tüm zaman karşılaştırmaları için her zaman TimeTradeServer() kullanmaktır:
//--- WRONG — risk of desynchronization datetime now = TimeLocal(); if(event.time - now < 1800) { ... } //--- RIGHT — guaranteed synchronization datetime now = TimeTradeServer(); if(event.time - now < 1800) { ... } //--- in the tester, TimeTradeServer() returns the model time, so the logic works identically to live
Öneri:
TimeToString(TimeTradeServer(), TIME_MINUTES) çıktısını hata ayıklama günlüğüne ekleyin ve olay zamanıyla karşılaştırın - dönüştürme olmadan eşleşmeleri gerekir.
4. "Olay alanlarının boş olabileceğini unuttum"
Yanlış beklenti:
actual_value, forecast_value ve diğer alanlar her zaman doğru sayısal değerleri içerir. Güvenle 1,000,000'a bölebilir ve karşılaştırabilirim.
Gerçek:
Dokümantasyona göre, MqlCalendarValue yapısının sayısal alanları bir milyonla çarpılmış değerleri veya herhangi bir değer belirtilmemişse LONG_MIN sabitini depolar. Kontrolü göz ardı edersek ne olur:
//--- error double actual = values[i].actual_value / 1000000.0; // if actual_value == LONG_MIN, result: -9223372036.854776 if(actual > forecast) // comparison with a "garbage" number causes a false alarm OpenBuy();
Doğru yaklaşım, değerleri güvenli bir şekilde elde etmek için MqlCalendarValue yapısının yerleşik metotlarını kullanmaktır:
//--- the right approach is built-in methods if(values[i].HasActualValue() && values[i].HasForecastValue()) { double actual = values[i].GetActualValue(); double forecast = values[i].GetForecastValue(); if(!MathIsNaN(actual) && !MathIsNaN(forecast)) { double deviation = actual - forecast; // ... analysis logic } } //+------------------------------------------------------------------+
Not:
GetActualValue(), GetForecastValue() ve diğer fonksiyonlar veri yoksa NaN geri döndürür. Hesaplamalarda kullanmadan önce sonucu her zaman MathIsValidNumber() veya MathIsNaN() ile kontrol edin.
5. "OnTick() içinde takvim API fonksiyonlarını çağırabilirim"
Yanlış beklenti:
Her zaman güncel verilere sahip olmak için her tikte CalendarValueHistory() fonksiyonunu çağıracağım. Bu, Uzman Danışmanın hiçbir son dakika haberini kaçırmamasını sağlar.
Gerçek:
Takvim fonksiyonları, MetaTrader 5'in bağlandığı uzak bir sunucu aracılığıyla çalışır ve katı talep oranı sınırlarına sahiptir. OnTick() çağrısı (saniyede düzinelerce kez ateşlenebilir) sorunlara neden olacaktır:
- Hata 5204 (ERR_CALENDAR_TOO_MANY_REQUESTS) - takvime erişimin geçici olarak engellenmesi.
- İşlem gerçekleştirme gecikmeleri - işlem döngüsündeki bir ağ talebi kaymayı artırır.
- Aşırı trafik - aynı verinin tekrar tekrar indirilmesi.
//--- global variables MqlCalendarValue calendar_cache[]; bool cache_initialized = false; long last_change_id = 0; //+------------------------------------------------------------------+ int OnInit() { //--- initial history loading (once at startup) datetime from = TimeCurrent() - 7 * 86400; datetime to = TimeCurrent() + 30 * 86400; if(CalendarValueHistory(calendar_cache, from, to, "USD")) { cache_initialized = true; } //--- set a timer for periodic updates (no more than 5-10 minutes) EventSetTimer(300); return INIT_SUCCEEDED; } //+------------------------------------------------------------------+ void OnTimer() { if(!cache_initialized) return; MqlCalendarValue updates[]; //--- only request changes since the last update if(CalendarValueLast(last_change_id, updates, "USD") > 0) { if(ArraySize(updates) > 0) { //--- merge new data with the cache MergeUpdates(calendar_cache, updates); last_change_id = updates[ArraySize(updates) - 1].change_id; } } } //+------------------------------------------------------------------+ void OnTick() { //--- work only with local cache - no network delays if(cache_initialized) ProcessNewsSignals(calendar_cache); }
Öneri:
OnTick() yalnızca yerel verilerle çalışmalıdır. Ağ talepleri - yalnızca OnInit(), OnTimer() içinde veya kullanıcı olayı aracılığıyla.
6. "Yeni olaylarla test yapmak için Uzman Danışmanı yeniden derlemeyi unuttum"
Yanlış beklenti:
Dosyalar klasöründeki calendar_test_res.bin kaynak dosyasını güncelledim, artık sınayıcı yeni olayları otomatik olarak görecektir. Uzman Danışmanı yeniden derlemeye gerek yok.
Gerçek:
#resource yönergesi derleme sırasında .ex5 çalıştırılabilir dosyasına veri yerleştirir. Harici .bin dosyasındaki değişiklikler dinamik olarak alınmaz - Uzman Danışman, kaynağın son derleme zamanındaki halini kullanmaya devam eder.
Hata belirtileri:
- Sınayıcı günlüğü, son derlemeden sonra kaynağa eklenen olayları içermez.
- Strateji, dosyada olmasına rağmen önemli haberleri "görmez".
- Kod mantıksal olarak doğru olmasına rağmen test sonuçları beklentilerden farklıdır.
Doğru yaklaşım, kaynağı güncelledikten sonra Uzman Danışmanı her zaman yeniden derlemektir:
//--- at the beginning of the EA file #resource "\\Files\\USD_calendar_test_res.bin" as MqlCalendarValue USD_res_calendar_data[] //--- after USD_calendar_test_res.bin update: // 1. Save changes to the resource file. // 2. Press F7 in MetaEditor (or Compile in the menu). // 3. Make sure there are no errors in the compilation log. // 4. Run the test again.
Öneri:
.ex5'teki verilerin uygunluğunu görsel olarak izlemek için derleme günlüğüne kaynak sürümü çıktısı (örn. hash veya son güncelleme tarihi) ekleyin.
Notlar:
Bu bölümde tartışılan hatalar, MQL5 sözdizimi hakkındaki bilgi eksikliğinden değil, ekonomik verilerin (göstergelerin) doğasına ilişkin basitleştirilmiş bir anlayıştan kaynaklanmaktadır. Bu altı hatadan kaçınmayı öğrenen herkes sadece çalışan bir koda değil, piyasa değişikliklerine ve ekonomik düzenleyicilerin gereksinimlerine uyum sağlayabilen istikrarlı bir alım-satım sistemine sahip olacaktır. Algoritmik alım-satımda bir amatörü bir profesyonelden ayıran da bu yaklaşımdır.
Sonuç
MetaTrader 5 terminalindeki ekonomik takvim güçlü bir araçtır. Ancak her araç gibi bu da bağlamın anlaşılmasını, kullanım disiplininin sağlanmasını ve platform sınırlamalarının dikkate alınmasını gerektirir.
MetaTrader 5'te Uzman Danışman için haber API'sinin belirli bir uygulama ve kullanım yapısını ele aldık. Makale, bir araya getirildiğinde haberlere dayalı manuel alım-satımı tekrarlanabilir bir modüle dönüştüren bir dizi pratik unsur sunmaktadır:
- Takvim API'sini anlama (Olay ve Değer, MqlCalendarEvent/MqlCalendarValue yapıları, sunucu zamanı);
- Güvenli yükleme ve güncelleme yöntemleri (ilk yükleme için CalendarValueHistory, aşamalı güncellemeler için CalendarValueLast + change_id);
- Tipik hataları işleme ve talep sınırlarına uyma;
- Gürültüyü azaltmak ve 3-5 önemli olay bırakmak için para birimi, önem, olay kodu ve zaman pencerelerine göre çok seviyeli filtreleme;
- Filtrelenmiş verilerin ikili bir kaynağa aktarılması ve veri kaynağının "gerçek zamanlı" ↔ "strateji sınayıcı" olarak otomatik olarak değiştirilmesi için bir mekanizma; bu sayede gerçek zamanlı olarak ve geriye dönük testlerde aynı davranış sağlanır.
Modül hazır olma kriterleri: belirtilen döneme ait olaylar başarıyla yüklenir; aşamalı güncellemeler change_id aracılığıyla sınırları aşmadan çalışır; sınayıcıda Uzman Danışman kaynağı okur ve aynı girdi verileriyle gerçek zamanlıda olduğu gibi aynı kararları üretir.
Önerilen sonraki adımlar: dışa aktarıcıyı uygulayın, .bin dosyasını #resource yönergesine ekleyin, OnInit/OnTimer güncelleme mantığını test edin ve kontrollü geriye dönük testler çalıştırın (örneğin, "30 dakika boyunca işlem yapma / 60 dakika sonra devam et" senaryosu).
Bu, hipotezlerden test edilebilir, ölçeklenebilir bir haber tabanlı alım-satım sistemine geçmenizi sağlayacaktır. Haber tabanlı Uzman Danışmanları geliştirmek sadece programlama değildir; makroekonomik teori ile piyasa pratiği arasında bir köprü kurmaktır.
MetaTrader 5 Takvim API fonksiyonları ve bunların haberlere dayalı alım-satımda kullanımı hakkında derinlemesine bir çalışma için önerilen kaynaklar:
- Dokümantasyon - Ekonomik takvim fonksiyonları;
- Makale - MQL5 Ekonomik Takvim ile Alım-Satım (Bölüm 1): MQL5 Ekonomik Takvimin Fonksiyonlarında Uzmanlaşma;
- Makale - MQL5 Ekonomik Takvim ile Alım-Satım (Bölüm 7): Kaynak Tabanlı Haber Olayı Analizi ile Strateji Testine Hazırlanma;
- Makale - MQL5 Ekonomik Takvim ile Alım-Satım (Bölüm 8): Akıllı Olay Filtreleme ve Hedefli Günlükler ile Haber Odaklı Geriye Dönük Testleri Optimize Etme;
- Makale - MQL5 Yemek Kitabı - Ekonomik Takvim.
Makaleye ekli dosyaların listesi:
| Dosya adı | Açıklama |
|---|---|
| CalendarEventMonitor-EA.mq5 | Takvim verisi güncelleme fonksiyonunu test etmek için test komut dosyası |
| ExportCalendarForTester-S.mq5 | Belirtilen filtrelere sahip olayların ikili bir dosyaya aktarılmasını kontrol etmek için bir test komut dosyası |
| GetTodayEvents-S.mq5 | Geçerli gün için olayların alınmasını kontrol etmek için bir test komut dosyası |
| ImportCalendarValidation-EA.mq5 | Strateji sınayıcıda bir kaynaktan haber alımını kontrol etmek için bir test Uzman Danışmanı |
| ImportTesterLog.txt | ImportCalendarValidation-EA.mq5 Uzman Danışmanının sınayıcıda görsel modda tek testinin sonuçları |
| LoadLiveLog.txt | ImportCalendarValidation-EA.mq5 Uzman Danışmanında olayların Canlı yüklenme sonuçları |
MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/22196
Uyarı: Bu materyallerin tüm hakları MetaQuotes Ltd'ye aittir. Bu materyallerin tamamen veya kısmen kopyalanması veya yeniden yazdırılması yasaktır.
Yeni Raylara Adım Atın: MQL5'te Özel Göstergeler
Python + MetaTrader 5: Veriler, Özellikler ve Prototipler için Hızlı Araştırma Çerçevesi
İşte Karışınızda Yeni MetaTrader 5 ve MQL5
Rutin İşler Olmadan Algoritmik Alım-Satım: SQLite ile MetaTrader 5'te Hızlı İşlem Analizi
- Ücretsiz alım-satım uygulamaları
- İşlem kopyalama için 8.000'den fazla sinyal
- Finansal piyasaları keşfetmek için ekonomik haberler
Web sitesi politikasını ve kullanım şartlarını kabul edersiniz

Yazılan:
MQL5 API'sinde bir değişiklik olduysa beni düzeltin, ancak eskiden takvim, yaz saati uygulamasını (DST) dikkate alarak GEÇERLİ saat dilimine göre ayarlanıyordu; yani yaz aylarında işlev sorguları, örneğin UTC+3 saat diliminde zaman damgaları döndürürken, kışın aynı tarih aralığı için yapılan sorgu, sunucu yaz saati uygulamasına (DST) geçiş yapıp geri dönüyorsa, UTC+2 saat diliminde zaman damgalarına sahip olayları döndürürdü. Bu nedenle, yarım yıl veya daha uzun bir süreye ait takvim geçmişini doğru bir şekilde yüklemek için, brokerın saat dilimi geçiş geçmişini analiz etmek gerekir. Ayrıntılar kod tabanında yer almaktadır.
Ayrıca, takvim önbelleğini bir kaynak olarak bağlantı yoluyla kullanma yaklaşımı pek pratik görünmüyor ve özellikle makalede bahsedilen hatalara yol açıyor (örneğin, uzmanı yeniden derlemeyi unutmayın gibi). Takvim önbelleğini, tüm ajanlar tarafından erişilebilen Common klasöründeki bir dosya olarak giriş parametresinde neden belirtmiyoruz?
Peki neden fiyatlar (genel olarak tüm zaman damgaları) örneğin UTC'de tutulmuyor?
Neden dealerların tikleri, aynı zaman sayımını farklı sayısal biçimlerde gösteriyor?
Felsefi bir soru :-) Gelenek böyle, ancak bu yanlış ve yok yere sorunlara yol açıyor.
Not: Bu nedenle "geçmiş haberleri" diğer kaynaklardan almak daha iyidir.
Ve asla "saat çevrim geçmişini" kendiniz "analiz etmemelisiniz" — bunların hepsi zaten mevcuttur; bu, işletim sisteminin bir işlevi ya da en azından sistem kütüphanelerinin bir parçasıdır. Google'da tzdata'yı arayın
Bisiklet ne kadar yapılabilir ki, üstelik de çarpık olanlardan
Eskiden takvim, yaz saati uygulamasını (DST) dikkate alarak GEÇERLİ saat dilimine göre ayarlanırdı; yani yaz aylarında işlev çağrıları, örneğin UTC+3 saat diliminde zaman damgaları döndürürken, kışın aynı tarih aralığı için yapılan bir sorgu, sunucu yaz saati uygulamasına (DST) geçiş yapıp geri dönüyorsa, UTC+2 saat diliminde zaman damgalarına sahip olayları döndürür.
Not: Bu nedenle "tarihsel haberler"i başka kaynaklardan almak daha iyidir.
Ve asla "saat çevirilerinin tarihçesini" kendiniz "analiz etmeye" kalkışmayın — bunların hepsi zaten mevcut, bu bir işletim sistemi işlevi ya da en azından sistem kütüphanelerinin bir parçasıdır. Google'da "tzdata" araması yapın.
Bisikletler ne kadar yapılabilir ki, üstelik de çarpık olanlar
Diğer kaynaklar sorunu çözmez, çünkü sorun MT5'te fiyatların saklanma biçiminde yatıyor.
Öncelikle kendi düz bisikletinizi gösterin, sonra da tavsiyelerde bulunun.
Günümüz haber tabanlı yatırımcılarının başlıca sorunları, dağınık araç seti ve sistematik, algoritmik bir işlem akışının olmamasıdır. İşlem yaparken dikkatinizi internet tarayıcınız (haber sitelerini gezmek) ile işlem terminaliniz arasında bölmek oldukça zordur.
Bir haber tabanlı yatırımcının iş akışı şu şekildedir: Web tarayıcınızda haber takvimini hızlıca açıp olaylarda herhangi bir değişiklik olup olmadığını kontrol edin → Yaklaşan olayları hızlıca değerlendirin ve neyi nasıl işlem yapacağınıza karar verin → MetaTrader 5 terminaline gidin – ya bekleyen emirler verin ya da terminal başında oturup haberin yayınlanmasını bekleyerek karar verin. Bu senaryoda, yatırımcı genellikle bağlamı kaçırır; bu da haberlere tepki vermede gecikmelere yol açar ve sonuçta zarara neden olur.
Haber ticareti, net kurallar, tekrarlanabilir sonuçlar ve otomatik testler içeren bir mühendislik problemi gibi çalışsın ister misiniz? Bu makalenin amacı, MetaTrader 5 için bir haber katmanının çalışma mimarisini göstermektir: tek bir veri kaynağı, takvim API’sinin doğru kullanımı, filtreleme ve önbellekleme mekanizması, geçmiş olayların test cihazı için bir kaynağa aktarılması ve Canlı ile Test Cihazı arasında otomatik geçiş — böylece aynı kod hem gerçek zamanlı hem de geçmiş verilerde belirleyici sonuçlar üretir.
Evet, bu haber ticareti için gerçek bir sorun noktasıdır.
Tarayıcı, takvim ve terminal arasında geçiş yapmak konsantrasyonu bozar ve tepki süresini önemli ölçüde yavaşlatır. Haberleri doğrudan işlem ortamına çeken birleşik bir iş akışı veya sisteme sahip olmak, işlemlerin gerçekleştirilmesini kesinlikle daha hızlı ve tutarlı hale getirecektir.
Bunu, test ve otomasyon içeren yapılandırılmış, tekrarlanabilir bir “mühendislik tarzı” kurulum haline getirme fikri, duygusal veya gecikmeli kararları önlemek açısından aslında çok mantıklıdır.