English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano
MQL5 Programlama Temelleri: Zaman

MQL5 Programlama Temelleri: Zaman

MetaTrader 5Örnekler | 13 Ocak 2022, 09:17
502 0
Dmitry Fedoseev
Dmitry Fedoseev

İçindekiler


Giriş

MQL5, zaman ile çalışmaya yönelik bir dizi basit fonksiyon sunar ve bunlara aşina olmakta zorlanmamalısınız. Tarih ve saat kullanımını gerektiren görev aralığı oldukça dardır. Ana görevler şunlardır:

  • Belirli eylemleri belirli bir zaman noktasında gerçekleştirmek (Şekil 1). Bunlar, her gün aynı saatte veya günün belirli bir saatinde ve haftalık olarak haftanın belirli bir gününde gerçekleştirilen veya yalnızca belirli bir tarih ve saatte gerçekleştirilen eylemler olabilir.

    Şekil 1. Zaman noktası.
    Şekil 1. Zaman noktası.

  • Belirli bir zaman aralığında (zaman oturumu) belirli eylemleri etkinleştirmek veya devre dışı bırakmak. Bu, gün içinde bir zaman oturumunu (bir zaman noktasından diğerine her gün), haftanın belirli günlerinde belirli eylemleri etkinleştirmeyi/devre dışı bırakmayı, haftanın bir günündeki belirli bir zamandan haftanın başka bir günündeki belirli bir zamana kadar olan zaman oturumlarını ve yalnızca belirtilen tarih ve saat aralığında yer alan eylemleri içerebilir.

    Şekil 2. Zaman aralığı.
    Şekil 2. Zaman aralığı.

Pratikte zamanın kullanımı oldukça karmaşıktır. Zorluklar, zaman ölçümünün özellikleri ve Uzman Danışmanların ve göstergelerin faaliyet göstereceği ortam ile bağlantılıdır:

  • Fiyat değişikliği olmadığından grafikte atlanan çubuklar. Bunlar özellikle daha kısa zaman aralıklarında belirgindir: M1, M5 ve hatta M15. Atlanan çubuklar daha uzun zaman aralıklarında da gözlemlenebilir.

  • Bazı işlem merkezlerinden kotasyonlar, aslında pazartesiye ait olması gereken pazar çubuklarını içerir.

  • Hafta sonları. Pazartesiden bir önceki hafta günü pazar değil, cuma günüdür. Cuma gününden sonra cumartesi değil, pazartesi gelir.

  • Pazar çubuklarına ek olarak, bazı işlem merkezleri kotasyonları tüm hafta sonu dahil olmak üzere kesintisiz olarak sağlar. Hafta içi günlere göre oldukça düşük olmasına rağmen, fiyat etkinliği tüm hafta sonu boyunca mevcuttur.

  • Alım satım sunucusu ile yerel bilgisayar (yatırımcının bilgisayarı ve alım satım terminali) arasındaki saat dilimi farkı. Farklı işlem merkezlerinin sunucu süresi değişiklik gösterebilir.

  • Yaz Saati.

Makale zaman ile ilgili bazı genel teorilerle başlayacaktır. Daha sonra, zaman ile çalışmak için standart MQL5 fonksiyonlarını gözden geçirmeye devam edeceğiz ve bazı programlama tekniklerini değerlendirip pratik problemleri ele alarak bitireceğiz.

Makale çok uzun bir süre önce çıktı, bu yüzden MQL5'i yakın zamanda keşfetmeye başlayan acemi programcılar hepsiyle tek seferde başa çıkamayacaktır. Bunun için en az üç gün ayırmak daha iyi olacaktır.


Zaman Ölçümünün Özellikleri

Konudan biraz uzaklaşalım ve astronomiye dönelim. Dünya'nın Güneş'in etrafında döndüğü ve aynı zamanda kendi ekseni etrafında döndüğü bilinen bir gerçektir. Dünya'nın ekseni, Güneş etrafındaki yörüngesine göre hafif eğimlidir. Dünya'nın astronomik (göksel, global) koordinatlarda ekseni üzerinde tam bir dönüşü için gereken zaman astronomik veya yıldız günü olarak adlandırılır.

Yıldız günü, dünyadaki sıradan insanları (gökbilimcilerin aksine) pek ilgilendirmez. Daha önemlisi, gündüz ve gecenin değişmesidir. Bir gün-gece döngüsü için gereken süre güneş günü olarak adlandırılır. Güneş sistemine Dünya'nın Kuzey Kutbunun üzerinden baktığımızda (Şekil 3) Dünya'nın kendi ekseni etrafında döndüğünü ve Güneş'in etrafında saat yönünün tersine döndüğünü görebiliriz. Bu nedenle, ekseni üzerinde Güneş'e göre tam bir dönüş yapması için, Dünya'nın 360 derecenin biraz üzerinde dönmesi gerekir. Sonuç olarak bir güneş günü, bir yıldız gününden biraz daha uzun olur.

Şekil 3. Dünya'nın kendi ekseni ve Güneş etrafındaki dönüş yönü (Dünya'nın Kuzey Kutbunun üzerinden bakıldığında).
Şekil 3. Dünya'nın kendi ekseni ve Güneş etrafındaki dönüş yönü (Dünya'nın Kuzey Kutbunun üzerinden bakıldığında).

Kolaylık ve doğruluk için, zaman ölçümlerinde bir güneş günü temel alınır. Bir güneş günü 24 parçaya bölünür ve bir saat 60 dakika sürer. Bir yıldız günü 23 saat 56 dakika ve 4 saniyedir. Dünya ekseninin yörünge düzlemine göre hafif bir eğimi, yeryüzündeki canlılar tarafından fark edilen mevsim değişiklikleri ile sonuçlanır.

