논문
글쓴이
Evan Gatev
Simon Fraser University
William N. Goetzmann
Yale School of Management - International Center for Finance; National Bureau of Economic Research (NBER)
K. Geert Rouwenhorst
Yale School of Management - International Center for Finance
소개
논문은 1962년부터 2002년 기간의 일간 데이터를 이용하여 "Pair Trading"이라는 월가의 투자 전략을 테스트하고 결과를 정리합니다.
핵심이론
- Enter a long position on the spread if it is below -1 STD.
- Enter a short position on the spread if it is above 1 STD.
프로세스
- 데이터 (binance,bitmart,huobi,gateio,bittrex)
- indicator 정립
- Strategy 정립
- 데이터 -> indicator -> Strategy -> broker 연결
Bactrader 목표
- custom indicator 만들기
- broker 다루어 보기
논문구현
python 으로 코드구현을 해보았다
사용한 라이브러리 : ccxt backtrader, empyrical, pandas, numpy, matplotlib
사용한 환경 : colab
설정
import datetime
from datetime import datetime as dt
import pandas as pd
import numpy as np
import ccxt
import backtrader as bt
import empyrical as ep
import matplotlib.pyplot as plt
from pylab import rcParams
%matplotlib inline
rcParams['figure.figsize'] = 16,9
rcParams['figure.facecolor'] = '#eeeeee'
plt.title('dummy')
plt.plot([1,3,2,4])
plt.close()
데이터 불러오기 (binance BTC/USDT, binance ETH/USDT)
def get_data(place,coin) :
start_date = int(datetime.datetime(2020, 1, 1, 0, 0).timestamp() * 1000)
if place == 'binance' :
binance = ccxt.binance()
ohlcvs = binance.fetch_ohlcv(coin, timeframe='1d', since=start_date, limit = 365)
if place == 'okex' :
okex = ccxt.okex()
ohlcvs = okex.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'upbit' :
upbit = ccxt.upbit()
ohlcvs = upbit.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'ftx' :
ftx = ccxt.ftx()
ohlcvs = ftx.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'huobi' :
huobi = ccxt.huobi()
ohlcvs = huobi.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'bitmart' :
bitmart = ccxt.bitmart()
ohlcvs = bitmart.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'gateio' :
gateio = ccxt.gateio()
ohlcvs = gateio.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'bitrue' :
bitrue = ccxt.bitrue()
ohlcvs = bitrue.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
if place == 'bittrex' :
bittrex = ccxt.bittrex()
ohlcvs = bittrex.fetch_ohlcv(coin, timeframe='1d', since=start_date , limit = 365)
for idx, ohlcv in enumerate(ohlcvs):
ohlcvs[idx] = [dt.fromtimestamp(ohlcv[0]/1000).strftime('%Y-%m-%d %H:%M:%S'), ohlcv[1], ohlcv[2], ohlcv[3], ohlcv[4],ohlcv[5]]
df = pd.DataFrame(ohlcvs)
df.columns = ['Time', 'Open','High','Low','Close','Volume']
df['Time'] = pd.to_datetime(df['Time'], format='%Y-%m-%d %H:%M:%S', errors='raise')
df.set_index('Time',inplace=True)
return df
indicator 설정
class Pair(bt.indicators.PeriodN):
params = {'period': 10} # even if defined, we can redefine the default value
lines = ('zscore',) # our output line
def __init__(self):
self.transform = bt.ind.OLS_TransformationN(self.data0, self.data1,
period=self.p.period)
self.lines.zscore = self.transform.zscore
Strategy 설정
class Test_Strategy(bt.Strategy):
params = dict(
threshold=1,
)
def __init__(self):
self.lines.zscore = Pair(self.data0,self.data1)
self.threshold = self.p.threshold
def next(self):
# if not self.position:
if (self.lines.zscore[0] < abs(self.threshold)) :
self.order = self.buy()
# else:
if (self.lines.zscore[0] > self.threshold) :
self.order = self.sell()
실행
binance_btc = get_data('binance','BTC/USDT')
binance_eth = get_data('binance','ETH/USDT')
data0=bt.feeds.PandasData(dataname=binance_btc)
data1=bt.feeds.PandasData(dataname=binance_eth)
data0=bt.feeds.PandasData(dataname=binance_btc)
data1=bt.feeds.PandasData(dataname=binance_eth)
cerebro = bt.Cerebro()
cerebro.adddata(data0)
cerebro.adddata(data1)
cerebro.addstrategy(Test_Strategy)
cerebro.addanalyzer(bt.analyzers.PyFolio)
cerebro.broker.setcash(1000000)
cerebro.addsizer(bt.sizers.FixedSize, stake=5)
print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
# Run over everything
results = cerebro.run() # [15]
# Print out the final result
print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
Analyze
strat = results[0]
pyfoliozer = strat.analyzers.getbyname('pyfolio')
returns, positions, transactions, gross_lev = pyfoliozer.get_pf_items()
SIMPLE_STAT_FUNCS = [
ep.annual_return,
ep.cum_returns_final,
ep.annual_volatility,
ep.sharpe_ratio,
ep.calmar_ratio,
ep.stability_of_timeseries,
ep.max_drawdown,
ep.omega_ratio,
ep.sortino_ratio,
ep.tail_ratio,
]
STAT_FUNC_NAMES = {
'annual_return': 'Annual return',
'cum_returns_final': 'Cumulative returns',
'annual_volatility': 'Annual volatility',
'sharpe_ratio': 'Sharpe ratio',
'calmar_ratio': 'Calmar ratio',
'stability_of_timeseries': 'Stability',
'max_drawdown': 'Max drawdown',
'omega_ratio': 'Omega ratio',
'sortino_ratio': 'Sortino ratio',
'skew': 'Skew',
'kurtosis': 'Kurtosis',
'tail_ratio': 'Tail ratio',
'common_sense_ratio': 'Common sense ratio',
'value_at_risk': 'Daily value at risk',
'alpha': 'Alpha',
'beta': 'Beta',
}
stats = pd.Series()
for i,stat_func in enumerate(SIMPLE_STAT_FUNCS):
stats[STAT_FUNC_NAMES[stat_func.__name__]] = stat_func(returns)
stats.iloc[i] = str(np.round(stats.iloc[i] * 100,3)) + '%'
perf_stats = pd.DataFrame(stats, columns=['Backtest'])
Result
Reference
https://papers.ssrn.com/sol3/papers.cfm?abstract_id=141615
Pairs Trading: Performance of a Relative Value Arbitrage Rule
47 Pages Posted: 28 Dec 1998 Last revised: 24 Jan 2008 Abstract We test a Wall Street investment strategy, pairs trading, with daily data over 1962-2002. Stocks are matched into pairs with minimum distance between normalized historical prices. A simple tra
papers.ssrn.com
https://quantpedia.com/strategies/pairs-trading-with-stocks/
Pairs Trading with Stocks - QuantPedia
We’ve already analyzed tens of thousands of financial research papers and identified more than 600 attractive trading systems together with hundreds of related academic papers. Browse Strategies Unlocked Screener & 200+ Advanced Charts600+ uncommon tradi
quantpedia.com
https://www.quantconnect.com/tutorials/strategy-library/pairs-trading-with-stocks
QuantConnect Tutorials
Learn to use QuantConnect with guided tutorials
www.quantconnect.com
https://towardsdatascience.com/pairs-trading-with-cryptocurrencies-e79b4a00b015
Pairs Trading with Cryptocurrencies
The article describes a brief introduction to pairs trading including concept, basic math, strategy algorithm, trading robot development…
towardsdatascience.com
https://medium.com/@dinodecastro/pair-trading-with-cryptocurrencies-part-2-a820ca121400
Pair-trading With Cryptocurrencies Part 2
How To Implement A Pair-trading Strategy Using Python
medium.com
https://github.com/lamres/pairs_trading_cryptocurrencies_strategy_catalyst
GitHub - lamres/pairs_trading_cryptocurrencies_strategy_catalyst: Pairs trading strategy example based on Catalyst
Pairs trading strategy example based on Catalyst. Contribute to lamres/pairs_trading_cryptocurrencies_strategy_catalyst development by creating an account on GitHub.
github.com
https://github.com/mementum/backtrader/blob/master/contrib/samples/pair-trading/pair-trading.py
GitHub - mementum/backtrader: Python Backtesting library for trading strategies
Python Backtesting library for trading strategies. Contribute to mementum/backtrader development by creating an account on GitHub.
github.com
'금융공학 > 논문구현' 카테고리의 다른 글
논문 리뷰 및 구현 - Does Trend Following Work on Stocks? (2005) (0) | 2022.01.19 |
---|---|
논문 리뷰 및 구현 - Testing the Significance of Calendar Effects(2003) (0) | 2022.01.03 |
논문구현 을 어떤 방향으로 할것인가? (0) | 2021.12.30 |
논문 리뷰 및 구현 - Option-Expiration Week Effect (0) | 2021.12.30 |
논문 리뷰 및 구현 - Trading Cryptocurrencies Using Second OrderStochastic Dominance (0) | 2021.12.30 |