Otomatik Ticaretin Yükselişi: S&P 500'de Ticaret Yapan Makineler
Yayınlanan: 2022-03-11Günümüzde, farklı varlıklarla (hisse senetleri, endeks vadeli işlemleri, emtialar gibi) alım satım faaliyetlerinin yüzde 60'ından fazlası artık “insan” tüccarlar tarafından yapılmamakta, bunun yerine otomatik ticarete güvenmektedir. Uzun vadede pozitif bir getiri elde etmek amacıyla farklı pazarlarda varlıkları otomatik olarak alıp satan belirli algoritmalara dayalı özel programlar vardır.
Bu makalede, olumlu bir kazanç elde etmek için bir sonraki ticaretin nasıl yapılması gerektiğini iyi bir doğrulukla nasıl tahmin edeceğinizi göstereceğim. Bu örnek için, alım satım yapılacak temel varlık olarak, daha büyük sermayeli 500 ABD şirketinin ağırlıklı ortalaması olan S&P 500 endeksini seçtim. Uygulanması çok basit bir strateji, Wall Street Exchange işlem görmeye başladığında S&P 500 endeksini sabah 9:30'da satın almak ve kapanış seansında Doğu Saati ile 16:00'da satmaktır. Endeksin kapanış fiyatı açılış fiyatından yüksekse pozitif kazanç olurken, kapanış fiyatı açılış fiyatından düşükse negatif kazanç sağlanır. Öyleyse soru şudur: İşlem seansının açılış fiyatından daha yüksek bir kapanış fiyatıyla sonuçlanıp sonuçlanmayacağını nasıl bilebiliriz? Makine Öğrenimi, böylesine karmaşık bir görevi başarmak için güçlü bir araçtır ve ticaret kararlarımızda bizi desteklemek için yararlı bir araç olabilir.
Makine Öğrenimi, birçok faydalı gerçek yaşam uygulamasının yeni sınırıdır. Finansal ticaret bunlardan biridir ve bu sektörde çok sık kullanılmaktadır. Makine Öğrenimi ile ilgili önemli bir kavram, örüntü tanıma gibi her türlü olası kural için kod yazmamıza gerek olmamasıdır. Bunun nedeni, Makine Öğrenimi ile ilişkili her modelin verilerin kendisinden öğrenmesi ve daha sonra görünmeyen yeni verileri tahmin etmek için kullanılabilmesidir.
Sorumluluk Reddi : Bu makalenin amacı, Makine Öğrenimi yöntemlerinin nasıl eğitileceğini göstermektir ve verilen kod örneklerinde her işlev açıklanmamıştır. Bu makale, makalenin kapsamı dışında kalan bazı ayrıntılar eksik olduğundan, bir kişinin tüm kodu kopyalayıp yapıştırmasına ve sağlanan aynı testleri çalıştırmasına izin vermeyi amaçlamamaktadır. Ayrıca, temel Python bilgisi gereklidir. Makalenin temel amacı, finans sektöründeki alım ve satımları tahmin etmede makine öğreniminin nasıl etkili olabileceğine dair bir örnek göstermektir. Ancak gerçek para ile ticaret, para yönetimi ve risk yönetimi gibi birçok başka beceriye sahip olmak demektir. Bu makale “büyük resmin” sadece küçük bir parçası.
İlk Finansal Verilerinizi Otomatik Alım Satım Programınızı Oluşturma
Finansal verileri analiz etmek ve doğru ticareti tahmin etmek için ilk programınızı mı oluşturmak istiyorsunuz? Sana nasıl olduğunu göstereyim. Python for Machine Learning kodunu kullanacağım ve Yahoo Finance hizmetinden geçmiş verileri kullanacağız. Daha önce de belirtildiği gibi, tahminlerimizi yapmadan önce modeli eğitmek için tarihsel veriler gereklidir.
Başlamak için yüklememiz gerekiyor:
- Python ve özellikle IPython notebook kullanmanızı öneririm.
- Yahoo Finance Python paketi (tam adı
yahoo-finance
) terminal komutu aracılığıyla:pip install yahoo-finance
. - GraphLab adlı Machine Learning paketinin ücretsiz deneme sürümü. Bu kitaplığın faydalı belgelerini kontrol etmekten çekinmeyin.
GraphLab'ın yalnızca bir bölümünün açık kaynak, SFrame olduğunu unutmayın, bu nedenle kitaplığın tamamını kullanmak için bir lisansa ihtiyacımız var. Öğrenciler veya Kaggle yarışmalarına katılanlar için 30 günlük ücretsiz bir lisans ve ticari olmayan bir lisans vardır. Benim bakış açıma göre, GraphLab Create, verileri analiz etmek ve Makine Öğrenimi modellerini eğitmek için çok sezgisel ve kullanımı kolay bir kitaplıktır.
Python Kodunda Kazma
İnternetten finansal verilerin nasıl indirileceğini görmek için bazı Python kodlarını inceleyelim. Aşağıdaki kodu test etmek için IPython notebook kullanmanızı öneririm, çünkü IPython'un geleneksel bir IDE'ye kıyasla birçok avantajı vardır, özellikle kaynak kodu, yürütme kodunu, tablo verilerini ve grafikleri aynı belge üzerinde birleştirmemiz gerektiğinde. IPython not defterini kullanmak için kısa bir açıklama için lütfen IPython Not Defterine Giriş makalesine bakın.
Şimdi yeni bir IPython not defteri oluşturalım ve S&P 500 endeksinin geçmiş fiyatlarını indirmek için bir kod yazalım. Diğer araçları kullanmayı tercih ederseniz, tercih ettiğiniz IDE'de yeni bir Python projesiyle başlayabileceğinizi unutmayın.
import graphlab as gl from __future__ import division from datetime import datetime from yahoo_finance import Share # download historical prices of S&P 500 index today = datetime.strftime(datetime.today(), "%Y-%m-%d") stock = Share('^GSPC') # ^GSPC is the Yahoo finance symbol to refer S&P 500 index # we gather historical quotes from 2001-01-01 up to today hist_quotes = stock.get_historical('2001-01-01', today) # here is how a row looks like hist_quotes[0] {'Adj_Close': '2091.580078', 'Close': '2091.580078', 'Date': '2016-04-22', 'High': '2094.320068', 'Low': '2081.199951', 'Open': '2091.48999', 'Symbol': '%5eGSPC', 'Volume': '3790580000'}
Burada hist_quotes
, sözlüklerin bir listesidir ve her sözlük nesnesi, Open
, High
, Low
, Close
, Adj_close
, Volume
, Symbol
ve Date
değerlerine sahip bir işlem günüdür. Her işlem günü boyunca, fiyat genellikle Open
fiyatından başlayarak Close
fiyatına kadar değişir ve bir maksimum ve bir minimum değeri High
ve Low
değerlerine ulaşır. Bunu baştan sona okumamız ve en alakalı verilerin her birinin listelerini oluşturmamız gerekiyor. Ayrıca, veriler ilk başta en son değerlere göre sıralanmalıdır, bu nedenle onu tersine çevirmemiz gerekir:
l_date = [] l_open = [] l_high = [] l_low = [] l_close = [] l_volume = [] # reverse the list hist_quotes.reverse() for quotes in hist_quotes: l_date.append(quotes['Date']) l_open.append(float(quotes['Open'])) l_high.append(float(quotes['High'])) l_low.append(float(quotes['Low'])) l_close.append(float(quotes['Close'])) l_volume.append(int(quotes['Volume']))
İndirilen tüm alıntıları, yüksek düzeyde ölçeklenebilir sütun tabanlı bir veri çerçevesi olan ve sıkıştırılmış bir SFrame
nesnesine paketleyebiliriz. Avantajlarından biri de disk destekli olduğu için RAM miktarından daha büyük olabilmesidir. SFrame hakkında daha fazla bilgi edinmek için belgelere göz atabilirsiniz.
Öyleyse, tarihsel verileri depolayalım ve sonra kontrol edelim:
qq = gl.SFrame({'datetime' : l_date, 'open' : l_open, 'high' : l_high, 'low' : l_low, 'close' : l_close, 'volume' : l_volume}) # datetime is a string, so convert into datetime object qq['datetime'] = qq['datetime'].apply(lambda x:datetime.strptime(x, '%Y-%m-%d')) # just to check if data is sorted in ascending mode qq.head(3)
kapat | tarih saat | yüksek | düşük | açık | hacim |
1283.27 | 2001-01-02 00:00:00 | 1320.28 | 1276.05 | 1320.28 | 1129400000 |
1347.56 | 2001-01-03 00:00:00 | 1347.76 | 1274.62 | 1283.27 | 1880700000 |
1333.34 | 2001-01-04 00:00:00 | 1350.24 | 1329.14 | 1347.56 | 2131000000 |
Artık SFrame
yöntemi save
ile verileri diske aşağıdaki gibi kaydedebiliriz:
qq.save(“SP500_daily.bin”) # once data is saved, we can use the following instruction to retrieve it qq = gl.SFrame(“SP500_daily.bin/”)
Bakalım S&P 500 Nasıl Görünüyor?
Yüklenen S&P 500 verilerinin nasıl görüneceğini görmek için aşağıdaki kodu kullanabiliriz:
import matplotlib.pyplot as plt %matplotlib inline # only for those who are using IPython notebook plt.plot(qq['close'])
Kodun çıktısı aşağıdaki grafiktir:
Bazı Makine Öğrenimi Modellerinin Eğitimi
Sonuç Ekleme
Bu yazının giriş kısmında belirttiğim gibi her modelin amacı kapanış fiyatının açılış fiyatından daha yüksek olup olmayacağını tahmin etmektir. Dolayısıyla, bu durumda, dayanak varlığı satın alırken pozitif bir getiri elde edebiliriz. Bu nedenle, verilerimize target
veya predicted
değişken olacak bir outcome
sütunu eklememiz gerekiyor. Bu yeni sütunun her satırı şöyle olacaktır:
-
Closing
fiyatıOpening
fiyatından yüksek olan bir Yukarı gün için+1
. -
-1
Closing
fiyatıOpening
fiyatından daha düşük olan bir Aşağı gün için.
# add the outcome variable, 1 if the trading session was positive (close>open), 0 otherwise qq['outcome'] = qq.apply(lambda x: 1 if x['close'] > x['open'] else -1) # we also need to add three new columns 'ho' 'lo' and 'gain' # they will be useful to backtest the model, later qq['ho'] = qq['high'] - qq['open'] # distance between Highest and Opening price qq['lo'] = qq['low'] - qq['open'] # distance between Lowest and Opening price qq['gain'] = qq['close'] - qq['open']
Son işlem gününden birkaç gün önce değerlendirme yapmamız gerektiğinden, verileri bir veya daha fazla gün geciktirmemiz gerekiyor. Bu tür bir gecikme işlemi için, GraphLab paketinden TimeSeries
adlı başka bir nesneye ihtiyacımız var. TimeSeries
, verileri belirli sayıda satır geride bırakan bir yöntem shift
sahiptir.
ts = gl.TimeSeries(qq, index='datetime') # add the outcome variable, 1 if the bar was positive (close>open), 0 otherwise ts['outcome'] = ts.apply(lambda x: 1 if x['close'] > x['open'] else -1) # GENERATE SOME LAGGED TIMESERIES ts_1 = ts.shift(1) # by 1 day ts_2 = ts.shift(2) # by 2 days # ...etc.... # it's an arbitrary decision how many days of lag are needed to create a good forecaster, so # everyone can experiment by his own decision
Tahminci Ekleme
Tahminciler , modeli eğitmek ve sonucumuzu tahmin etmek için seçilmesi gereken bir dizi özellik değişkenidir . Bu nedenle, tahmin faktörü seçimi, tahmincinin en önemli bileşeni olmasa da çok önemlidir.
Sadece birkaç örnek vermek gerekirse, dikkate alınması gereken bir faktör, bugünün kapanışının dünkü kapanıştan daha yüksek olup olmadığı ve bunun önceki iki günün kapanışıyla uzatılabileceği vb. olabilir. Benzer bir seçim aşağıdaki kodla çevrilebilir:
ts['feat1'] = ts['close'] > ts_1['close'] ts['feat2'] = ts['close'] > ts_2['close']
Yukarıda gösterildiği gibi, karşılaştırma doğruysa 1
, aksi takdirde 0
içeren veri kümemize ( ts
) feat1
ve feat2
olmak üzere iki yeni özellik sütunu ekledim.
Bu makale, Finans sektörüne uygulanan bir Makine Öğrenimi örneği vermeyi amaçlamaktadır. Makine Öğrenimi modellerinin finansal verilerle nasıl kullanılabileceğine odaklanmayı tercih ediyorum ve modelleri eğitmek için doğru faktörlerin nasıl seçileceğine ilişkin ayrıntılara girmeyeceğiz. Karmaşıklığın önemli ölçüde artması nedeniyle, belirli faktörlerin neden diğerlerine göre kullanıldığını açıklamak çok ayrıntılıdır. Benim iş araştırmam, iyi bir tahmin edici oluşturmak için faktörlerin seçilmesine ilişkin birçok hipotezi incelemektir. Bu nedenle başlangıç olarak, modelin doğruluğunu artırıp artıramayacaklarını görmek için birçok farklı faktör kombinasyonunu denemenizi öneririm.
# add_features is a helper function, which is out of the scope of this article, # and it returns a tuple with: # ts: a timeseries object with, in addition to the already included columns, also lagged columns # as well as some features added to train the model, as shown above with feat1 and feat2 examples # l_features: a list with all features used to train Classifier models # l_lr_features: a list all features used to train Linear Regression models ts, l_features, l_lr_features = add_features(ts) # add the gain column, for trading operations with LONG only positions. # The gain is the difference between Closing price - Opening price ts['gain'] = ts['close'] - ts['open'] ratio = 0.8 # 80% of training set and 20% of testing set training = ts.to_sframe()[0:round(len(ts)*ratio)] testing = ts.to_sframe()[round(len(ts)*ratio):]
Karar Ağacı Modeli Eğitimi
GraphLab Create, Machine Learning modellerini uygulamak için çok temiz bir arayüze sahiptir. Her modelin, modele bir eğitim veri seti uydurmak için kullanılan bir create
yöntemi vardır. Tipik parametreler şunlardır:
-
training
- özellik sütunları ve bir hedef sütunu içeren bir eğitim setidir. -
target
- hedef değişkeni içeren sütunun adıdır. -
validation_set
- modelin genelleme performansını izlemek için bir veri kümesidir. Bizim durumumuzdavalidation_set
yok. -
features
- modeli eğitmek için kullanılan özelliklerin sütun adlarının bir listesidir. -
verbose
-true
, eğitim sırasında ilerleme bilgilerini yazdırın.
Diğer parametreler modelin kendisine özgüdür, örneğin:
-
max_depth
- bir ağacın maksimum derinliğidir.
Aşağıdaki kod ile karar ağacımızı oluşturuyoruz:
max_tree_depth = 6 decision_tree = gl.decision_tree_classifier.create(training, validation_set=None, target='outcome', features=l_features, max_depth=max_tree_depth, verbose=False)
Takılan Modelin Performansını Ölçme
Doğruluk , tahmincinin iyiliğini değerlendirmek için önemli bir ölçümdür. Toplam veri noktalarının sayısına bölünen doğru tahminlerin sayısıdır. Model eğitim verileriyle donatıldığından, eğitim seti ile değerlendirilen doğruluk, bir test seti ile elde edilenden daha iyidir.
Kesinlik , pozitif olan pozitif tahminlerin oranıdır. "Mükemmel" bir kazanma oranı elde etmek için 1
yakın bir sayı olmak için hassasiyete ihtiyacımız var. GraphLab Create paketinden başka bir sınıflandırıcı olarak decision_tree
, uygun modelin birçok önemli metriğini elde etmek için kendi yöntemini evaluate
.
Geri çağırma , bir sınıflandırıcının olumlu örnekleri tahmin etme yeteneğini ölçer. Geri çağırma, rastgele seçilen bir pozitif örneğin sınıflandırıcı tarafından doğru olarak tanımlanma olasılığı olarak yorumlanabilir. "Mükemmel" bir kazanma oranı elde etmek için kesinliğin 1
yakın bir sayı olmasına ihtiyacımız var.
Aşağıdaki kod, hem eğitim seti hem de test seti ile takılan modelin doğruluğunu gösterecektir:
decision_tree.evaluate(training)['accuracy'], decision_tree.evaluate(testing)['accuracy'] (0.6077348066298343, 0.577373211963589)
Yukarıda gösterildiği gibi, test seti ile modelin doğruluğu yaklaşık yüzde 57'dir, bu da bir şekilde yazı tura atmaktan (yüzde 50) daha iyidir.
Verileri Tahmin Etme
GraphLab Create, farklı takılan modellerden verileri tahmin etmek için aynı arayüze sahiptir. Hedef outcome
tahmin etmek için bir test setine ihtiyaç duyan predict
yöntemini bizim durumumuzda kullanacağız. Şimdi, test setinden verileri tahmin edebiliriz:
predictions = decision_tree.predict(testing) # and we add the predictions column in testing set testing['predictions'] = predictions # let's see the first 10 predictions, compared to real values (outcome column) testing[['datetime', 'outcome', 'predictions']].head(10)
tarih saat | sonuç | tahminler |
2013-04-05 00:00:00 | -1 | -1 |
2013-04-08 00:00:00 | 1 | 1 |
2013-04-09 00:00:00 | 1 | 1 |
2013-04-10 00:00:00 | 1 | -1 |
2013-04-11 00:00:00 | 1 | -1 |
2013-04-12 00:00:00 | -1 | -1 |
2013-04-15 00:00:00 | -1 | 1 |
2013-04-16 00:00:00 | 1 | 1 |
2013-04-17 00:00:00 | -1 | -1 |
2013-04-18 00:00:00 | -1 | 1 |
Yanlış pozitifler , modelin pozitif bir sonuç öngördüğü, ancak test setinden elde edilen gerçek sonucun negatif olduğu durumlardır. Tersine, Yanlış negatifler , test setinden elde edilen gerçek sonucun pozitif olduğu durumlarda modelin negatif bir sonuç öngördüğü durumlardır.
Ticaret stratejimiz, S&P 500'ü Opening
fiyatından satın almak ve Closing
fiyatından satmak için pozitif tahmin edilen bir sonucu bekler, bu nedenle umudumuz kayıpları önlemek için en düşük Yanlış pozitif oranına sahip olmaktır. Başka bir deyişle, modelimizin en yüksek kesinlik oranına sahip olmasını bekliyoruz.
Gördüğümüz gibi, tahmin edilen ilk on değer içinde iki yanlış negatif (2013-04-10 ve 2013-04-11) ve iki yanlış pozitif (2013-04-15 ve 2013-04-18) vardır. test seti.
Basit bir hesaplamayla, bu küçük on tahmin kümesini göz önünde bulundurarak:
- doğruluk = 6/10 = 0,6 veya %60
- kesinlik =3/5 = 0,6 veya %60
- hatırlama = 3/5 = 0,6 veya %60
Genellikle yukarıdaki sayıların birbirinden farklı olduğunu, ancak bu durumda aynı olduklarını unutmayın.
Modeli Geri Test Etme
Şimdi, modelin tahmin edilen değerlerini kullanarak nasıl işlem yapacağını simüle ediyoruz. Tahmin edilen sonuç +1
eşitse, bir Yukarı gün beklediğimiz anlamına gelir. Yukarı gün ile seans başında endeksi alırız ve aynı gün içinde seans sonunda endeksi satarız. Tersine, tahmin edilen sonuç -1
eşitse, bir Aşağı gün bekleriz, bu nedenle o gün boyunca ticaret yapmayacağız.
Bu örnekte, yuvarlak dönüş olarak da adlandırılan eksiksiz bir günlük ticaret için Kar ve Zarar ( pnl
) şu şekilde verilmiştir:
-
pnl = Close - Open
(her işlem günü için)
Aşağıda gösterilen kodla, kümülatif kazanç eğrisi (eşitlik eğrisi) ile bir grafik oluşturmak için plot_equity_chart
yardımcı fonksiyonunu çağırıyorum. Çok derine inmeden, sadece bir dizi kar ve zarar değeri alır ve çizilecek kümülatif toplamlar dizisini hesaplar.
pnl = testing[testing['predictions'] == 1]['gain'] # the gain column contains (Close - Open) values # I have written a simple helper function to plot the result of all the trades applied to the # testing set and represent the total return expressed by the index basis points # (not expressed in dollars $) plot_equity_chart(pnl,'Decision tree model')
Mean of PnL is 1.843504 Sharpe is 1.972835 Round turns 511
Burada Sharpe, ticaret modelinin iyiliğinin önemli bir göstergesi olan Yıllık Sharpe oranıdır.
Gün gün ifade edilen işlemler göz önüne alındığında, mean
, kar ve zarar listesinin ortalamasıdır ve sd
, standart sapmadır. Yukarıda gösterilen formülde basitlik için, 0'a eşit risksiz bir getiri düşündüm.
Ticaret Hakkında Bazı Temel Bilgiler
Endeksin ticareti, doğrudan endeksten türetilen bir varlığın satın alınmasını gerektirir. Birçok broker, S&P 500 endeksini, iki taraf arasında bir sözleşmenin açılış fiyatı ile kapanış fiyatı arasındaki farkı değiştirmek için yapılan bir anlaşma olan CFD (Fark Sözleşmesi) adlı bir türev ürünle çoğaltır.
Örnek : Open
1 CFD S&P 500 satın alın (değer 2000), Günün Close
sat (değer 2020). Fark, dolayısıyla kazanç, 20 puandır. Her noktanın değeri 25$ ise:
- 1 CFD sözleşmesi ile Brüt Kazanç
20 points x $25 = $500
dır.
Diyelim ki komisyoncu kendi geliri için 0,6 puanlık bir kayma tuttu:
- Net kazanç
(20 - 0.6) points x $25 = $485
dır.
Dikkate alınması gereken bir diğer önemli husus, bir ticarette önemli kayıplardan kaçınmaktır. Tahmin edilen sonuç +1
olduğunda ancak gerçek sonuç değeri -1
olduğunda meydana gelebilirler, bu nedenle yanlış bir pozitiftir . Bu durumda, kapanış seansı açılış fiyatından daha düşük bir kapanış fiyatına sahip bir Down gün olur ve bir zarar alırız.

