定投改變命運(yùn)?python 幫你解答

文 |?太陽(yáng)雪
來(lái)源:Python 技術(shù)「ID: pythonall」

最近股市火熱,有很多人躍躍欲試,面對(duì)琢磨不透的市場(chǎng),除了隨波逐流,勇當(dāng)韭菜的命運(yùn)外,還有沒(méi)有其他選擇呢?今天就用 Python,從定投的視角上重新認(rèn)識(shí)下股市。
投資有風(fēng)險(xiǎn)!決策需謹(jǐn)慎!
定投
很多人都聽(tīng)說(shuō)過(guò)定投的概念,定投就是定期定額買(mǎi)入一個(gè)標(biāo)的(股票、基金或者其他有增長(zhǎng)空間的投資物),并且長(zhǎng)期持有,最終會(huì)獲得很好的收益,是很好的投資策略
關(guān)于長(zhǎng)期,股神巴菲特說(shuō):
如果你沒(méi)打算將一只股票持有十年,甚至都不用考慮持有十分鐘
言下之意長(zhǎng)期就是十年或者永遠(yuǎn)。
為什么要定投?一般認(rèn)為,定投可以拉低購(gòu)買(mǎi)的成本價(jià),使收益擴(kuò)大
不過(guò)也可能抬高成本價(jià)
真正原因是,市場(chǎng)中的 熊市比牛市長(zhǎng)很多很多,定投相當(dāng)于在長(zhǎng)期的熊市里積聚力量,最終在牛市中展現(xiàn)出投資的價(jià)值
真是這樣的嗎?
下面我們就研究下國(guó)內(nèi)市場(chǎng)上的一些股票基金,看看結(jié)果如何
獲取數(shù)據(jù)
我們以網(wǎng)易財(cái)經(jīng) http://quotes.money.163.com/old/#HS 作為數(shù)據(jù)來(lái)源
通過(guò)指定股票或者基金代碼獲取數(shù)據(jù)
由于網(wǎng)易財(cái)經(jīng)股票和基金 url 和 展示頁(yè)不同,所以需要分別處理,以獲取基金數(shù)據(jù)為例:
def?fund(code):
????url?=?'http://quotes.money.163.com/fund/jzzs_%s_%d.html?start=2001-01-01&end=2020-12-31&sort=TDATE&order=asc'
????data?=?pd.DataFrame()
????for?i?in?range(0,?100):
????????html?=?getHtml(url?%?(code,?i))
????????page?=?dataFund(html)
????????if?page?is?not?None:
????????????data?=?data.append(page,?ignore_index=True)
????????else:
????????????break
????????print("page?",?i)
????????time.sleep(1)
????filename?=?'fund_%s.xlsx'?%?code
????data.to_excel(filename,?index=False)
????print("數(shù)據(jù)文件:",?filename)
def?getHtml(url)):
????while(True):
????????rp?=?rq.get(url)
????????rp.encoding?=?'utf-8'
????????if?rp.text.find("對(duì)不起!您所訪問(wèn)的頁(yè)面出現(xiàn)錯(cuò)誤")?>?-1:
????????????print("獲取過(guò)于頻繁,等待?5?秒再試")
????????????time.sleep(5)
????????????continue
????????else:
????????????break
????return?rp.text
def?dataFund(html):
????table?=?Bs(html,?'html.parser').table
????if?table?is?None:
????????print(html)
????????return?None
????rows?=?table.find_all('tr',?recursive=True)
????data?=?[]
????columns?=?[th.text?for?th?in?rows[0].find_all('th')]
????for?i?in?range(1,?len(rows)):
????????data.append(rows[i].text.split('\n')[1:-1])
????if?len(data)?>?0:
????????pdata?=?pd.DataFrame(np.array(data),?columns=columns)
????????return?pdata
????else:
????????return?None
方法 fund為基金數(shù)據(jù)獲取總方法,接受基金代碼作為參數(shù)通過(guò)特定的 url,可查詢到 2001 年到 2020 年間的數(shù)據(jù),數(shù)據(jù)開(kāi)始時(shí)間晚于 2001 年的,會(huì)以實(shí)際開(kāi)始時(shí)間來(lái)獲取 數(shù)據(jù)是分頁(yè)展示的,預(yù)設(shè)最大為 100 頁(yè),循環(huán)每一頁(yè)獲取數(shù)據(jù) 將獲取的數(shù)據(jù)追加到 data中,data為 pandas 的 DataFrame最后將數(shù)據(jù)存入以類(lèi)型和代碼命名的 Excel 文件中 方法 getHtml接受 url 作為參數(shù),返回 html 字符串rq是 requests 的別名,通過(guò) get 方法,獲取頁(yè)面的 html 字符串判斷是否被拒絕訪問(wèn),如果被拒絕,等待 5 秒再試 方式 dataFund接受 html 字符串作為參數(shù),從中抓取基金數(shù)據(jù)因?yàn)轫?yè)面只有一個(gè) table,所以先拿到 table,然后提取所有行 從第一行中獲取列名 然后獲取其他行的數(shù)據(jù),存入 data 列表 如果獲取到了數(shù)據(jù),將數(shù)據(jù)轉(zhuǎn)換為 DataFrame 對(duì)象返回,否則返回 None
例如獲取代碼為 150124 的基金:
fund('150124')
最后在當(dāng)前目錄中,生成 fund_150124.xlsx 文件
相應(yīng)的股票對(duì)應(yīng)的方法是 stock,例如獲取代碼為 601600 的股票數(shù)據(jù):
fund('601600')
生成的數(shù)據(jù)文件則為: stock_601600.xlsx
整理數(shù)據(jù)
股票數(shù)據(jù)和基金數(shù)據(jù)列有所不同,需要在分析前將數(shù)據(jù)處理為統(tǒng)一的形式
另外,定投而言,只需保留日期和價(jià)格,這樣也有助于減少數(shù)據(jù)量
代碼如下:
def?dataFormat(code,?type_='fund',?cycleDays=5,?begin='2001-01-01'):
????rawdf?=?pd.read_excel('%s_%s.xlsx'?%?(type_,?code))
????#?選擇對(duì)應(yīng)的列
????if?type_?==?'fund':
????????buydf?=?buydf[['公布日期','單位凈值']]
????else:
????????buydf?=?buydf[['日期','收盤(pán)價(jià)']]
????buydf.columns?=?["日期","單價(jià)"]
????buydf?=?buydf[buydf['日期']>=begin]
????buydf?=?buydf[buydf.index?%?cycleDays==0]?#?選出定投時(shí)機(jī)
????return?buydf
方法 dataFormat為數(shù)據(jù)整理方法參數(shù) code為股票或者基金代碼,type_用來(lái)指定分析的是股票還是基金參數(shù) cycleDays表示定投時(shí)間間隔,默認(rèn)為 5 天,即一個(gè)星期(扣除周末)參數(shù) begin為開(kāi)始定投日期,默認(rèn)為 2001-01-01,這也是獲取數(shù)據(jù)最早的日期根據(jù) code和type_用 pandas 讀取數(shù)據(jù)文件,存入原始數(shù)據(jù)rawdf中然后根據(jù) type_參數(shù)抽取需要的列,即日期和價(jià)格,由于股票數(shù)據(jù)和基金數(shù)據(jù)的列名不同,需要更新為統(tǒng)一的列,日期和單價(jià)然后再篩選出開(kāi)始日期及以后的數(shù)據(jù),作為定投數(shù)據(jù) 最后過(guò)濾出購(gòu)買(mǎi)定投的數(shù)據(jù),即從開(kāi)始日期起,把每隔定投時(shí)間間隔的數(shù)據(jù)篩選出來(lái),并返回
呈現(xiàn)
開(kāi)始之前,需要先搞清楚怎么計(jì)算定投的價(jià)值
首先在每個(gè)定投點(diǎn)上,需要定投固定的金額,這個(gè)金額除以當(dāng)前價(jià)格,會(huì)得到購(gòu)買(mǎi)份數(shù)
持續(xù)下去,到將來(lái)某個(gè)點(diǎn)上,價(jià)值是多少呢?應(yīng)該是 此前所有購(gòu)買(mǎi)份數(shù)之和乘以這個(gè)點(diǎn)上的價(jià)格
對(duì)比每個(gè)點(diǎn)上定投的金額合計(jì)與這個(gè)點(diǎn)上的價(jià)值,就能知道此點(diǎn)上是盈是虧,用圖表來(lái)展示更加直觀
代碼如下:
def?show(buydf,?amount=1000):
????buydf.insert(2,'定投金額',?np.array(len(buydf)*[amount]))??##?增加定投列
????buydf.insert(3,'數(shù)量',?buydf['單價(jià)'].apply(lambda?x:?amount/x))??#?計(jì)算出價(jià)值
????buydf.insert(4,'累計(jì)本金',?buydf['定投金額'].cumsum())??##?計(jì)算定投累計(jì)
????buydf.insert(5,'累計(jì)數(shù)量',?buydf['數(shù)量'].cumsum())??##?計(jì)算價(jià)值累計(jì)
????buydf.insert(6,'當(dāng)前價(jià)值',?buydf['累計(jì)數(shù)量']*buydf['單價(jià)'])?##?計(jì)算實(shí)際單價(jià)
????##?凈值趨勢(shì)
????tend?=?pd.DataFrame(columns=['單價(jià)'],index=buydf['日期'].to_list(),data={'單價(jià)':buydf['單價(jià)'].to_list()})
????tend.plot.line(title="凈值走勢(shì)",?linewidth=1.5,?yticks=[])
????plt.show()
????##?選取投資比較
????data?=?pd.DataFrame(columns=['累計(jì)本金','當(dāng)前價(jià)值'],
????????index=buydf['日期'].to_list(),
????????data={'累計(jì)本金':?buydf['累計(jì)本金'].to_list(),
??????????????'當(dāng)前價(jià)值':?buydf['當(dāng)前價(jià)值'].to_list()})
????data.plot.line(title="定投效果",?linewidth=1.5,?yticks=[])
????plt.show()
方法 show數(shù)據(jù)展示方法,接受兩個(gè)參數(shù),buydf為需要定投的數(shù)據(jù),amount為定投金額向 buydf中插入輔助計(jì)算的列,并利用 pandas 的集合運(yùn)算計(jì)算出數(shù)量、累計(jì)本金、累計(jì)數(shù)量和當(dāng)前價(jià)值,其中 DataFrame 的cumsum方法會(huì)計(jì)算每行的累計(jì)值再提取 單價(jià)用于展示價(jià)格走勢(shì)最后提取 累計(jì)本金和當(dāng)前價(jià)值作為投資效果展示
價(jià)格走勢(shì)和投資效果最好展示在一個(gè)圖表上,試試有什么辦法可以做到,歡迎在學(xué)習(xí)群里交流
以基金建信央視50B (150124) 為例,從2015年5月26日開(kāi)始到現(xiàn)在的定投:
show(dataFormat('150124',?begin='2015-05-26'))
圖表如下:


