Perdagangan berpasangan berdasarkan teknologi yang didorong data

Penulis:Kebaikan, Dicipta: 2019-08-21 13:50:23, Dikemas kini: 2023-10-19 21:01:31

img

Perdagangan berpasangan adalah contoh yang baik untuk membuat strategi dagangan berdasarkan analisis matematik. Dalam artikel ini, kami akan menunjukkan bagaimana menggunakan data untuk membuat dan mengotomatiskan strategi dagangan berpasangan.

Prinsip asas

假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.

Apabila terdapat perbezaan harga sementara, perdagangan akan menjual matawang pelabur yang berprestasi baik (matawang pelabur yang meningkat) dan membeli matawang pelabur yang berprestasi buruk (matawang pelabur yang menurun). Anda pasti bahawa perbezaan keuntungan antara kedua-dua matawang pelabur akhirnya akan berlaku melalui penurunan matawang pelabur yang berprestasi baik atau pemulihan matawang pelabur yang berprestasi buruk atau kedua-duanya. Dagangan anda akan menghasilkan wang dalam semua senario yang sama.

Oleh itu, perdagangan berpasangan adalah strategi perdagangan netral pasaran yang membolehkan peniaga mendapat keuntungan daripada hampir semua keadaan pasaran: tren menaik, tren menurun, atau penyesuaian merata.

Konsep penafsiran: dua tanda pelaburan yang diandaikan

  • Kami membina persekitaran penyelidikan kami di platform pencipta kuantiti.

Pertama sekali, untuk kerja berjalan lancar, kita perlu membina persekitaran penyelidikan kita, dan dalam artikel ini kita menggunakan platform kuantitatif pencipta.FMZ.COMPerisian ini digunakan untuk membina persekitaran penyelidikan, terutamanya untuk menggunakan API yang mudah dan cepat untuk platform ini dan pembungkusan sistem Docker yang lengkap.

Dalam nama rasmi platform kuantiti pencipta, sistem Docker ini dikenali sebagai sistem hosts.

Untuk maklumat mengenai cara menggunakan pentadbir dan bot, sila rujuk artikel saya sebelum ini:https://www.fmz.com/bbs-topic/4140

Untuk pembaca yang ingin membeli pelayan pelayaran pelayaran awan mereka sendiri, lihat artikel ini:https://www.fmz.com/bbs-topic/2848

Selepas berjaya menggunakan perkhidmatan dan sistem pentadbir awan yang baik, seterusnya kita akan memasang python terbesar: Anaconda

Untuk mewujudkan semua persekitaran program yang berkaitan yang diperlukan untuk artikel ini (dependencies, version management, dan lain-lain), cara yang paling mudah adalah dengan menggunakan Anaconda. Ia adalah ekosistem sains data Python yang terbungkus dan pengurus perpustakaan bergantung.

Untuk cara memasang Anaconda, sila lihat panduan rasmi Anaconda:https://www.anaconda.com/distribution/

本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.

Kerja-kerja asas di atas juga boleh dirujuk ke artikel saya sebelumnya mengenai cara menyediakan persekitaran Anaconda dan perpustakaan kedua-dua, numpy dan pandas, untuk maklumat lanjut:https://www.fmz.com/digest-topic/4169

Seterusnya, mari kita gunakan kod untuk mewujudkan "dua hipotesis modal".

import numpy as np
import pandas as pd

import statsmodels
from statsmodels.tsa.stattools import coint
# just set the seed for the random number generator
np.random.seed(107)

import matplotlib.pyplot as plt

Ya, kita juga akan menggunakan perpustakaan grafik dalam Python yang sangat terkenal, matplotlib.

Mari kita hasilkan X dari satu indikator pelaburan yang diandaikan dan simulasi pulangan harian dengan pembahagian normal. Kemudian kita melakukan pengumpulan untuk mendapatkan nilai X harian.

# Generate daily returns
Xreturns = np.random.normal(0, 1, 100) 
# sum them and shift all the prices up
X = pd.Series(np.cumsum(
    Xreturns), name='X') 
    + 50
