ETF基金定投数据分析1——数据收集

ETF基金定投数据分析1——数据收集

作为一个80后的小伙,我错过了一次又一次让自己财富增加的机会,唯一的投资理财就是把钱通通放到某额宝里。一年前,我开始学习理财的知识,最后选择进行etf基金定投来投资。找了一家券商开了户。投资的品种就两个:300ETF和纳指ETF,分别追踪沪深300指数和纳斯达克指数。选择这两个指数之前我用python跑了一下历史数据,二者的相关性很低,也许可以做风险对冲? 开始是每个月一次,后来逐渐增加到每个月三次,隔十天左右进行一次。单纯买入,没有止盈止损。我计划是先这么投一年,再看结果来调整。截止2019年1月9日,账户收益情况如下: 亏的。前几天美股暴跌,亏得更多。近一年定投的感受就是,这种投资方式真的很考验人性,好几次我都想卖了,忍住了。 现在,我们就用Python来分析一下近一年来的投资数据吧。开发环境:由于条件限制,我是在安卓手机上用Pydroid3做编程环境的,Python版本3.6.2。 常用的一些库都能安装,看自带的例子,似乎还能写安卓APP,我还没试过。与在电脑上编程相比,有两个限制:首先画图不能直接显示,要用savefig保存图片到文件;其次,深度学习的一些库,如Tensorflow等,装不了,可能是因为与硬件相关吧。但机器学习的库,如scikit- learn等,可以安装的。另外还安装了Termux等,用于进行git操作。 开发环境搞定了,接下来就是获取数据的问题了。我从券商的APP上把数据一个一个搬到Excel表格里,像这样: 本来想就这么读了,发现还可以另存为csv文件。那更好。于是数据就有了。开工吧。先导入相关的库,然后用read_csv读入数据:

    import pandas as pd
    from pandas import Series, DataFrame
    
    
    #从csv文件读入数据
    def ImportData(FileName):
        df = pd.read_csv(FileName)
        return df
       
       
    #主程序
    if __name__ == "__main__":
        etfdata = ImportData("etfdata.csv")
        print(etfdata)

OK,没问题。 接下来就开始折腾数据吧。DataFrame是一种表格式的,含有多列的数据结构。每列的数据类型可以不一样。每行/每列数据都有一个索引。用DataFrame.columns()得到每列的索引。

    #探索数据
    def ExploreData(Data):
        #每列的索引名称
        print(Data.columns)

用每列索引名称可以提取相应列的数据

    print(Data["成交金额"])

还可以用"变量名.列名"的方式,结果是一样的。

    print(Data.成交金额)

还可以用相同的方式输出指定行的信息:

    print(Data.ix[1])

用values属性可以返回DataFrame的值。

    #返回Data的值   
    print(Data.values)

现在,可以把原始数据按买入的etf分成两个了:

    #分离数据:根据买入的etf的不同划分数据
    def DivData(Data):
        df_300 = Data[Data["证券名称"] == "300ETF"]
        df_nas = Data[Data["证券名称"] == "纳指ETF"]
        return (df_300, df_nas)
        用describe描述数据特征
    #描述数据
        print(df_300.describe())
        print(df_nas.describe())

按成交均价,画个图看看吧。

    import matplotlib.pyplot as plt
    
    
    plt.plot(df_300["成交均价"])
        plt.plot(df_nas["成交均价"])
        plt.savefig("成交均价.png")

OK,接下来要计算收益率等信息了,需要知道历史股价信息,用tushare库。这是国产的库,用来获取各种金融数据。官方版本已经到1.2.15了,我在pydroid3里装的是0.6.8,升级出现pyzmq错误,搜了半天没找到解决方法,就暂时用旧的那个好了。 用get_k_data函数,因为其日期数据是yyyy-mm-dd格式的,先转换一下。

    #将八位数字的日期转换为yyyy-mm-dd
    def TransfDate(d):
        year = int(d/10000)
        month = int((d - year*10000)/100)
        day = int((d - year*10000 - month*100))
        date = format("%4d-%02d-%02d" % (year, month, day))
        return date

