Kurs
Bu yazıda, R kullanarak loyal3’te listelenen hisseleri nasıl toplayacağınızı, Yahoo’dan geçmiş verileri nasıl alacağınızı ve ardından basit bir algoritmik alım satım stratejisi uygulayacağınızı göstereceğim. Bu süreçte, biraz web kazıma, bir finans API’ına istek atan bir fonksiyon ve etkileşimli bir zaman serisi grafiği yapmak için bir htmlwidget öğreneceksiniz.
Bu yazı için, bir alım satım algoritması, kestirimsel bir model ya da zaman serisi tahmini yerine alım ya da satım olayını tetikleyen bir dizi kural olarak tanımlanmıştır. Bu, en basit alım satım algoritması türüdür; ancak R ile finansı daha derinlemesine incelemek isterseniz, DataCamp’in R’de nicel bir alım satım stratejisi modelleme kursunu öneririm.
Arka Plan
2015’te loyal3’te küçük yatırımlarla başladım. Hizmetleri sıradışıdır ve yatırım yolculuğunuza başlamak için harika bir yerdir. İşlemler için yatırımcıdan ücret almak yerine, loyal3 platformlarında listelenmek için şirketlerden ücret alır. Varsayım şudur: Bir şirketin hizmetini seven insanlar hissesini de alır ve böylece güçlü marka savunucuları haline gelir. Platformu daha cazip kılan, kesirli hisse alabilmenizdir. Yani, $800 değerindeki amazon hissesine sadece $10 ile girebilir ve her ay sonunda biraz fazladan nakdiniz olduğunda bir $10’luk kesir daha alabilirsiniz. Elbette, işlem pencerelerinde alım satım yapmanız gerektiğinden ve tüm portföyünüz ~70 hisse ile sınırlı olduğundan sürtünme maliyetleri vardır; ancak loyal3, hisse senedi alım satımını keşfetmek için eğlenceli ve düşük maliyetli bir yol sunar. Sadece $10 ile oyuna gerçek bir pay koyabilirsiniz!
Açık olmak gerekirse, tipik emeklilik ve yatırım hesaplarım var; ama loyal3’ün uygulamadaki sade arayüzünü ve ücret olmamasını seviyorum. Doğrudan seçtiğim hisselerin performansını görmek hem kolay hem de eğlenceli olduğundan, eğlence amaçlı loyal3 portföyümü yatırım fonlarımdan daha sık kontrol ediyorum.
Çalışma Alanınızı Hazırlama
Başlamak için kütüphaneleri ortamınıza yükleyin. Günümüzde web kazıma için neredeyse her zaman rvest kullanıyorum. RSelenium dahil çalışan başka paketler de var; ancak rvest’in ne kadar kolay çalıştığını seviyorum.
İkinci paket pbapply isteğe bağlıdır; çünkü yalnızca apply fonksiyonlarına bir ilerleme çubuğu ekler. Yüzlerce web sayfasını kazıyabileceğiniz için süreyi tahmin etmede bir ilerleme çubuğu faydalı olabilir.
Sonraki paket TTR, yeni yeni keşfetmeye başladığım bir paket. Kütüphane, “Teknik Alım Satım Kuralları” oluşturmak için kullanılır. Bu yazıda basit bir alım satım algoritması öğrenecek olsanız da, TTR daha gelişmiş hesaplamalar yapabilir ve öğrenmeye değerdir.
dygraphs kütüphanesi, hızlı ve açık kaynaklı bir JavaScript grafik kütüphanesine sarmalayıcıdır. R grafikleri daha dinamik hale getiren ve statik görsel yerine bir html dosyasının parçası olan htmlwidget’lardan biridir. Son olarak, lubridate paketini tarihleri kolayca işlemek için kullanıyoruz.
library(rvest)
library(pbapply)
library(TTR)
library(dygraphs)
library(lubridate)
Veri Toplama
Tüm loyal3 hisseleri tek bir sayfada listelenmiştir. Alım satım algoritmanızı oluşturmak için tek tek günlük hisse fiyatlarına bakmadan önce, mevcut tüm hisse sembollerini toplamanız gerekir. İlk yapılacak şey, stock.list’i bir URL dizesi olarak tanımlamaktır. Ardından read_html() kullanarak R oturumunuzun bir internet oturumu başlatmasını ve sayfadaki tüm html bilgisini bir XML düğüm kümesi olarak toplamasını sağlayın. Sayfa CSS’inde “.company-name” adlı bir ID var. html_nodes() çağrılırken bunu parametre olarak kullanarak yalnızca bu düğüme bağlı XML verilerini seçin. Son olarak html_text() kullanarak şirket adlarının gerçek metin değerlerini toplayın.
stock.list<-'https://www.loyal3.com/stocks'
stocks<-read_html(stock.list)
stocks.names<-html_nodes(stocks,'.company-name')
stocks.names<-html_text(stocks.names)
loyal3’te mevcut hisseleri incelemek için stocks.names nesnesini konsolunuza yazdırabilirsiniz. Bu, şirket adlarını bir metin vektörü olarak döndürür.
stocks.names
Hisse fiyatlarını araştırmak için önce sembolü (ticker) almanız gerekir. loyal3 sitesindeyken, şirket kartına tıklayarak hisse sembolünü ve diğer şirket bilgilerini içeren bir sayfayı yükleyebilirsiniz.
html_nodes()’u stocks üzerinde kullanarak “a” ile işaretlenmiş tüm düğümleri çekersiniz. HTML’de <a> etiketi, bir sayfadan diğerine bağlantı oluşturmak için kullanılan köprüyü tanımlar. Köprü etiketinde “href” tam URL adresini ifade eder. Dolayısıyla html_attr() içine “href” geçirirseniz sayfadaki TÜM bağlantıların URL’lerini çıkarır.
Biraz elle inceleme yaptıktan sonra, sayfadaki 54’ten 123’e kadar olan bağlantıların, sembol bilgisini kazımak için gerekli şirket sayfalarını temsil ettiğini buldum. Son satır, temel URL dizesi ’http://www.loyal3.com` ile “/WALMART” gibi belirli şirket sayfalarını birleştirmek için paste0() kullanır. Örneğin, http://www.loyal3.com/WALMART:
loyal.links<-html_nodes(stocks, "a")
loyal.links<-html_attr(loyal.links, "href")
stock.links<-paste0('http://www.loyal3.com',loyal.links[54:123])
Her şirket sayfasında bir açıklama, son kapanış fiyatı ve sembol bulunur. Tüm şirket sayfaları aynı şekilde düzenlendiği için, sembolü çıkarmak için özel get.ticker() fonksiyonu kullanılabilir.
Bir şirketin web sayfasında “ticker-price” adlı bir tablo bulunur. Fonksiyon, bir şirket sayfasına gider, ilgili tabloyu belirler ve html_text() ile metni çıkarır. Son olarak, ^([[:alpha:]]*).* ve \\1 düzenli ifadesiyle birlikte sub() kullanmak, tüm alfabetik karakterleri korur. Sonuç olarak $, gibi özel karakterler ve kapanış fiyatı gibi sayısal karakterler kaldırılır. Fonksiyon 70 sayfanın her birini okurken yalnızca hisse sembolünü toplar.
get.ticker<-function(url){
x<-read_html(url)
x<-html_node(x,'.ticker-price')
x<-html_text(x)
x<-sub("^([[:alpha:]]*).*", "\\1", x)
return(x)
}
Özel fonksiyonunuzla donanmış olarak, her bir şirket sayfasını içeren stock.links’e pblapply() uygulayın. Ortaya çıkan stock.tickers nesnesi, her elemanı bir şirkete karşılık gelen tekil hisse sembollerinden oluşan bir listedir.
stock.tickers<-pblapply(stock.links,get.ticker)
Elemanlardan oluşan bir listeyi düz bir nesneye dönüştürmenin bir yolu do.call() ile olur. Burada, her liste elemanını tek bir vektörde satır birleştirmek için rbind uyguluyorsunuz. Son olarak, sembol ve şirket adı bilgileriyle bir veri çerçevesi oluşturuyorsunuz.
stock.ticks<-do.call(rbind,stock.tickers)
stock.ticks<-data.frame(symbol=stock.ticks,name=stocks.names)
Analizde tutarlı olmak için, her hisse için toplayacağınız geçmiş bilgi miktarını sınırlamak isteyebilirsiniz. Sys.Data() fonksiyonu, bir tarih nesnesini yıl, ay ve gün olarak saklar. Yılları bir tamsayı ile kullanmak, start.date nesnesinden belirli bir süre çıkarmanızın bir yoludur.
start.date<-Sys.Date()
end.date<-Sys.Date()-years(3)
Yahoo finance verilerini almak için, tarih nesnesinin tire içermeyen basit karakter nesnelerine dönüştürülmesi gerekir. Hem start.date hem de end.date üzerinde gsub() genel değiştirme fonksiyonunu kullanmak, sınıfı değiştirir ve aynı anda tireleri kaldırır. gsub() içinde, aranacak karakter desenini ve ardından yerine geçecek karakterleri geçin. Bu durumda, yerine geçecek desen tırnak içindeki boş karakterdir. Son parametre, gsub()’un uygulanacağı nesnedir.
start.date<-gsub('-','', start.date)
end.date<-gsub('-','', end.date)
TTR() paketindeki getYahooData() fonksiyonu bir hisse sembolü ile başlangıç ve bitiş tarihi kabul eder. Fonksiyon, zaman serisi bilgisi içeren bir veri çerçevesi döndürür. Her satır bir tarihtir ve sütunlarda bir hisse için “Açılış”, “Yüksek”, “Düşük” ve “Kapanış” fiyatları gibi bilgiler bulunur. Birden fazla şirketi sorguladığınız için lapply() veya pblapply() kullanabilirsiniz. Şirket sembollerinin vektörünü, ardından getYahooData() fonksiyonunu ve son olarak tarih bilgilerini geçin. date nesneleri, getYahooData() her hisse sembolüne uygulandığında her seferinde yeniden kullanılan parametrelerdir.
stocks.ts<-pblapply(stock.ticks$symbol,getYahooData,end.date, start.date)
Döndürülen stocks.ts listesini gezinmeyi kolaylaştırmak için liste elemanlarına ad ekleyebilirsiniz. stocks.ts nesnesiyle birlikte $symbol vektörünü adlar olarak atayın.
names(stocks.ts)<-stock.ticks$symbol
Büyük listelerle çalışırken, sonucun beklediğim gibi olduğundan emin olmak için ortaya çıkan nesneyi incelemeyi severim. Artık elemanların isimleri olduğuna göre, doğrudan referans verebilirsiniz. Bu örnekte AMC Entertainment Holdings (AMC) için ilk 6 satırı inceliyorsunuz. Listede $AMC’ye referans verirken head() kullanmak, bu hisse için zaman serisinin bir kısmını döndürecektir:
head(stocks.ts$AMC)
Hisse Verilerini İnceleme
Finans haberlerini dinlediğimde yorumcuların sıklıkla grafiklere atıfta bulunduğunu görüyorum. Yüksek frekanslı alım satım ve başkalarının yaptığı aktif yönetime rağmen, birçok küçük yatırımcı hâlâ içgörü kazanmak için grafiklere başvuruyor. Zaman serisi nesnesi, plot kullanılarak hızlıca gösterilebilir. $AMC gibi adlandırılmış elemana referans veren listeyi ve sonra göstermek istediğiniz sütunu, burada $Close, geçin.
plot(stocks.ts$AMZN$Close)