X.plot(figsize=(15,7))
plt.show()

img

X tanda pelaburan, dengan pembahagian normal untuk mensimulasikan pengembalian harian

Sekarang, Y yang kita hasilkan mempunyai hubungan yang kuat dengan X, jadi harga Y harus sangat serupa dengan perubahan X. Kita membuat model dengan mengambil X, memindahkannya ke atas dan menambah beberapa bunyi rawak yang diambil dari pengagihan normal.

noise = np.random.normal(0, 1, 100)
Y = X + 5 + noise
Y.name = 'Y'
pd.concat([X, Y], axis=1).plot(figsize=(15,7))
plt.show()

img

X dan Y untuk penyesuaian pelaburan

Perpaduan

协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:

Y = X + e

Di mana y adalah nisbah yang tetap, dan e adalah bunyi.

Untuk pasangan transaksi antara dua siri masa, nisbah ini mestilah menyentuh nilai yang dijangkakan dari masa ke masa, iaitu mereka harus bersekongkol. Siri masa yang kita bina di atas adalah bersekongkol. Kita akan melukis nisbah antara kedua-duanya sekarang supaya kita dapat melihat penampilannya.

(Y/X).plot(figsize=(15,7)) 
plt.axhline((Y/X).mean(), color='red', linestyle='--') 
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()

img

Rasio dan purata antara harga kedua-dua mata pelaburan yang disatukan

Ujian bersama

Satu kaedah yang mudah untuk menguji adalah dengan menggunakan statsmodels.tsa.stattools. Kita sepatutnya melihat nilai p yang sangat rendah kerana kita secara buatan mencipta dua siri data yang selaras mungkin.

# compute the p-value of the cointegration test
# will inform us as to whether the ratio between the 2 timeseries is stationary
# around its mean
score, pvalue, _ = coint(X,Y)
print pvalue

Hasilnya ialah: 1.81864477307e-17

Perhatian: Kesan dan integriti

Walaupun berkaitan dan bersekongkol secara teori serupa, tetapi tidak sama. Jom lihat contoh siri data yang berkaitan tetapi tidak bersekongkol, dan sebaliknya. Mula-mula mari kita periksa hubungan siri yang baru kita hasilkan.

X.corr(Y)

Hasilnya ialah: 0.951.

Seperti yang kita jangkakan, ini sangat tinggi. Tetapi bagaimana dengan dua siri yang berkaitan tetapi tidak bersatu? Contoh mudah adalah dua siri data yang menyimpang.

ret1 = np.random.normal(1, 1, 100)
ret2 = np.random.normal(2, 1, 100)

s1 = pd.Series( np.cumsum(ret1), name='X')
s2 = pd.Series( np.cumsum(ret2), name='Y')

pd.concat([s1, s2], axis=1 ).plot(figsize=(15,7))
plt.show()
print 'Correlation: ' + str(X_diverging.corr(Y_diverging))
score, pvalue, _ = coint(X_diverging,Y_diverging)
print 'Cointegration test p-value: ' + str(pvalue)

img

Dua siri yang berkaitan (tidak disatukan)

Koefisien berkaitan: 0.998 P-nilai pemeriksaan kointegrasi: 0.258

Contoh sederhana keserasian tanpa kaitan adalah siri pembahagian normal dan gelombang persegi.

Y2 = pd.Series(np.random.normal(0, 1, 800), name='Y2') + 20
Y3 = Y2.copy()
Y3[0:100] = 30
Y3[100:200] = 10
Y3[200:300] = 30
Y3[300:400] = 10
Y3[400:500] = 30
Y3[500:600] = 10
Y3[600:700] = 30
Y3[700:800] = 10
Y2.plot(figsize=(15,7))
Y3.plot()
plt.ylim([0, 40])
plt.show()
# correlation is nearly zero
print 'Correlation: ' + str(Y2.corr(Y3))
score, pvalue, _ = coint(Y2,Y3)
print 'Cointegration test p-value: ' + str(pvalue)

img