转换函数留着备用。 先找出最早开始定投的时间:

    beginTime = df_300.成交日期.min()
    endTime = df_300.成交日期.max()

然后就用tushare抓取历史数据

    #抓取历史数据
    def GetHistoryData(Code, BeginTime, EndTime):
        df = ts.get_k_data(Code, index = False,  start = TransfDate(BeginTime), end = TransfDate(EndTime))
        return df

输出一下看看

    df_300_hist = GetHistoryData("510300", beginTime, endTime)
        df_nas_hist = GetHistoryData("513100", beginTime, endTime)
        print(df_300_hist)

没问题啦。现在就可以用历史数据计算定投的持仓收益情况了。这个要考虑一下计算方法:就从开始定投的交易日开始,每个交易日计算一次。根据每次交易的成交量和手续费,计算一个总投入。再根据买入股票的量,计算一个持仓量,根据持仓量就可以算出当前股票的市值。再减去总投入,就是总收益了。用收盘价计算吧。 先筛选下载的历史数据,只保留日期和收盘价。

    df_300_hist = df_300_hist.loc[0:len(df_300_hist), ["date", "close"]]
        df_nas_hist = df_nas_hist.loc[0:len(df_nas_hist), ["date", "close"]]

接下来就计算数据啦。出现很多问题,折腾半天,发现是原始数据中有同一天对同一只基金多次买入的问题。搞不定,最后用手工合并啦。 计算数据费了很多功夫,主要是因为不是每个交易日都有交易,而每个交易日股价都在变动,市值和收益率也在变动,因此交易记录和股价记录长度不一致,要换算。这是最长的一个函数了,一定还有更简洁的方法。我之前学的C/C++,c语言的"味道"很浓。

    #根据投资记录和历史数据计算持仓收益率等数据。
    def Calculator(inverstData, histData):
        i = 0
        j = 0
        vol = []    #持仓股票数量
        fee = []    #手续费
        money = []   #投资总额
        rate = []     #收益率
        time = []   #时间
        market = []  #股票市值
    
        for date in histData.date:
            d1 = TransfDate2(date)
            d2 = inverstData.成交日期[i]
            b = (d1 == d2)
            time.append(d1)
            #该日期有交易,改变数据
            if b == True:
                if i == 0: #第一天,直接插
                    vol.append(inverstData.成交量[i])
                    fee.append(inverstData.手续费[i])
                    money.append(inverstData.发生金额[i])
                    market.append(vol[i]*histData.close[i])
                    #计算收益率=市值/投资总额
                    rate.append(market[i]/money[i] - 1.0)
                else: #不是第一天,但有交易
                     vol.append(vol[j-1] + inverstData.成交量[i])
                     fee.append(fee[j-1] + inverstData.手续费[i])
                     money.append(money[j-1] + inverstData.发生金额[i])
                     market.append(vol[j]*histData.close[j])
                     #计算收益率=市值/投资总额
                     rate.append(market[j]/money[j] -1.0)
                i = i+1
            else: #没有交易,复制上一天的数据
                vol.append(vol[j-1])
                fee.append(fee[j-1])
                money.append(money[j-1])
                market.append(vol[j]*histData.close[j])
                rate.append(market[j]/money[j] - 1.0)
            j = j+1
        data = pd.DataFrame({
        "日期":time,
        "持仓量":vol,
        "手续费":fee,
        "成本":money,
        "市值":market,
        "收益率":rate})
        return data

搞定!再把收益率趋势图画出来。

        plt.figure()
        plt.plot(data_300.收益率, label = "300etf")
        plt.plot(data_nas.收益率, label = "纳指etf")
        plt.legend(loc = "upper right")
        plt.savefig("收益率.png")

