Engine Kütüphanesi Nedir?
Engine Kütüphanesi, algoritmalarınızı kolayca kodlayabilmeniz için bazı finansal indikatör ve
fonksiyonları barındıran kütüphanedir. Engine kütüphanesi C# yazılım dili altyapısıyla
oluşturulmuştur. Engine kütüphanesi içinde bulunan tüm metotları temel C# bilgisiyle
kullanabilirsiniz. Kodlama editöründe "Engine." komutu ile kullanabileceğiniz bu kütüphane
ile ilgili bilgilere bu makalede yer vereceğiz.
Stratejilerinizi Kodlamaya Başlarken
Engine kütüphanesi kendi içinde kolaylık sağlayan bazı genel tanımlamalara sahiptir. Bu
tanımları kodunuzun içinde istediğiniz yerde kullanabilirsiniz.
Sembol
readonly string Sembol
Stratejinizi çalıştırdığınız sembolü getiren değişkendir.
Periyot
readonly string Sembol
Stratejinizi çalıştırdığınız periyodu alabileceğiniz değişkendir.
barlar
List<Engine.Bar> barlar;
barlar değişkeni ile algoritmanızın çalıştığı sembole ve periyoda ait bar verisini liste olarak
alabilirsiniz. Bar listesi kendi içinde Open,High,Low,Close,Volume,Date değişkenlerini
barındıran bir obje listesidir.
SonPozisyon
float SonPozisyon = 0f;
Algoritmanızın son pozisyonuna ait miktar bilgisini bu değişkende tutulur. Örneğin 1 lot SATIŞ
işleminde -1 olarak eşitlenir, pozisyon durumunuzu öğrenmek için bu değişkeni
çağırabilirsiniz.
SonYon
string SonYon;
Algoritmanızın son yönünü bu değişkende saklayabilirsiniz. Stratejinizin aynı yönde birden fazla işlem yapmaması için bu değişkeni kullanabilirsiniz. Stratejilerin çoğunda arka arkaya aynı işlemin yapılması istenmediğinden bu değişken genellikle kullanılacaktır. Sonraki bölümlerde bu değişkenin kullanımıyla ilgili örneklere yer vereceğiz.
Parametreler
public Dictionary Parametreler = new Dictionary();
Kendinize ait bir değişken saklamak için “Parametreler” sözlüğünü kullanabilirsiniz. Detaylı örneklerine sonraki bölümlerde yer verilecektir.
Sistem Fonksiyonları
ParametreEkle
public void ParametreEkle(string name, object obj)
Bu fonksiyon ile “Parametreler” sözlüğüne yeni bir değişken ekleyebilirsiniz. Eklediğiniz bu bilgi strateji çalıştığı sırada hafızada tutulacaktır. Böylece strateji içinde bu bilgiyi kullanabilirsiniz. Detaylı örneklerine sonraki bölümlerde yer verilecektir.
BarGetir
public void BarGetir(string symbol, string period)
Stratejinizde birden fazla sembolün verisini kullanmak istiyorsanız bu fonksiyon ile o sembole ait verileri çekebilirsiniz. Bu fonksiyonu kodunuzun başında bir defa çağırmanız yeterlidir. İlk parametreye büyük harflerle sembolün adı, ikinci parametreye ise dakika cinsinden periyot verilmelidir.
EmirGonder
public void EmirGonder(string sembol, string yon, float miktar,string emirTipi = ""piyasa"",float price = 0, string emirSuresi = ""kie"")
Emir göndermek için bu fonksiyon kullanılır. İlk üç parametresi zorunlu olmakla birlikte emir tipi, emir fiyatı ve emir geçerlilik süresi gibi değişkenler isteğe bağlı olarak ayarlanabilir.
Sembol : Emrin gönderileceği sembol string olarak verilmelidir.
Yon : Emrin yönü birkaç farklı şekilde verilebilir; “A”,”ALIŞ”,”ALIS”,”BUY” veya “S”,”SATIŞ”,”SATIS”,”SELL”
Miktar : Emrin kaç lot olacağı float olarak verilmelidir.
EmirTipi :“piyasa” veya “limit” olmalıdır. Limir emir verilmesi durumunda sonraki parametrede fiyat bilgisi girilmelidir.
Fiyat : Limit emirlerde emrin fiyatını belirler.
Pozisyonlari Kapat
public void PozisyonlariKapat(string sembol)
Bu metot stratejinizin o anki pozisyon bilgisini okuyarak ters yönde aynı miktarda emir gönderir. Böylece stratejiye ait açık pozisyonlarınız sıfırlanmış olur.
Engine Fonksiyonları
Engine kütüphanesi fonksiyonları algoritmalarda sık kullanılan işlemleri barındır. Örneğin standart sapma, kare kök alma gibi fonksiyonlara sahiptir. Ayrıca "FiyatGetir" gibi fonksiyonlarla bar listesinden kapanış, açılış, yüksek, düşük gibi listeleri elde edebileceğiniz fonksiyonlarda bulunur. Engine fonksiyonlarının detaylarına diğer makalelerde yer verilmiştir.
Engine İndikatörleri
Engine kütüphanesi 50 üzerinde indikatörle geniş bir yelpazeye sahiptir. Bu indikatörleri "Engine." komutuyla listeletebilir ve parametrelerini görebilirsiniz. İndikatörlerin ne işe yaradıkları, kullanımları ile ilgili makaleleri Teknik Kütüphane'de bulabilirsiniz.
İlk Stratejim
Bir sembolde belirli bir fiyat seviyesi kesildiğinde işlem yapacak bir strateji yazalım.
//Kod içinde yorum veya notlarınızı bu şekilde yazabilirsiniz.
//İlk olarak mum grafiğinden kapanış listesini alalım.
var C = Engine.FiyatGetir(barlar, "kapanis");
//İşlemin gerçekleşmesini istediğimiz seviyeyi belirleyelim.
float seviye = 2.06f;
//İşlemimizin miktarını belirleyelim.
int lot = 1000;
//Bu koşulda eğer kapanışların son değeri belirlediğimiz seviyeden büyükse diyoruz.
//Ayrıca SonYon değerimiz alış değilse koşulu eklemeliyiz çünkü seviye geçildikten sonra algoritma arka arkaya bu koşulu kontrol
//ederek işlemler açabilir. Tekrarlayan işlemler olmaması için SonYon değerimizi kontrol ediyoruz.
if(Engine.SonDeger(C) >= seviye && SonYon != "A"){
//ALIŞ koşulu gerçekleşti, SonYon değerimizi eşitliyoruz.
SonYon = "A";
//Emir gönder fonksiyonu ile emri belirlediğimiz “lot” miktarında gönderiyoruz.
EmirGonder(Sembol, "ALIS", lot);
}
İndikatör Kullanmak
İki hareketli ortalamanın kesişimine göre çalışan bir strateji yazalım. Buna göre 1. Hareketli ortalama değeri 2. Hareketli ortalamadan büyükse “ALIŞ”, tersi durumda “SATIŞ” yapalım.
//Birinci hareketli ortalamamızı alıyoruz.
var ma1 = Engine.MA(barlar,"Basit",50);
//Hareketli ortalamamızın 1 önceki değerini alıyoruz.
//1 önceki değeri almamızın sebebi canlı işlem sırasında mum grafiğindeki son değer sürekli olarak değişecektir.
//Bu durum koşulların birden fazla kere çalışmasına sebep olabilir.
var madeger1 = Engine.OncekiDeger(ma1,1);
//İkinci hareketli ortalamamızı alıyoruz.
var ma2 = Engine.MA(barlar,"Basit",200);
//Hareketli ortalamamızın 1 önceki değerini alıyoruz.
var madeger2 = Engine.OncekiDeger(ma2,1);
//1. Hareketli ortalamanın değeri ikinci hareketli ortalamadan büyükse ve “ALIŞ” yönünde değilsek koşulu :
if(madeger1 > madeger2 && SonYon != "ALIS")
{
SonYon = "ALIS";
//Piyasa fiyatlı 1 lot emir gönder
EmirGonder(Sembol,"ALIS",1,"piyasa");
}
//1. Hareketli ortalamanın değeri ikinci hareketli ortalamadan küçükse ve “SATIŞ” yönünde değilsek koşulu :
if(madeger1 < madeger2 && SonYon != "SATIS")
{
SonYon = "SATIS";
//Piyasa fiyatlı 1 lot emir gönder
EmirGonder(Sembol,"SATIS",1,"piyasa");
}
İndikatör Kullanmak 2
Bazı indikatörlerde birden fazla çizgi bulunur. Örneğin Bollinger Bantları Üst, Orta ve Alt bantlar olmak üzere 3 çizgiye sahiptir. Bollinger Bantları kullanan bir strateji oluşturalım.
//Kapanışlar listesini alalım.
var C = Engine.FiyatGetir(barlar, "kapanış");
//Bollinger indikatörünü alalım.
var bollinger = Engine.BollingerBands(barlar, 14, 2);
//Bollinger çizgilerinden hangisini almak istediğimizi aşağıdaki gibi belirteceğiz.
//Alt çizgi
List<float>altBollinger = bollinger[2];
//Orta çizgi
List <float>ortaBollinger = bollinger[1];
//Üst çizgi 0 verilmesinin sebebi ilk sıranın her zaman 0'dan başlamısıdır.
List<float>ustBollinger = bollinger[0];
//Üst çizginin kapanmış son mumdaki değerini alalım.
float ustSonDeger = Engine.OncekiDeger(ustBollinger, 1);
//Alt çizginin kapanmış son mumdaki değerini alalım.
float altSonDeger = Engine.OncekiDeger(altBollinger, 1);
//Bir önceki kapanış değerimizi alalım.
float sonKapanis = Engine.OncekiDeger(C, 1);
//Kapanış değeri üst çizginin üstünde kalırsa ALIŞ yapalım
if(sonKapanis > ustSonDeger && SonYon != "ALIS")
{
SonYon = "ALIS";
EmirGonder(Sembol,"ALIS",1,"piyasa");
}
//Kapanış değeri alt çizginin altında kalırsa SATIŞ yapalım
else if(sonKapanis < altSonDeger && SonYon != "SATIS")
{
SonYon = "SATIS";
EmirGonder(Sembol,"SATIS",1,"piyasa");
}
Double Lot Strateji
İşleme girerken bir önceki pozisyonu kapatacak ve diğer yönde pozisyona geçecek bir strateji yazalım. Bu stratejide açığa satış durumu söz konusu olduğu için sadece VİOP sembollerinde çalıştırılması tavsiye edilir.
Emir gönderilirken “SonPozisyon” değişkeni otomatik olarak emir miktarı kadar artar veya azalır. Örneğin 3 lot ALIŞ işlemi sonrası SonPozisyon = 3 olacaktır. Daha sonra 4 lot SATIŞ işlemi gönderildiğinde SonPozisyon = (3 -4) = -1 olacaktır.
Aşağıda geçmiş örnekte verdiğimiz stratejiyi ters işleme girecek şekilde değiştireceğiz.
//İşlem yapacağımız lotu belirleyelim.
int lot = 500;
var ma1 = Engine.MA(barlar,"Basit",50);
var madeger1 = Engine.OncekiDeger(ma1,1);
var ma2 = Engine.MA(barlar,"Basit",200);
var madeger2 = Engine.OncekiDeger(ma2,1);
if(madeger1 > madeger2 && SonYon != "ALIS")
{
SonYon = "ALIS";
//SonPozisyon değişkeninin mutlak değerini alıp üzerine lot miktarımızı ekliyoruz.
EmirGonder(Sembol,"ALIS",Engine.MutlakDeger(SonPozisyon) + lot,"piyasa");
}
if(madeger1 < madeger2 && SonYon != "SATIS")
{
SonYon = "SATIS";
//SonPozisyon değişkeninin mutlak değerini alıp üzerine lot miktarımızı ekliyoruz.
EmirGonder(Sembol,"SATIS",Engine.MutlakDeger(SonPozisyon) + lot,"piyasa");
}
Zamana Bağlı Strateji
Stratejilerde zamana bağlı koşullar yazılabilir. Örneğin saat 17 sonrasında işlemleri kapatacak bir koşul yazabiliriz. Zamana bağlı strateji kullanırken iki farklı tarihten yola çıkabiliriz. Birincisi sistem saatini kullanarak o anki saati elde etmek. İkincisi ise mum grafiğindeki son mum çubuğunun tarihini alarak en yakın saati elde etmek.
Örnek verecek olursak 5 dakikalık periyotta çalışan bir strateji için;
//Saat şu anda 12.03, “sonSaat” değerimiz 12.03 olur
DateTime sonSaat = DateTime.Now;
//5 dakikalık periyottaki son bar tarihi 12.00 olacağı için “sonMumSaat” 12.00 olacaktır.
DateTime sonMumSaat = barlar[barlar.Count - 1].Date;
RSI indikatörünün 30 ve 70 seviyelerini geçmesi durumunda işlem yapan ve saat 17’de pozisyonları kapatan bir strateji yazalım.
int lot = 500;
var rsi = Engine.RSI(barlar,14);
var rsideger1 = Engine.OncekiDeger(rsi,1);
//Stratejinin çalıştığı mum grafiğindeki son mum tarihini alalım.
DateTime sonMumTarihi = barlar[barlar.Count - 1].Date;
//Son mum barının saati 17'den küçükse ALIŞ veya SATIŞ yapılabilsin.
if(sonMumTarihi.Hour < 17)
{
if(rsideger1 > 70 && SonYon != "ALIS")
{
SonYon = "ALIS";
EmirGonder(Sembol,"ALIS",lot,"piyasa");
}
if(rsideger1 < 30 && SonYon != "SATIS")
{
SonYon = "SATIS";
EmirGonder(Sembol,"SATIS",Engine.MutlakDeger(SonPozisyon) + lot,"piyasa");
}
}
//Son mum barının saati 17 ise işlemler kapansın.
if(sonMumTarihi.Hour == 17 && SonYon != "FLAT"){
//Pozisyonları kapat ve son yönü flat yap.
SonYon = "FLAT";
PozisyonlariKapat(Sembol);
}
Çoklu Sembol&Periyot Stratejisi
Stratejiler çalıştırılırken bir sembol ve periyot seçilir. Fakat bazı stratejilerde birden fazla sembol ve periyot kullanma ihtiyacı olabilir. Bu durumda stratejinin çalıştırıldığı sembol ve periyot haricinde bir veri almak için aşağıdaki gibi kodlama yapılmalıdır. Bu örnekte stratejiyi GARAN 15 dakikalık periyotta çalıştırdığımızı düşünelim. Buna ek olarak stratejide GARAN 120 dakikalık periyota ait verileri de kullanacağız.
//Kodun en başında kullanmak istediğimiz sembol ve periyotu belirtiyoruz.
BarGetir("GARAN","120");
//GARAN 120 dakika mum grafik listesini aşağıdaki gibi elde edebiliriz.
var barlar120 = TumBarlar["GARAN"]["120"];
//120 dakikalık periyotta SAR indikatörü kullanalım.
var SAR120 = Engine.SAR(barlar120, 0.02f,0.2f);
//Stratejinin çalıştığı sembol ve periyotta kapanış listesi ve hareketli ortalama alalım
var C = Engine.FiyatGetir(barlar, "Kapanis");
var MA = Engine.MA(barlar, "Basit", 22);
//120 dakikalık SAR ve diğer periyottaki kapanış değerini karşılaştıran koşulumuz
if(Engine.OncekiDeger(C,1) > Engine.OncekiDeger(SAR120,1) && Engine.OncekiDeger(C,1) > Engine.OncekiDeger(MA,1) && SonYon != "A"){
SonYon = "A";
EmirGonder(Sembol, "ALIS", 1);
}
else if(Engine.OncekiDeger(C,1) < Engine.OncekiDeger(SAR120,1) && Engine.OncekiDeger(C,1) < Engine.OncekiDeger(MA,1) && SonYon != "S"){
SonYon = "S";
EmirGonder(Sembol, "SATIS", 1);
}
Özel Parametre Kullanmak
Stratejiler içinde tanımlanan değişkenler her fiyat değişiminde yeniden hesaplanır. Bazı durumlarda değişkenleri hafızada tutma ihtiyacı ortaya çıkabilir. Örneğin yapılan son işlemin fiyatını bir değişkende saklayıp daha sonra bu değişkene göre farklı bir işlem yapılmasını istersek stratejide özel bir parametre tanımlamamız gerekecektir.
var C = Engine.FiyatGetir(barlar, "kapanis");
var MA5 = Engine.MA(barlar, "Simple", 5);
var MA22 = Engine.MA(barlar, "Simple", 22);
var RSI14 = Engine.RSI(barlar, 14);
//Emir fiyatımızı hafızada tutacak değişkeni ekleyelim.
ParametreEkle("hangiKosulGerceklesti", "");
//Kar al yüzdemizi belirleyelim
float karAlYuzde = 0.01f;
//Stop yüzdemizi belirleyelim
float stopYuzde = 0.01f;
//Hareketli ortalama ALIŞ koşulu
if(Engine.OncekiDeger(MA5,1) > Engine.OncekiDeger(MA22,1) && SonYon != "A")
{
SonYon = "A";
EmirGonder(Sembol,"ALIS", 1);
//Emrin gönderildiği koşulu hafızaya alalım.
Parametreler["hangiKosulGerceklesti"] = "MA";
}
//Hareketli ortalama ALIŞ koşulu
if(Engine.OncekiDeger(RSI14,1) > 70 && SonYon != "A")
{
SonYon = "A";
EmirGonder(Sembol,"ALIS", 1);
//Emrin gönderildiği koşulu hafızaya alalım.
Parametreler["hangiKosulGerceklesti"] = "RSI";
}
string kosul = Parametreler["hangiKosulGerceklesti"].ToString();
//Eğer RSI koşulu ile işleme girildiyse
//RSI 30 altında SATIŞ yap
if(kosul == "RSI" && Engine.OncekiDeger(RSI14,1) < 30 && SonYon != "S")
{
SonYon = "S";
EmirGonder(Sembol,"SATIS", 1);
}
//Eğer MA koşulu ile işleme girildiyse
//MA 5 periyot 22 den küçük olduğunda SATIŞ yap
if(kosul == "MA" && Engine.OncekiDeger(MA5,1) < Engine.OncekiDeger(MA22,1) && SonYon != "S")
{
SonYon = "S";
EmirGonder(Sembol,"SATIS", 1);
}
Take Profit & Stop Loss Örneği
Belirli bir yüzde ile kar al veya zarar durdur yapan bir strateji oluşturalım. Bu stratejide hareketli ortalama koşuluna göre işleme gireceğiz. İşleme girdiğimiz fiyatı bir değişkende saklamamız gerekiyor çünkü daha sonra bu fiyata göre kar al veya zarar durdur işlemi yapacağız.
//Kapanışları ve 2 farklı hareketli ortalamayı alalım
var C = Engine.FiyatGetir(barlar, "kapanis");
var MA5 = Engine.MA(barlar, "Simple", 5);
var MA22 = Engine.MA(barlar, "Simple", 22);
//Emir fiyatımızı hafızada tutacak değişkeni ekleyelim.
ParametreEkle("fiyat", 0f);
//Kar al yüzdemizi belirleyelim
float karAlYuzde = 0.01f;
//Stop yüzdemizi belirleyelim
float stopYuzde = 0.01f;
//Hareketli ortalama ALIŞ koşulu
if(Engine.OncekiDeger(MA5,1) > Engine.OncekiDeger(MA22,1) && SonYon != "A")
{
SonYon = "A";
EmirGonder(Sembol,"ALIS", 1);
//Emrin gönderildiği fiyatı hafızaya alalım.
Parametreler["fiyat"] = Engine.SonDeger(C);
}
//ALIŞ yönlü işlem yapıldıysa.
if(SonYon == "A")
{
//Hafızada tutulan son emrin fiyatını alalım.
float sonEmirFiyati = Convert.ToSingle(Parametreler["fiyat"]);
//Kar al kontrolü
if(sonEmirFiyati * (1+karAlYuzde) < Engine.SonDeger(C))
{
//Pozisyonları kapat ve yönü Flat yap
PozisyonlariKapat(Sembol);
SonYon = "F";
}
//Stop loss kontolü
if(sonEmirFiyati * (1-karAlYuzde) > Engine.SonDeger(C))
{
//Pozisyonları kapat ve yönü Flat yap
PozisyonlariKapat(Sembol);
SonYon = "F";
}
}
Kendi İndikatörünü Yaratmak
Engine kütüphanesinde bulunmayan veya size özel indikatörleri de kodlayarak oluşturabilirsiniz. Örneğin son 10 mum çubuğundaki en yüksek ve düşük değerin ortalamasını alan ve bunu bir indikatör gibi kullanan bir strateji yazalım.
//Yüksek, düşük ve kapanış listelerini alalım.
var H = Engine.FiyatGetir(barlar, "yüksek");
var L = Engine.FiyatGetir(barlar, "düşük");
var C = Engine.FiyatGetir(barlar, "kapanış");
//İndikatörümüzün periyotunu belirleyelim
int period = 10;
//İndikatörümüzü yeni bir liste olarak oluşturalım.
List<float> indikatorum = new List<float>();
//10. bardan itibaren son bara kadar indikatörümüzü hesaplayacağız.
for(int i = period; i < barlar.Count; i ++)
{
//Son 10 barı listeye alalım.
var subList = C.GetRange(i-period, period);
//Son 10 barın en düşüğünü bulalım
float enDusuk = Engine.EnDusukDeger(subList);
//Son 10 barın en yükseğini bulalım
float enYuksek = Engine.EnYuksekDeger(subList);
//En yüksek ve düşüğün ortalamasını alalım
float ortalama = (enYuksek + enDusuk) / 2f;
//İndikatör listemize değeri ekleyelim.
indikatorum.Add(ortalama);
}
//İndikatörümüzü kullanarak ALIŞ ve SATIŞ koşulu oluşturalım.
if(Engine.OncekiDeger(indikatorum, 1) > Engine.OncekiDeger(indikatorum, 2) && SonYon != "A")
{
SonYon = "A";
EmirGonder(Sembol,"ALIS", 1);
}
else if(Engine.OncekiDeger(indikatorum, 1) < Engine.OncekiDeger(indikatorum, 2) && SonYon != "S")
{
SonYon = "S";
EmirGonder(Sembol,"SATIS", 1);
}
Backtest İçin Log Yazdırmak
Kodlama yaparken sorun çözmek için kullanılabilecek en önemli yöntem backtest’e log yazdırmaktır. Böylece stratejinizde hangi değerlerin kullanıldığını veya hangi koşulların gerçekleştiğini backtest içinde kontrol edebilirsiniz. Aşağıdaki örnekte her yeni mum çubuğunda hareketli ortalamaların son değerlerini log olarak yazdıracaktır. Ayrıca alış ve satış durumunda da tarihle birlikte log yazdıracaktır. Backtest yapıldığında log sekmesi açılacak ve yazdırılanlar burada görülecektir.
var ma1 = Engine.MA(barlar,"Basit",50);
var madeger1 = Engine.OncekiDeger(ma1,1);
var ma2 = Engine.MA(barlar,"Basit",200);
var madeger2 = Engine.OncekiDeger(ma2,1);
if(madeger1 > madeger2 && SonYon != "ALIS")
{
SonYon = "ALIS";
EmirGonder(Sembol,"ALIS",1,"piyasa");
Log += barlar[barlar.Count - 1].Date + " :: ALIŞ KOŞULU TETİKLENDİ." + Environment.NewLine;
}
if(madeger1 < madeger2 && SonYon != "SATIS")
{
SonYon = "SATIS";
EmirGonder(Sembol,"SATIS",1,"piyasa");
Log += barlar[barlar.Count - 1].Date + " :: SATIŞ KOŞULU TETİKLENDİ." + Environment.NewLine;
}
Log += barlar[barlar.Count - 1].Date + " :: "+ madeger1 + " " + madeger2 + Environment.NewLine;