由于第三章的国外网站无法翻墙,拿不到数据。故跳过第三章,直接进行第四章.
由于篇幅较长,故分篇章实现。
PS:这次下周的数据截止到2019年2月的数据,和书上的数据相比数据有小量增加。出现的问题也比较多,在尝试处理。如果有做的不对或者不合理的地方,还希望各位老师、小伙伴指正。有更好的想法也可以给我留言。
# -*- encoding:utf-8 -*- import numpy as np import pandas as pd import matplotlib.pyplot as plt from patsy import dmatrix from sklearn.ensemble import RandomForestClassifier from sklearn import linear_model ipos = pd.read_csv(r'ipo_data.csv',encoding='latin-1') # print(ipos) #看到对于每个IPO都有不少信息:发行日期、发行者、发行价、开盘价等 #下面进行清洗工作,以正确格式化所有列。去掉美元和百分比符号 ipos = ipos.applymap(lambda x:x if not '$' in str(x) else x.replace('$','')) ipos = ipos.applymap(lambda x :x if not '%' in str(x) else x.replace('%','')) ipos = ipos.applymap(lambda x :x if not '(' in str(x) else x.replace('(','')) ipos = ipos.applymap(lambda x :x if not ')' in str(x) else x.replace(')','')) # print(ipos) # print(ipos.info()) """ 修正所有列的数据类型。目前都是对象,需要数值型。 """ ipos.replace('N/C',0,inplace=True) # ipos['TradeDate'] = pd.to_datetime(ipos['TradeDate']) # ipos['OfferPrice'] = ipos['OfferPrice'].astype('float') # ipos['OpeningPrice'] = ipos['OpeningPrice'].astype('float') # ipos['1stDayClose'] = ipos['1stDayClose'].astype('float') # ipos['1stDay% Px Chng'] = ipos['1stDay% Px Chng'].astype('float') # ipos['ChangeClose'] = ipos['ChangeClose'].astype('float') # ipos['ChangeOpening'] = ipos['ChangeOpening'].astype('float') # ipos['StarRatings'] = ipos['StarRatings'].astype('int') #会发现有日期格式错误列 # print(ipos[ipos['TradeDate'] == '11/120']) #发现这个错误,修正 ipos.loc[1353,'TradeDate'] = '2012-11-20' ipos.loc[679,'ChangeClose'] = '1.07' ipos.loc[3211,'ChangeClose'] = '1.07' ipos['TradeDate'] = pd.to_datetime(ipos['TradeDate']) ipos['OfferPrice'] = ipos['OfferPrice'].astype('float') ipos['OpeningPrice'] = ipos['OpeningPrice'].astype('float') ipos['1stDayClose'] = ipos['1stDayClose'].astype('float') ipos['1stDay% Px Chng '] = ipos['1stDay% Px Chng '].astype('float') ipos['ChangeClose'] = ipos['ChangeClose'].astype('float') ipos['ChangeOpening'] = ipos['ChangeOpening'].astype('float') ipos['StarRatings'] = ipos['StarRatings'].astype('int') # print(ipos.info()) """ 终于可以开始探索了,首先从第一天的评均收益百分比开始。 """ # bar_mean = ipos.groupby(ipos['TradeDate'].dt.year)['1stDay% Px Chng '].mean().plot(kind='bar',figsize=(12,10),\ color='k',title='1stDayMeanIPOPercentageChange') """ 有图可知,均值最高的事2000年,高达35,2019年是负值,可能因为目前是2019年2月15日,数据量比较少。 """ #看看中位数的值如何 # bar_median = ipos.groupby(ipos['TradeDate'].dt.year)['1stDay% Px Chng '].median().plot(kind='bar',figsize=(12,10),\ # color='k',title='1stDayMedianIPOPercentageChange') # plt.show() """ 通过平均值和中位数的对比,可以看出一些较大的异常值造就了回报分布的偏差,下面仔细观察一下数据。 """ # print(ipos['1stDay% Px Chng '].describe()) """ count 3218.000000 mean 13.078060 std 27.292428 min -41.080000 25% 0.000000 50% 4.250000 75% 18.995000 max 353.850000 """ #借助图形观察更直观 # ipos['1stDay% Px Chng '].hist(figsize=(12,8),bins=100,color='green') # plt.show() """ 由图可看到,大多数的回报集中在0附近,但是有个长尾一直拖到右侧,那里有一些真正的全垒打的发行价。 看到第一天的百分比变化,就是从发行价到当天收盘价的差距,但是很少有人在发行价的时候买入。 既然如此,看下开盘价的到收盘价的收益率。有助于理解:所以收益都是给那些拿到发行价的人, 还是说在第一天人们仍然有机会冲入并获得超高的回报? """ #首先创建两个新的列 ipos['$ChgopentoClose'] = ipos['ChangeClose']-ipos['ChangeOpening'] ipos['%ChgopentoClose'] = (ipos['$ChgopentoClose']/ipos['OpeningPrice'])*100 # ipos['$ChgopentoClose'] = ipos['$ChgopentoClose'].astype('float') ipos['%ChgopentoClose'] = ipos['%ChgopentoClose'].astype('float') # print(ipos) # print(ipos['%ChgopentoClose'].describe()) """ count 3219.000000 mean 2.735321 std 10.344234 min -106.601942 25% -1.135075 50% 0.777778 75% 5.360564 max 113.333333 Name: %ChgopentoClose, dtype: float64 """ """ 根据数据可以看出来,开盘后竟然下跌到-106!太不现实了。可以去看看原始数据,找到异常数据。 找异常数据的时候,费了很大劲,第一次使用ipos[ipos['%ChgopentoClose'] ==-106.601942来找异常列, 发展不管怎么比对都报错,更改了float格式也不对。最后使用min方法才找到异常列是695行数据。 注意:多试几次,找不到不要放弃。总会有柳暗花明的时候! """ # print(ipos[ipos['%ChgopentoClose'] == min(ipos['%ChgopentoClose'])]) #695行出现异常 #找到异常数据,要修正数据 ipos.loc[695,'ChangeOpening']=.09 ipos.loc[695,'OpeningPrice']=11.26 ipos.loc[2313,'ChangeOpening']=.01 ipos.loc[2313,'OpeningPrice']=11.26 ipos['$ChgopentoClose'] = ipos['ChangeClose']-ipos['ChangeOpening'] ipos['%ChgopentoClose'] = (ipos['$ChgopentoClose']/ipos['OpeningPrice'])*100 # print(ipos['%ChgopentoClose'].describe()) # print(ipos[ipos['%ChgopentoClose'] == min(ipos['%ChgopentoClose'])]) #2313为异常数据,再次修改 #发现还是有将近99%的跌幅,还是有异常数据,在找找看 """ count 3219.000000 mean 2.771941 std 10.164132 min -98.522167 25% -1.132931 50% 0.780234 75% 5.366556 max 113.333333 """ #经过两次异常值修正,得出的结果如下: """ count 3219.000000 mean 2.803127 std 10.006018 min -49.281222 25% -1.130554 50% 0.781250 75% 5.366556 max 113.333333 """ #看上面的数据,损失下降到49%,也令人质疑。不过观测后,发现是Zillow的IPO。Zillow开盘的似乎炒的很火热, #收盘的时候很快就跌到地面。说明异常值差不多清理完了。 #下面继续观测数据,争取清除大部分的错误。 ipos['%ChgopentoClose'].hist(figsize=(10,7),bins=100,color='grey') # plt.show() """ 从上图看到开盘价和收盘价变化的分布情况,和发行价和收盘价变化的分布图相比,有着明显的差异。 平均值和中位数都有显著下降,而且紧贴着原点右侧的条形看上去是一个比较健康的梯度,而原点左侧的条形 似乎也按照比例进行增长。 注意:右边的长尾么有这么明显了,但是仍然需要注意。 """ #4.1.3基本的IPO策略 """ 现在对市场有一点了解了。如果以其开盘价购买每个IPO股票,然后在收盘是卖出,最终受益如何?看看2015年至今的数据。 """ # print(ipos[ipos['TradeDate']>='2015-01-01']['$ChgopentoClose'].describe()) """ count 451.000000 mean 0.367871 std 2.203211 min -6.260000 25% -0.345000 50% 0.010000 75% 0.650000 max 20.040000 """ # print(ipos[ipos['TradeDate']>='2015-01-01']['$ChgopentoClose'].sum()) #165.91 #拆分一下盈利的交易和亏损的交易 # print(ipos[(ipos['TradeDate']>='2015-01-01')&(ipos['$ChgopentoClose']>0)]['$ChgopentoClose'].describe()) """ count 229.000000 mean 1.490480 std 2.407834 min 0.010000 25% 0.160000 50% 0.650000 75% 1.850000 max 20.040000 """ print(ipos[(ipos['TradeDate']>='2015-01-01')&(ipos['$ChgopentoClose']<0)]['$ChgopentoClose'].describe()) """ count 186.000000 mean -0.943065 std 1.161020 min -6.260000 25% -1.100000 50% -0.550000 75% -0.150000 max -0.010000 """ """ 由上面数据可知,如果2015年投资每一个IPO,将会有451家IPO,有229,约一半会收益,186家会亏损。 整体上是有利润的,假设没有交易差额或者佣金成本。显然不是发家致富,脱贫实现财富自由的方法, 因为平均收益率低于1%。 """