Bir yıldaki güneş günü sayısı tam değildir. Biraz daha fazladır: 365 gün ve 6 saat. Dolayısıyla, her dört yılda bir (4'ün katı yılda) bir gün daha ekleyerek, 29 Şubat (artık yıl), takvim periyodik olarak ayarlanır. Bununla birlikte, bu ayarlama tamamen doğru değildir (biraz fazladan zaman eklenir), dolayısıyla bazı yıllar, 4'ün katı olmasına rağmen, artık yıl değildir. "00" ile biten yıllarda (100'ün katları) takvimde herhangi bir ayarlama yapılmaz. Ancak hepsi bu değil.

Bir yıl aynı anda 100 ve 400'ün katı ise, bu yıl artık yıl olarak kabul edilir ve takvimin ayarlanması gerekir. 1900 yılı 4 ve 100'ün katıdır, ancak 400'ün katı değildir, bu yüzden artık yıl değildir. 2000 yılı 4, 100 ve 400'ün katıdır, bu da artık yıl olmasını sağlar. 4 ve 100'ün katı olan bir sonraki yıl 2100 yılıdır. Ancak 400'ün katı olmadığı için artık yıl olmayacaktır. Bu makalenin okuyucularının, 4'ün katı olan her yılın artık yıl olduğu çağda kaldıkları ortaya çıkıyor. 100'ün katı olan ve aynı zamanda artık yıl olan sonraki yıl 2400'dür.


Saat Dilimleri

Dünya, kendi ekseni üzerinde dönerek gece ve gündüzün değişmesine neden olur. Dünyanın farklı yerlerinde aynı anda Gündüz veya gece veya daha günün herhangi bir saati olabilir. Bir gün 24 saati olduğundan, Dünya'nın çevresi her biri saat dilimi olarak adlandırılan 15 derecelik 24 bölüme ayrılmıştır. Kolaylık açısından, saat dilimlerinin sınırları her zaman boylam çizgilerini izlemez; bunun yerine, örneğin ülkelerin sınırları, bölgeler vb. olmak üzere idari bölge bölünmesi sınırlarına uygun olarak çalışır.

Referans noktası Greenwich Meridyeni adı verilen ana meridyendir. Bu meridyen, adını aldığı Londra'nın Greenwich bölgesinden geçmektedir. Greenwich Saati, Greenwich meridyeninin her iki tarafında 7,5 derece uzanır. Greenwich Saatinin doğusunda ölçülen 12 saat dilimi (+1'den +12'ye) ve Greenwich Saatinin batısında ölçülen 12 saat dilimi (-1'den -12'ye) vardır. Aslında, -12 ve +12 saat dilimleri 15 yerine yalnızca 7,5 derece genişliğindedir. -12 ve +12 saat dilimleri, Uluslararası Tarih Çizgisi olarak adlandırılan 180. meridyenin sağında ve solunda bulunur.

Greenwich'te öğlen (12:00) olduğunu varsayarsak, -12 saat diliminde 00:00, yani gün başlangıcıdır ve +12 saat diliminde -24:00, yani sonraki günün 00:00'ıdır. Aynı şey diğer saatler için de geçerlidir: Saatteki zaman aynı olsa da takvimdeki tarihler farklıdır. -12 saat dilimi aslında kullanılmaz ve +12 ile değiştirilir. Aynı şey, -11 saat dilimi için de geçerlidir, bu da +13 saat dilimi ile değiştirilir. Bunun muhtemelen ekonomik ilişkilerle ilgisi vardır: örneğin, +13 saat diliminde bulunan Bağımsız Samoa Devletinin Japonya ile güçlü ekonomik ilişkileri vardır, bu yüzden Japonya zamanına daha yakın olan zaman daha uygun görülmüştür.

Ek olarak, -04:30, +05:45, vb. gibi olağandışı saat dilimleri vardır. Meraklılar, Windows saat ayarlarında mevcut tüm saat dilimlerinin listesini bulabilir.


Yaz Saati

Dünyanın birçok ülkesi, gün ışığından daha verimli yararlanmak ve enerji tasarrufu sağlamak için Yaz Saati uygulaması olarak saatlerini bir saat ileri almaktadır. Dünya çapında 80 ülke Yaz Saati uygulamasını kullanırken diğerleri kullanmamaktadır. Büyük kısmı Yaz Saatini kullanırken bazı kısımlarının uygulamadan vazgeçtiği ülkeler (ABD dahil) de vardır. Büyük ve ekonomik açıdan gelişmiş ülkelerde ve bölgelerde Yaz Saati uygulaması izlenmektedir: hemen hemen tüm Avrupa ülkeleri (Almanya, İngiltere, İsviçre dahil), ABD (New York, Chicago), Avustralya (Sidney) ve Yeni Zelanda (Wellington). Japonya Yaz saati uygulamasını kullanmamaktadır. Rusya, 27 Mart 2011'de saatlerini son kez bir saat ileri kaydırmış ve ekim ayında standart saate geri dönmemiştir. O zamandan beri Rusya resmi olarak Yaz Saati uygulamasından çıkmıştır.

Yaz saatine geçiş prosedürü ülkeden ülkeye değişmektedir. Amerika Birleşik Devletleri'nde değişim, mart ayının ikinci pazar günü yerel saatle 02:00'da gerçekleşir ve saat kasım ayının ilk pazar günü saat 02:00'da yeniden geriye alınır. Avrupa'da saatler, mart ayının son pazar günü saat 02:00'da Yaz Saatine geçirilir ve ekim ayının son pazar günü saat 03:00'da ise standart saate geri döndürülür. Tüm Avrupa ülkelerinde geçiş, yerel saate geçiş yerine tek seferde gerçekleştirilir: saat dilimlerine göre Londra'da 02:00, Berlin'de 03:00'dır vb. Saatler Londra'da 03:00, Berlin'de 04:00 vb. olduğunda standart saate geri alınır.

Avustralya ve Yeni Zelanda, Güney Yarımkürede yer almaktadır, burada yaz Kuzey Yarımküreye kış geldiğinde başlar. Sonuç olarak, Avustralya ekim ayının ilk pazar günü Yaz saatine geçer ve nisan ayının ilk pazar günü standart saate geri döner. Yaz Saati söz konusu olduğunda Avustralya'ya dair kesin konuşmak zordur, çünkü başlangıç ve bitiş tarihleri ülkenin farklı bölgelerinde her zaman birbirini tutmamaktadır. Yeni Zelanda'da Yaz Saatine geçiş, eylül ayının son pazar günü saat 02:00'da gerçekleştirilir ve nisan ayının ilk pazar günü saat 03:00'da geriye alınır.


Saat Standardı

Daha önce belirtildiği gibi, zaman ölçümlerinde bir güneş günü temel alınır ve diğer tüm saat dilimlerindeki zamanın belirlendiği zaman standardı olarak Greenwich Saati temel alınır. Greenwich Saati genellikle GMT olarak kısaltılır.

Bununla birlikte, Dünya'nın dönüşünün hafif tekdüze olmadığı tespit edilmiş ve zamanı ölçmek için bir atom saati kullanılmıştır ve UTC (Eşgüdümlü Evrensel Saat) yeni zaman standardı haline gelmiştir. UTC, şu anda Yaz Saati için gerekli ayarlamaların yapılması ile, tüm saat dilimlerindeki saat ölçümlerinin temeli olan tüm dünya için birincil saat standardı görevi görmektedir. UTC Yaz Saati Uygulamasına tabi değildir.

Güneş tabanlı GMT'nin atomik saat temelli UTC'ye tam olarak uymamasından dolayı, UTC ile GMT arasında her 500 günde bir yaklaşık 1 saniyeye varan bir fark oluşmaktadır. Bu bağlamda, zaman zaman 30 Haziran veya 31 Aralık'ta bir saniyelik bir ayarlama yapılır.


Tarih ve Saat Formatları

Tarih biçimleri ülkeden ülkeye değişiklik gösterir. Örneğin, Rusya'da geleneksel olarak ilk olarak gün, ardından ay ve yıl yazılır. Tarihlerdeki sayılar noktalarla ayrılır, örneğin 01.12.2012 - 1 Aralık 2012. ABD'de tarih biçimi ay/gün/yıl şeklindedir ve tarihlerdeki sayılar eğik çizgi "/" ile birbirinden ayrılır. Noktalara ve eğik çizgilere "/" ek olarak bazı biçim standartlarında tarihteki sayıları ayırmak için çizgi "-" kullanılabilir. Zamanı belirtirken saat, dakika ve saniye iki nokta üst üste ":" ile ayrılır, örneğin 12:15:30 = 12 saat, 15 dakika, 30 saniye.

Tarih ve saat biçimini belirtmenin basit bir yolu vardır. Örneğin, "gg.aa.yyyy", ilk olarak günü (iki basamaktan oluşan ayın günü; gün 1'den 9'a kadar bir sayı ise, başa 0 ekleriz), sonra ayı (iki basamaktan oluşması gerekir) ve dört basamaktan oluşan yılı yazmamız gerektiğini ifade eder. "g-a-yy", ilk olarak günü (tek basamaklı sayı olabilir), ardından ayı (tek basamaklı sayıya izin verilir) ve iki basamaktan oluşan yılı -örneğin 1/12/12 - 1 Aralık 2012- yazmamız gerektiğini ifade eder. Gün, ay ve yıl değerleri çizgi "-" ile ayrılır.

Saat, bir boşluk ile tarihten ayrılır. Saat biçimi, saatler için "s", dakikalar için "dk" ve saniyeler için "sn" kullanılır ve bunlar aynı zamanda gerekli basamak sayısını belirtir. Örneğin, "ss:dk:sn", ilk olarak saati (1'den 9'a kadar olan değerlerin önüne 0 eklenmelidir), sonra dakikayı (2 basamak gereklidir) ve saniyeyi (2 basamak) yazacağımızı ifade eder, burada saat, dakika ve saniye değerleri iki nokta üst üste ile ayrılır.

Programcının bakış açısından en doğru olduğu düşünülen tarih ve saat biçimi "yyyy.aa.gg ss:dk:sn" biçimidir. Dizeleri bu gösterim kullanılarak yazılan tarihlere göre sıralarken bunlar kronolojik sıraya göre kolayca düzenlenir. Her gün metin dosyalarında bilgileri sakladığınızı ve bunları aynı klasörde sakladığınızı varsayalım. Dosyalarınızı bu biçimi kullanarak adlandırırsanız, klasördeki dosyalar uygun şekilde sıralanır ve sıralı olarak düzenlenir.

Artık teorik kısmı tamamladığımıza göre, uygulamaya geçelim.


MQL5'te Zaman

MQL5'te, 1 Ocak 1970'te başlayan Unix döneminin başlangıcından itibaren geçen süre saniye cinsinden ölçülür. Zamanı saklamak için datetime türü değişkenlerini kullanırız. Bir datetime türü değişkenin minimum değeri 0'dır (dönemin başladığı tarihe karşılık gelir), maksimum değer ise 32 535 244 799'dur (31 Aralık 3000'de 23:59:59'a karşılık gelir).


Mevcut Sunucu Saatini Belirleme

Geçerli saati belirlemek için timecurrent() fonksiyonunu kullanırız. Bu fonksiyon, bilinen son sunucu saatini döndürür:

datetime tm=TimeCurrent();
//--- output result
Alert(tm);

Grafikteki çubukların zamanını belirtmek için aynı sunucu saati kullanılır. Bilinen son sunucu saati, Piyasa İzleme penceresinde açılan sembollerden herhangi birinin fiyatındaki son değişiklik zamanıdır. Piyasa İzleme penceresinde yalnızca EURUSD varsa, TimeCurrent() fonksiyonu EURUSD'nin son fiyat değişikliğini döndürür. Piyasa İzleme penceresi, çoğunlukla önemli sayıda sembol görüntülediğinden, fonksiyon temel olarak mevcut sunucu saatini döndürür. Ancak, fiyatlar hafta sonu değişmediğinden, fonksiyon tarafından döndürülen değer mevcut sunucu saatinden çok farklı olacaktır.

Sunucu saatini belirli bir sembole göre (son fiyat değişikliğinin zamanı) öğrenmeniz gerekirse, SymbolInfoInteger() fonksiyonunu SYMBOL_TIME tanımlayıcısı ile kullanabilirsiniz:

datetime tm=(datetime)SymbolInfoInteger(_Symbol,SYMBOL_TIME);
//--- output result
Alert(tm);


Mevcut Yerel Saati Belirleme

Yerel saat (kullanıcının PC saati ile gösterilir) TimeLocal() fonksiyonu ile belirlenir:

datetime tm=TimeLocal();
//--- output result
Alert(tm);

Pratikte, EA'ları ve göstergeleri programlanırken çoğunlukla sunucu zamanını kullanırsınız. Yerel saat, uyarılar ve günlük girişlerinde kullanışlıdır: Bir mesajın veya girişin ne kadar süre önce kaydedildiğini görmek için, kullanıcının, bir mesajı veya giriş zaman damgasını PC saatinin gösterdiği zaman ile karşılaştırması daha uygundur. Ancak MetaTrader 5 terminali, Alert() ve Print() fonksiyonlarını kullanarak çıktısı sağlanan mesajlara ve günlük girişlerine zaman damgasını otomatik olarak ekler. Bu nedenle, TimeLocal() fonksiyonunu kullanma ihtiyacı çok nadiren ortaya çıkabilir.


Zaman Çıktısı

Lütfen yukarıdaki koddaki tm değişkeni değerinin çıktısının Alert() fonksiyonu kullanılarak sağlandığını unutmayın. Bununla birlikte, değer, okunması kolay bir biçimde görüntülenir, örneğin: "2012.12.05 22:31:57". Bunun nedeni, Alert() fonksiyonunun kendisine aktarılan bağımsız değişkenleri string türüne dönüştürmesidir (aynı şey, Print() ve Comment() fonksiyonunu kullanırken ve metin ve csv dosyalarının çıktısını sağlarken de olur). Bir datetime türü değişkeninin değerini içeren bir metin mesajı oluştururken, tür dönüştürme yapılması sizin sorumluluğunuzdadır. Biçimlendirilmiş zamanı elde etmeniz gerekiyorsa dize türüne dönüştürün veya sayısal bir değere ihtiyacınız varsa long türüne ve ardından dize türüne dönüştürün:

datetime tm=TimeCurrent();
//--- output result
Alert("Formatted: "+(string)tm+", in seconds: "+(string)(long)tm);

Long ve ulong türündeki değişkenlerin değer aralıkları datetime türündeki değişkenin değer aralığını kapsar, bu nedenle zamanı saklamak için de kullanılabilir; ancak bu durumda biçimlendirilmiş zamanın çıktısı sağlamak için long türünü datetime türüne ve ardından dize türüne dönüştürmeniz veya sayısal bir değer çıktısı sağlamak istiyorsanız yalnızca dize türüne dönüştürmeniz gerekir:

long tm=TimeCurrent();
//--- output result
Alert("Formatted: "+(string)(datetime)tm+", in seconds: "+(string)tm);


Saat Biçimlendirme

Saat biçimlendirme, "MQL5 Programlama Temelleri: Dizeler" adlı makalede, çeşitli değişkenlerin bir dizeye dönüştürülmesine ayrılmış bölümde değerlendirilmiştir. Buradaki kilit noktaları kısaca özetleyelim. MQL5, türleri dönüştürmenin yanı sıra, bunları bir dizeye dönüştürürken tarih ve saat biçimini belirtmenize de olanak sağlayan bir fonksiyon sunar: TimeToString() fonksiyonu:

datetime tm=TimeCurrent();
string str1="Date and time with minutes: "+TimeToString(tm);
string str2="Date only: "+TimeToString(tm,TIME_DATE);
string str3="Time with minutes only: "+TimeToString(tm,TIME_MINUTES);
string str4="Time with seconds only: "+TimeToString(tm,TIME_SECONDS);
string str5="Date and time with seconds: "+TimeToString(tm,TIME_DATE|TIME_SECONDS);
//--- output results
Alert(str1);
Alert(str2);
Alert(str3);
Alert(str4);
Alert(str5);

TimeToString() fonksiyonu, datetime türündeki değişkenler ile long ve ulong türündeki değişkenlere ve diğer bazı tamsayı değişken türlerine de uygulanabilir, ancak bunlar zamanı saklamak için kullanılmamalıdır.

Bir metin mesajını StringFormat() fonksiyonunu kullanarak biçimlendirirken tür dönüştürmeye dikkat etmeniz gerekir.

  • Bir datetime türü değişkende zamanı saklarken:

    datetime tm=TimeCurrent();
    //--- generating a string
    string str=StringFormat("Formatted: %s, in seconds: %I64i",(string)tm,tm);
    //--- output result
    Alert(str);
  • Bir long türü değişkende zamanı saklarken:

    long tm=TimeCurrent();
    //--- generating a string
    string str=StringFormat("Formatted: %s, in seconds: %I64i",(string)(datetime)tm,tm);
    //--- output result
    Alert(str);
  • Veya TimeToString() fonksiyonunu kullanırken:

    datetime tm=TimeCurrent();
    //--- generating a string
    string str=StringFormat("Date: %s",TimeToString(tm,TIME_DATE));
    //--- output result
    Alert(str);


Zamanı Sayılara Dönüştürme. Saat Ekleme ve Çıkarma

Biçimlendirilmiş bir tarihi (dize) bir sayıya (dönemin başlangıcından bu yana geçen saniye sayısı) dönüştürmek için StringToTime() fonksiyonu kullanılır:

datetime tm=StringToTime("2012.12.05 22:31:57");
//--- output result
Alert((string)(long)tm);

Yukarıdaki kodun sonucunda, saniye cinsinden çıktı süresi "1354746717" olacaktır, bu ise şu tarihe karşılık gelir: "2012.12.05 22:31:57".

Zaman bir sayı olarak gösterildiğinde, bununla yapılan çeşitli işlemler kolay ve kullanışlı hale gelir, örneğin geçmişteki veya gelecekteki tarih ve saati bulabilirsiniz. Zaman saniye cinsinden ölçüldüğünden, saniye cinsinden ifade edilen bir süre eklemeniz gerekir. Bir dakikanın 60 saniye olduğunu ve bir saatin 60 dakika veya 3600 saniye olduğunu bildiğimize göre, herhangi bir zamanın süresini hesaplamak fazla çaba gerektirmeyecektir.

Mevcut saatten bir saat (3600 saniye) çıkarın veya mevcut saate bir saat ekleyin, böylece bir saat önce olan veya bir saat sonra olacak zamanı elde edersiniz:

datetime tm=TimeCurrent();
datetime ltm=tm-3600;
datetime ftm=tm+3600;
//--- output result
Alert("Current: "+(string)tm+", an hour ago: "+(string)ltm+", in an hour: "+(string)ftm);

StringToTime() fonksiyonuna aktarılan tarihin tam olması gerekmez. Ayrıca, tarihi saatsiz veya saati de tarihsiz olarak aktarabilirsiniz. Tarihi saatsiz aktarırsanız, fonksiyon belirtilen tarihin 00:00:00 değerini döndürür:

datetime tm=StringToTime("2012.12.05");
//--- output result
Alert(tm);

Yalnızca saati aktarırsanız, fonksiyon mevcut tarihin belirtilen saatine karşılık gelen değeri döndürür:

datetime tm=StringToTime("22:31:57");
//--- output result
Alert((string)tm);

Zaman saniyesiz de aktarılabilir. Tarihi aktarırsanız, aktarılabilecek tek saat bileşeni saatlerdir. Bu pratikte neredeyse hiç gerekli olmayacak. Ancak merak ediyorsanız, kendi başınıza denemekten çekinmeyin.


Tarih ve Saat Bileşenleri

Tarih ve saat bileşenlerinin (yıl, ay, tarih vb.) değerlerini tek tek belirlemek için TimeToStruct() fonksiyonunu ve MqlDateTime yapısını kullanırız. Yapı fonksiyona referans ile aktarılır. Fonksiyonu çalıştırdıktan sonra, yapı, kendisine aktarılan tarihin bileşenlerinin değerleri ile doldurulacaktır:

datetime    tm=TimeCurrent();
MqlDateTime stm;
TimeToStruct(tm,stm);
//--- output date components
Alert("Year: "        +(string)stm.year);
Alert("Month: "      +(string)stm.mon);
Alert("Day: "      +(string)stm.day);
Alert("Hour: "        +(string)stm.hour);
Alert("Minute: "     +(string)stm.min);
Alert("Second: "    +(string)stm.sec);
Alert("Day of the week: "+(string)stm.day_of_week);
Alert("Day of the year: "  +(string)stm.day_of_year);

Yapının tarih bileşenlerine ek birkaç ek alan da içerdiğini unutmayın: haftanın günü (day_of_week alanı) ve yılın günü (day_of_year). Haftanın günleri 0'dan itibaren sayılır (0 - pazar, 1 - pazartesi vb.). Yılın günleri de sıfırdan itibaren sayılır. Diğer değerler genel kabul görmüş numaralandırma sırasını takip eder (aylar ve günler 1'den itibaren sayılır).

TimeCurrent() fonksiyonunu çağırmanın başka bir yolu vardır. MqlDateTime türünde bir yapı, fonksiyona referans ile aktarılır. Fonksiyon çalıştırıldıktan sonra, yapı, mevcut tarih bileşenleri ile doldurulacaktır:

MqlDateTime stm;
datetime tm=TimeCurrent(stm);
//--- output date components
Alert("Year: "        +(string)stm.year);
Alert("Month: "      +(string)stm.mon);
Alert("Day: "      +(string)stm.day);
Alert("Hour: "        +(string)stm.hour);
Alert("Minute: "     +(string)stm.min);
Alert("Second: "    +(string)stm.sec);
Alert("Day of the week: "+(string)stm.day_of_week);
Alert("Day of the year: "  +(string)stm.day_of_year);

TimeLocal() fonksiyonu da bu şekilde çağrılabilir.


Bileşenlerinden Tarih Oluşturma

MqlDateTime yapısını datetime türüne tersine de dönüştürebilirsiniz. Bunun için, StructToTime() fonksiyonunu kullanırız.

Tam bir ay önceki zamanı belirleyelim. Bir aydaki gün sayısı değişir. 30 veya 31 günü olan aylar vardır ve şubat 28 veya 29 gün olabilir. Dolayısıyla, daha önce değerlendirdiğimiz saat çıkarma ve ekleme yöntemi tam olarak uygun değildir. Bu nedenle, tarihleri bileşenlerine ayıracağız, ay değerini 1 azaltacağız ve ay değeri 1 ise, 12'ye ayarlayacağız ve yıl değerini 1 azaltacağız:

datetime tm=TimeCurrent();
MqlDateTime stm;
TimeToStruct(tm,stm);
if(stm.mon==1)
  {
   stm.mon=12;
   stm.year--;
  }
else
  {
   stm.mon--;
  }
datetime ltm=StructToTime(stm);
//--- output result
Alert("Current: "+(string)tm+", a month ago: "+(string)ltm);


Çubuk Saatini Belirleme

Bir gösterge geliştirirken, MetaEditor otomatik olarak OnCalculate() fonksiyonunun iki sürümünden birini oluşturur.

Sürüm 1:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   return(rates_total);
  }