注意:基金為隨意挑選,并不具備投資參考價(jià)值
結(jié)論
對(duì)多個(gè)不同的基金、股票做定投分析,發(fā)現(xiàn)以下結(jié)論:
更早的投資,獲取收益的可能性較大 熊市越久,最后獲得的收益越好 無(wú)論是熊市還是牛市買(mǎi)入,長(zhǎng)期來(lái)看對(duì)最終結(jié)果影響不大 最重要的是:即使在最高點(diǎn)買(mǎi)入,在價(jià)格收復(fù)之前,價(jià)值便會(huì)超過(guò)成本,太神奇了!
最終可以得到一個(gè)與眾不同的觀點(diǎn),定投策略幾乎可以穩(wěn)賺,只要堅(jiān)持的時(shí)間夠久
與大多數(shù)人認(rèn)知不同的是,熊市是最終收益的基礎(chǔ),進(jìn)一步證實(shí)了:
市場(chǎng)中的熊市比牛市長(zhǎng)很多很多,定投相當(dāng)于在長(zhǎng)期的熊市里積聚力量,最終在牛市中展現(xiàn)出投資的價(jià)值
看來(lái)只要選對(duì)具有上升空間的標(biāo)的,堅(jiān)持長(zhǎng)期定投,就能獲得豐厚回報(bào)
不過(guò)還得提醒:
投資有風(fēng)險(xiǎn)!決策需謹(jǐn)慎!
你怎么看的,跑下代碼試試看
總結(jié)
習(xí)得一個(gè)技能,不僅僅可以提高效率,更重要的是它可能改變我們的思考方式,將之前視而不見(jiàn)的東西,看的更清楚,理解的更透徹了,就像帶上了眼鏡,面對(duì)的是相同的世界,卻看的更清晰了。
參考
https://www.liaoxuefeng.com/wiki/1016959663602400/1017785454949568 https://blog.csdn.net/ajian6/article/details/93615594 https://www.pythonf.cn/read/71 https://zhuanlan.zhihu.com/p/33450843 https://ri.firesbox.com/#/cn/
PS:公號(hào)內(nèi)回復(fù)「Python」即可進(jìn)入Python 新手學(xué)習(xí)交流群,一起 100 天計(jì)劃!
老規(guī)矩,兄弟們還記得么,右下角的 “在看” 點(diǎn)一下,如果感覺(jué)文章內(nèi)容不錯(cuò)的話,記得分享朋友圈讓更多的人知道!


【代碼獲取方式】
