금융공학/논문구현
논문 리뷰 및 구현 - Testing the Significance of Calendar Effects(2003)
냥냥펀치데스
2022. 1. 3. 17:19
728x90
논문
글쓴이
더보기
Peter Reinhard Hansen
University of North Carolina (UNC) at Chapel Hill - Department of Economics; Copenhagen Business School, Finance; Aarhus University - CREATES
Asger Lunde
CREATES; Aarhus University - School of Business and Social Sciences
James M. Nason
North Carolina State University - Department of Economics
소개
Day trade 를 직업으로 하는 사람들에게는 holiday 이전이 마지막 거래일수 있음으로 나타나는 특이현상에 대한 분석
핵심이론
- PublicHoliday 2일전에 buy
- 당일 sell
논문구현
python 으로 코드구현을 해보았다
사용한 라이브러리 : ccxt, backtrader, empyrical, pandas, numpy, matplotlib
사용한 환경 : colab
환경설정
import datetime
from datetime import datetime as dt
import pandas as pd
from pandas.tseries.holiday import USFederalHolidayCalendar as calendar
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()
Data 준비
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
휴일설정
2틀전 거래를 할것임으로 2일 뒤로 shift
cal = calendar()
holidays = cal.holidays(start=binance_btc.index.min(), end=binance_btc.index.max())
binance_btc['Holiday'] = binance_btc.index.isin(holidays)
binance_btc['Holiday'] = binance_btc['Holiday'].shift(-2)
binance_btc.fillna(False)
데이터 설정
class pandasDataFeed(bt.feeds.PandasData):
lines = ('Holiday',)
params = (
('datetime', None),
('high', 'High'),
('low', 'Low'),
('open', 'Open'),
('close', 'Close'),
('volume', None),
('Holiday', 'Holiday')
)
전략설정
class Test_Strategy(bt.Strategy):
params = dict(
status = 0,
)
def __init__(self):
self.status = self.p.status
def next(self):
if self.status >= 2 :
self.status -= 1
if not self.position:
# Not yet ... we MIGHT BUY if ...
if self.data.Holiday :
# Keep track of the created order to avoid a 2nd order
self.order = self.buy()
self.status = 3
else:
if self.status == 1:
# Keep track of the created order to avoid a 2nd order
self.order = self.sell()
self.stauts = 0
코드실행
df=pandasDataFeed(dataname=binance_btc)
cerebro = bt.Cerebro()
cerebro.adddata(df)
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]
strat = results[0] # [16]
# 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'])