Sürüm 2:

int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
   return(rates_total);
  }

Fonksiyonun ilk sürümünün parametreleri time[] dizisini içerir, bunun öğeleri tüm çubukların zamanını içerir.

İkinci sürümü kullanırken ve EA'ları programlarken ve diğer zaman aralıklarındaki çubukların zamanına göstergeler tarafından erişimi düzenlerken CopyTime() fonksiyonunu kullanırız. Bu fonksiyon üç sürüm halinde mevcuttur. Tüm sürümlerde, ilk iki fonksiyon parametresi çubuk zamanının belirlendiği sembolü ve grafik zaman aralığını tanımlar. Son parametre ise, döndürülen değerleri saklayan bir diziyi tanımlar ve iki orta parametre kullanılan fonksiyonun sürümüne bağlıdır.

CopyTime - Sürüm 1. Çubuk indisini ve kopyalanacak öğe sayısını belirtmeniz gerekir:

//--- variables for function parameters
int start = 0; // bar index
int count = 1; // number of bars
datetime tm[]; // array storing the returned bar time
//--- copy time 
CopyTime(_Symbol,PERIOD_D1,start,count,tm);
//--- output result
Alert(tm[0]);

Bu örnek, D1 zaman aralığındaki son çubuğun zamanını kopyalamanın uygulanmasını göstermektedir. Kullandığımız fonksiyon sürümü, kendisine aktarılan parametrelerin türüne bağlıdır. Yukarıdaki örnek, int türü değişkenlerin kullanımını içerir; bunun anlamı, belirtilen çubuk sayısı için zamanı çubuk numarasına göre elde etmemiz gerekmesidir.

Çubuklar, CopyTime() fonksiyonunu kullanırken sağdan sola sıfırdan itibaren sayılır. Elde edilen değerler için kullanılan dinamik bir dizi (son parametre), CopyTime() fonksiyonunun kendisi tarafından istenilen boyuta ölçeklendirilir. Statik bir dizi de kullanabilirsiniz, ancak bu durumda dizi boyutu istenilen öğe sayısına (4. parametrenin değeri) tam olarak karşılık gelmelidir.

Aynı anda birkaç çubuktan zaman elde edildiğinde, döndürülen dizideki öğelerin sırasının anlaşılması önem taşımaktadır. Grafikteki çubuklar belirtilen çubuktan başlayarak sağdan sola doğru sayılırken, dizi öğeleri soldan sağa doğru düzenlenir:

//--- variables for function parameters
int start = 0; // bar index
int count = 2; // number of bars
datetime tm[]; // array storing the returned bar time
//--- copy time 
CopyTime(_Symbol,PERIOD_D1,start,count,tm);
//--- output result
Alert("Today: "+(string)tm[1]+", yesterday: "+(string)tm[0]);

Bu kodun sonucunda, dünün çubuğunun zamanı tm dizisinin 0 öğesinde saklanırken, 1. öğe bugünün çubuğunun zamanını içerecektir.

Bazı durumlarda, grafikteki sayma çubuklarının sırası ile aynı sırada düzenlenmiş dizide zamana sahip olmak daha uygun görünebilir. ArraySetAsSeries() fonksiyonu burada iş görebilir:

//--- variables for function parameters
int start = 0; // bar index
int count = 2; // number of bars
datetime tm[]; // array storing the returned bar time
ArraySetAsSeries(tm,true); // specify that the array will be arranged in reverse order
//--- copy time 
CopyTime(_Symbol,PERIOD_D1,start,count,tm);
//--- output result
Alert("Today: "+(string)tm[0]+", yesterday: "+(string)tm[1]);