Berkaitan: 0.007546 Nilai p pemeriksaan kointegrasi: 0.0

Perhubungan sangat rendah, tetapi nilai p menunjukkan keserasian yang sempurna!

Bagaimana untuk membuat transaksi pasangan?

Oleh kerana dua siri masa yang bersesuaian (seperti X dan Y di atas) berdekatan dan berlawanan antara satu sama lain, kadang-kadang terdapat keadaan margin tinggi dan margin rendah. Kami melakukan perdagangan berpasangan dengan membeli satu mata wang dan menjual mata wang yang lain. Oleh itu, jika kedua-dua mata wang jatuh atau naik bersama-sama, kita tidak membuat wang atau kehilangan wang, iaitu kita adalah netral dalam pasaran.

Kembali ke Y = x + e di atas, X dan Y, sehingga nisbah ((Y / X) bergerak di sekitar nilai purata, kita membuat wang dengan nisbah nilai purata. Untuk melakukan ini, kita akan melihat keadaan apabila X dan Y jauh dari satu sama lain, iaitu ambang terlalu tinggi atau terlalu rendah:

  • Membuat perbandingan yang lebih banyak: ini adalah apabila perbandingan berkurangan sangat kecil dan kita menjangkakan ia akan menjadi lebih besar. Dalam contoh di atas, kita membuka dagangan dengan melakukan Y yang lebih banyak dan X kosong.

  • Rasio kosong: ini adalah apabila nisbah bergelombang besar dan kita mengharapkannya berubah pada jam. Dalam contoh di atas, kita membuka dagangan dengan kosong Y dan melakukan lebih X.

Perhatikan bahawa kita sentiasa mempunyai pegangan pegangan pegangan pegangan: jika nilai pembelian dan kehilangan tanda dagangan, kedudukan kosong akan membuat wang, dan sebaliknya, oleh itu kita kebal terhadap pergerakan pasaran secara keseluruhan.

Jika X dan Y dalam indeks bergerak berbanding satu sama lain, kita akan membuat wang atau kerugian.

Menggunakan data untuk mencari tingkah laku yang serupa dengan tanda dagangan

Cara terbaik untuk melakukan ini adalah dengan mulakan dengan tanda dagangan yang anda mengesyaki mungkin bersatu dan menjalankan ujian statistik.Perbandingan bergandaPerbuatan yang tidak baik.

Perbandingan bergandaIni merujuk kepada peningkatan peluang untuk menghasilkan nilai p yang penting secara salah apabila menjalankan banyak ujian kerana kita perlu menjalankan banyak ujian. Jika 100 kali ujian dilakukan terhadap data rawak, kita sepatutnya melihat 5 nilai p kurang daripada 0.05. Jika anda ingin membandingkan n tanda urus niaga untuk melakukan perbandingan keseluruhan, maka anda akan melakukan n ((n-1) / 2 perbandingan dan anda akan melihat banyak nilai p yang tidak betul, yang akan meningkat dengan peningkatan sampel ujian anda. Untuk mengelakkan keadaan ini, pilih beberapa pasangan transaksi yang kecil yang mempunyai alasan untuk anda pasti mungkin berkolaborasi, dan kemudian uji mereka secara berasingan. Ini akan mengurangkan secara besar.Perbandingan berganda

Oleh itu, mari kita cuba mencari beberapa tanda dagangan yang menunjukkan keserasian. Sebagai contoh, mari kita ambil satu bakul saham teknologi besar Amerika Syarikat dalam Indeks S&P 500 yang beroperasi di segmen pasaran yang serupa dan mempunyai harga keserasian.

Kembali ke matriks pemeriksaan integrasi pecahan, matriks nilai p, dan semua pasangan nilai p yang kurang daripada 0.05.Kaedah ini mudah berlaku dengan banyak kecacatan perbandingan, jadi mereka sebenarnya memerlukan pengesahan kedua.Dalam artikel ini, untuk kemudahan kita, kita memilih untuk mengabaikan ini dalam contoh.

def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs

Perhatikan: Kami memasukkan penanda aras pasaran (SPX) dalam data - pasaran mendorong pergerakan banyak penanda perdagangan, biasanya anda mungkin mendapati dua penanda perdagangan yang nampaknya bersekutu; tetapi sebenarnya mereka tidak bersekutu antara satu sama lain, tetapi bersekutu dengan pasaran. Ini dikenali sebagai pembolehubah campuran.

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','AAPL','ADBE','SYMC','EBAY','MSFT','QCOM',
                 'HPQ','JNPR','AMD','IBM']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['Adj Close']
data.head(3)

img

Sekarang mari kita cuba menggunakan kaedah kami untuk mencari pasangan transaksi yang bersepadu.

# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print pairs
[('ADBE', 'MSFT')]

img

Rupanya aluminium ADBE dan aluminium MSFT berfungsi bersama-sama. Mari kita lihat harga untuk memastikan ia benar-benar bermakna.

S1 = data['ADBE']
S2 = data['MSFT']
score, pvalue, _ = coint(S1, S2)
print(pvalue)
ratios = S1 / S2
ratios.plot()
plt.axhline(ratios.mean())
plt.legend([' Ratio'])
plt.show()

img

Grafik nisbah harga antara MSFT dan ADBE 2008 - 2017

Nisbah ini memang kelihatan seperti purata yang stabil. Nisbah mutlak tidak berguna secara statistik. Sinyal kita lebih membantu dengan menstandarisasikannya sebagai z-score. Z-score didefinisikan sebagai:

Z Score (Value) = (Value Mean) / Penyimpangan Standard

Peringatan

Sebenarnya, kita biasanya akan cuba untuk membuat beberapa penyempurnaan terhadap data, tetapi dengan syarat data ini adalah pembahagian normal. Walau bagaimanapun, banyak data kewangan bukan pembahagian normal, jadi kita mesti sangat berhati-hati untuk tidak hanya menganggap normal atau mana-mana pembahagian tertentu semasa menghasilkan data statistik. Pembagian benar nisbah mungkin mempunyai kesan akhir yang membesar, dan data yang cenderung ke arah yang melampau akan membuat model kita menjadi kacau dan menyebabkan kerugian yang besar.

def zscore(series):
    return (series - series.mean()) / np.std(series)
zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()

img

Nisbah harga Z antara MSFT dan ADBE antara 2008 - 2017

Sekarang lebih mudah untuk melihat peratusan bergerak di dekat purata, tetapi kadang-kadang mudah untuk mengalami perbezaan besar dengan purata, dan kita boleh memanfaatkan ini.

Sekarang kita telah membincangkan asas-asas strategi perdagangan berpasangan dan menentukan tanda dagangan yang disatukan bersama berdasarkan harga sejarah, mari kita cuba membangunkan isyarat dagangan. Pertama, mari kita lihat langkah-langkah untuk membangunkan isyarat dagangan menggunakan teknologi data:

  • Mengumpul data yang boleh dipercayai dan membersihkan data

  • Mencipta fungsi untuk mengenalpasti isyarat/logik dagangan dari data

  • Fungsi boleh menjadi purata bergerak atau data harga, perbandingan relevansi atau isyarat yang lebih kompleks - menggabungkannya untuk mewujudkan fungsi baru

  • Fungsi ini digunakan untuk menjana isyarat dagangan, iaitu isyarat membeli, menjual atau melihat kosong

Nasib baik, kita ada platform pencipta kuantitatif.fmz.comKami telah menyelesaikan empat aspek di atas untuk kami, dan ini adalah berita gembira besar bagi pemaju strategi, yang boleh menghabiskan tenaga dan masa mereka untuk reka bentuk logik strategi dan memperluas fungsi.

Dalam platform inventor kuantiti, terdapat pelbagai antara muka yang terbungkus dengan baik untuk bursa utama, semua yang perlu kita lakukan adalah memanggil antara muka API ini, dan yang tersisa adalah logik pelaksanaan bawah, yang telah diasah oleh pasukan profesional.

Untuk kelengkapan logik dan penerangan prinsip, kami akan membuat persembahan yang seperti Ludding pada logik asas ini, tetapi dalam operasi sebenar, pembaca boleh menghubungi API yang diukur oleh pencipta secara langsung untuk menyelesaikan empat perkara di atas.

Mari kita mulakan:

Langkah 1: Tetapkan masalah anda

Di sini, kita cuba untuk membuat isyarat yang memberitahu kita apakah kadar yang akan dibeli atau dijual pada masa akan datang, iaitu, pembolehubah ramalan kita Y:

Y = Nisbah adalah beli (1) atau menjual (-1)

Y(t)= Sign(Ratio(t+1) Ratio(t))

Perhatikan bahawa kita tidak perlu meramalkan harga tanda dagangan sebenar, atau bahkan tidak perlu meramalkan nilai sebenar nisbah (walaupun kita boleh), hanya perlu meramalkan arah nisbah seterusnya

Langkah 2: Kumpulkan data yang boleh dipercayai dan tepat

Pencipta Kuantiti adalah kawan anda! Anda hanya perlu menentukan tanda dagangan yang akan diperdagangkan dan sumber data yang akan digunakan, dan ia akan mengekstrak data yang diperlukan dan membersihkannya untuk melakukan pemisahan dividen dan tanda dagangan. Jadi data kami di sini bersih.

Kami menggunakan data berikut untuk hari dagangan 10 tahun yang lalu (sekitar 2500 titik data) dengan menggunakan Yahoo Finance: harga buka, harga tutup, harga tertinggi, harga terendah dan jumlah dagangan

Langkah ketiga: Memisahkan data

Jangan lupa langkah penting ini untuk menguji ketepatan model. Kami menggunakan pembahagian latihan / pengesahan / ujian dengan data berikut

  • Latihan 7 tahun ~ 70%

  • Ujian ~ 3 tahun 30%

ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]

