我们根据你获得的hs300数据,来查看下沪深300的年化收益。
import arrow
import numpy as np
end = arrow.get("2024-09-03")
year_ago = end.shift(years = -1)
year_ago = hs300[hs300.index >= np.datetime64(year_ago)].index[0]
print(year_ago)
# 计算买入并持有的收益(最近一年)
buy_price = hs300[hs300.index == year_ago].iloc[0]["close"]
buy_and_hold = hs300["close"][-1]/buy_price - 1
print(f"买入并持收益:{buy_and_hold:.2%}")
# 通过均值推算年化收益
market_returns = hs300["close"].pct_change().dropna()
market_annual = (1 + market_returns[market_returns.index >= year_ago].mean()) ** 242 - 1
print(f"年化收益: {market_annual:.2%}")
2023-09-04 00:00:00
买入并持收益:-14.95%
年化收益: -12.87%
C:\Users\Administrator\AppData\Local\Temp\ipykernel_5664\1405670539.py:7: UserWarning: no explicit representation of timezones available for np.datetime64
  year_ago = hs300[hs300.index >= np.datetime64(year_ago)].index[0]
C:\Users\Administrator\AppData\Local\Temp\ipykernel_5664\1405670539.py:12: FutureWarning: Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`
  buy_and_hold = hs300["close"][-1]/buy_price - 1
通过两种方法进行推算得到,过去一年沪深300的收益大约在-15%左右。
接下来,我们获取沪深300成份股,以便从中抽取个股进行检验。请使用变量名 index_stock_cons_df 来保存你获取的成份股数据。
# 在此写下你的代码
import akshare as ak
index_stock_cons_df = ak.index_stock_cons(symbol="399300")
# 打印结果
print(index_stock_cons_df)
最终,我们应该得到类似输出:
       品种代码  品种名称        纳入日期
0    001965  招商公路  2024-06-17
1    000807  云铝股份  2024-06-17
2    300442  润泽科技  2024-06-17
3    600415  小商品城  2024-06-17
4    603296  华勤技术  2024-06-17
..      ...   ...         ...
295  600660  福耀玻璃  2005-04-08
296  600690  青岛海尔  2005-04-08
297  600741  巴士股份  2005-04-08
298  600795  国电电力  2005-04-08
299  600900  长江电力  2005-04-08
接下来,我们随机取10支股票,获取行情,并计算每日收益率:
# 随机抽取10支股票,获取行情并计算每日收益
# 请在此写下你的代码
np.random.seed(78)
stocks = random.sample(index_stock_cons_df['品种代码'].to_list(), 10)
frames = {}
now = arrow.now()
start = now.shift(years = -1)
end = now.format("YYYYMMDD")
start = start.format("YYYYMMDD")
print(end)
print(start)
# 获取 10 支股票的行情数据
for code in stocks:
    bars = ak.stock_zh_a_hist(symbol=code, period="daily", start_date=start, end_date=end, adjust="qfq")
    bars.index = pd.to_datetime(bars["日期"])
    frames[code] = bars["收盘"]
# 与指数行情数据合并
start = np.datetime64(now.shift(years = -1))
frames["399300"] = hs300[hs300.index >= start]["close"]
df = pd.DataFrame(frames)
# 计算每日收益
returns = df.pct_change()
# 如果存在 NAN,则后面的回归法将无法聚合
returns.dropna(how='any', inplace=True)
returns.head().style.format('{:,.2%}')
为了后面的代码能够运行,请将行情数据保存在df变量中,每日收益保存在returns中。最终,returns应该是类似下面的结果:
                    688396  600941  600346  002410  000776  601916  300896  600332  601601  601788  399300
2023-09-05 00:00:00 -1.29%  -1.06%  0.55%   -0.62%  -1.13%  -1.22%  -0.69%  -0.43%  -1.26%  -1.41%  -0.74%
2023-09-06 00:00:00 -1.46%  -1.02%  1.17%   1.05%   -0.34%  0.00%   -0.22%  -0.13%  1.59%   0.12%   -0.22%
2023-09-07 00:00:00 -1.92%  0.28%   -0.95%  -1.16%  -1.01%  -0.41%  -2.59%  -1.73%  -0.48%  0.42%   -1.40%
2023-09-08 00:00:00 -0.59%  1.48%   -0.76%  -1.17%  0.34%   -0.41%  -1.63%  -0.34%  -0.27%  0.59%   -0.49%
2023-09-11 00:00:00 0.07%   0.85%   0.07%   2.30%   1.29%   0.42%   3.18%   2.10%   -1.37%  0.94%   0.74%
提示,你可能需要使用这些方法:
- random.sample
- stock_zh_a_hist
- pd.to_datetime
- np.datetime64
- df.pct_change
- df.dropna
- df.style.format
接下来,我们就可以实施CAPM模型。这里我们仅用多项式拟合法。
cols = df.columns
betas = {}
for name in cols:
    beta, alpha = np.polyfit(returns[name], returns["399300"], deg=1)
    print(name, f"{beta:.2%} {alpha:.2%}")
    betas[name] = beta
688396 24.96% -0.02%
600941 1.46% -0.06%
600346 30.01% -0.06%
002410 18.09% 0.00%
000776 58.21% -0.02%
601916 33.28% -0.07%
300896 15.09% -0.02%
600332 36.72% -0.05%
601601 23.79% -0.07%
601788 33.63% -0.05%
399300 100.00% 0.00%
最好的一支是002410。我们就看看,如果买入这一支,它的alpha和beta是多少:
code = "002410"
beta = betas[code]
# 回归法得到的预期收益
expected_return = rf + beta * (market_annual - rf)
print(f"code beta: {beta:.2f}, Er: {expected_return:.2%}")
code beta: 0.18, Er: -0.80%