Şimdi, bugünün çubuğunun zamanı indis 0 olan öğede ve dünün çubuğunun zamanı indis 1 olan öğededir.

CopyTime - Sürüm 2. CopyTime() fonksiyonunu çağırırken, kopyalamanın başladığı çubuğun zamanını ve kopyalanacak çubuk sayısını belirtmemiz gerekir. Bu sürüm, bir alt zaman aralığından bir çubuk içeren bir üst zaman aralığındaki zamanı belirlemek için uygun olacaktır:

//--- get the time of the last bar on M5
int m5_start=0; 
int m5_count=1;
datetime m5_tm[];
CopyTime(_Symbol,PERIOD_M5,m5_start,m5_count,m5_tm);
//--- determine the bar time on H1 that contains the bar on M5
int h1_count=1;
datetime h1_tm[];
CopyTime(_Symbol,PERIOD_H1,m5_tm[0],h1_count,h1_tm);
//--- output result
Alert("The bar on М5 with the time "+(string)m5_tm[0]+" is contained in the bar on H1 with the time "+(string)h1_tm[0]);

Çubuğun, bir üst zaman aralığındaki başlangıcı olan, alt zaman aralığındaki çubuğun zamanını belirlemeniz gerekirse durum daha karmaşık hale gelir. Bir üst zaman aralığındaki çubuğun zamanı ile aynı zamana sahip olan bir çubuk, bir alt zaman aralığında eksik olabilir. Böyle bir durumda, bir üst zaman aralığına sahip önceki çubukta içerilen, bir alt zaman aralığındaki son çubuğun zamanını elde ederiz. Yani, bir alt zaman aralığındaki çubuğun sayısını belirlememiz ve bir sonraki çubuğun zamanını elde etmemiz gerekir.

Aşağıda, yukarıdaki uygulama kullanılmaya hazır bir fonksiyon biçiminde yer almaktadır:

bool LowerTFFirstBarTime(string aSymbol,
                         ENUM_TIMEFRAMES aLowerTF,
                         datetime aUpperTFBarTime,
                         datetime& aLowerTFFirstBarTime)
  {
   datetime tm[];
//--- determine the bar time on a lower time frame corresponding to the bar time on a higher time frame 
   if(CopyTime(aSymbol,aLowerTF,aUpperTFBarTime,1,tm)==-1)
     {
      return(false);
     }
   if(tm[0]<aUpperTFBarTime)
     {
      //--- we got the time of the preceding bar
      datetime tm2[];
      //--- determine the time of the last bar on a lower time frame
      if(CopyTime(aSymbol,aLowerTF,0,1,tm2)==-1)
        {
         return(false);
        }
      if(tm[0]<tm2[0])
        {
         //--- there is a bar following the bar of a lower time frame  that precedes the occurrence of the bar on a higher time frame
         int start=Bars(aSymbol,aLowerTF,tm[0],tm2[0])-2;
         //--- the Bars() function returns the number of bars from the bar with time tm[0] to
         //--- the bar with time tm2[0]; since we need to determine the index of the bar following 
         //--- the bar with time tm2[2], subtract 2
         if(CopyTime(aSymbol,aLowerTF,start,1,tm)==-1)
           {
            return(false);
           }
        }
      else
        {
         //--- there is no bar of a lower time frame contained in the bar on a higher time frame
         aLowerTFFirstBarTime=0;
         return(true);
        }
     }
//--- assign the obtained value to the variable 
   aLowerTFFirstBarTime=tm[0];
   return(true);
  }

Fonksiyon parametreleri:

  • aSymbol - sembol;
  • aLowerTF - alt zaman aralığı;
  • aUpperTFBarTime - üst zaman aralığındaki çubuk zamanı;
  • aLowerTFFirstBarTime - bir alt zaman aralığının döndürülmüş değeri.

Fonksiyon, CopyTime() fonksiyonunun başarılı olup olmadığını tüm kod boyunca kontrol eder ve bir hata durumunda fonksiyon false değerini döndürür. Çubuk zamanı, aLowerTFFirstBarTime parametresine referans ile döndürülür.

Fonksiyon kullanımının bir örneği aşağıda gösterilir:

//--- time of the bar on the higher time frame H1
   datetime utftm=StringToTime("2012.12.10 15:00");
//--- variable for the returned value
   datetime val;
//--- function call
   if(LowerTFFirstBarTime(_Symbol,PERIOD_M5,utftm,val))
     {
      //--- output result in case of successful function operation
      Alert("val = "+(string)val);
     }
   else
     {
      //--- in case of an error, terminate the operation of the function from which the LowerTFFirstBarTime() function is called
      Alert("Error copying the time");
      return;
     }

Fonksiyon bir üst zaman aralığına sahip mevcut olmayan bir çubuğun zamanını alırsa, bir üst zaman aralığına sahip bir çubukta içerilen fakat bir alt zaman aralığında çubuğun bulunmadığı bir durum ortaya çıkabilir. Bu durumda, fonksiyon true değerini döndürür ve 0 zaman değeri aLowerTFFirstBarTime değişkenine yazılır. Bir üst zaman aralığına sahip bir çubuk varsa, alt zaman aralıklarından her birinde her zaman en az bir karşılık gelen çubuk olacaktır.

Son çubuğun zamanını, bir üst zaman aralığına sahip bir çubukta bulunan bir alt zaman aralığında bulmak biraz daha kolaydır. Bir sonraki çubuğun zamanını bir üst zaman aralığında hesaplarız ve elde edilen değeri ilgili çubuğun zamanını bir alt zaman aralığında belirlemek için kullanırız. Ortaya çıkan süre bir üst zaman aralığının hesaplanan süresine eşitse, bir alt zaman aralığında önceki çubuğun zamanını belirlememiz gerekir. Ortaya çıkan süre daha azsa, o zaman doğru zamanı elde etmişizdir.

Aşağıda, yukarıdaki uygulama kullanılmaya hazır bir fonksiyon biçiminde yer almaktadır:

bool LowerTFLastBarTime(string aSymbol,
                        ENUM_TIMEFRAMES aUpperTF,
                        ENUM_TIMEFRAMES aLowerTF,
                        datetime aUpperTFBarTime,
                        datetime& aLowerTFFirstBarTime)
  {
//--- time of the next bar on a higher time frame
   datetime NextBarTime=aUpperTFBarTime+PeriodSeconds(aUpperTF);
   datetime tm[];
   if(CopyTime(aSymbol,aLowerTF,NextBarTime,1,tm)==-1)
     {
      return(false);
     }
   if(tm[0]==NextBarTime)
     {
      //--- There is a bar on a lower time frame corresponding to the time of the next bar on a higher time frame.
      //--- Determine the time of the last bar on a lower time frame
      datetime tm2[];
      if(CopyTime(aSymbol,aLowerTF,0,1,tm2)==-1)
        {
         return(false);
        }
      //--- determine the preceding bar index on a lower time frame
      int start=Bars(aSymbol,aLowerTF,tm[0],tm2[0]);
      //--- determine the time of this bar
      if(CopyTime(aSymbol,aLowerTF,start,1,tm)==-1)
        {
         return(false);
        }
     }
//--- assign the obtain value to the variable 
   aLowerTFFirstBarTime=tm[0];
   return(true);
  }

Fonksiyon parametreleri:

  • aSymbol - sembol;
  • aUpperTF - üst zaman aralığı;
  • aLowerTF - alt zaman aralığı;
  • aUpperTFBarTime - üst zaman aralığındaki çubuk zamanı;
  • aLowerTFFirstBarTime - bir alt zaman aralığının döndürülmüş değeri.

Fonksiyon, CopyTime() fonksiyonunun başarılı olup olmadığını tüm kod boyunca kontrol eder ve bir hata durumunda fonksiyon false değerini döndürür. Çubuk zamanı, aLowerTFFirstBarTime parametresine referans ile döndürülür.

Fonksiyon kullanımının bir örneği aşağıda gösterilir:

//--- time of the bar on the higher time frame H1
datetime utftm=StringToTime("2012.12.10 15:00");
//--- variable for the returned value
datetime val;
//--- function call
if(LowerTFLastBarTime(_Symbol,PERIOD_H1,PERIOD_M5,utftm,val))
  {
//--- output result in case of successful function operation
   Alert("val = "+(string)val);
  }
else
  {
//--- in case of an error, terminate the operation of the function from which the LowerTFFirstBarTime() function is called
   Alert("Error copying the time");
   return;
  }

Dikkat! Fonksiyona aktarılan zamanın, bir üst zaman aralığının tam zamanı olduğu varsayılır. Çubuğun tam zamanı bilinmiyorsa ve yalnızca o çubuktaki veya bir üst zaman aralığındaki çubukta içerilen bir alt zaman aralığındaki bir çubuğun belirli bir tik işaretinin zamanını biliyorsak, zaman normalizasyonu gerekecektir. MetaTrader 5 terminalinde kullanılan zaman aralıkları günü integral sayıda çubuğa ayırır. Dönemin başlangıcından bu yana çubuk sayısını belirleriz ve bunu saniye cinsinden çubuk uzunluğu ile çarparız:

datetime BarTimeNormalize(datetime aTime,ENUM_TIMEFRAMES aTimeFrame)
  {
   int BarLength=PeriodSeconds(aTimeFrame);
   return(BarLength*(aTime/BarLength));
  }

Fonksiyon parametreleri:

  • aTime - zaman;
  • aTimeFrame - zaman aralığı.

Fonksiyon kullanımının bir örneği aşağıda gösterilir:

//--- the time to be normalized
datetime tm=StringToTime("2012.12.10 15:25");
//--- function call
datetime tm1=BarTimeNormalize(tm,PERIOD_H1);
//--- output result
Alert(tm1);

Bununla birlikte, bu hem bir zaman normalleştirme yöntemi hem de bir üst zaman aralığının zamanını bir alt zaman aralığına göre belirlemenin diğer bir yöntemidir.

CopyTime - Sürüm 3. Bu durumda CopyTime() fonksiyonunu çağırırken, zaman aralığını zamanın kopyalanmasının gerektiği çubuklara göre belirtiriz. Bu yöntem, daha yüksek bir zaman aralığının çubuğunda içerilen bir alt zaman aralığının tüm çubuklarını kolayca elde etmemizi sağlar:

//--- time of the bar start on H1
datetime TimeStart=StringToTime("2012.12.10 15:00");
//--- the estimated time of the last bar on
//--- M5
datetime TimeStop=TimeStart+PeriodSeconds(PERIOD_H1)-PeriodSeconds(PERIOD_M5);
//--- copy time
datetime tm[];
CopyTime(_Symbol,PERIOD_M5,TimeStart,TimeStop,tm);
//--- output result 
Alert("Bars copied: "+(string)ArraySize(tm)+", first bar: "+(string)tm[0]+", last bar: "+(string)tm[ArraySize(tm)-1]);


