配列取引は,数学的分析に基づく取引戦略の策定の良い例です.この記事では,データを活用して配列取引戦略を作成し,自動化する方法を示します.
假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.
臨時的な価格差がある場合,取引は優れた投資指標を売り上げ,劣悪な投資指標を購入する.両投資指標の利息差は,優れた投資指標の低下,劣悪な投資指標の回復,または両方によって最終的に起こる.あなたの取引は,これらの類似したシナリオのすべてで利益を得ます.投資指標が1回上昇または低下し,その間の差を変化させずに移動した場合,あなたはお金を得たり損したりしません.
したがって,配列取引は市場中立的な取引戦略であり,トレーダーは上向き,下向き,横向きの整合など,ほぼすべての市場条件から利益を得ることができる.
まず,作業が順調に進むためには,私たちは研究環境を構築する必要があります.FMZ.COMこの研究環境は,このプラットフォームの便利なAPIと完全なDockerシステムをパッケージ化するために開発された.
発明者による量化プラットフォームの公式名称では,このDockerシステムはホストシステムと呼ばれています.
管理者やロボットの配備については,私の前の記事を参照してください.https://www.fmz.com/bbs-topic/4140
クラウドサーバーの展開管理者を購入したい人は,この記事を参照してください:https://www.fmz.com/bbs-topic/2848
Pythonの最大級の神社である Anaconda をインストールします. これは,Python の最大級の神社である Anaconda をインストールします.
本文に必要なすべての関連するプログラム環境 (依存庫,バージョン管理など) を実現するには,最も簡単な方法はAnacondaです.これはパッケージ化されたPythonデータサイエンスのエコシステムであり,依存庫管理者です.
アナコンダのインストール方法については,Anacondaの公式ガイドを参照してください.https://www.anaconda.com/distribution/
本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.
上記の基礎作業は, Anaconda 環境とnumpyとpandasの2つのライブラリをどのように設定するかについての私の前の記事にも参照できます.https://www.fmz.com/digest-topic/4169
次に,2つの仮説の投資指標をコードで実現しましょう.
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
このビデオでは,matplotlibという有名なPythonのグラフライブラリを使います.
仮の投資指標のXを生成し,正規分布でその日々の返済をシミュレートしましょう. そして,日々のX値を得るために累積を実行します.
# 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()
投資指標のXは,正規分布による日々の収益をシミュレーションします.
YとXが強く相互関係しているので,Yの価格がXの変化に非常に似ているはずです. これをモデル化するには,Xを取って上へと移動し,正規分布から抽出したランダムなノイズを追加します.
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()
XとYを組み合わせる投資指標
协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:
Y =
2つの時間配列間の取引対に対して,この比率は時間とともに予想される値が均等に収束しなければならない,つまりそれらは共存すべきである.上述の時間配列は共存している.我々は今,両者の比率を描画して,その外観を見ることができる.
(Y/X).plot(figsize=(15,7))
plt.axhline((Y/X).mean(), color='red', linestyle='--')
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()
2つの協同投資指標の価格の比率と平均値
簡単なテスト方法として,statsmodels.tsa.stattools を使います. 我々は非常に低いp値を見るべきです.
# 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
検索結果: 1.81864477307e-17
関連性と協同性とは理論的には似ていますが,同じではありません. 関連性があるが協同性がないデータ系列の例を見てみましょう. そして,その逆の例を見てみましょう. まず,私たちが生成した一連の関連性を調べましょう.
X.corr(Y)
答えは0.951でした.
予想通り,これは非常に高い. しかし,関連しているが,相互に一致していない2つの列はどうでしょうか. 簡単な例として,2つの偏差したデータ列を挙げます.
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)
2つの関連シリーズ (統合されていない)
関連系数:0.998 協調検査のp値:0.258
関連性のない協同体の簡単な例は正規分布の配列と方波である.
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)
関連性:0.007546 統合検査のp値:0.0
関連性は非常に低いが,p値は完璧な共存を示している!
2つの協調した時間列 (例えば上記のXとY) が互いに並んで,互いに偏っているため,時折高基差と低基差が発生する.我々は1つの投資指数を買い,もう1つの投資指数を売り,配列取引を行う.したがって,2つの投資指数が一緒に下がったり上昇したりした場合,我々は既得も損もせず,つまり我々は市場の中立者である.
上方にあるY=
多比率:これは比率が小さいときであり,それが大きくなるのを期待しているときです.上記の例では,多 Y をして空 X をして取引を開始します.
空白率:これは,比率が大きくなり,時間によって変化することを期待しているときである.上記の例では,空白Yと多Xで取引を開始した.
注意してください,私たちは常に強固なヘッジポジションの強固性を持っています. 取引先の買取損失値が上昇した場合,空頭ポジションは利益を得ます. 逆に,私たちは全体的な市場の動きに免疫を持っています.
取引指標のXとYが互いに相関して動くと,我々は利益を得たり損をする.
これをする最良の方法は,協調性があるかもしれない取引指標から始め,統計的テストを実行することです.多重比較偏差犠牲者にもなる.
多重比較偏差多くのテストを実行するときに重要なp値が誤って生成される機会が増加する場合を指します. 多くのテストを実行する必要があるからです. 100回のランダムデータに対するテストを行えば,0.05未満の5つのp値が見られるはずです. nつのトレンドマークを整合するために比較する場合は,n (n − 1) / 2の比較を行います.多くの誤ったp値が見られます. これはテストサンプルが増加するにつれて増加します.多重比較偏差。
そこで,協調性を示す取引先を探してみましょう.S&P500のバスケットの中の米国の大手テクノロジー株を例に挙げましょう. これらの取引先は,類似したセグメント市場で運営され,協調性のある価格を持っています.
返される共積は,分数マトリックス,p値マトリックス,およびp値が0.05未満のすべてのペアリングである.この方法では,複数の比較偏差が起こりやすいので,実際には二次検証が必要です.この記事では,説明の便宜のために,例ではこれを省略することを選択します.
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
注意:我々はデータに市場基数 (SPX) を含んでいる.市場が多くの取引指標の流動を推進しているため,通常,あなたは2つの相互に協調しているように見えた取引指標を見つけることができます.しかし,実際にはそれらは相互に協調するのではなく,市場と協調しています.これは混同変数と呼ばれます.あなたが発見したどんな関係でも市場参加をチェックすることは重要です.
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)
では,この方法を使って,協調性のある取引のペアリングを試しましょう.
# 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')]
ADBE
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()
2008 - 2017年のMSFTとADBEの価格比率グラフ
この比率は確かに安定した平均値のように見えます. 絶対比率は統計学的にはあまり役に立たない. Zスコアとして標準化することで,私たちの信号をより助けます. Zスコアは次のように定義されています.
Zスコア (値) = (値
実際には,我々は通常,データにいくつかの拡張を試みますが,そのデータが正規分布である前提で. しかし,多くの財務データは正規分布ではないので,統計データを生成するときに,単に正規性または特定の分布を仮定しないように非常に注意する必要があります. 割合の真分布は肥満尾根効果があり,極端に傾いているデータは,私たちのモデルを混乱させ,大きな損失をもたらす可能性があります.
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()
MSFTとADBEの間の2008年から2017年のZ価格比率
現在,比率が平均値に近い動きを観察することが容易ですが,時には平均値と大きな差が起こりやすいので,これを利用することができます.
配列取引戦略の基礎を議論し,歴史的な価格に基づいて共同で統合された取引指標を決定した今,取引信号を開発してみましょう. まず,データ技術を使用して取引信号を開発するためのステップを振り返ってみましょう.
信頼性の高いデータ収集とデータ清掃
データから取引信号/論理を識別する機能を作成する
機能は,移動平均値や価格データ,関連性,またはより複雑な信号の比率 - これらの組み合わせで新しい機能を作成します
これらの機能を使用して,どの信号が買い,売り,空売りなのかを表示する取引信号を生成します.
幸運にも,私たちは発明者の定量化プラットフォームを持っています.fmz.com戦略開発者にとって大きな福音であり,戦略論理の設計と機能の拡張に エネルギーと時間を費やすことができます.
発明者による量化プラットフォームでは,様々な主流の取引所のインターフェースがパッケージ化されています. 必要なのは,これらのAPIを呼び出すだけです.
本文では,論理の完全性や原理の説明のために,これらの底辺の論理を
この記事へのトラックバックです.
予想変数Yは,次の瞬間に,この比率が買いか売るか示す信号を作成します.
Y = 割引は,買 (1) か売 (-1)
Y (t) =サイン (t) 比 (t+1)
実際の取引指標の価格を予測する必要はないし,比率の実際の価値を予測する必要もありません (しかし,私たちはできます) 単に比率の次の方向を予測する必要があります.
発明者の量化があなたの友だちです! 取引対象の指標と使用対象のデータソースを指定するだけで,必要なデータを抽出し,それを分割して,配当と取引対象を分割します.
この10年間の取引日 (約2500のデータポイント) のデータには,Yahoo Financeを使って入手した次のデータがあります. オープン価格,終了価格,最高価格,最低価格,取引量.
この非常に重要なステップを忘れないでください. 我々は,次のデータを使って訓練/検証/テストを分割しています.
訓練7年~70%
試験~3年 30%
ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]
理想的には,検証セットも作るべきですが,今のところは作れません.
関連機能は何でしょうか? 我々は比率が変化する方向を予測したい. 我々は既に我々の2つの取引標識が協調していることを見てきたので,この比率は往々にして移動し,平均値に戻る.我々の特徴は比率が平均値である特定のメタファーであり,現在の値と平均値の差が我々の取引信号を生成できるようである.
フォローしているサイトは,
60日間の移動平均比率:移動平均の測定
5日間の移動平均比率:平均値の現在の値の測定
60日標準差
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()
60dと5dMAの価格比率
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()
60-5 Zスコア価格比率
ローリング平均値のZスコアは,実際に比率の平均値回帰性をもたらします.
非常に簡単なモデルから始めましょう. zスコアグラフを見て, zスコアがあまりにも高く,または低すぎると,それが戻ってくるのを見ることができます.
割引値が0.0以下になると,割引値が上昇します.
z が 1.0 よりも大きいとき,割引は売れ (−1) になります. z が 0 に戻ると予想されるので割引は減ります.
このシグナルが実際の比率でどのように表現されるか見てみましょう.
# 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()
価格比率の信号
このシグナルが合理的に見えるのは,私たちが高いときまたは増加しているとき (赤点) を売り,低いとき (緑点) と減少しているとき (赤点) を買い戻しているように見えます.これは私たちの取引の実際の取引指標に何を意味しますか?
# 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()
MSFTとADBEの株の購入・売却のシグナル
"短足"でお金を稼ぐときや"長い足"でお金を稼ぐときや,両方があるときを注意してください.
訓練データからのシグナルに満足しています. このシグナルがどんな利益をもたらすのか見てみましょう. 格差が低いとき,簡単な回計を作って,1つの比率で購入します. 1つのADBE株を買って売る比率xMSFT株を買って売る比率xMSFT株を買って売る比率xMSFT株を買って売る比率1つの比率で販売します. そしてこれらの比率のPnL取引を計算します.
# 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)
検索結果: 1783.375
移動平均時間窓を変更し,買/売平値等を変更し,検証データの性能改善をチェックすることができます.
論理回帰,SVMなどより複雑なモデルを試して1/-1予測をします.
このモデルをさらに進めてみましょう.
また,発明者による量化プラットフォームは,高性能QPS/TPS回測エンジンを使用して,現実的な歴史的環境を再現し,一般的な量化回測の罠を取り除く.
この記事では,原理を説明したり,基礎論理を示したり,実用的な応用を提案したり,発明者の定量化プラットフォームを使用することをお勧めします.
この関数でテストのPnLを表示します.
trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)
答えは,5262,868でした.
モデルがうまくいきました! これは私たちの最初のシンプルなペア対取引モデルになりました.
議論を締めくくる前に,特に過適性についてお話ししたいと思います.過適性とは取引戦略の中で最も危険な罠です.過適性アルゴリズムは,リバウンドで非常に優れたパフォーマンスを発揮しますが,新しい目に見えないデータで失敗する可能性があります.これは,データのトレンドを実際に明らかにしていないことを意味し,実際の予測能力がないことを意味します.簡単な例をお見せします.
私たちのモデルでは,スクロールパラメータを予測して,そのために時間窓の長さを最適化したい.我々は,単純にすべての可能性,合理的な時間窓の長さを繰り返して,私たちのモデルが最もうまく機能する時間長さを選択することを決定するかもしれない.下記では,訓練データのpnlに基づいて時間窓の長さを評価し,最適なループを見つけるための簡単なループを書いています.
# 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)
テストデータに対するモデルのパフォーマンスを調べてみると,この時間窓の長さは最適ではないことがわかりました.これは,当初の選択が明らかにサンプルデータに過剰に適合しているからです.
# 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)
明らかに,私たちのサンプルデータには常に良い結果が出ない.ただテストのために,二つのデータセットから計算した長さの分数を図に描いてみましょう.
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()
20〜50の間のものは,時間窓の良い選択肢です.
過剰なフィットメントを避けるために,我々は経済推論やアルゴリズムの性質を使用して時間窓の長さを選択することができる.また,我々はカールマンフィルターを使用することもできる.それは私たちが長さを指定する必要がなく,別の記事で後でこの方法について説明します.
この記事では,取引戦略の開発のプロセスを示すための簡単な紹介方法を示しています.実際は,より複雑な統計データを使用すべきです.以下のような選択肢を検討してください:
ハースター指数
オーンスタイン・ウレンベックプロセスから推論された平均値回帰の半衰期
カルマンフィルター
bk_fundこのパックが見つかりませんでした.
bk_fundバックテスター.データソース.yahoo_data_sourceをインストールする