四分位數分析
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
from pandas import Series,DataFrame
from datetime import datetime
from dateutil.parser import parse
import time
from pandas.tseries.offsets import Hour,Minute,Day,MonthEnd
import pytz
import random;random.seed(0)
import string
from numpy.random import rand
### import pandas.io.data as web # old version
from pandas_datareader import data, wb
import tushare as ts
%matplotlib inline
def to_index(rets): # 轉換為收益率指數(隔夜收益率)
index = (1 + rets).cumprod()
#下面是將第一個有效值的位置拿出來
# first_loc = max(index.notnull().argmax() - 1,0)
# index.values[first_loc] = 1
first_ix = index.notnull().argmax() - pd.Timedelta(3,unit='D')
index[first_ix] = 1
return index
def trend_signal(rets,lookback,lag):
# signal = pd.rolling_sum(rets,lookback,min_periods = lookback - 5)
# pd.rolling_sum is deprecated for Series and will be removed in a future version,
# replace with Series.rolling(min_periods=95,window=100,center=False).sum()
signal = rets.rolling(lookback, min_periods=lookback-5).sum() # 相當於通達信的 SUM(roc1,lookback)
return signal.shift(lag)
數據下載和規整化
- 從tushare網下載數據:
- 以研究為目的話, 一定要用
ts.get_k_data()接口函數
- 以研究為目的話, 一定要用
- 惱人的數據規整化:
- 一直遭受者數據不規整的折磨, 主要表現為:
- 1號軸上的ohlc的排列順序不統一, 需要規整為dohlcv的順序
- 0號軸上的數據格式不統一, 需要規整為datetimeIndex類型
- 用到的方法: 傳入設定的index:
index=pd.to_datetime(df.date.values)
- 用到的方法: 傳入設定的index:
- 嚴格遵守上述規則, 否則自己的udf無法執行或者得不到預期的結果
- 一直遭受者數據不規整的折磨, 主要表現為:
# df=ts.get_hist_data('002242','2010-01-01', '2016-12-31')
# df=df.sort_index()
# 實際上得不到6年的日線數據
# 這種方式獲取數據的特點: 期數不能超過500, 列數還包括3條均線+3條成交量的均線, 0軸是降序排列的
df=ts.get_k_data('002242', '2010-01-01','2016-12-31',ktype='D')
# 這種方式獲取數據的特點: 7列+0軸是序號, 升序排列,
# 很適合做歷史數據的研究
# date open close high low volume code
# 重構數據框: 按照常規的dohlcv順序+常規索引轉為時間索引
df= DataFrame({
'open' :df.open.values,
'high' :df.high.values,
'low' :df.low.values,
'close' :df.close.values,
'volume':df.volume.values,
'code' :df.code.values },
index= pd.to_datetime(df.date.values),
columns=['open','high','low','close', 'volume', 'code'],
)
iclose = df.close
iroc1 = iclose.pct_change(); iroc1.name='roc1'
ipnl = (1+iroc1).cumprod(); ipnl.name='pnl_index'
iclose.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x6cb9d30>


ipnl.plot()

signal=trend_signal(iroc1, 100,3)
trade_friday=signal.resample('W-FRI').mean().resample('B').ffill()
trade_rets = trade_friday.shift(1) * iroc1
trade_friday.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x6edfc30>


trade_rets.plot()
<matplotlib.axes._subplots.AxesSubplot at 0x706cd50>


#然后將該策略的收益率轉換為一個收益指數,並繪制一張圖表
profit_index = to_index(trade_rets)
profit_index.plot()
# plt.show()
<matplotlib.axes._subplots.AxesSubplot at 0x7061dd0>


四分位分析
需要解決的問題是: 依據波動性把隔夜波動率或者策略的收益率划分出4個階段(4個分組), 該策略的績效在哪個分組里表現最好呢?
假設: 這里衡量策略績效的標准為夏普比, 我們需要分組聚合Sharpe.
詳細步驟如下:
- 計算波動性volatile
- 計算四分位數的分組鍵:
key = pd.qcut(volatile,4) - 計算分組對象:
grouper = data.groupby(by=key) - 構造計算夏普比的udf: sharpe
- 在分組的基礎上應用(實施--apply aggregate function)聚合函數:
grouper.agg(sharpe)
# 假如希望將該策略的性能按不同大小的交易期波幅進行划分。
# 年度標准差是計算波幅的一種簡單辦法,
# 可以通過計算夏普比率來觀察不同波動機制下的風險收益率:
# vol = pd.rolling_std(returns,250,min_periods = 200) * np.sqrt(250)
volatile = iroc1.rolling(window=250,min_periods = 200,
center=False).std() * np.sqrt(250) # 年化波動性
volatile.name='volatility'
# pd.rolling_std is deprecated for Series and will be removed in a future version,
# replace with: Series.rolling(min_periods=200,window=250,center=False).std()
def sharpe(rets,ann = 250):
return rets.mean() / rets.std() * np.sqrt(ann)
isharpe = iroc1.groupby(by=pd.qcut(volatile,4)).agg(sharpe); isharpe.name='sharpe'
# print isharpe
isharpe
volatility
[0.231, 0.312] 0.208484
(0.312, 0.41] 0.696361
(0.41, 0.513] 0.493069
(0.513, 0.797] 0.097292
Name: sharpe, dtype: float64
isharpe.index
CategoricalIndex([u'[0.231, 0.312]', u'(0.312, 0.41]', u'(0.41, 0.513]',
u'(0.513, 0.797]'],
categories=[u'[0.231, 0.312]', u'(0.312, 0.41]', u'(0.41, 0.513]', u'(0.513, 0.797]'], ordered=True, name=u'volatility', dtype='category')
對聚合結果的分析和結論
由上述聚合數據表可知: 第二四分位對應的夏普比最高. 也就是說: 對於九陽股份而言, 當它的年化波動性位於(0.312, 0.41]之區間時, 夏普比達到最佳值, 這時匯聚得到的sharpe值為0.69.