Gün Başlangıç Saatini ve Gün Başlangıcından itibaren Geçen Süreyi Belirleme

Günün başlangıç saatini belirli bir zamana göre belirlemenin en belirgin yolu, saati bileşenlerine ayırmak; saat, dakika ve saniyeleri sıfırlamak; ve bunu tekrar eklemektir. Ancak, bunun daha kolay bir yolu var. Bir gün 86400 saniyedir. Zamanın bir günde saniye sayısına bölünmesinin sonucunda bir tamsayı elde etmeli ve bunu bir gündeki saniye sayısı ile çarpmalıyız:

datetime tm=TimeCurrent();
tm=(tm/86400)*86400;
//--- output result
Alert("Day start time: "+(string)tm);

Dikkat! Bu hile yalnızca tamsayı değişkenleri ile etkilidir. Hesaplamalarınızdan herhangi birinde double ve float türünde değişkenler görünürse, MathFloor() fonksiyonunu kullanarak kesirli kısmı kesmeniz gerekir:

MathFloor(tm/86400)*86400

Çarpmadan sonra, değerler NormalizeDouble() fonksiyonu kullanılarak normalleştirilmelidir. Elde edilen değerin bir tamsayı olması gerektiğinden, bir yuvarlama fonksiyonu kullanabilirsiniz: MathRound():

MathRound(MathFloor(tm/86400)*86400)

Tamsayı değişkenleri kullanıldığında, kalan otomatik olarak atılır. Zaman ile uğraşırken, double veya float türündeki değişkenlere neredeyse hiç ihtiyaç duyulmayacak ve bunların kullanımı büyük olasılıkla temel olarak yanlış bir yaklaşımı belirtecektir.

Gün başlangıcından itibaren geçen saniye sayısını belirlemek için, yalnızca zamanın 86400'e bölümünden kalanı elde etmemiz gerekir:

datetime tm=TimeCurrent();
long seconds=tm%86400;
//--- output result
Alert("Time elapsed since the day start: "+(string)seconds+" sec.");

Benzer yöntemler, elde edilen zamanın saniye cinsinden saat, dakika ve saniyeye dönüştürülmesi için de kullanılabilir. Bir fonksiyon olarak uygulama:

int TimeFromDayStart(datetime aTime,int &aH,int &aM,int &aS)
  {
//--- Number of seconds elapsed since the day start (aTime%86400),
//--- divided by the number of seconds in an hour is the number of hours
   aH=(int)((aTime%86400)/3600);
//--- Number of seconds elapsed since the last hour (aTime%3600),
//--- divided by the number of seconds in a minute is the number of minutes 
   aM=(int)((aTime%3600)/60);
//--- Number of seconds elapsed since the last minute 
   aS=(int)(aTime%60);
//--- Number of seconds since the day start
   return(int(aTime%86400));
  }

İlk aktarılan parametre zamandır. Döndürülen değerler için diğer parametreler kullanılır: aH - saat, aM - dakika, aS - saniye. Fonksiyonun kendisi, gün başlangıcından itibaren geçen toplam saniye sayısını döndürür. Fonksiyonu kontrol edelim:

datetime tm=TimeCurrent();
int t,h,m,s;
t=TimeFromDayStart(tm,h,m,s);
//--- output result
Alert("Time elapsed since the day start ",t," s, which makes ",h," h, ",m," m, ",s," s ");

Gün başlangıcı çubuğunu belirlemek için, göstergelerde kullanılacak gün sayısını da hesaplayabilirsiniz:

bool NewDay=(time[i]/86400)!=(time[i-1]/86400);

Çubukların soldan sağa indislendiği varsayılır, burada time[i] mevcut çubuğun zamanıdır ve time[i-1] önceki çubuğun zamanıdır.


Hafta Başlangıç Saatini ve Hafta Başlangıcından itibaren Geçen Süreyi Belirleme

Hafta başlangıç saatini belirlemek, gün başlangıcını belirlemekten biraz daha karmaşıktır. Bir haftadaki gün sayısı sabit olmasına ve bir haftanın süresini saniye cinsinden (604800 saniye) hesaplayabilmemize rağmen, dönemin başlangıcından itibaren geçen hafta sayısını hesaplamak ve bunu haftanın süresi ile çarpmak yeterli değildir.

Sorun şudur: Çoğu ülkede hafta pazartesi günü başlarken diğer bazı ülkelerde (ABD, Kanada, İsrail ve diğerleri) pazar günü başlar. Ancak hatırladığımız gibi, zaman ölçümünün dönemi perşembe günü başlar. Perşembe haftanın ilk günü olsaydı, bu basit hesaplamalar yeterli olurdu.

Kolaylık için, hafta başlangıcını belirleme özelliklerini, 0 değerine karşılık gelen ilk dönem günü örneğiyle ele alacağız. Zamana eklendiğinde, sıfırdan itibaren sayılan dönemin ilk gününü (1970.01.01 00:00) dördüncü gün olarak değiştirecek bir değer bulmamız, yani dört günlük süre eklememiz gerekir. Hafta pazartesi günü başlıyorsa, perşembe dördüncü gün olmalı, bu yüzden üç günlük süre eklemeliyiz. Ancak hafta pazar günü başlıyorsa, perşembe beşinci gün olur, bu yüzden dört günlük süre eklememiz gerekir.

Bir hafta sayısının hesaplanması için bir fonksiyon yazalım:

long WeekNum(datetime aTime,bool aStartsOnMonday=false)
  {
//--- if the week starts on Sunday, add the duration of 4 days (Wednesday+Tuesday+Monday+Sunday),
//    if it starts on Monday, add 3 days (Wednesday, Tuesday, Monday)
   if(aStartsOnMonday)
     {
      aTime+=259200; // duration of three days (86400*3)
     }
   else
     {
      aTime+=345600; // duration of four days (86400*4)  
     }
   return(aTime/604800);
  }

Bu fonksiyon, yeni haftanın ilk çubuğunu belirlemeye yönelik göstergelerde yararlı olabilir:

bool NewWeek=WeekNum(time[i])!=WeekNum(time[i-1]);

Çubukların soldan sağa indislendiği varsayılır, burada time[i] mevcut çubuğun zamanıdır ve time[i-1] önceki çubuğun zamanıdır.

Şimdi, hafta başlangıcının saatini hesaplayabiliriz. Haftanın sayısını hesaplamak için, dönemin üç (veya dört) gün daha erken başladığı varsayıldığından, şimdi ters zaman düzeltmesi yapmalıyız:

long WeekStartTime(datetime aTime,bool aStartsOnMonday=false)
  {
   long tmp=aTime;
   long Corrector;
   if(aStartsOnMonday)
     {
      Corrector=259200; // duration of three days (86400*3)
     }
   else
     {
      Corrector=345600; // duration of four days (86400*4)
     }
   tmp+=Corrector;
   tmp=(tmp/604800)*604800;
   tmp-=Corrector;
   return(tmp);
  }  

Fonksiyon, ilk haftanın değeri negatif olabileceğinden (dönemin başlangıcından üç ila dört gün önce) long türünde bir değer döndürür. Fonksiyonun ikinci parametresi haftanın pazar mı yoksa pazartesi mi başlayacağını belirleyebilir.

Artık hafta başlangıcının zamanını elde ettiğimize göre, hafta başlangıcından itibaren geçen saniye sayısını hesaplayabiliriz:

long SecondsFromWeekStart(datetime aTime,bool aStartsOnMonday=false)
  {
   return(aTime-WeekStartTime(aTime,aStartsOnMonday));
  }

Saniyeler gün, saat, dakika ve saniyeye dönüştürülebilir. Gün başlangıcından itibaren saat, dakika ve saniye hesaplamak zor olmasa da, bu durumda TimeToStruct () fonksiyonunu kullanmak daha kolay olacaktır:

long sfws=SecondsFromWeekStart(TimeCurrent());
MqlDateTime stm;
TimeToStruct(sfws,stm);
stm.day--;
Alert("Time elapsed since the week start "+(string)stm.day+" d, "+(string)stm.hour+" h, "+(string)stm.min+" m, "+(string)stm.sec+" s");

Lütfen stm.day değerinin 1 azaltıldığını unutmayın. Tam gün sayısını belirlememiz gerektiğinden ayın günleri 1'den itibaren sayılır. Bazılarınız bu bölümün fonksiyonlarını pratik açıdan yararsız bulabilir, ancak bu fonksiyonlara dair anlayışınız zaman ile çalışma tecrübesi olarak büyük önem taşıyacaktır.


Belirli bir Tarihten, Yıl Başlangıcından veya Ay Başlangıcından itibaren Hafta Sayısını Belirleme

Özellikle day_of_year alanı olmak üzere MqlDateTime yapısının alanlarına bakıldığında, yıl başlangıcından ve ay başlangıcından itibaren geçen hafta sayısını belirleyecek fonksiyonlar oluşturmak istenebilir. Belirli bir tarihten itibaren hafta sayısını belirlemek için genel bir fonksiyon yazmak daha iyidir. Fonksiyonun çalışma prensibi, dönemin başlangıcından itibaren hafta sayısını belirlemek için kullanılana benzerdir:

long WeekNumFromDate(datetime aTime,datetime aStartTime,bool aStartsOnMonday=false)
  {
   long Time,StartTime,Corrector;
   MqlDateTime stm;
   Time=aTime;
   StartTime=aStartTime;
//--- determine the beginning of the reference epoch
   StartTime=(StartTime/86400)*86400;
//--- determine the time that elapsed since the beginning of the reference epoch
   Time-=StartTime;
//--- determine the day of the week of the beginning of the reference epoch
   TimeToStruct(StartTime,stm);
//--- if the week starts on Monday, numbers of days of the week are decreased by 1,
//    and the day with number 0  becomes a day with number 6
   if(aStartsOnMonday)
     {
      if(stm.day_of_week==0)
        {
         stm.day_of_week=6;
        }
      else
        {
         stm.day_of_week--;
        }
     }
//--- calculate the value of the time corrector 
   Corrector=86400*stm.day_of_week;
//--- time correction
   Time+=Corrector;
//--- calculate and return the number of the week
   return(Time/604800);
  }

Bu fonksiyonu temel alarak, yıl başlangıcından itibaren ve ay başlangıcından itibaren hafta sayısını belirlemek için iki fonksiyon yazalım. Bunun için, ilk olarak yıl başlangıcı zamanını ve ay başlangıcı zamanını belirlememiz gerekir. Zamanı bileşenlerine ayırın, bazı alanların değerlerini ayarlayın ve bileşenleri zaman gösterimine dönüştürün.

  • Yıl başlangıcı zamanını belirleme fonksiyonu:

    datetime YearStartTime(datetime aTime)
          {
           MqlDateTime stm;
           TimeToStruct(aTime,stm);
           stm.day=1;
           stm.mon=1;
           stm.hour=0;
           stm.min=0;
           stm.sec=0;
           return(StructToTime(stm));
          }
  • Ay başlangıcı zamanını belirleme fonksiyonu:

    datetime MonthStartTime(datetime aTime)
          {
           MqlDateTime stm;
           TimeToStruct(aTime,stm);
           stm.day=1;
           stm.hour=0;
           stm.min=0;
           stm.sec=0;
           return(StructToTime(stm));
          }