Idealnya, kita juga harus membuat set pengesahan, tetapi kita tidak akan melakukannya buat masa ini.

Langkah keempat: Senibina ciri

Apakah fungsi yang berkaitan? Kita mahu meramalkan arah perubahan kadar. Kita telah melihat bahawa kedua-dua tanda dagangan kita adalah bersama-sama, jadi kadar ini sering bergeser dan kembali ke purata. Nampaknya ciri kita harus menjadi beberapa metrik purata kadar, dan perbezaan antara nilai semasa dan purata boleh menghasilkan isyarat dagangan kita.

Kami menggunakan ciri berikut:

  • Rata-rata bergerak 60 hari: Pengukuran purata bergerak

  • Peratusan purata bergerak 5 hari: pengukuran nilai masa kini purata

  • 60 hari perbezaan standard

  • Z: ((5d MA - 60d MA) / 60d SD

ratios_mavg5 = train.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = train.rolling(window=60,
                               center=False).mean()
std_60 = train.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()

img

Rasio harga 60d dan 5d MA

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()

img

60-5 Z skor nisbah harga

Z-score pada rata-rata bergolak memang membawa sifat regresi rata-rata pada nisbah!

Langkah 5: Pilih model

Mari kita mulakan dengan model yang sangat mudah. Lihatlah carta z-score dan kita boleh melihat bahawa ia akan kembali apabila z-score terlalu tinggi atau terlalu rendah. Mari kita gunakan + 1 / -1 sebagai ambang kami untuk menentukan terlalu tinggi dan terlalu rendah, dan kemudian kita boleh menggunakan model berikut untuk menghasilkan isyarat dagangan:

  • Jika z kurang daripada -1.0, nisbah adalah membeli ((1) kerana kita menjangkakan z akan kembali kepada 0, jadi nisbah meningkat

  • Apabila z lebih tinggi daripada 1.0, nisbahnya adalah jual (−1) kerana kita menjangkakan z akan kembali ke 0, jadi nisbahnya berkurangan

Langkah keenam: Latihan, pengesahan dan pengoptimuman

Akhirnya, mari kita lihat kesan sebenar model kita terhadap data sebenar.

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1] = 0
buy[60:].plot(color=’g’, linestyle=’None’, marker=’^’)
sell[60:].plot(color=’r’, linestyle=’None’, marker=’^’)
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,ratios.min(),ratios.max()))
plt.legend([‘Ratio’, ‘Buy Signal’, ‘Sell Signal’])
plt.show()

