import sys
sys.path.insert(0, "../../")
# 演示必要的准备代码,使用该库时不需重复此单元格命令
import xalpha as xa
import pandas as pd
本文将分析大陆公募基金市场中和石油商品相关的基金,考察其相关性和可替代性
hb = xa.fundinfo("162411") # 华宝油气
gf = xa.fundinfo("162719") # 广发石油
ha = xa.fundinfo("160416") # 华安石油
nf = xa.fundinfo("501018") # 南方原油
yfd = xa.fundinfo("161129") # 易方达原油
js = xa.fundinfo("160723") # 嘉实原油
oilcomp = xa.evaluate(hb, gf, ha, nf, yfd, js)
oilcomp.v_correlation()
观察上述的相关系数图,可以看到高关联的基金自动分成两个区。三个跟踪原油期货的基金关联极高。同时三个在美股为主跟踪石油产业企业股票指数的基金(对应指数不同)关联极高。另一方面,两者之间关联并没有特别高。像经常宣传和原油价格走势关联很高的华宝油气,其关联系数也只有 0.67 左右,并不是很高。这种跟踪意义不大,下面不同基金的净值图将这个问题表现的更明显。 如果非想持有石油股票指数来减少原油期货换仓损失的话,华安石油相比华宝油气具有更高的关联性,相关系数在 0.73 左右,高于另两个石油股票基金。
oilcomp.v_netvalue()
可以看到三个追踪原油期货的基金,走势几乎完全一致,在两年多的时间中产生的误差很有限。 奇怪的是,在这段区间石油价格有所回升,同时美股一直运行在牛市,但主力在美股的石油企业的股票走势还比不上原油价格本身,尤其是华宝油气表现极差。也就是说,美股里这些企业估值在不断走低,对应了大家的夕阳产业预期。
华宝油气:0.15+1.28, 标普石油天然气上游股票指数
华安石油: 0.12+1.28, 标普全球石油指数
广发石油: 0.39 亿,规模低于清盘线,请谨慎申购, 0.12+1.3, 道琼斯美国石油开发与生产指数
易方达原油: 0.12+1.25,标普高盛原油商品指数
南方原油: 0.12+1.28, 60%WTI原油价格收益率 + 40%BRENT原油价格收益率
嘉实原油: 0.12+1.28,100%WTI原油价格收益率
for fund in oilcomp.fundobjs:
print(fund.name, fund.algorithm_volatility())
华宝标普油气上游股票 0.31330039728004055 广发道琼斯石油指数人民币A 0.23449795919975377 华安标普全球石油指数 0.1684688810075437 南方原油A 0.23465224682648175 易方达原油A类人民币 0.2244510474007535 嘉实原油(QDII-LOF) 0.22860537822326174
大多数人投资石油基金并不是为了长期价值投资,而是为了做波段,因此波动率越高越好。由此可以看出,华宝油气是波动最大的。
我们现在研究下原油基金的换仓损耗到底有多高,首先爬取过去一年的 WTI 原油期货价格日线数据
import requests
import datetime as dt
r = requests.get(
"https://cn.investing.com/common/modules/js_instrument_chart/api/data.php?pair_id=8849&pair_id_for_news=8849&chart_type=area&pair_interval=86400&candle_count=120&events=yes&volume_series=yes&period=1-year",
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
"Referer": "https://cn.investing.com/commodities/crude-oil",
"Host": "cn.investing.com",
"X-Requested-With": "XMLHttpRequest",
},
)
tz_utc = dt.timezone(dt.timedelta(hours=0))
date = []
netvalue = []
for line in r.json()["candles"]:
date.append(dt.datetime.fromtimestamp(line[0] / 1000, tz_utc).replace(tzinfo=None))
netvalue.append(line[1])
df = pd.DataFrame(data={"date": date, "netvalue": netvalue})
df
date | netvalue | |
---|---|---|
0 | 2018-08-24 | 68.72 |
1 | 2018-08-27 | 68.87 |
2 | 2018-08-28 | 68.53 |
3 | 2018-08-29 | 69.51 |
4 | 2018-08-30 | 70.25 |
5 | 2018-08-31 | 69.80 |
6 | 2018-09-02 | 69.92 |
7 | 2018-09-03 | 70.12 |
8 | 2018-09-04 | 69.87 |
9 | 2018-09-05 | 68.72 |
10 | 2018-09-06 | 67.77 |
11 | 2018-09-07 | 67.75 |
12 | 2018-09-10 | 67.54 |
13 | 2018-09-11 | 69.25 |
14 | 2018-09-12 | 70.37 |
15 | 2018-09-13 | 68.59 |
16 | 2018-09-14 | 68.99 |
17 | 2018-09-17 | 68.91 |
18 | 2018-09-18 | 69.85 |
19 | 2018-09-19 | 71.12 |
20 | 2018-09-20 | 70.80 |
21 | 2018-09-21 | 70.78 |
22 | 2018-09-24 | 72.08 |
23 | 2018-09-25 | 72.28 |
24 | 2018-09-26 | 71.57 |
25 | 2018-09-27 | 72.12 |
26 | 2018-09-28 | 73.25 |
27 | 2018-10-01 | 75.30 |
28 | 2018-10-02 | 75.23 |
29 | 2018-10-03 | 76.41 |
... | ... | ... |
234 | 2019-07-15 | 59.58 |
235 | 2019-07-16 | 57.62 |
236 | 2019-07-17 | 56.78 |
237 | 2019-07-18 | 55.30 |
238 | 2019-07-19 | 55.63 |
239 | 2019-07-22 | 56.22 |
240 | 2019-07-23 | 56.77 |
241 | 2019-07-24 | 55.88 |
242 | 2019-07-25 | 56.02 |
243 | 2019-07-26 | 56.20 |
244 | 2019-07-29 | 56.87 |
245 | 2019-07-30 | 58.05 |
246 | 2019-07-31 | 58.58 |
247 | 2019-08-01 | 53.95 |
248 | 2019-08-02 | 55.66 |
249 | 2019-08-05 | 54.69 |
250 | 2019-08-06 | 53.63 |
251 | 2019-08-07 | 51.09 |
252 | 2019-08-08 | 52.54 |
253 | 2019-08-09 | 54.50 |
254 | 2019-08-12 | 54.93 |
255 | 2019-08-13 | 57.10 |
256 | 2019-08-14 | 55.23 |
257 | 2019-08-15 | 54.47 |
258 | 2019-08-16 | 54.87 |
259 | 2019-08-19 | 56.21 |
260 | 2019-08-20 | 56.34 |
261 | 2019-08-21 | 55.68 |
262 | 2019-08-22 | 55.35 |
263 | 2019-08-23 | 53.95 |
264 rows × 2 columns
我们还需要额外爬取人民币美元汇率数据用于比较
r = requests.get(
"https://cn.investing.com/common/modules/js_instrument_chart/api/data.php?pair_id=2111&pair_id_for_news=2111&chart_type=area&pair_interval=86400&candle_count=120&events=yes&volume_series=yes&period=1-year",
headers={
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.100 Safari/537.36",
"Referer": "https://cn.investing.com/commodities/currencies/usd-cny",
"Host": "cn.investing.com",
"X-Requested-With": "XMLHttpRequest",
},
)
tz_utc = dt.timezone(dt.timedelta(hours=0))
date = []
netvalue = []
for line in r.json()["candles"]:
date.append(dt.datetime.fromtimestamp(line[0] / 1000, tz_utc).replace(tzinfo=None))
netvalue.append(line[1])
usdf = pd.DataFrame(data={"date": date, "netvalue": netvalue})
usdf
date | netvalue | |
---|---|---|
0 | 2018-08-24 | 6.8070 |
1 | 2018-08-27 | 6.8156 |
2 | 2018-08-28 | 6.8030 |
3 | 2018-08-29 | 6.8213 |
4 | 2018-08-30 | 6.8445 |
5 | 2018-08-31 | 6.8315 |
6 | 2018-09-03 | 6.8228 |
7 | 2018-09-04 | 6.8442 |
8 | 2018-09-05 | 6.8305 |
9 | 2018-09-06 | 6.8355 |
10 | 2018-09-07 | 6.8438 |
11 | 2018-09-10 | 6.8556 |
12 | 2018-09-11 | 6.8730 |
13 | 2018-09-12 | 6.8606 |
14 | 2018-09-13 | 6.8448 |
15 | 2018-09-14 | 6.8690 |
16 | 2018-09-17 | 6.8570 |
17 | 2018-09-18 | 6.8616 |
18 | 2018-09-19 | 6.8483 |
19 | 2018-09-20 | 6.8468 |
20 | 2018-09-21 | 6.8571 |
21 | 2018-09-24 | 6.8571 |
22 | 2018-09-25 | 6.8665 |
23 | 2018-09-26 | 6.8786 |
24 | 2018-09-27 | 6.8902 |
25 | 2018-09-28 | 6.8689 |
26 | 2018-10-01 | 6.8689 |
27 | 2018-10-02 | 6.8689 |
28 | 2018-10-03 | 6.8689 |
29 | 2018-10-04 | 6.8689 |
... | ... | ... |
231 | 2019-07-15 | 6.8777 |
232 | 2019-07-16 | 6.8762 |
233 | 2019-07-17 | 6.8736 |
234 | 2019-07-18 | 6.8800 |
235 | 2019-07-19 | 6.8822 |
236 | 2019-07-22 | 6.8811 |
237 | 2019-07-23 | 6.8792 |
238 | 2019-07-24 | 6.8725 |
239 | 2019-07-25 | 6.8726 |
240 | 2019-07-26 | 6.8792 |
241 | 2019-07-29 | 6.8934 |
242 | 2019-07-30 | 6.8845 |
243 | 2019-07-31 | 6.8841 |
244 | 2019-08-01 | 6.8986 |
245 | 2019-08-02 | 6.9405 |
246 | 2019-08-05 | 7.0508 |
247 | 2019-08-06 | 7.0264 |
248 | 2019-08-07 | 7.0602 |
249 | 2019-08-08 | 7.0451 |
250 | 2019-08-09 | 7.0624 |
251 | 2019-08-12 | 7.0582 |
252 | 2019-08-13 | 7.0435 |
253 | 2019-08-14 | 7.0244 |
254 | 2019-08-15 | 7.0340 |
255 | 2019-08-16 | 7.0428 |
256 | 2019-08-19 | 7.0507 |
257 | 2019-08-20 | 7.0605 |
258 | 2019-08-21 | 7.0632 |
259 | 2019-08-22 | 7.0836 |
260 | 2019-08-23 | 7.0960 |
261 rows × 2 columns
df.iloc[-2].netvalue * usdf.iloc[-2].netvalue / df.iloc[0].netvalue / usdf.iloc[
0
].netvalue # 一年真实的油价变化(人民币计价)
0.8381712364505961
fund = js
float(fund.price[fund.price["date"] == "2019-08-22"].netvalue) / float(
fund.price[fund.price["date"] == "2018-08-24"].netvalue
)
0.8154402005603893
一年大约落后跟踪基准 2.7%, 考虑到嘉实原油一年 1.28% 的管理费,大约还会跑输 1.5% 左右。特别是,这一年,美元走强,基金又有一定现金份额来抵消石油价格下降,因此真实跑输大于 1.5%。其中大部分没意外,都是期货换仓的损失。所以粗略估计,每年的持仓额外成本在 1 到 2 个百分点。
由于另两个原油基准宣称的基准略有不同,以下列出仅供参考:
fund = yfd
float(fund.price[fund.price["date"] == "2019-08-22"].netvalue) / float(
fund.price[fund.price["date"] == "2018-08-24"].netvalue
)
0.8271919660100425
fund = nf
float(fund.price[fund.price["date"] == "2019-08-22"].netvalue) / float(
fund.price[fund.price["date"] == "2018-08-24"].netvalue
)
0.8347042694868781