Aşağıda, yıl başlangıcından itibaren ve ay başlangıcından itibaren hafta sayısını belirlemek için fonksiyonlar yer almaktadır.

  • Yıl başlangıcından itibaren:

    long WeekNumYear(datetime aTime,bool aStartsOnMonday=false)
          {
           return(WeekNumFromDate(aTime,YearStartTime(aTime),aStartsOnMonday));
          }
  • Ay başlangıcından itibaren:

    long WeekNumMonth(datetime aTime,bool aStartsOnMonday=false)
          {
           return(WeekNumFromDate(aTime,MonthStartTime(aTime),aStartsOnMonday));
          }

Son olarak, tamamen pratik görevlere geçiyoruz.


Deneysel Araç Seti Oluşturma

Daha önce de bahsedildiği gibi, kotasyonları pazar çubuklarını içeren ve tüm hafta sonu boyunca kesintisiz olarak kotasyon sağlayan işlem merkezleri vardır. Gerekli fonksiyonların her durumda düzgün çalıştığından emin olmalıyız. Tabii ki internette uygun işlem merkezlerini bulabilir ve fonksiyonların çalışmasını demo hesaplarındaki kotasyonları kullanarak test edebiliriz. Ancak, gerekli testleri çalıştırmak için doğru işlem merkezini aramanın dışında grafikteki yerleri de aramak zorunda kalacağız.

Fonksiyonları test etmek için kendi test alanımızı oluşturalım. Özel ilgi alanımız cuma, hafta sonları ve pazartesi. Cuma, pazartesi ve hafta sonu çubuklarının zamanını içeren bir diziyi gerektiği şekilde oluşturacağız. Toplamda dört seçenek olacak:

  1. Hafta sonu çubuğu olmayacak.
  2. Bazı çubuklar, diyelim 4, pazar gününün sonunda olacak.
  3. Kesintisiz hafta sonu kotasyonları.
  4. Cumartesi çubukları var, ama pazar çubukları yok.

Dizinin çok büyümesini engellemek için H1 zaman aralığını kullanacağız. Maksimum dizi boyutu 96 öğe (günde 24 çubuğa 4 gün) olacaktır ve dizinin kendisi, grafik nesneleri kullanılarak çizildiğinde grafiğe uyacaktır. Böylece, zamana sahip bir gösterge tamponu benzer bir şey elde edeceğiz ve dizi üzerinde bir döngüde bir göstergeyi başlatırken OnCalculate() fonksiyonunun ilk yürütülmesine benzer şekilde yineleme yapacağız. Böylece fonksiyon çalışmasını görselleştirebileceğiz.

Bu araç, bu makaleye eklenmiş bir betik (sTestArea.mq5 dosyası) biçiminde uygulanır. Hazırlık, betiğin OnStart() fonksiyonunda gerçekleştirilir. Fonksiyon kodunun en başındaki Variant değişkeni, yukarıda listelenen dört seçenekten birini seçmenize olanak sağlar. Göstergelerin OnCalculate() fonksiyonuna benzer LikeOnCalculate() fonksiyonunu OnStart() fonksiyonunun altında görebilirsiniz. Bu fonksiyonun iki parametresi vardır: rates_total - çubuk sayısı ve time[] - çubukların zamanına sahip dizi.

Bu fonksiyonda bir gösterge yazıyormuşuz gibi çalışmaya devam ederiz. SetMarker() fonksiyonunu çağırarak fonksiyondan bir işaretçi ayarlayabilirsiniz. SetMarker() fonksiyonuna aktarılan parametreler şunlardır: çubuk indisi, tampon indisi (işaretçinin görüntülendiği satır) ve işaretçi rengi.

Şekil 4 betik performans sonuçlarını gösterir, burada Variant değişkeni 2'ye eşittir ve her çubuğun altında iki satır işaretçi ayarlanır (çubuklar ilgili zaman damgalarıyla işaretlidir). Tüm grafik öğelerine ayarlanan renk görünmezdir.

Şekil 4. sTestArea.mq5 betik performansı.
Şekil 4. sTestArea.mq5 betik performansı.

Çubuk zaman damgaları haftanın gününe göre renk alır: Cuma - kırmızı, cumartesi - macenta, pazar - yeşil, pazartesi - mavi. Şimdi, hafta sonu çubuklarına özel bir yaklaşım gerektiren çeşitli fonksiyonlar yazmaya devam ederek bunların çalışmasını görsel olarak izleyebiliriz.


Pivot Göstergesi - Seçenek 1

İlk olarak basit bir Pivot göstergesi oluşturmaya çalışalım. Pivot çizgisini hesaplamak için dünün kapanış fiyatının yanı sıra dünün maksimum ve minimum fiyatlarını bilmemiz gerekir. Gösterge değeri bu üç değerin ortalaması olarak hesaplanır. Gün içinde yeni yüksek ve düşük değerleri belirleyeceğiz, yeni günün başındaki Pivot değerini hesaplayacağız ve gün boyunca seviyeyi daha fazla çizip görüntüleyeceğiz.

Gösterge çalışmasının iki sürümünü sağlayacağız:

  1. Pivot her yeni gün hesaplanır (hafta sonu çubuğu olmadığı varsayılır). Hafta sonu çubukları varsa, cumartesi ve pazar çubukları farklı şekilde işlem görecektir.
  2. Cumartesi çubukları cuma gününe ait olacak, pazar çubukları ise pazartesiye ait olacaktır (bu, kotasyonların hafta sonu boyunca kesintisiz olarak sağlandığı ve yalnızca pazar çubuklarının bulunduğu durumlar için geçerlidir). Burada, hafta sonu hiç çubuk olmayabileceğini unutmamalısınız.

İlk sürümde, sadece yeni gün başlangıcını belirlemek yeterlidir. Mevcut zamanı (aTimeCur) ve önceki zamanı (aTimePre) fonksiyona aktarırız, dönemin başlangıcından itibaren geçen gün sayısını hesaplarız ve bunlar eşleşmiyorsa yeni günün başladığı sonucunu çıkarırız:

bool NewDay1(datetime aTimeCur,datetime aTimePre)
  {
   return((aTimeCur/86400)!=(aTimePre/86400));
  }

İkinci sürüm. Cumartesi başladıysa, gün başlangıcı yok sayılmalıdır. Pazar başladıysa, gün başlangıcı tanımlarız (bu doğal olarak başka bir gündür). Pazardan sonra pazartesi başladıysa, gün başlangıcını atlayın. Pazartesiden önce haftanın herhangi bir günü geldiyse, örneğin cumartesi veya cuma, gün başlangıcı tanımlayın. Elde ettiğimiz fonksiyon aşağıdaki gibidir:

bool NewDay2(datetime aTimeCur,datetime aTimePre)
  {
   MqlDateTime stm;
//--- new day
   if(NewDay1(aTimeCur,aTimePre))
     {
      TimeToStruct(aTimeCur,stm);
      switch(stm.day_of_week)
        {
         case 6: // Saturday
            return(false);
            break;
         case 0: // Sunday
            return(true);
            break;
         case 1: // Monday
            TimeToStruct(aTimePre,stm);
            if(stm.day_of_week!=0)
              { // preceded by any day of the week other than Sunday
               return(true);
              }
            else
              {
               return(false);
              }
            break;
         default: // any other day of the week
            return(true);
        }
     }
   return(false);
  }

Sürüme dayalı genel fonksiyon şu şekildedir:

bool NewDay(datetime aTimeCur,datetime aTimePre,int aVariant=1)
  {
   switch(aVariant)
     {
      case 1:
         return(NewDay1(aTimeCur,aTimePre));
         break;
      case 2:
         return(NewDay2(aTimeCur,aTimePre));
         break;
     }
   return(false);
  }

"sTestArea" aracını (ekli sTestArea_Pivot1.mq5 dosyası; gün başlangıcı kahverengi olarak işaretlenmiştir) kullanarak fonksiyon çalışmasını test edelim. Sekiz test çalıştırmanız gerekecektir: Dört çubuk oluşturma seçeneği için 2 fonksiyon sürümü. Fonksiyonların düzgün çalıştığından emin olduktan sonra, güvenle bir gösterge geliştirmeye başlayabiliriz. Bununla birlikte, göstergelerin geliştirilmesi bu makalenin odak noktası olmadığından, buraya hazır bir gösterge ekledik (Pivot1.mq5 dosyası), bunun geliştirilmesinin en zor kısmı ayrıntılı olarak ele alınmıştır.


Zaman Oturumunu Belirleme

Uzman Danışmanın, gün içinde belirtilen süre aralığında ve her gün aynı aralıkta işlem yapmasını sağlamalıyız. Alım satım oturumu başlangıcının saatini ve dakikasını ve alım satım oturumu bitişinin saatini ve dakikasını belirtiriz. "14:00" olarak belirtilen zamana sahip dize değişkenleri yerine ayrı ayrı belirtilen saat ve dakikalar, fonksiyonun Uzman Danışmanında kullanılması durumunda Strateji Test Cihazında optimizasyonlar yapmamıza olanak sağlar.

Zaman oturumunu belirlemek için aşağıdakileri yapın:

  1. Zamanın başlangıç noktası için gün başlangıcından itibaren geçen süreyi saniye cinsinden hesaplayın ve aynısını zamanın bitiş noktası için de yapın.
  2. Mevcut saati, gün başlangıcından itibaren geçen saniye cinsinden hesaplayın.
  3. Mevcut zamanı başlangıç ve bitiş zamanı ile karşılaştırın.

Bir alım satım oturumunun bir gün başlaması ve başka bir gün bitmesi, yani bir alım satım oturumu gece yarısını geçtiğinde, imkansız değildir; bu durumda gün başlangıcından itibaren hesaplanan bitiş zamanı başlangıç zamanından daha küçük olur. Bu nedenle iki kontrol yapmamız gerekir. Elde ettiğimiz fonksiyon aşağıdaki gibidir:

bool TimeSession(int aStartHour,int aStartMinute,int aStopHour,int aStopMinute,datetime aTimeCur)
  {
//--- session start time
   int StartTime=3600*aStartHour+60*aStartMinute;
//--- session end time
   int StopTime=3600*aStopHour+60*aStopMinute;
//--- current time in seconds since the day start
   aTimeCur=aTimeCur%86400;
   if(StopTime<StartTime)
     {
      //--- going past midnight
      if(aTimeCur>=StartTime || aTimeCur<StopTime)
        {
         return(true);
        }
     }
   else
     {
      //--- within one day
      if(aTimeCur>=StartTime && aTimeCur<StopTime)
        {
         return(true);
        }
     }
   return(false);
  }