img

Isyarat Rasio Harga Beli dan Jual

Isyarat ini nampaknya munasabah, kita nampaknya menjual kadar apabila ia tinggi atau meningkat (titik merah) dan membeli semula apabila ia rendah (titik hijau) dan berkurangan.

# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1 = data['ADBE'].iloc[:1762]
S2 = data['MSFT'].iloc[:1762]
S1[60:].plot(color='b')
S2[60:].plot(color='c')
buyR = 0*S1.copy()
sellR = 0*S1.copy()
# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]
# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['ADBE','MSFT', 'Buy Signal', 'Sell Signal'])
plt.show()

img

Isyarat untuk membeli dan menjual saham MSFT dan ADBE

Perhatikan bagaimana kita kadang-kadang membuat wang dengan kaki pendek, kadang-kadang dengan kaki panjang, dan kadang-kadang kedua-duanya.

Kami berpuas hati dengan isyarat data latihan. Mari kita lihat apa keuntungan yang boleh dihasilkan oleh isyarat ini. Apabila nisbahnya rendah, kita boleh membuat retarget sederhana, membeli 1 nisbah (membeli 1 saham ADBE dan menjual nisbah x saham MSFT), menjual 1 nisbah (membeli 1 saham ADBE dan membeli nisbah x saham MSFT) apabila ia tinggi dan mengira perdagangan PnL nisbah ini.