美股跟a股相关性果然很低。接下来就是具体折腾数据啦。先把两个股票的数据合并一下,算出一个总持仓的收益数据。

    #合并两个数据,算出总的持仓收益率等数据
    def MergeData(data1, data2, histData1, histData2):
        #合并日期,持仓金额,手续费,市值,并计算持仓收益率
        money = [] #成本
        fee = [] #手续费总额
        market = [] #总的股票市值
        rate = [] #总的收益率
        time = [] #日期
        i = 0
        for date in histData1.date:
            date = TransfDate2(date)
            time.append(date)
            money.append(data1.成本[i] + data2.成本[i])
            fee.append(data1.手续费[i] + data2.手续费[i])
            market.append(data1.市值[i] + data2.市值[i])
            #计算收益率
            rate.append(market[i]/money[i] - 1.0)
            i = i + 1
        data = pd.DataFrame({
        "日期":time,
        "成本":money,
        "手续费":fee,
        "市值":market,
        "收益率":rate
        })
        return data

再把总的收益率也画到一个图里看看。

    #将收益率数据合并,算出总的持仓数据
        data_total = MergeData(data_300, data_nas, df_300_hist, df_nas_hist)
        plt.figure()
        plt.plot(data_300.收益率, label = "300etf")
        plt.plot(data_nas.收益率, label = "nasetf")
        plt.plot(data_total.收益率, label = "etf")
        plt.legend(loc = "upper right")
        plt.savefig("收益率.png")

可以看到同时定投两个市场的指数的确可以平衡风险。数据的收集处理就到这里了。接下来就是数据分析啦,作为一篇公众号文章,已经太长了,就下回分解吧。 几点说明: 1.我本职是一名牙医,编程是我的爱好,以前用得最多的是C/C++(不过也只是写一些几千行的小程序),python用的时间不长,所以代码里好多C的味道。 2.写本文是因为crossin编程教室公众号搞了个征稿活动,正好我也打算用python分析一下自己近一年的etf定投数据,就想着把分析过程记录下来,不是说分享就是最好的学习吗? 3.我学习的体会,这种带着问题在做中学,是要比那种一本书或者一个课程从头看到尾要好一些,在这个过程中会碰到各种各样想不到的问题,就想办法解决或者去搜。写程序也是这样,开始只是一个想法:我要分析自己的ETF定投数据,接着就慢慢拆问题:怎么收集数据,需要哪些数据,数据如何处理得到自己想要的数据,如何分析…每个问题又可以拆成更多的问题,直到问题小到可以直接解决。这是计算机的思维方法,也可以用到其它领域,比如我自己的专业领域。 4.本文的主要参考资料:《Python for Data Analysis》,Pandas库作者写的,对,是英文版的。再多说一句,能读原文的最好读原文,其实没那么难的。我读原文书的想法是来自于我自己的专业:口腔医学。以前除了教科书,其它专业书我是基本不看的,看不下去(最主要还是没兴趣)。后来想把自己专业搞好了,开始看书,发现很多书翻译过来要么是比较老的版本了,要么根本就没有翻译的,最重要的是专业书都是厚本厚本的,死贵了。后来发现一个搜英文书的网站:b-ok,很多专业书都能找到英文电子版,还往往是最新的。于是下了很多口腔专业的电子书,上班就在诊室电脑上看,看着看着我发现,看原文也没那么难。这个过程不太长的,就两三个月。从此我又有了一个习惯:看到翻译过来的新书,想看,用英文书名去搜,往往能找到电子版。 5.本文的代码已经上传到github里: https://github.com/zwdnet/etfdata 后期如果写新的内容,可能会开新的分支。 6.我自己开了个博客: https://zwdnet.github.io 还有一个微信订阅号:赵瑜敏的口腔医学学习园地,二维码在最后。主要都是口腔医学的东西,而且不是科普,是给牙医同行看的。所以不是同行的话可以不用看了。谢谢! 最后声明:本文只是探讨python数据处理技术,不构成投资建议。投资有风险,入市需谨慎。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值