Oturumun gece yarısını geçiyorsa, mevcut saat oturum başlangıç ​​saatinden büyük veya buna eşit VEYA oturum bitiş saatinden küçük olmalıdır. Oturum gün içinde gerçekleşirse, mevcut saat başlangıç ​​saatinden büyük veya buna eşit VE bitiş saatinden küçük olmalıdır.

Fonksiyon çalışmasını test etmek için oluşturulan bir gösterge, makalenin sonuna eklenmiştir (Session.mq5 dosyası). Uygulamanın diğer herhangi bir göstergesi gibi, bu da sadece test ve diğer pratik amaçlar için kullanılabilir.


Gün içinde Bir Zaman Noktasını Belirleme

Tikler düzenli aralıklarla oluşmadığından ve birkaç saniye ile birkaç dakika arasında gecikmeler olabileceğinden, belirtilen zamana eşitlik açısından basit bir kontrol düzgün çalışmayacaktır. Belirtilen saatte piyasada herhangi bir tik işareti olmaması çok muhtemeldir. Belirli bir zaman damgasının kesişme noktasını kontrol etmemiz gerekir.

Mevcut saat, belirtilen zamana eşit veya bundan daha büyük olmalı, önceki saat ise belirtilen zamandan daha küçük olmalıdır. Gün içinde bir zaman noktası belirlemek gerektiğinden, gün başlangıcından itibaren mevcut saati (ve önceki zamanı) saniyeye çevirmemiz gerekir. Benzer şekilde, verilen zaman parametreleri (saat ve dakika) saniyeye dönüştürülmelidir. Önceki saat bir önceki güne denk geliyor olabilir, yani gün başlangıcından itibaren saniyeye dönüştürüldüğünde mevcut saatten daha büyük olabilir. Bu durumda, zaman oturumunu belirlerken olduğu gibi ilerleyerek iki kontrol yaparız.

Elde ettiğimiz fonksiyon aşağıdaki gibidir:

bool TimeCross(int aHour,int aMinute,datetime aTimeCur,datetime aTimePre)
  {
//--- specified time since the day start
   datetime PointTime=aHour*3600+aMinute*60;
//--- current time since the day start
   aTimeCur=aTimeCur%86400;
//--- previous time since the day start
   aTimePre=aTimePre%86400;
   if(aTimeCur<aTimePre)
     {
      //--- going past midnight
      if(aTimeCur>=PointTime || aTimePre<PointTime)
        {
         return(true);
        }
     }
   else
     {
      if(aTimeCur>=PointTime && aTimePre<PointTime)
        {
         return(true);
        }
     }
   return(false);
  }

Bu fonksiyona dayalı olarak oluşturulmuş bir gösterge vardır (makaleye eklenen TimePoint.mq5 dosyası).


Pivot Göstergesi - Seçenek 2

Artık bir zaman noktasının nasıl belirleneceğini öğrendiğimize göre, Pivot göstergesini karmaşıklaştıralım. Gün, her zamanki 00:00 yerine, artık herhangi bir zamanda başlayacak. Buna kullanıcı tanımlı bir gün diyeceğiz. Kullanıcı tanımlı bir gün başlangıcını belirlemek için daha önce açıklanan TimeCross() fonksiyonunu kullanacağız. Hafta sonlarında farklı çubuk oluşturma seçenekleri nedeniyle bazı günlerin çıkarılması gerekecektir. Şu anda tüm kontrol kurallarını bulmak zor, bu yüzden sıra sıra ilerleyeceğiz. Önemli olan, başlamak için elimizde bir şey olması ve nasıl devam edeceğinize dair seçeneklerimizin olması. Bir test betiğimiz var, sTestArea.mq5, böylece doğru çözüm deneysel olarak bile bulunabilir.

"Hafta sonu çubukları yok" durumu en basitidir: yeni bir gün, belirli bir zaman damgasının zaman ile kesişme noktasında başlar.

Pazar gününün sonunda yalnızca birkaç çubuk olması durumunda, TimeCross() fonksiyonu, herhangi bir fonksiyon parametresi verildiğinde ilk pazar çubuğunu gün başlangıcı olarak tanımlar. Hafta sonları kotasyon olmadığı varsayılır (pazar çubukları pazartesiye aittir), bu nedenle pazar yok sayılmalıdır. Belirli bir saat bir dizi pazar çubuğunun ortasında bir yerde bulunuyorsa, yeni gün başlangıcı zaten cuma günü kaydedildiğinden, bu da yok sayılmalıdır.

Kesintisiz hafta sonu kotasyonları: Kullanıcı tanımlı bir gün başlangıcı bir takvim gününün ortasında bulunuyorsa (Şekil 5),

Şekil 5. Kullanıcı tanımlı bir gün takvim gününün ortasında başlıyor. Cuma - kırmızı, cumartesi - macenta, pazar - yeşil, pazartesi - mavi.
Şekil 5. Kullanıcı tanımlı bir gün, bir takvim gününün ortasında başlıyor.
Cuma - kırmızı, cumartesi - macenta, pazar - yeşil, pazartesi - mavi.

Cumartesinin yarısı cuma olarak kabul edilebilir, pazarın yarısı ise pazartesi olarak kabul edilebilir. Ancak cumartesi ortasından pazar ortasına kadar olup hiçbir yere ait olmayan çubuklar vardır. Elbette cumartesi ile pazar arasındaki aralığı eşit parçalara bölebilir ve bir yarısını cuma olarak ve diğer yarısını pazartesi olarak kabul edebiliriz. Bu da, hafta sonu kotasyonları çok önemli değilken, çok basit bir göstergeyi önemli ölçüde karmaşıklaştıracaktır.

En makul çözüm, tüm cumartesi ve pazar çubuklarını, cumadan pazartesiye kadar süren kullanıcı tanımlı bir gün olarak değerlendirmek olacaktır. Bunun anlamı, cumartesi ve pazar günleri başlayan kullanıcı tanımlı günlerin atlanmasıdır.

Elde ettiğimiz fonksiyon aşağıdaki gibidir:

bool NewCustomDay(int aHour,int aMinute,datetime aTimeCur,datetime aTimePre)
  {
   MqlDateTime stm;
   if(TimeCross(aHour,aMinute,aTimeCur,aTimePre))
     {
      TimeToStruct(aTimeCur,stm);
      if(stm.day_of_week==0 || stm.day_of_week==6)
        {
         return(false);
        }
      else
        {
         return(true);
        }
     }
   return(false);
  }

Bu fonksiyona dayalı olarak oluşturulmuş bir gösterge vardır (makaleye ekli Pivot2.mq5 dosyası).


Haftanın Alım Satım Günlerini Belirleme

Bir Uzman Danışmanın yalnızca belirli günlerde işlem yapmasına izin vermek oldukça kolaydır. TimeToStruct() fonksiyonunu kullanarak zamanı bileşenlerine ayırırız ve Uzman Danışman parametrelerinde haftanın her günü için bool türü değişkenler bildiririz. Fonksiyon, haftanın gününe göre, karşılık gelen değişkenin değerini döndürür.

Bu işlem daha optimal bir şekilde yapılabilir. Bir Uzman Danışman veya gösterge başlatırken, bir diziyi belirli günlerde alım satıma izin veren veya vermeyen değişkenlerin değerleri ile doldurun. Ardından, haftanın bu gününe karşılık gelen dizi öğesinin değerini kontrol edin. İki fonksiyon elde ederiz: Biri başlatma sırasında çağrılırken diğeri gerektiğinde çağrılır.

Değişkenler:

input bool Sunday   =true; // Sunday
input bool Monday   =true; // Monday
input bool Tuesday  =true; // Tuesday 
input bool Wednesday=true; // Wednesday
input bool Thursday =true; // Thursday
input bool Friday   =true; // Friday
input bool Saturday =true; // Saturday

bool WeekDays[7];

Başlatma fonksiyonu:

void WeekDays_Init()
  {
   WeekDays[0]=Sunday;
   WeekDays[1]=Monday;
   WeekDays[2]=Tuesday;
   WeekDays[3]=Wednesday;
   WeekDays[4]=Thursday;
   WeekDays[5]=Friday;
   WeekDays[6]=Saturday;
  }

Ana fonksiyon:

bool WeekDays_Check(datetime aTime)
  {
   MqlDateTime stm;
   TimeToStruct(aTime,stm);
   return(WeekDays[stm.day_of_week]);
  }

Bu fonksiyona dayalı olarak oluşturulan bir gösterge, makalenin sonuna eklenmiştir (TradeWeekDays.mq5 dosyası).


Haftanın Alım Satım Zamanını Belirleme

Haftanın bir gününün belirli bir saatinden haftanın başka bir gününün belirli bir saatine kadar olan alım satım oturumlarını belirlememiz gerekiyor. Bu fonksiyon, TimeSession() fonksiyonuna benzerdir; tek fark, hesaplamaların hafta başlangıcından itibaren geçen süreyi temel almasıdır. Elde ettiğimiz fonksiyon aşağıdaki gibidir:

bool WeekSession(int aStartDay,int aStartHour,int aStartMinute,int aStopDay,int aStopHour,int aStopMinute,datetime aTimeCur)
  {
//--- session start time since the week start
   int StartTime=aStartDay*86400+3600*aStartHour+60*aStartMinute;
//--- session end time since the week start
   int StopTime=aStopDay*86400+3600*aStopHour+60*aStopMinute;
//--- current time in seconds since the week start
   long TimeCur=SecondsFromWeekStart(aTimeCur,false);
   if(StopTime<StartTime)
     {
      //--- passing the turn of the week
      if(TimeCur>=StartTime || TimeCur<StopTime)
        {
         return(true);
        }
     }
   else
     {
      //--- within one week
      if(TimeCur>=StartTime && TimeCur<StopTime)
        {
         return(true);
        }
     }
   return(false);
  }

Bu fonksiyona dayalı olarak oluşturulan bir gösterge, makalenin sonuna eklenmiştir (SessionWeek.mq5 dosyası).

Zamanla ilgili en yaygın görevlerin neredeyse hepsini ele aldık ve bunları çözmek için gerekli olan ilgili programlama tekniklerini ve standart MQL5 fonksiyonlarını gözden geçirdik.


Ek MQL5 Fonksiyonları

Zaman ile çalışmak için birkaç MQL5 fonksiyonu daha vardır: TimeTradeServer(), TimeGMT(), TimeDaylightSavings() ve TimeGMTOffset(). Bu fonksiyonların ana özelliği, bunların bir kullanıcının PC'sinin saat ve zaman ayarlarında kullanılmalarıdır.

TimeTradeServer() fonksiyonu. TimeCurrent() fonksiyonunun hafta sonları yanlış zamanı (cuma günü son fiyat değişikliği zamanı) göstereceği makalenin başında belirtilmişti. TimeTradeServer() fonksiyonu doğru sunucu saatini hesaplar:

