アルゴリズム取引の台頭により、Pythonはクオンツ開発者にとって不可欠なツールとなっています。これは主に、Pythonが科学技術計算やデータ分析において強力なエコシステムを持ち、優れたサードパーティライブラリに支えられているためです。Pandas、NumPy、SciPyなどのライブラリは、データ操作、数値計算、科学的分析において豊富な機能を提供しており、クオンツリサーチや戦略開発をより効率的に行うことができます。本日は、5つの代表的なクオンツ取引戦略と、それぞれに対応するPythonコードの例をご紹介します。
#1 平均回帰戦略(Mean Reversion Strategy)
平均回帰戦略は、資産価格が長期的な平均値の周りを変動するという仮定に基づいた統計的アービトラージ手法です。短期的な価格変動があっても、価格は時間とともに平均に戻ると考えられます。以下は、単純移動平均を使って資産の「平均」を定義し、標準偏差を用いて売買シグナルを生成するシンプルなPythonコード例です:
import matplotlib.pyplot as plt
'Date': pd.date_range(start='2023-01-01', periods=100),
'Close': np.random.normal(100, 10, 100)
data.set_index('Date', inplace=True)
data['Moving Average'] = data['Close'].rolling(window=window).mean()
data['Standard Deviation'] = data['Close'].rolling(window=window).std()
data['Upper Bound'] = data['Moving Average'] + data['Standard Deviation']
data['Lower Bound'] = data['Moving Average'] - data['Standard Deviation']
data.loc[data['Close'] < data['Lower Bound'], 'Position'] = 1
data.loc[data['Close'] > data['Upper Bound'], 'Position'] = -1
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Moving Average'], label='Moving Average')
plt.fill_between(data.index, data['Upper Bound'], data['Lower Bound'], color='gray', alpha=0.3, label='Mean Reversion Band')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=100),
'Close': np.random.normal(100, 10, 100)
})
data.set_index('Date', inplace=True)
window = 20
data['Moving Average'] = data['Close'].rolling(window=window).mean()
data['Standard Deviation'] = data['Close'].rolling(window=window).std()
data['Upper Bound'] = data['Moving Average'] + data['Standard Deviation']
data['Lower Bound'] = data['Moving Average'] - data['Standard Deviation']
data['Position'] = 0
data.loc[data['Close'] < data['Lower Bound'], 'Position'] = 1
data.loc[data['Close'] > data['Upper Bound'], 'Position'] = -1
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Moving Average'], label='Moving Average')
plt.fill_between(data.index, data['Upper Bound'], data['Lower Bound'], color='gray', alpha=0.3, label='Mean Reversion Band')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta')
plt.legend()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=100),
'Close': np.random.normal(100, 10, 100)
})
data.set_index('Date', inplace=True)
window = 20
data['Moving Average'] = data['Close'].rolling(window=window).mean()
data['Standard Deviation'] = data['Close'].rolling(window=window).std()
data['Upper Bound'] = data['Moving Average'] + data['Standard Deviation']
data['Lower Bound'] = data['Moving Average'] - data['Standard Deviation']
data['Position'] = 0
data.loc[data['Close'] < data['Lower Bound'], 'Position'] = 1
data.loc[data['Close'] > data['Upper Bound'], 'Position'] = -1
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Moving Average'], label='Moving Average')
plt.fill_between(data.index, data['Upper Bound'], data['Lower Bound'], color='gray', alpha=0.3, label='Mean Reversion Band')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta')
plt.legend()
plt.show()
#2 トレンドフォロー戦略(Trend Following Strategy)
トレンドフォローは、資産の短期移動平均と長期移動平均を比較し、現在の市場トレンドを特定してその流れに従う戦略です。たとえば、株価が上昇トレンドで市場心理が強気の場合、その流れに従って株を買い持ちし、トレンドが反転するまで保有します。Pythonでは、MACD(移動平均収束拡散法)を使って短期トレンドを識別し、売買シグナルを生成することができます:
import matplotlib.pyplot as plt
'Date': pd.date_range(start='2023-01-01', periods=200),
'Close': np.random.normal(100, 15, 200)
data.set_index('Date', inplace=True)
data['Short MA'] = data['Close'].rolling(window=short_window).mean()
data['Long MA'] = data['Close'].rolling(window=long_window).mean()
data['Signal'][short_window:] = np.where(data['Short MA'][short_window:] > data['Long MA'][short_window:], 1, 0)
data['Position'] = data['Signal'].diff()
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Short MA'], label='40-Day Moving Average')
plt.plot(data['Long MA'], label='100-Day Moving Average')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta', marker='o', linestyle='None')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=200),
'Close': np.random.normal(100, 15, 200)
})
data.set_index('Date', inplace=True)
short_window = 40
long_window = 100
data['Short MA'] = data['Close'].rolling(window=short_window).mean()
data['Long MA'] = data['Close'].rolling(window=long_window).mean()
data['Signal'] = 0
data['Signal'][short_window:] = np.where(data['Short MA'][short_window:] > data['Long MA'][short_window:], 1, 0)
data['Position'] = data['Signal'].diff()
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Short MA'], label='40-Day Moving Average')
plt.plot(data['Long MA'], label='100-Day Moving Average')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.legend()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=200),
'Close': np.random.normal(100, 15, 200)
})
data.set_index('Date', inplace=True)
short_window = 40
long_window = 100
data['Short MA'] = data['Close'].rolling(window=short_window).mean()
data['Long MA'] = data['Close'].rolling(window=long_window).mean()
data['Signal'] = 0
data['Signal'][short_window:] = np.where(data['Short MA'][short_window:] > data['Long MA'][short_window:], 1, 0)
data['Position'] = data['Signal'].diff()
plt.figure(figsize=(14, 7))
plt.plot(data['Close'], label='Close Price')
plt.plot(data['Short MA'], label='40-Day Moving Average')
plt.plot(data['Long MA'], label='100-Day Moving Average')
plt.plot(data.index, data['Position'] * 50, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.legend()
plt.show()
#3 ペアトレーディング(Pair Trading)
ペアトレーディングは、強い相関関係を持つ2つの資産の価格差に基づく統計的アービトラージ手法です。価格差が通常の範囲を超えて乖離したとき、割安な資産を買い、割高な資産を売ることで利益を狙います。長期的には価格が平均に戻るとされ、短期的なアービトラージの機会を提供します。
2つの資産の過去の価格関係を分析し、予想されるスプレッドからの乖離を元に取引シグナルを作成します:
import matplotlib.pyplot as plt
'Date': pd.date_range(start='2023-01-01', periods=180),
'Asset_A': np.random.normal(100, 10, 180).cumsum() + 100,
'Asset_B': np.random.normal(100, 10, 180).cumsum() + 120
data.set_index('Date', inplace=True)
data['Price_Diff'] = data['Asset_A'] - data['Asset_B']
data['Mean_Diff'] = data['Price_Diff'].rolling(window=window).mean()
data['Std_Diff'] = data['Price_Diff'].rolling(window=window).std()
data['Upper_Bound'] = data['Mean_Diff'] + data['Std_Diff']
data['Lower_Bound'] = data['Mean_Diff'] - data['Std_Diff']
data.loc[data['Price_Diff'] > data['Upper_Bound'], 'Position'] = -1 # 做空Asset A,做多Asset B
data.loc[data['Price_Diff'] < data['Lower_Bound'], 'Position'] = 1 # 做多Asset A,做空Asset B
plt.figure(figsize=(14, 7))
plt.plot(data['Asset_A'], label='Asset A')
plt.plot(data['Asset_B'], label='Asset B')
plt.plot(data['Price_Diff'], label='Price Difference')
plt.plot(data['Mean_Diff'], label='Mean Difference')
plt.fill_between(data.index, data['Upper_Bound'], data['Lower_Bound'], color='gray', alpha=0.3, label='Trading Zone')
plt.plot(data.index, data['Position'] * 20, label='Trading Signal', color='magenta', marker='o', linestyle='None')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=180),
'Asset_A': np.random.normal(100, 10, 180).cumsum() + 100,
'Asset_B': np.random.normal(100, 10, 180).cumsum() + 120
})
data.set_index('Date', inplace=True)
data['Price_Diff'] = data['Asset_A'] - data['Asset_B']
window = 30
data['Mean_Diff'] = data['Price_Diff'].rolling(window=window).mean()
data['Std_Diff'] = data['Price_Diff'].rolling(window=window).std()
data['Upper_Bound'] = data['Mean_Diff'] + data['Std_Diff']
data['Lower_Bound'] = data['Mean_Diff'] - data['Std_Diff']
data['Position'] = 0
data.loc[data['Price_Diff'] > data['Upper_Bound'], 'Position'] = -1 # 做空Asset A,做多Asset B
data.loc[data['Price_Diff'] < data['Lower_Bound'], 'Position'] = 1 # 做多Asset A,做空Asset B
plt.figure(figsize=(14, 7))
plt.subplot(211)
plt.plot(data['Asset_A'], label='Asset A')
plt.plot(data['Asset_B'], label='Asset B')
plt.legend()
plt.subplot(212)
plt.plot(data['Price_Diff'], label='Price Difference')
plt.plot(data['Mean_Diff'], label='Mean Difference')
plt.fill_between(data.index, data['Upper_Bound'], data['Lower_Bound'], color='gray', alpha=0.3, label='Trading Zone')
plt.plot(data.index, data['Position'] * 20, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.legend()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=180),
'Asset_A': np.random.normal(100, 10, 180).cumsum() + 100,
'Asset_B': np.random.normal(100, 10, 180).cumsum() + 120
})
data.set_index('Date', inplace=True)
data['Price_Diff'] = data['Asset_A'] - data['Asset_B']
window = 30
data['Mean_Diff'] = data['Price_Diff'].rolling(window=window).mean()
data['Std_Diff'] = data['Price_Diff'].rolling(window=window).std()
data['Upper_Bound'] = data['Mean_Diff'] + data['Std_Diff']
data['Lower_Bound'] = data['Mean_Diff'] - data['Std_Diff']
data['Position'] = 0
data.loc[data['Price_Diff'] > data['Upper_Bound'], 'Position'] = -1 # 做空Asset A,做多Asset B
data.loc[data['Price_Diff'] < data['Lower_Bound'], 'Position'] = 1 # 做多Asset A,做空Asset B
plt.figure(figsize=(14, 7))
plt.subplot(211)
plt.plot(data['Asset_A'], label='Asset A')
plt.plot(data['Asset_B'], label='Asset B')
plt.legend()
plt.subplot(212)
plt.plot(data['Price_Diff'], label='Price Difference')
plt.plot(data['Mean_Diff'], label='Mean Difference')
plt.fill_between(data.index, data['Upper_Bound'], data['Lower_Bound'], color='gray', alpha=0.3, label='Trading Zone')
plt.plot(data.index, data['Position'] * 20, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.legend()
plt.show()
#4 統計的アービトラージ(Statistical Arbitrage)
統計的アービトラージは、複数の資産間の価格の歪みを利用する取引手法です。よくある方法は、歴史的な関係から乖離した株のペアやグループを特定し、それに基づいて取引を行うことです。以下は、2つの株の価格スプレッドに基づいた基本的な統計的アービトラージ戦略のPython実装例です:
import matplotlib.pyplot as plt
'Date': pd.date_range(start='2023-01-01', periods=250),
'Stock_A': np.random.normal(0, 1, 250).cumsum() + 50,
'Stock_B': np.random.normal(0, 1, 250).cumsum() + 50
data.set_index('Date', inplace=True)
data['Spread'] = data['Stock_A'] - data['Stock_B']
data['Spread Mean'] = data['Spread'].rolling(window=window).mean()
data['Spread Std'] = data['Spread'].rolling(window=window).std()
data['Upper Threshold'] = data['Spread Mean'] + entry_z * data['Spread Std']
data['Lower Threshold'] = data['Spread Mean'] - entry_z * data['Spread Std']
data['Exit Threshold'] = data['Spread Mean'] + exit_z * data['Spread Std']
data.loc[data['Spread'] > data['Upper Threshold'], 'Position'] = -1 # 做空Stock A,做多Stock B
data.loc[data['Spread'] < data['Lower Threshold'], 'Position'] = 1 # 做多Stock A,做空Stock B
data.loc[data['Spread'] * data['Position'] < data['Exit Threshold'], 'Position'] = 0 # 退出信号
plt.figure(figsize=(14, 7))
plt.plot(data['Stock_A'], label='Stock A')
plt.plot(data['Stock_B'], label='Stock B')
plt.title('Stock Prices')
plt.plot(data['Spread'], label='Spread')
plt.plot(data['Spread Mean'], label='Mean Spread')
plt.fill_between(data.index, data['Upper Threshold'], data['Lower Threshold'], color='gray', alpha=0.3, label='Entry Zone')
plt.plot(data.index, data['Position'] * 10, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Spread and Trading Signals')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=250),
'Stock_A': np.random.normal(0, 1, 250).cumsum() + 50,
'Stock_B': np.random.normal(0, 1, 250).cumsum() + 50
})
data.set_index('Date', inplace=True)
data['Spread'] = data['Stock_A'] - data['Stock_B']
window = 20
data['Spread Mean'] = data['Spread'].rolling(window=window).mean()
data['Spread Std'] = data['Spread'].rolling(window=window).std()
entry_z = 2
exit_z = 0
data['Upper Threshold'] = data['Spread Mean'] + entry_z * data['Spread Std']
data['Lower Threshold'] = data['Spread Mean'] - entry_z * data['Spread Std']
data['Exit Threshold'] = data['Spread Mean'] + exit_z * data['Spread Std']
data['Position'] = 0
data.loc[data['Spread'] > data['Upper Threshold'], 'Position'] = -1 # 做空Stock A,做多Stock B
data.loc[data['Spread'] < data['Lower Threshold'], 'Position'] = 1 # 做多Stock A,做空Stock B
data.loc[data['Spread'] * data['Position'] < data['Exit Threshold'], 'Position'] = 0 # 退出信号
plt.figure(figsize=(14, 7))
plt.subplot(211)
plt.plot(data['Stock_A'], label='Stock A')
plt.plot(data['Stock_B'], label='Stock B')
plt.title('Stock Prices')
plt.legend()
plt.subplot(212)
plt.plot(data['Spread'], label='Spread')
plt.plot(data['Spread Mean'], label='Mean Spread')
plt.fill_between(data.index, data['Upper Threshold'], data['Lower Threshold'], color='gray', alpha=0.3, label='Entry Zone')
plt.plot(data.index, data['Position'] * 10, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Spread and Trading Signals')
plt.legend()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
data = pd.DataFrame({
'Date': pd.date_range(start='2023-01-01', periods=250),
'Stock_A': np.random.normal(0, 1, 250).cumsum() + 50,
'Stock_B': np.random.normal(0, 1, 250).cumsum() + 50
})
data.set_index('Date', inplace=True)
data['Spread'] = data['Stock_A'] - data['Stock_B']
window = 20
data['Spread Mean'] = data['Spread'].rolling(window=window).mean()
data['Spread Std'] = data['Spread'].rolling(window=window).std()
entry_z = 2
exit_z = 0
data['Upper Threshold'] = data['Spread Mean'] + entry_z * data['Spread Std']
data['Lower Threshold'] = data['Spread Mean'] - entry_z * data['Spread Std']
data['Exit Threshold'] = data['Spread Mean'] + exit_z * data['Spread Std']
data['Position'] = 0
data.loc[data['Spread'] > data['Upper Threshold'], 'Position'] = -1 # 做空Stock A,做多Stock B
data.loc[data['Spread'] < data['Lower Threshold'], 'Position'] = 1 # 做多Stock A,做空Stock B
data.loc[data['Spread'] * data['Position'] < data['Exit Threshold'], 'Position'] = 0 # 退出信号
plt.figure(figsize=(14, 7))
plt.subplot(211)
plt.plot(data['Stock_A'], label='Stock A')
plt.plot(data['Stock_B'], label='Stock B')
plt.title('Stock Prices')
plt.legend()
plt.subplot(212)
plt.plot(data['Spread'], label='Spread')
plt.plot(data['Spread Mean'], label='Mean Spread')
plt.fill_between(data.index, data['Upper Threshold'], data['Lower Threshold'], color='gray', alpha=0.3, label='Entry Zone')
plt.plot(data.index, data['Position'] * 10, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Spread and Trading Signals')
plt.legend()
plt.show()
#5 ボラティリティ取引(Volatility Trading)
ボラティリティ取引戦略は、市場の変動性の変化から利益を得ることを目的としています。例えば、株の1日ごとのリターンと過去のボラティリティ(年率換算の標準偏差)を計算し、以下のような条件を設定できます:ボラティリティが平均の1.2倍を超えたら売り、0.8倍を下回ったら買い。以下はそのPython実装です:
import matplotlib.pyplot as plt
dates = pd.date_range(start='2023-01-01', periods=250)
prices = np.random.normal(0, 1, 250).cumsum() + 100
data.set_index('Date', inplace=True)
data['Returns'] = data['Price'].pct_change()
data.dropna(inplace=True)
data['Volatility'] = data['Returns'].rolling(window=window).std() * np.sqrt(252) # 年化波动性
threshold_high = data['Volatility'].mean() * 1.2
threshold_low = data['Volatility'].mean() * 0.8
data.loc[data['Volatility'] > threshold_high, 'Position'] = -1
data.loc[data['Volatility'] < threshold_low, 'Position'] = 1
plt.figure(figsize=(14, 10))
plt.plot(data['Price'], label='Price')
plt.plot(data['Volatility'], label='Volatility')
plt.axhline(y=threshold_high, color='r', linestyle='--', label='High Threshold')
plt.axhline(y=threshold_low, color='g', linestyle='--', label='Low Threshold')
plt.plot(data.index, data['Position'] * 0.01, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Volatility and Trading Signals')
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', periods=250)
prices = np.random.normal(0, 1, 250).cumsum() + 100
data = pd.DataFrame({
'Date': dates,
'Price': prices
})
data.set_index('Date', inplace=True)
data['Returns'] = data['Price'].pct_change()
data.dropna(inplace=True)
window = 20
data['Volatility'] = data['Returns'].rolling(window=window).std() * np.sqrt(252) # 年化波动性
threshold_high = data['Volatility'].mean() * 1.2
threshold_low = data['Volatility'].mean() * 0.8
data['Position'] = 0
data.loc[data['Volatility'] > threshold_high, 'Position'] = -1
data.loc[data['Volatility'] < threshold_low, 'Position'] = 1
plt.figure(figsize=(14, 10))
plt.subplot(211)
plt.plot(data['Price'], label='Price')
plt.title('Stock Price')
plt.legend()
plt.subplot(212)
plt.plot(data['Volatility'], label='Volatility')
plt.axhline(y=threshold_high, color='r', linestyle='--', label='High Threshold')
plt.axhline(y=threshold_low, color='g', linestyle='--', label='Low Threshold')
plt.plot(data.index, data['Position'] * 0.01, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Volatility and Trading Signals')
plt.legend()
plt.show()
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
np.random.seed(42)
dates = pd.date_range(start='2023-01-01', periods=250)
prices = np.random.normal(0, 1, 250).cumsum() + 100
data = pd.DataFrame({
'Date': dates,
'Price': prices
})
data.set_index('Date', inplace=True)
data['Returns'] = data['Price'].pct_change()
data.dropna(inplace=True)
window = 20
data['Volatility'] = data['Returns'].rolling(window=window).std() * np.sqrt(252) # 年化波动性
threshold_high = data['Volatility'].mean() * 1.2
threshold_low = data['Volatility'].mean() * 0.8
data['Position'] = 0
data.loc[data['Volatility'] > threshold_high, 'Position'] = -1
data.loc[data['Volatility'] < threshold_low, 'Position'] = 1
plt.figure(figsize=(14, 10))
plt.subplot(211)
plt.plot(data['Price'], label='Price')
plt.title('Stock Price')
plt.legend()
plt.subplot(212)
plt.plot(data['Volatility'], label='Volatility')
plt.axhline(y=threshold_high, color='r', linestyle='--', label='High Threshold')
plt.axhline(y=threshold_low, color='g', linestyle='--', label='Low Threshold')
plt.plot(data.index, data['Position'] * 0.01, label='Trading Signal', color='magenta', marker='o', linestyle='None')
plt.title('Volatility and Trading Signals')
plt.legend()
plt.show()