# Trade using a simple strategy
def trade(S1, S2, window1, window2):
    
    # If window length is 0, algorithm doesn't make sense, so exit
    if (window1 == 0) or (window2 == 0):
        return 0
    
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2
    ma1 = ratios.rolling(window=window1,
                               center=False).mean()
    ma2 = ratios.rolling(window=window2,
                               center=False).mean()
    std = ratios.rolling(window=window2,
                        center=False).std()
    zscore = (ma1 - ma2)/std
    
    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
            print('Selling Ratio %s %s %s %s'%(money, ratios[i], countS1,countS2))
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
            print('Buying Ratio %s %s %s %s'%(money,ratios[i], countS1,countS2))
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.75:
            money += S1[i] * countS1 + S2[i] * countS2
            countS1 = 0
            countS2 = 0
            print('Exit pos %s %s %s %s'%(money,ratios[i], countS1,countS2))
            
            
    return money
trade(data['ADBE'].iloc[:1763], data['MSFT'].iloc[:1763], 60, 5)

Hasilnya ialah: 1783.375

Jadi strategi ini nampaknya menguntungkan! Kini, kita boleh mengoptimumkan lebih lanjut dengan mengubah tetingkap masa purata bergerak, dengan mengubah ambang jual beli / jual dan lain-lain, dan memeriksa peningkatan prestasi data pengesahan.

Kita juga boleh mencuba model yang lebih kompleks, seperti logistic regression, SVM, dan lain-lain untuk membuat ramalan 1/-1.

Sekarang, mari kita majukan model ini, yang membawa kita kepada

Langkah 7: Uji semula data ujian

Ini adalah platform kuantitatif pencipta, yang menggunakan enjin pengukuran semula QPS / TPS yang berprestasi tinggi, mewujudkan semula persekitaran sejarah yang benar, menghilangkan perangkap pengukuran semula kuantitatif yang biasa, dan mengesan kekurangan strategi pada masa yang tepat, sehingga membantu pelaburan sebenar yang lebih baik.

Artikel ini menjelaskan prinsip, atau memilih untuk menunjukkan logik asas, dalam penggunaan praktikal, atau mengesyorkan pembaca menggunakan platform kuantitatif pencipta, selain menjimatkan masa, penting untuk meningkatkan kadar kesalahan.