Yukarıdaki grafik statiktir ve pek ilgi çekici değildir.
Keşfedebileceğiniz bir grafik yapmak için bir JavaScript kütüphanesi kullanalım. Bu kod parçasında “%>%” ya da pipe operatörünü görebilirsiniz. Pipe operatörü, özlü kod yazmanın iyi bir yoludur. Bir nesneyi, bu yazının önceki kısımlarında yaptığınız gibi nesne adını yeniden yazmak zorunda bırakmadan bir sonraki fonksiyona iletir.
Bu örnekte, Twitter hissesine, $TWTR, ve ardından çizmek istediğiniz sütuna, $Close, referans vererek bir dygraph oluşturuyorsunuz. dygraph içinde, main tırnak içindeki başlığı ekler. “%>%” ile bu bütün nesne bir sonraki fonksiyon olan dyRangeSelector()’a iletilir. c() içinde başlangıç ve bitiş tarih aralığı belirterek varsayılan bir aralık belirleyebilirsiniz. Ortaya çıkan HTML nesnesi, altta bir tarih kaydırıcısı bulunan, Twitter hissesine ait dinamik bir zaman serisidir.
Unutmayın, gösterilen hisseyi değiştirmek için stocks.ts listesindeki sembolü ve ardından grafik başlığını değiştirin.
dygraph(stocks.ts$TWTR$Close, main = "TWTR Stock Price") %>%
dyRangeSelector(dateWindow = c("2013-12-18", "2016-12-30"))
Basit Bir Alım Satım Stratejisi: Trendi Takip Etme
Yüksek frekanslı alım satımcılar ve hedge fonları, işlemleri yürütmek için sofistike modeller ve kurala dayalı yaklaşımlar kullanır. Daha fazlasını öğrenmek isterseniz ileri düzey yaklaşımlar için www.quantopian.com’u ziyaret etmenizi öneririm. Daha basit yaklaşımlar için www.Investopedia.com’daki bu sayfayla başlayın.
Aşağıdaki kodda, basit bir momentum alım satım stratejisini görselleştireceksiniz. Temel olarak, bir hisse fiyatı için 200 ve 50 günlük hareketli ortalamaları hesaplamak istersiniz. 50 günlük hareketli ortalamanın 200 günlük hareketli ortalamanın üzerinde olduğu herhangi bir günde alım yapar ya da pozisyonunuzu korursunuz. 200 günlük ortalamanın 50 günlük ortalamadan yüksek olduğu günlerde ise hisselerinizi satarsınız. Bu stratejiye trendi takip etme stratejisi denir. Zaman temelli iki ortalama arasındaki pozitif ya da negatif ilişki, hissenin momentumunu temsil eder.
TTR paketi, basit hareketli ortalamayı hesaplamak için SMA() sunar. Bu kod parçasında, Twitter’ın 200 ve 50 günlük hareketli ortalamaları için ilk 6 değeri inceliyorsunuz. SMA(), bir hisse için zaman serisi verisini ve Close gibi belirli bir sütunu geçirerek çalışır. Bu, TWTR hissesine ait kapanış fiyatlarının tek boyutlu bir vektörüdür. İkinci parametre, hareketli ortalama için gözlem sayısını temsil eden bir tamsayıdır. head() kullanmadan SMA() fonksiyonu tüm değerleri döndürür.
head(SMA(stocks.ts$TWTR$Close, 200))
head(SMA(stocks.ts$TWTR$Close, 50))
Hareketli ortalama fonksiyonunu ayrıntılı olarak incelediğinize göre, bunu 70 hissenin her birine uygulamanız gerekir. stocks.ts, tek tek hisse verilerini içeren 70 veri çerçevesinden oluşan bir listedir. Her veri çerçevesinin dördüncü sütunu, hareketli ortalamalar için kullanmak istediğimiz kapanış fiyatını içerir.
mov.avgs() adlı özel fonksiyon, hareketli ortalamaları hesaplamak üzere tek bir hisse veri çerçevesini kabul eder. İlk satır, [,4] indekslediği için kapanış fiyatlarını seçerek stock.close’u oluşturur. Sonraki adımda fonksiyon, veri çerçevesindeki satır sayısını kontrol etmek için ifelse kullanır. Özellikle, veri çerçevesindeki nrow (2*260)’tan küçükse, fonksiyon “NA” içeren hareketli ortalamalar veri çerçevesi oluşturur.
Bu sayıyı seçtim; çünkü yılda yaklaşık 250 işlem günü vardır, bu da zaman serisinin yaklaşık 2 yıl veya daha uzun olup olmadığını kontrol eder. loyal3 bazen halka arzlara erişebildiğinden ve hisse yeni halka arz edilmişse 200 günlük hareketli ortalama için yeterli veri olmayacaktır. Ancak nrow değeri 2*260’tan büyükse, fonksiyon orijinal verilerle birlikte 200 ve 50 günlük hareketli ortalamaları yeni sütunlar olarak ekleyen bir veri çerçevesi oluşturur. colnames kullanarak sütun adlarını tanımlarım. Fonksiyonun son kısmı, 200 günlük hareketli ortalama sütununda değer olup olmadığını kontrol etmek için complete.cases kullanır. Değeri olmayan satırlar nihai sonuçtan çıkarılır.
mov.avgs<-function(stock.df){
stock.close<-stock.df[,4]
ifelse((nrow(stock.df)<(2*260)),
x<-data.frame(stock.df, 'NA', 'NA'),
x<-data.frame(stock.df, SMA(stock.close, 200), SMA(stock.close, 50)))
colnames(x)<-c(names(stock.df), 'sma_200','sma_50')
x<-x[complete.cases(x$sma_200),]
return(x)
}
Bu mov.avgs() fonksiyonu ile, 70 veri çerçevesinin her birine hareketli ortalama hesaplamalarını eklemek için pblapply() kullanabilirsiniz.
stocks.ts<-pblapply(stocks.ts, mov.avgs)
Bir hissenin hareketli ortalamalarını bir dygraph ile görselleştirmek için aşağıdaki kodu kullanın. Yine, bu kod nesneleri iletmek için “%>%” operatörünü kullanıyor. dygraph() fonksiyonu stocks.ts$FOX veri çerçevesini kabul eder. Özellikle, veri çerçevesi c('sma_200','sma_50') ile sütun adına göre indekslenir. Bu nesne sonraki 2 satırda dySeries()’e aktarılır. Bir sütuna adıyla referans verebilirsiniz; böylece dySeries() satır 2 ve 3’te “sma_50” ve “sma_200” değerleri için birer çizgi çizer. Bu nesne tekrar dyRangeSelector()’a iletilerek seçicinin yüksekliği ayarlanır. Son olarak, alım ya da elde tutmak isteyeceğiniz dönemleri ve pozisyonunuza bağlı olarak hisselerinizi satmanız ya da uzak durmanız gereken bir dönemi tanımlamak için biraz gölgeleme ekledim.
dygraph(stocks.ts$FOX[,c('sma_200','sma_50')],main = 'FOX Moving Averages') %>%
dySeries('sma_50', label = 'sma 50') %>%
dySeries('sma_200', label = 'sma 200') %>%
dyRangeSelector(height = 30) %>%
dyShading(from = '2016-4-28', to = '2016-7-27', color = '#CCEBD6') %>%
dyShading(from = '2016-7-28', to = '2016-12-30', color = '#FFE6E6')
İşte etkileşimli bir zaman serisi içindeki nihai sonuç.
Sonuç
Gelişmekte olan bir algoritmik alım satımcı olarak 70 hissenin tamamını çizmeniz gerekmez. Bunun yerine, kodu her gün çalıştırır ve “50 günlük hareketli ortalama 200 günlük hareketli ortalamanın üzerindeyse al” kuralına uyan hisseleri programatik olarak belirleme yolu eklersiniz. Yukarıdaki grafiği incelerken, yeşil bölüm FOX hissesini alacağınız zamanı gösterir. Kırmızı bölüm, hisselerinizi satmanız ve yeniden girmemeniz gereken zamanı temsil eder.
Grafik etkileşimli olduğundan, kaydırıcıyı kullanarak görselin boyutunu değiştirebilirsiniz. Bu basit algo alım satım yaklaşımına göre, şimdi FOX almak için iyi bir zaman olabilir! 30 Aralık 2016, 50 günlük hareketli ortalamanın 200 günlük hareketli ortalamadan $0,01 daha yukarı çıktığı bir işlem günüydü!
Elbette, tüm yatırımların değer kaybedebileceğini unutmayın. Finans ve algo alım satım hakkında daha fazla bilgi edinmek için DataCamp’in buradaki kurslarına göz atın.
R’de Temel Programlama Becerileri eğitimimize de göz atın.
