import pandas as pd
return = P(t) / P(t-k) - 1
# 导入数据
stock = pd.read_csv('stockszA.csv', index_col='Trddt')
wanke = stock[stock.Stkcd == 2]
close_price = wanke.Clsprc
# 转化为时间序列
close_price.index = pd.to_datetime(close_price.index)
close_price.index.name = 'Date'
lag_close_price = close_price.shift(1)
cal_close_price = pd.DataFrame({
'close': close_price, 'lagclose': lag_close_price})
# 计算单期简单收益率
simple_1_ret = (close_price - lag_close_price) / lag_close_price
simple_1_ret.name = 'simple_1_return'
cal_ret = pd.merge(cal_close_price, pd.DataFrame(simple_1_ret),
left_index=True, right_index=True)
# 计算2期简单收益率
simple_2_ret = (close_price - close_price.shift(2)) / close_price.shift(2)
simple_2_ret.name = 'simple_2_return'
cal_ret['simple_2_return'] = simple_2_ret
# 查看某一日的数据
print(cal_ret.iloc[5, :])
# close 7.460000
# lagclose 7.420000
# simple_1_return 0.005391
# simple_2_return 0.004038
# Name: 2014-01-09 00:00:00, dtype: float64
import ffn
ffn_simple_ret = ffn.to_returns(close_price)
ffn_simple_ret.name = 'ffn_simple_1_ret'
cal_ret['ffn_simple_1_ret'] = ffn_simple_ret
print(cal_ret[:5])
# close lagclose simple_1_return simple_2_return ffn_simple_ret
# Date
# 2014-01-02 7.99 NaN NaN NaN NaN
# 2014-01-03 7.84 7.99 -0.018773 NaN -0.018773
# 2014-01-06 7.48 7.84 -0.045918 -0.063830 -0.045918
# 2014-01-07 7.43 7.48 -0.006684 -0.052296 -0.006684
# 2014-01-08 7.42 7.43 -0.001346 -0.008021 -0.001346
针对不同周期的单期简单收益率计算年化简单收益率.
# 假设一年有245个交易日
def annualized_ret(returns, period):
if period == 'day':
return ((1 + returns).cumprod()[-1] ** (245 / len(returns)) - 1)
elif period == 'month':
return ((1 + returns).cumprod()[-1] ** (12 / len(returns)) - 1)
elif period == 'quarter':
return ((1 + returns).cumprod()[-1] ** (4 / len(returns)) - 1)
elif period == 'year':
return ((1 + returns).cumprod()[-1] ** (1 / len(returns)) - 1)
else:
raise Exception('Wrong period')
print(annualized_ret(simple_1_ret, 'day'))
① 股利宣告日
② 股权登记日
股权登记日这一天收市后仍持有该公司股票的投资者有权利参与此次股利发放
③ 除权除息日
上市公司向股东**分派股息**时需要对股票进行**除息**
上市公司向股东**送红股**时需要对股票进行**除权**
进行股权登记后,股票要除权除息,也就是将股票中含有的分红权利得以解除,通常股权登记日的下一个交易日即是除权除息日.
除权除息日根据股权登记日收盘价与分红现金的数量,送配股的数量和配股价的高低等结合起来算出调整后的前日收盘价.
ⅰ 除息价: 除息价=股息登记日的收盘价-每股红利现金额
ⅱ 除权价: 送红股后的除权价=股权登记日的收盘价 / (1+每股送红股数或转增股数)
ⅲ 除息除权价: 除权除息价=(股权登记日的收盘价-每股红利现金额) / (1+每股送红股数或转增股数)
④ 股利发放日
股息率 = Div / Price * 100%
市盈率(本益比, P/E) = 每股市价 / 每股盈利
import numpy as np
# method 1
compo_ret = np.log(close_price / lag_close_price)
compo_ret.name = 'compo_ret'
cal_ret['compo_ret'] = compo_ret
# method 2
ffn_compo_ret = ffn.to_log_returns(close_price)
cal_ret['ffn_compo_ret'] = ffn_compo_ret
print(cal_ret[:5])
# close lagclose ... compo_ret ffn_compo_ret
# Date ...
# 2014-01-02 7.99 NaN ... NaN NaN
# 2014-01-03 7.84 7.99 ... -0.018952 -0.018952
# 2014-01-06 7.48 7.84 ... -0.047006 -0.047006
# 2014-01-07 7.43 7.48 ... -0.006707 -0.006707
# 2014-01-08 7.42 7.43 ... -0.001347 -0.001347
compo_2_ret = np.log(close_price / close_price.shift(2))
compo_2_ret.name = 'compo_2_ret'
cal_ret['compo_2_ret'] = compo_2_ret
compo_ret = compo_ret.dropna()
sum_compo_ret = compo_ret + compo_ret.shift(1)
sum_compo_ret.name = 'sum_compo_ret'
cal_ret['sum_compo_ret'] = sum_compo_ret
print(cal_ret.iloc[:5, [0, 5, 6, 7, 8]])
# close compo_ret ffn_compo_ret compo_2_ret sum_compo_ret
# Date
# 2014-01-02 7.99 NaN NaN NaN NaN
# 2014-01-03 7.84 -0.018952 -0.018952 NaN NaN
# 2014-01-06 7.48 -0.047006 -0.047006 -0.065958 -0.065958
# 2014-01-07 7.43 -0.006707 -0.006707 -0.053713 -0.053713
# 2014-01-08 7.42 -0.001347 -0.001347 -0.008054 -0.008054
import matplotlib.pyplot as plt
plt.switch_backend('TkAgg')
plt.plot(cal_ret.index, cal_ret.simple_1_return)
plt.show()
plt.plot(cal_ret.index,(1 + cal_ret.simple_1_return).cumprod() - 1)
plt.show()
sa_power = pd.read_csv('SAPower.csv', index_col='Date')
dalian_rp = pd.read_csv('DalianRP.csv', index_col='Date')
sa_power.index = pd.to_datetime(sa_power.index)
dalian_rp.index = pd.to_datetime(dalian_rp.index)
return_s = ffn.to_returns(sa_power.Close).dropna()
return_d = ffn.to_returns(dalian_rp.Close).dropna()
print(return_s.std())
print(return_d.std())
# 0.041511404614033375
# 0.020319411733180383
下行风险用**下行偏差(Downside Deviation)**来表示,通常用可接受的最低收益率(Minimum Acceptable Rate of Return, MARR),其中MARR可以是无风险收益率、0或者资产收益率的平均值。
# 用收益率的均值作为MARR
def cal_half_dev(returns):
mu = returns.mean()
temp = returns[returns < mu]
half_deviation = (sum((mu - temp) ** 2) / len(returns)) ** 0.5
return half_deviation
print(cal_half_dev(return_s), cal_half_dev(return_d))
# 0.03559345345188915 0.013699709683876092
VaR是给定的置信水平和目标时段下预期的最大损失(或最坏情况下的损失)。
在市场正常波动的条件下、在一定概率水平ɑ%下,某一金融资产或金融资产组合的VaR是在未来特定的一段时间内的最大可能损失。
VaR的估算关键在于描述投资组合在评估期间收益的概率分布,常见方式有:
1. 历史模拟法 historical simulation approach
本质上是将未来收益的分布用历史分布代替,一般样本数据不得少于1500个。
print(return_d.quantile(0.05), return_s.quantile(0.05))
# -0.03408596308105866 -0.043192456894806296
则d:有5%的概率会下跌超过3.41%;s:有5%的概率会下跌4.32%。
2. 协方差矩阵法 variance-covariance approach
该法假设各资产的收益率服从正态分布且投资组合的收益率与个资产的收益率呈线性关系,这样投资组合的收益率也服从正态分布。
from scipy.stats import norm
print(norm.ppf(0.05, return_d.mean(), return_d.std()))
print(norm.ppf(0.05, return_s.mean(), return_s.std()))
# -0.03274944602236822
# -0.06621086216022148
则d:有5%的概率会下跌超过3.27%;s:有5%的概率会下跌6.62%。
3. 蒙特卡洛模拟法 Monte Carlo simulation approach
一种随机模拟方法,随机产生大量情景,由此得到投资组合的收益分布。
与VaR相似,考虑的是超过VaR水平损失的期望值,也就是最坏的ɑ%损失的平均值。
print(return_d[return_d <= return_d.quantile(0.05)].mean())
print(return_s[return_s <= return_s.quantile(0.05)].mean())
# -0.045367282385701486
# -0.09673316088802106
MDD(T)对应的是在(0, T)时段内资产价值从最高峰值回落到最低谷底的幅度。
最大回撤常用来描述投资者在持有资产时可能面临的最大亏损,比如某投资人在投资时不够理性,以高位价格X追买了基金A,之后基金A价格回落,曾一度达到最低价格Y,并在没有回到X的价位,如果一直持有这只基金,那么在持有基金期间,面临的最大损失为X-Y,即最大回撤。
# Method 1
# 利用各期收益率序列求最大回撤
import datetime
r = pd.Series([0, 0.1, -0.1, -0.01, 0.01, 0.02],
index=[datetime.date(2015, 7, x) for x in range(3, 9)])
print(r)
value = (1 + r).cumprod()
# 各时点回撤值
D = value.cummax() - value
# 各时点回撤率
d = D / (D + value)
# 最大回撤
MDD = D.max()
print(MDD)
最大回撤率
mdd = d.max()
print(mdd)
'''
2015-07-03 0.00
2015-07-04 0.10
2015-07-05 -0.10
2015-07-06 -0.01
2015-07-07 0.01
2015-07-08 0.02
dtype: float64
0.1199
0.109
'''
# Method 2
# ffn.calc_max_drawdown(prices) ----prices为收益率序列
print(ffn.calc_max_drawdown(value))
# -0.10899999999999999
import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# plt.switch_backend('TkAgg') # 偶尔出现plt不显示的情况
# 获取数据
pro = ts.pro_api('your token')
df = pro.daily(ts_code='601360.SH', start_date='20140101', end_date='20141231')
# 排序、抓取
df = df.sort_values(by='trade_date', axis=0, ascending=True)
df.index = range(1, len(df) + 1)
data = df[['trade_date', 'close']]
# Dataframe全部显示
pd.set_option('expand_frame_repr', False)
# 计算
returns = (data.close - data.close.shift(1)) / data.close.shift(1) # 日简单收益率
data['returns'] = returns
comp_returns = np.log(data.close / data.close.shift(1)) # 日复合收益率
data['comp_returns'] = comp_returns
print(comp_returns.sum()) # 2014年度复合收益率
print(data)
# 制图
plt.plot(returns, label='简单收益率', color='b')
plt.plot(comp_returns, label='累计收益率', color='r')
plt.legend()
plt.show()