datetime tm=TimeTradeServer();
//--- output result
Alert(tm);

TimeGMT() fonksiyonu. Fonksiyon, bir kullanıcının bilgisayarının saat değerlerine ve zaman ayarlarına göre GMT saatini hesaplar: saat dilimi ve Yaz Saati Uygulaması:

datetime tm=TimeGMT();
//--- output result
Alert(tm);

Daha net olarak fonksiyon UTC zamanını döndürür.

TimeDaylightSavings() fonksiyonu. Fonksiyon, kullanıcının bilgisayar ayarlarından Yaz Saati Uygulaması için düzeltme değerini döndürür.

int val=TimeDaylightSavings();
//--- output result
Alert(val);

Saati Yaz Saati Uygulaması için düzeltme değeri olmaksızın elde etmek için düzeltme değerini yerel saate eklemelisiniz.

TimeGMTOffset() fonksiyonu. Fonksiyon, bir kullanıcının bilgisayarının saat dilimini elde etmenizi sağlar. Değer, GMT saatini elde etmek için yerel saate eklenmek üzere saniye cinsinden döndürülür.

int val=TimeGMTOffset();
//--- output result
Alert(val);

Bir kullanıcının bilgisayarındaki saat TimeGMT()-TimeGMTOffset()-TimeDaylightSavings() olacaktır:

datetime tm1=TimeLocal();
datetime tm2=TimeGMT()-TimeGMTOffset()-TimeDaylightSavings();
//--- output result
Alert(tm1==tm2);


Zamanla İlgili Diğer Faydalı Fonksiyonlar

Artık yılı belirleme fonksiyonu

bool LeapYear(datetime aTime)
  {
   MqlDateTime stm;
   TimeToStruct(aTime,stm);
//--- a multiple of 4 
   if(stm.year%4==0)
     {
      //--- a multiple of 100
      if(stm.year%100==0)
        {
         //--- a multiple of 400
         if(stm.year%400==0)
           {
            return(true);
           }
        }
      //--- not a multiple of 100 
      else
        {
         return(true);
        }
     }
   return(false);
  }

Artık yılın belirlenmesi ilkesi, yukarıda Zaman Ölçümünün Özellikleri bölümünde açıklanmıştır.

Bir aydaki gün sayısını belirleme fonksiyonu

int DaysInMonth(datetime aTime)
  {
   MqlDateTime stm;
   TimeToStruct(aTime,stm);
   if(stm.mon==2)
     {
      //--- February
      if(LeapYear(aTime))
        {
         //--- February in a leap year 
         return(29);
        }
      else
        {
         //--- February in a non-leap year 
         return(28);
        }
     }
   else
     {
      //--- other months
      return(31-((stm.mon-1)%7)%2);
     }
  }

Fonksiyon, şubat için uygun 28 veya 29 değerini döndürmek için yılın artık yıl olup olmadığını kontrol eder ve diğer aylar için gün sayısını hesaplar. İlk 7 aydaki gün sayısı aşağıdaki gibi değişir: 31, 30, 31, 30 vb. ile kalan 5 ayın gün sayısı. Bu nedenle fonksiyon 7'ye bölümün kalanını hesaplar. Ardından tek eşlik kontrolü yapılır ve elde edilen düzeltme 31'den çıkarılır.


Strateji Test Cihazında Zaman Fonksiyonu İşleminin Özellikleri

Strateji Test Cihazı, kendi kotasyon akışını oluşturur ve TimeCurrent() fonksiyonunun değerleri Strateji Test Cihazındaki kotasyon akışına karşılık gelir. TimeTradeServer() fonksiyon değerleri TimeCurrent() değerlerine karşılık gelir. Benzer şekilde, TimeLocal() fonksiyon değerleri TimeCurrent() değerlerine karşılık gelir. Strateji Test Cihazındaki TimeCurrent() fonksiyonu, saat dilimlerini ve Yaz Saati Uygulaması düzeltmesini hesaba katmaz. Uzman Danışmanların çalışması fiyat değişikliklerine bağlıdır, bu nedenle Uzman Danışmanınızın zamanı ele alması gerekiyorsa TimeCurrent() fonksiyonunu kullanın. Bu işlem, Uzman Danışmanınızı Strateji Test Cihazında güvenle test etmenizi sağlayacaktır.

TimeGMT(), TimeDaylightSavings() ve TimeGMTOffset() fonksiyonları, yalnızca bir kullanıcının bilgisayarının mevcut ayarlarına göre çalışır (Strateji Test Cihazında Yaz Saati Uygulamasına geçişler ve normal saate dönüşler simüle edilmez). Bir Uzman Danışmanı test ederken zamanın Yaz Saati Uygulamasına ve standart saate geri kaydırılmasındaki değişiklikleri simüle etmeniz gerekiyorsa (bu gerçekten gerekliyse), bununla kendiniz ilgilenmelisiniz. Bu da, saati değiştirmek için kesin tarihler ve saate dair bilgi ve kapsamlı bir analiz gerektirecektir.

Bu sorunun çözümü, tek bir makalenin kapsamının çok ötesindedir ve burada ele alınmamıştır. Bir Uzman Danışman Avrupa veya Amerika oturum saatleri dahilinde çalışıyorsa, Asya oturumunun aksine, işlem merkezi Yaz Saati Uygulamasına uyarken sunucu saati ile olay saati arasında herhangi bir tutarsızlık olmayacaktır (Japonya Yaz Saati Uygulamasına uymamaktadır ve Avustralya kasım ayında saatlerini Yaz Saati Uygulamasına kaydırır).


Sonuç

Makale, zaman ile çalışmak için standart MQL5 fonksiyonlarının tamamını kapsar. Zamanla ilgili görevleri yerine getirirken kullanılan programlama tekniklerini ortaya koyar. Makale ayrıca, sağlanan çalışma ilkelerinin ayrıntılı açıklamasıyla birlikte çeşitli göstergelerin ve birkaç yararlı fonksiyonun oluşturulmasını da göstermiştir.

Zaman ile çalışmak için tüm standart fonksiyonlar birkaç kategoriye ayrılabilir:

  1. TimeCurrent() ve TimeLocal(), mevcut saati belirlemek için kullanılan ana fonksiyonlardır.
  2. TimeToString(), StringToTime(), TimeToStruct() ve StructToTime() zaman işleme fonksiyonlarıdır.
  3. CopyTime() çubuk zamanı ile çalışmaya yönelik bir fonksiyondur.
  4. TimeTradeServer(), TimeGMT(), TimeDaylightSavings() ve TimeGMTOffset() kullanıcının bilgisayar ayarlarına bağlı olan fonksiyonlardır.


Ekli Dosyalar

  • sTestArea.mq5 - karmaşık zaman fonksiyonlarının test edilmesi için bir betik.
  • sTestArea_Pivot1.mq5 - Pivot1.mq5 göstergesinin zaman fonksiyonlarının test edilmesi için kullanılan sTestArea.mq5 betiği.
  • Pivot1.mq5 - standart günleri kullanan bir Pivot göstergesi (NewDay fonksiyonu).
  • Session.mq5 - günün alım satım oturumu göstergesi (TimeSession fonksiyonu).
  • TimePoint.mq5 - belirli bir zaman noktasının bir göstergesi (TimeCross fonksiyonu).
  • Pivot2.mq5 - kullanıcı tarafından tanımlanan günleri kullanan bir Pivot göstergesi (NewCustomDay fonksiyonu).
  • TradeWeekDays.mq5 - haftanın alım satım günlerinin bir göstergesi (WeekDays_Check fonksiyonu).
  • SessionWeek.mq5 - haftanın alım satım oturumu göstergesi (WeekSession fonksiyonu).
  • TimeFunctions.mqh - bu makalede sağlanan tüm zaman fonksiyonları, tek bir dosyada.

MetaQuotes Ltd tarafından Rusçadan çevrilmiştir.
Orijinal makale: https://www.mql5.com/ru/articles/599

Ekli dosyalar |
stestarea.mq5 (4.96 KB)
pivot1.mq5 (4.5 KB)
session.mq5 (3.51 KB)
timepoint.mq5 (3.32 KB)
pivot2.mq5 (4.14 KB)
tradeweekdays.mq5 (3.59 KB)
sessionweek.mq5 (5.08 KB)
timefuncions.mqh (20.52 KB)
Gösterge Emisyonlarının İntegral Özelliklerini Hesaplama Gösterge Emisyonlarının İntegral Özelliklerini Hesaplama
Gösterge emisyonları, piyasa araştırmasında az çalışılmış bir alandır. Bunun öncelikli nedeni, zamanla değişen çok büyük veri dizilerinin işlenmesinden kaynaklanan analiz zorluğudur. Mevcut grafik analizi oldukça kaynak yoğundur; ve dolayısıyla emisyonların zaman serilerini kullanan kısa ve öz bir algoritmanın geliştirilmesini tetiklemiştir. Bu makale, görsel (sezgisel görüntü) analizin, emisyonların integral özelliklerinin incelenmesi ile nasıl değiştirilebileceğini gösterir. Hem yatırımcıların hem de otomatik alım satım sistemlerinin geliştiricilerinin ilgisini çekebilir.
MetaTrader 4 ve MetaTrader 5 İçin Nasıl Sinyal Sağlayıcı Olunur? MetaTrader 4 ve MetaTrader 5 İçin Nasıl Sinyal Sağlayıcı Olunur?
Ticaret sinyallerinizi sunmak ve kazanç elde etmek ister misiniz? MQL5.com web sitesine Satıcı olarak kaydolun, işlem hesabınızı belirtin ve yatırımcılara ticaret işlemlerinizi kopyalamaları için abonelik sunun.
MetaTrader 4 ve MetaTrader 5 için Alım Satım Sinyallerine dair Genel Bilgi MetaTrader 4 ve MetaTrader 5 için Alım Satım Sinyallerine dair Genel Bilgi
MetaTrader 4 / MetaTrader 5 Alım Satım Sinyalleri, yatırımcıların bir Sinyal Sağlayıcının alım satım işlemlerini kopyalamasına olanak sağlayan bir hizmettir. Amacımız, Aboneleri koruyan, onları gereksiz maliyetlerden kurtaran ve kitlesel olarak kullanılan yeni bir hizmet geliştirmekti.
Satın Almadan Önce Bir Alım Satım Robotu Nasıl Test Edilir? Satın Almadan Önce Bir Alım Satım Robotu Nasıl Test Edilir?
MQL5 Markette bir alım satım robotu satın almanın diğer tüm benzer seçeneklere göre açık bir avantajı vardır: Sunulan otomatik sistem MetaTrader 5 terminalinde doğrudan kapsamlı bir şekilde test edilebilir. Bir Uzman Danışman, satın alımdan önce, sistemi tam olarak kavramak için yerleşik Strateji Test Cihazındaki tüm olumsuz modlarda dikkatli bir şekilde çalıştırılabilir ve çalıştırılmalıdır.