Bir ticarette tahammül edebileceğimiz maksimum kayba karşı koruma sağlamak için bir zararı durdur emri verilmelidir ve böyle bir emir, varlığın fiyatı daha önce belirlediğimiz sabit bir değerin altına düştüğünde tetiklenir.
Bu makalenin başında Yahoo Finance'den indirilen zaman serilerine bakarsak, her gün o gün içinde ulaşılan en düşük fiyat olan Low
bir fiyat vardır. Opening
fiyatından -3
puan uzakta bir stop seviyesi belirlersek ve Low - Open = -5
stop emri tetiklenir ve açılan pozisyon -5
yerine -3
puan kayıpla kapatılır. Bu riski azaltmak için basit bir yöntemdir. Aşağıdaki kod, durdurma seviyesi olan bir ticareti simüle etmek için yardımcı işlevimi temsil eder:
# This is a helper function to trade 1 bar (for example 1 day) with a Buy order at opening session # and a Sell order at closing session. To protect against adverse movements of the price, a STOP order # will limit the loss to the stop level (stop parameter must be a negative number) # each bar must contains the following attributes: # Open, High, Low, Close prices as well as gain = Close - Open and lo = Low - Open def trade_with_stop(bar, slippage = 0, stop=None): """ Given a bar, with a gain obtained by the closing price - opening price it applies a stop limit order to limit a negative loss If stop is equal to None, then it returns bar['gain'] """ bar['gain'] = bar['gain'] - slippage if stop<>None: real_stop = stop - slippage if bar['lo']<=stop: return real_stop # stop == None return bar['gain']
Ticaret Maliyetleri
İşlem maliyetleri, menkul kıymetleri alırken veya satarken katlanılan giderlerdir. İşlem maliyetleri, komisyoncu komisyonlarını ve spreadleri (krupiyenin bir menkul kıymet için ödediği fiyat ile alıcının ödediği fiyat arasındaki fark) içerir ve gerçek bir senaryoya benzer şekilde stratejimizi geriye dönük test etmek istiyorsak, bunların dikkate alınması gerekir. Hisse senedi ticaretinde kayma, genellikle spreadde bir değişiklik olduğunda meydana gelir. Bu örnekte ve sonraki devam eden simülasyonlar için ticaret maliyetleri şu şekilde sabitlenmiştir:
- Kayma = 0,6 puan
- Komisyon = her işlem için 1$ (bir tur 2$'a mal olacak)
Sadece bazı rakamlar yazmak gerekirse, brüt kazancımız 10 puan, 1 puan = 25$, yani alım satım maliyetleri dahil 250$ olsaydı, net kazancımız (10 - 0.6)*$25 - 2 = $233
olurdu.
Aşağıdaki kod, -3 puanlık stop loss ile önceki ticaret stratejisinin bir simülasyonunu göstermektedir. Mavi eğri, birikimli getirilerin eğrisidir. Hesaplanan tek maliyet kaymadır (0,6 puan) ve sonuç baz puan olarak ifade edilir (Yahoo Finance'ten indirilen S&P 500 değerlerinin aynı temel birimi).
SLIPPAGE = 0.6 STOP = -3 trades = testing[testing['predictions'] == 1][('datetime', 'gain', 'ho', 'lo', 'open', 'close')] trades['pnl'] = trades.apply(lambda x: trade_with_stop(x, slippage=SLIPPAGE, stop=STOP)) plot_equity_chart(trades['pnl'],'Decision tree model') print("Slippage is %s, STOP level at %s" % (SLIPPAGE, STOP))
Mean of PnL is 2.162171 Sharpe is 3.502897 Round turns 511 Slippage is 0.6 STOP level at -3
Aşağıdaki kod, biraz farklı bir şekilde tahmin yapmak için kullanılır. Lütfen output_type = “probability”
ek parametresiyle çağrılan predict
yöntemine dikkat edin. Bu parametre, sınıf tahminleri yerine tahmin edilen değerlerin olasılıklarını döndürmek için kullanılır (pozitif tahmin edilen bir sonuç için +1
, negatif olarak tahmin edilen bir sonuç için -1
). 0.5
eşit veya daha büyük bir olasılık, +1
tahmini değeriyle ve 0.5
küçük bir olasılık değeri, -1
tahmini değeriyle ilişkilendirilir. Bu olasılık ne kadar yüksek olursa, gerçek bir Yukarı Günü tahmin etme şansımız o kadar artar.
predictions_prob = decision_tree.predict(testing, output_type = 'probability') # predictions_prob will contain probabilities instead of the predicted class (-1 or +1)
Şimdi, kayma ve komisyonlar da dahil olmak üzere kümülatif getiri serilerini hesaplayan ve değerlerini backtest_ml_model
adlı bir yardımcı fonksiyonla modeli geriye dönük test ediyoruz. Kısaca, backtest_ml_model
işlevini tam olarak açıklamadan, vurgulanması gereken önemli ayrıntı, önceki örnekte yaptığımız gibi o günleri tahmini bir outcome = 1
ile filtrelemek yerine, şimdi bu predictions_prob
bir threshold = 0.5
eşit veya daha büyük filtreliyoruz, aşağıdaki gibi:
trades = testing[predictions_prob>=0.5][('datetime', 'gain', 'ho', 'lo', 'open', 'close')]
Her işlem gününün Net kazancının şu olduğunu unutmayın: Net gain = (Gross gain - SLIPPAGE) * MULT - 2 * COMMISSION
.
Bir ticaret stratejisinin iyiliğini değerlendirmek için kullanılan bir diğer önemli ölçü, Maksimum Düşüştür . Genel olarak, yatırım yapılan bir portföyün değerinde zirveden dibe doğru en büyük tek düşüşü ölçer. Bizim durumumuzda, öz sermaye eğrisinin tepe noktasından en altına doğru en önemli düşüştür (portföyümüzde sadece bir varlığımız var, S&P 500). Bu nedenle, bir SArray
kar ve zarar pnl
, düşüşü şu şekilde hesaplarız:
drawdown = pnl - pnl.cumulative_max() max_drawdown = min(drawdown)
Yardımcı işlevin içinde backtest_summary
hesaplanır:
- Yukarıda gösterildiği gibi maksimum düşüş (dolar cinsinden).
- Doğruluk,
Graphlab.evaluation
yöntemiyle. -
Graphlab.evaluation
yöntemiyle kesinlik. -
Graphlab.evaluation
yöntemiyle hatırlayın.
Hepsini bir araya getirirsek, aşağıdaki örnek, model stratejisinin kümülatif getirilerini temsil eden öz sermaye eğrisini gösterir ve tüm değerler dolar cinsinden ifade edilir.
model = decision_tree predictions_prob = model.predict(testing, output_type="probability") THRESHOLD = 0.5 bt_1_1 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_1)
Mean of PnL is 54.054286 Sharpe is 3.502897 Round turns 511 Name: DecisionTree Accuracy: 0.577373211964 Precision: 0.587084148728 Recall: 0.724637681159 Max Drawdown: -1769.00025
Tahmin edilen değerlerin kesinliğini artırmak için, standart 0.5
(yüzde 50) olasılık yerine daha yüksek bir eşik değeri seçiyoruz ve modelin bir Yukarı gün tahmin ettiğinden daha emin oluyoruz.
THRESHOLD = 0.55 # it's the minimum threshold to predict an Up day so hopefully a good day to trade bt_1_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, MULT=25, SLIPPAGE=0.6, COMMISSION=1, plot_title='DecisionTree') backtest_summary(bt_1_2)
Mean of PnL is 118.244689 Sharpe is 6.523478 Round turns 234 Name: DecisionTree Accuracy: 0.560468140442 Precision: 0.662393162393 Recall: 0.374396135266 Max Drawdown: -1769.00025
Yukarıdaki grafikte görebileceğimiz gibi, öz sermaye eğrisi daha az yuvarlak dönüşle bile eskisinden çok daha iyi (Sharp 3,5 yerine 6,5'tir).
Bu noktadan sonra, standart bir değerden daha yüksek bir eşiği olan sonraki tüm modelleri ele alacağız.
Lojistik Sınıflandırıcı Eğitimi
Daha önce karar ağacında yaptığımız gibi araştırmamızı bir Lojistik Sınıflandırıcı modeline uygulayabiliriz. GraphLab Create, Logistic Classifier nesnesiyle aynı arayüze sahiptir ve aynı parametre listesiyle modelimizi oluşturmak için create
yöntemini çağıracağız. Ayrıca, tahmin edilen sınıf vektörü (olumlu bir sonuç için +1
ve olumsuz bir sonuç için -1
oluşur) yerine olasılık vektörünü tahmin etmeyi tercih ederiz, bu nedenle, daha iyi bir kesinlik elde etmek için 0.5
büyük bir eşiğimiz olur. tahmin.
model = gl.logistic_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_2_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_2_2)
Mean of PnL is 112.704215 Sharpe is 6.447859 Round turns 426 Name: LogisticClassifier Accuracy: 0.638491547464 Precision: 0.659624413146 Recall: 0.678743961353 Max Drawdown: -1769.00025
Bu durumda Karar Ağacına çok benzeyen bir özet var. Sonuçta, her iki model de sınıflandırıcıdır, yalnızca bir ikili sonuç sınıfını tahmin ederler ( +1
, -1
).
Doğrusal Regresyon Modeli Eğitimi
Bu modelin temel farkı, daha önce bahsedildiği gibi ikili sınıflar yerine sürekli değerlerle uğraşmasıdır. Modeli Up günler için +1
ve Down günler için -1
hedef değişkeni ile eğitmemize gerek yok, hedefimiz sürekli bir değişken olmalıdır. Olumlu bir kazanç, yani Açılış fiyatından daha yüksek bir Kapanış fiyatı tahmin etmek istediğimiz için, artık hedef, eğitim setimizin kazanç sütunu olmalıdır. Ayrıca, özellikler listesi, önceki Open
, Close
vb. gibi sürekli değerlerden oluşmalıdır.
Kısaca, doğru özelliklerin nasıl seçileceğinin ayrıntılarına girmeyeceğim, çünkü bu, bir veri kümesi üzerinde farklı Makine Öğrenimi modellerini nasıl uygulamamız gerektiğini göstermeye daha meyilli olan bu makalenin kapsamı dışındadır. Create yöntemine iletilen parametrelerin listesi şunlardır:
-
training
- özellik sütunları ve bir hedef sütunu içeren bir eğitim setidir. -
target
- hedef değişkeni içeren sütunun adıdır. -
validation_set
- modelin genelleme performansını izlemek için bir veri kümesidir. Bizim durumumuzdavalidation_set
yok. -
features
- modeli eğitmek için kullanılan özelliklerin sütun adlarının bir listesidir, bu model için Sınıflandırıcı modellerine göre başka bir küme kullanacağız. -
verbose
-true
ise, eğitim sırasında ilerleme bilgilerini yazdırır. -
max_iterations
- verilerde izin verilen maksimum geçiş sayısıdır. Veriler üzerinden daha fazla geçiş, daha doğru bir şekilde eğitilmiş bir modelle sonuçlanabilir.
model = gl.linear_regression.create(training, target='gain', features = l_lr_features, validation_set=None, verbose=False, max_iterations=100) predictions = model.predict(testing) # a linear regression model, predict continuous values, so we need to make an estimation of their # probabilities of success and normalize all values in order to have a vector of probabilities predictions_max, predictions_min = max(predictions), min(predictions) predictions_prob = (predictions - predictions_min)/(predictions_max - predictions_min)
Şimdiye kadar, tahmin edilen kazançların SArray
olan tahminlerimiz varken, predictions_prob
, predictions
değerleri normalleştirilmiş SArray
. İyi bir doğruluk ve belirli sayıda yuvarlak dönüş elde etmek için önceki modellerle karşılaştırılabilir bir eşik değeri seçtim 0.4
. 0.4
küçük bir predictions_prob
için, bir Aşağı gün beklendiği için backtest_linear_model
yardımcı işlevi bir işlem açmaz. Aksi takdirde, bir ticaret açılacaktır.
THRESHOLD = 0.4 bt_3_2 = backtest_linear_model(testing, predictions_prob, target='gain', threshold=THRESHOLD, STOP = -3, plot_title=model.name()) backtest_summary(bt_3_2)
Mean of PnL is 138.868280 Sharpe is 7.650187 Round turns 319 Name: LinearRegression Accuracy: 0.631989596879 Precision: 0.705329153605 Recall: 0.54347826087 Max Drawdown: -1769.00025
Güçlendirilmiş Ağaç Eğitimi
Daha önce bir karar ağacını eğittiğimiz gibi, şimdi diğer sınıflandırıcı modelleri için kullanılan aynı parametrelerle güçlendirilmiş bir ağaç sınıflandırıcıyı eğiteceğiz. Ek olarak, artırma için maksimum yineleme sayısını artırmak için max_iterations = 12
olarak ayarladık. Her yineleme, fazladan bir ağacın oluşturulmasıyla sonuçlanır. Ayrıca hassasiyeti artırmak için 0.5
daha yüksek bir eşik değeri belirledik.
model = gl.boosted_trees_classifier.create(training, target='outcome', features=l_features, validation_set=None, max_iterations=12, verbose=False) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.7 bt_4_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_4_2)
Mean of PnL is 112.002338 Sharpe is 6.341981 Round turns 214 Name: BoostedTreesClassifier Accuracy: 0.563068920676 Precision: 0.682242990654 Recall: 0.352657004831 Max Drawdown: -1769.00025
Rastgele Orman Eğitimi
Bu bizim son eğitilmiş modelimizdir, bir karar ağaçları topluluğu tarafından oluşturulan bir Rastgele Orman Sınıflandırıcısı. Modelde kullanılacak maksimum ağaç sayısı, çok fazla karmaşıklığı ve fazla uydurmayı önlemek için num_trees = 10
olarak ayarlanmıştır.
model = gl.random_forest_classifier.create(training, target='outcome', features=l_features, validation_set=None, verbose=False, num_trees = 10) predictions_prob = model.predict(testing, 'probability') THRESHOLD = 0.6 bt_5_2 = backtest_ml_model(testing, predictions_prob, target='outcome', threshold=THRESHOLD, STOP=-3, plot_title=model.name()) backtest_summary(bt_5_2)
Mean of PnL is 114.786962 sharpe is 6.384243 Round turns 311 Name: RandomForestClassifier Accuracy: 0.598179453836 Precision: 0.668810289389 Recall: 0.502415458937 Max Drawdown: -1769.00025
Collecting All the Models Together
Now we can join all the strategies together and see the overall result. It's interesting to see the summary of all Machine Learning models, sorted by their precision.
name | accuracy | precision | round turns | sharpe |
LinearRegression | 0.63 | 0.71 | 319 | 7.65 |
BoostedTreesClassifier | 0,56 | 0.68 | 214 | 6.34 |
RandomForestClassifier | 0.60 | 0.67 | 311 | 6.38 |
DecisionTree | 0,56 | 0.66 | 234 | 6.52 |
LogisticClassifier | 0.64 | 0.66 | 426 | 6.45 |
If we collect all the profit and loss for each one of the previous models in the array pnl
, the following chart depicts the equity curve obtained by the sum of each profit and loss, day by day.
Mean of PnL is 119.446463 Sharpe is 6.685744 Round turns 1504 First trading day 2013-04-09 Last trading day 2016-04-22 Total return 179647
Just to give some numbers, with about 3 years of trading, all models have a total gain of about 180,000 dollars. The maximum exposition is 5 CFD contracts in the market, but to reduce the risk they all are closed at the end of each day, so overnight positions are not allowed.
Statistics of the Aggregation of All Models Together
Since each model can open a trade, but we added 5 concurrent models together, during the same day there could be from 1 contract up to 5 CFD contracts. If all models agree to open trades during the same day, there is a high chance to have an Up day predicted. Moreover, we can group by the number of models that open a trade at the same time during the opening session of the day. Then we evaluate precision as a function of the number of concurrent models.
As we can see by the chart depicted above, the precision gets better as the number of models do agree to open a trade. The more models agree, the more precision we get. For instance, with 5 models triggered the same day, the chance to predict an Up day is greater than 85%.
Çözüm
Even in the financial world, Machine Learning is welcomed as a powerful instrument to learn from data and give us great forecasting tools. Each model shows different values of accuracy and precision, but in general, all models can be aggregated to achieve a better result than each one of them taken singularly. GraphLab Create is a great library, easy to use, scalable and able to manage Big Data very quickly. It implements different scientific and forecasting models, and there is a free license for students and Kaggle competitions.
Additional disclosure: This article has been prepared solely for information purposes, and is not an offer to buy or sell or a solicitation of an offer to buy or sell any security or instrument or to participate in any particular trading strategy. Examples presented on these sites are for educational purposes only. Past results are not necessarily indicative of future results.