PnL dalam data ujian adalah mudah, dan kita boleh menggunakan fungsi di atas untuk melihat

trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)

Hasilnya ialah: 5262.868

Model ini berfungsi dengan baik! Ia menjadi model pertama kami yang mudah dipasangkan untuk transaksi.

Mengelakkan pemasangan yang berlebihan

Sebelum menamatkan perbincangan, saya ingin membincangkan secara khusus mengenai overfiting. Overfiting adalah satu daripada perangkap yang paling berbahaya dalam strategi perdagangan. Overfiting algoritma boleh melakukan dengan sangat baik dalam ulasan balik tetapi gagal pada data baru yang tidak dapat dilihat - yang bermaksud ia tidak benar-benar mendedahkan apa-apa trend data dan tidak mempunyai keupayaan yang benar-benar meramalkan.

Dalam model kami, kami menggunakan ramalan parameter gulungan dan berharap untuk mengoptimumkan panjang tetingkap masa olehnya. Kami mungkin memutuskan untuk mengulangi semua kemungkinan, panjang tetingkap masa yang munasabah, dan memilih panjang masa yang terbaik mengikut prestasi model kami. Di bawah ini kami menulis loop mudah untuk menilai panjang tetingkap masa oleh pNL berdasarkan data latihan dan mencari loop yang terbaik.

# Find the window length 0-254 
# that gives the highest returns using this strategy
length_scores = [trade(data['ADBE'].iloc[:1762], 
                data['MSFT'].iloc[:1762], l, 5) 
                for l in range(255)]
best_length = np.argmax(length_scores)
print ('Best window length:', best_length)
('Best window length:', 40)

Sekarang kami memeriksa prestasi model pada data ujian, dan kami mendapati bahawa panjang tetingkap masa ini jauh dari yang terbaik! Ini kerana pilihan asal kami jelas terlalu sesuai dengan data sampel.

# Find the returns for test data
# using what we think is the best window length
length_scores2 = [trade(data['ADBE'].iloc[1762:], 
                  data['MSFT'].iloc[1762:],l,5) 
                  for l in range(255)]
print (best_length, 'day window:', length_scores2[best_length])
# Find the best window length based on this dataset, 
# and the returns using this window length
best_length2 = np.argmax(length_scores2)
print (best_length2, 'day window:', length_scores2[best_length2])
(40, 'day window:', 1252233.1395)
(15, 'day window:', 1449116.4522)

Jelasnya data sampel yang sesuai dengan kita tidak selalu menghasilkan hasil yang baik pada masa akan datang. Hanya untuk ujian, mari kita melukis pecahan panjang yang dikira dari dua set data.

plt.figure(figsize=(15,7))
plt.plot(length_scores)
plt.plot(length_scores2)
plt.xlabel('Window length')
plt.ylabel('Score')
plt.legend(['Training', 'Test'])
plt.show()

img

Kita boleh melihat bahawa apa-apa antara 20-50 adalah pilihan yang baik untuk tetingkap masa.

Untuk mengelakkan pemasangan yang berlebihan, kita boleh menggunakan sifat penalaran ekonomi atau algoritma untuk memilih panjang tingkap masa. Kita juga boleh menggunakan penapis Karman, yang tidak memerlukan kita menentukan panjangnya; kaedah ini akan diperkenalkan kemudian dalam artikel lain.

Langkah seterusnya

Dalam artikel ini, kami menawarkan beberapa kaedah pengenalan mudah untuk menunjukkan proses membangunkan strategi dagangan. Dalam amalan, anda boleh menggunakan data statistik yang lebih kompleks dan anda boleh mempertimbangkan pilihan berikut:

  • Indeks Hurst

  • Tempoh paruh kemunduran untuk regresi purata yang disimpulkan daripada proses Ornstein-Uhlenbeck

  • Penapis Kalman


Berkaitan

Lebih lanjut

bk_fundTidak dapat mencari beg ini

bk_fundDi mana anda boleh memasang backtester.dataSource.yahoo_data_source