投資有風險,入市需謹慎,本文不構成任何投資理財建議,僅做交流學習使用。
不知道大家有沒有在網上見過各種理財課程,說什么小白入門最簡單的就是定投指數基金,還說人家巴菲特也這么投,這種課程介紹是越寫越誇張,后面最誇張說還能打成一個小目標。
過分了啊,如果打成小目標這么簡單,那不是中國打成小目標的怎么地也有個百分之十左右了吧,但是我身邊好像沒見過達成小目標的人啊,難道是因為我太 qiong 的緣故?
還有那種用巴菲特舉例子的課程介紹,拜托下次介紹的時候把故事講完好不好,人家老巴是在美股定投基金,美股是一個熊短牛長的市場,已經連續十幾年的牛市了,當然哈,最近因為疫情的影響我們和老巴一起見證了五六次的熔斷。
想想都覺得自己牛逼,老巴這么大一把歲數,也不過比我們多見證了一次美股的熔斷,那么,是不是說我約等於老巴?
所以,本着對任何事情都抱有懷疑的態度,我今天就要實錘一下,看看無腦定投我們國內的指數基金到底能不能賺錢。
首先如果我們在低點開始定投,在高點賣出,這個是肯定能賺錢的,這個大家都沒什么疑問吧?如果這個再有問題就真的出門左轉吧。
但是如果我們在高點開始定投,在低點賣出,這個真的也能賺錢么?
接下來,我會通過科學的工具以及方法,看看能不能錘爆那些賣理財課的。
開錘
第一步,我們要選定一個指數基金,這里我就已自己買過的滬深 300 指數基金,開始錘起來。
國內有很多網站都可以查到基金的歷史凈值,我這里選擇天天基金網,選擇的是「易方達滬深300ETF聯接A(110020)」。名字和代碼都有了,這個就不多說。
首先,我們打開這款基金的查詢頁面,鏈接: http://fundf10.eastmoney.com/jjjz_110020.html 。
可以看到哈,這個基金成立日期是 2009 年,足夠我們做 10 年的數據回歸分析了。
下一步就是要把這只基金的 10 年的數據抓取下來,前面看過我的爬蟲系列的同學可以先停一下,自己動手試一下,沒看過的可以接着往下看。
祭出神器 F12 ,選擇 network 標簽欄,順便在頁面上選擇我們要的時間段,然后點擊查詢。
然后我們在 network 標簽欄中,可以看到這么一條請求:
http://api.fund.eastmoney.com/f10/lsjz?callback=jQuery18303890660068294629_1586089381722&fundCode=110020&pageIndex=1&pageSize=20&startDate=2010-01-01&endDate=2020-04-05&_=1586089722912
可以看到有兩個分頁有關的參數,一個是 pageSize (每頁數據量)另一個是 pageIndex (第幾頁),這里我們偷個懶,嘗試一次把所有的數據都拉回來,把 pageSize 設置為 4000 , 10 年, 4000 個工作日,應該足夠了。
接下來開始寫第一小段代碼:
import requests
startDate = '2010-01-01'
endDate = '2020-04-05'
foundCode = '110020'
pageSize = 4000
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36',
'Referer': f'http://fundf10.eastmoney.com/jjjz_110020.html'
}
url = f'http://api.fund.eastmoney.com/f10/lsjz?&fundCode=110020&pageIndex=1&pageSize={pageSize}&startDate={startDate}&endDate={endDate}&_=1586089722912'
response = requests.get(url, headers=header)
def write_file(content):
filename = '110020.txt'
with open(filename, 'a') as f:
f.write(content + '\n')
write_file(response.text)
這段代碼很簡單,就是把數據抓回來,並且創建了一個 txt 文件,然后把數據寫進去,給你們看下結果:
數據量有點大,貼不下,就簡單截個圖,大致看了下數據, 10 年間,共計有 2502 條數據(這個意思就是 10 年間,只有 2502 個工作日咯)。
計算收益
接下來要做的事情就很明顯了,我們要解析數據,開始按照定投的方式來計算收益了,對過程不敢興趣的同學可以直接跳過這一小節,直接看后面的數據分析。
我這里按照兩種定投方式做收益計算,一個是按周定投,每周投資 500 大洋;另一個是按月定投,每月投資 2000 大洋,看下最后的收益能差多少。
首先我們開始解析上面我們生成的那個 txt 文件,把我們需要的日期和金額取出來,使用 key 和 value 的形式組成一個 dict ,如下:
def get_data():
'''
獲取數據
:return: dict
'''
with open('110020.txt') as f:
line = f.readline()
result = json.loads(line)
date_price = {}
for found in result['Data']['LSJZList'][::-1]:
date_price[found['FSRQ']] = found['DWJZ']
return date_price
date_price = get_data()
print(date_price)
結果我還是截圖吧,數據畢竟也是有 2502 個key value 對的。
然后我們就開始制定我們的投資方式,第一個是按周定投,我們假定每周一定投,那么可以做一個函數 calculate_by_week(start_date, end_date)
來計算我們每周定投的收益情況,如下:
def calculate_by_week(start_date, end_date):
'''
每周一定投,每次定投 500
:param start_date: 開始時間
:param end_date: 結束時間
:return:
'''
total_stock = 0
total_amount = 0
nums = 0
day = start_date + datetime.timedelta(days=-1)
while day < end_date:
day = day + datetime.timedelta(days=1)
if day.weekday() != 1:
continue
while date_price.get(day.strftime('%Y-%m-%d'), None) is None and day < end_date:
day += datetime.timedelta(days=1)
if day == end_date:
break
nums += 1
total_stock += round(500 / float(date_price[day.strftime('%Y-%m-%d')]), 2)
total_amount += 500
# 計算盈利
while date_price.get(end_date.strftime('%Y-%m-%d'), None) is None:
end_date += datetime.timedelta(days=-1)
total_profit = round(total_stock, 2) * float(date_price[end_date.strftime('%Y-%m-%d')]) - total_amount
return nums, round(total_stock, 2), total_amount, round(total_profit)
上面這個函數會返回 4 個結果,分別是:定投次數,最終持有份額,買入總金額,實際收益。
接下來我們在寫一個按月定投的,規則簡單粗暴,每月 1 號定投,如果 1 號不是交易日,那么順延至第一個交易日,如下:
def get_first_day_of_next_month(date):
first_day = datetime.datetime(date.year, date.month, 1)
days_num = calendar.monthrange(first_day.year, first_day.month)[1] # 獲取一個月有多少天
return first_day + datetime.timedelta(days=days_num)
def calculate_by_month(start_date, end_date):
'''
按月定投,每月 1 號買入,如果 1 號不是交易日,則順延至下一交易日
:param start_date:
:param end_date:
:return:
'''
total_stock = 0
total_amount = 0
nums = 0
first_day = datetime.datetime(start_date.year, start_date.month, 1)
day = first_day + datetime.timedelta(days=-1) # 將日期設置為 start_date 上個月最后一天
while day < end_date:
day = get_first_day_of_next_month(day)
while date_price.get(day.strftime('%Y-%m-%d'), None) is None and day < end_date:
day = day + datetime.timedelta(days=1)
if day == end_date:
break
nums += 1
if day.strftime('%Y-%m-%d') in date_price:
total_stock += round(2000 / float(date_price[day.strftime('%Y-%m-%d')]), 2)
total_amount += 2000
# 計算盈利
while date_price.get(end_date.strftime('%Y-%m-%d'), None) is None:
end_date += datetime.timedelta(days=-1)
total_profit = round(total_stock, 2) * float(date_price[end_date.strftime('%Y-%m-%d')]) - total_amount
return nums, round(total_stock, 2), total_amount, round(total_profit)
數據分析
我們先看下 110020 這只基金本身自己近 10 年的走勢:
line = (
Line()
.add_xaxis(list(date_price.keys()))
.add_yaxis(
'',
y_axis=list(date_price.values())
)
.set_global_opts(
title_opts=opts.TitleOpts(title='110020 基金走勢圖'),
)
)
line.render()
結果如下:
從圖中我們可以看到,在 2015 年前后達到了一個峰值,接着在 2018 年前后又有一個小高峰,隨后在 2019 年一直陰跌,之后開始震盪。
原因嘛大家也都知道, 15 年有一個大牛市, 18 年也漲了一波,在 110020 這支基金的折線圖上體現的是淋漓盡致。
而且 2010 年年初就凈值和現在的凈值相差並不大,我查了下數據, 2010 年初的單位凈值為 1.06 元,而現在的單位凈值為 1.3018 元,漲幅也就個 22.81% ,也就是說當年如果買了 1 萬元的這個基金,到 10 年后點擊今天,也就賺了個 2281 元,一年賺了 200 多,好像看起來還不如余額寶賺的多。
接下來就是激動人心的時刻,我們來驗證我們定投的收益,我預計肯定會比一次買入賺的多,我們試試看。
首先第一組,我們從 10 年前開始買入,兩組數據代入,如下:
# 按周定投
print(calculate_by_week(datetime.datetime.strptime(startDate,'%Y-%m-%d').date(), datetime.datetime.strptime(endDate,'%Y-%m-%d').date()))
# 按月定投
print(calculate_by_month(datetime.datetime.strptime(startDate,'%Y-%m-%d'), datetime.datetime.strptime(endDate,'%Y-%m-%d')))
結果如下:
(533, 273836.56, 266500, 89980)
(125, 254918.67, 250000, 81853)
我先來解釋下上面這組數據,第一組是按周定投的結果,我們總共定投了 533 次,買入的總金額是 266500 元,實際收益是 89980 元。第二組是按月定投的結果,我們總共定投了 125 次,買入的總金額是 250000 元,實際收益是 81853 元。
我用計算器算了一下,基本上收益 / 買入金額 * 100% 結果都在 33% 左右。
10 年 33% ,好像收益比余額寶差不多了,不過這里還有一個概念,就是我們這筆錢是逐年投入的,而不是一次性投入,實際上收益應該是個 2 倍左右的關系。這個和分期還款的利息算法差不多,不多說。
那么,還剩一個問題,我們如果是在 2015 年,也就是大牛市的最高點開始定投,直到今天那么還能賺錢么?
來,我們接着代入數據:
# 2015年開始,按周定投
print(calculate_by_week(datetime.datetime.strptime('2015-01-01','%Y-%m-%d').date(), datetime.datetime.strptime(endDate,'%Y-%m-%d').date()))
# 2015年開始,按月定投
print(calculate_by_month(datetime.datetime.strptime('2015-01-01','%Y-%m-%d'), datetime.datetime.strptime(endDate,'%Y-%m-%d')))
結果如下:
(273, 113522.13, 136500, 11283)
(65, 106851.87, 130000, 9100)
當我看到這組數據的時候,說實話我是有點懵的,竟然真的還是能盈利的雖然賺的比例已經很低了,但是確實是還在賺錢的。
解釋一下,從 2015 年 1 月 1 日起開始周定投,共計定投了 273 次,買入的總金額是 136500 元,實際收益是 11283 元。按照月定投,共計定投了 65 次,買入總金額是 130000 ,實際收益是 9100 。
小結
小結一下吧,我們簡單的回測了 110020 這支滬深 300 的指數基金,當然我是使用 python 來完成的,如果您覺得不方便,通過 Excel 同樣可以完成,方法是次要的,目標完成了就好。
簡單分析一下,我們回測了 10 年定投和 5 年定投的結果,結果是 5 年定投的收益比 10 年定投的收益少了 7w 左右,當然,從牛市開始定投至今能達成正收益我自己也有點吃驚,不過還是可以簡單的證明,即使選擇在股市最高點入市,把時間拉長,指數定投也不會虧錢。
今天的實錘打的臉有點疼,我想靜靜。
最后還是那句話,投資有風險,入市需謹慎,本文不構成任何投資理財建議,僅做交流學習使用。
代碼上傳至代碼倉庫,有需要的同學可以自取。
示例代碼
老規矩,所有的示例代碼都會上傳至代碼管理倉庫 Github 和 Gitee 上,方便大家取用。