量化投资03---小市值轮动因子---准备工作01

import akshare as ak
import pandas as pd
#找出历史所有的股票(代码)

# 所有退市的股票代码及名称
df_stop = ak.stock_zh_a_stop_em()
d1 = df_stop[['代码','名称']]
col=['code','name']
d1.columns=col
d1.set_index('code',inplace=True)

#这里要特别注意,不管你把那一列设置为索引之后
# 索引这一列的数据类型为
print(type(d1.index))
# 取得这个类型的字符串值需要这样处理
print(d1.index.str)

d1 = d1.sort_index()
d1
#详细的查看退市的股票有哪些
#d1 = d1[~(d1.index.str.startswith('400'))] 
#d1 = d1[~(d1.index.str.startswith('420'))] 
#d1.shape
# 经过查看,都只是4开头的,这是为啥?
<class 'pandas.core.indexes.base.Index'>
<pandas.core.strings.accessor.StringMethods object at 0x000001F9D341B640>
name
code
400002长 白 5
400005海国实 5
400006京中兴1
400007华 凯 1
400008水仙A 5
......
420103*ST舜喆B
420108退市鹏起B
420120绿庭B5
420140东海B3
420153海创B3

154 rows × 1 columns

#获得A股分钟级历史股票数据
# 跟日历史数据不同
# 这里有昨收这个价格,而没有前收盘价,对于实时数据来讲是对的
# 这里有最新价,而没有收盘价,深市有收盘集合竞价
# 今开 不一定 跟做收对应,开盘有集合竞价

df_now = ak.stock_zh_a_spot_em()
df_now.columns
Index(['序号', '代码', '名称', '最新价', '涨跌幅', '涨跌额', '成交量', '成交额', '振幅', '最高', '最低',
       '今开', '昨收', '量比', '换手率', '市盈率-动态', '市净率', '总市值', '流通市值', '涨速', '5分钟涨跌',
       '60日涨跌幅', '年初至今涨跌幅'],
      dtype='object')
# 上市的股票代码及名称
d2 = df_now[['代码','名称']]
col=['code','name']
d2.columns=col
d2.set_index('code',inplace=True)
# 注意:一旦code被设置成索引,则dataframe的cloumns中将不包含code
d2 = d2.sort_index()

#股票代码规则请收看
#https://blog.csdn.net/turui/article/details/127113419
#找出我们需要的数据,上证,60,68开头(600,601,603,605,688),深证00,30开头(000,002,300,301)
# 605 是上海主板的新号段
# 001×××国债现货
# 003特殊时期股票
# 400 420 403 新三板的企业
# 689科创板的特殊股票
# 82,83,87以及新三板都是北交所的股票代码

#d2 = d2[~(d2.index.str.startswith('600'))] 
#d2 = d2[~(d2.index.str.startswith('601'))] 
#d2 = d2[~(d2.index.str.startswith('603'))] 
#d2 = d2[~(d2.index.str.startswith('605'))] 
#d2 = d2[~(d2.index.str.startswith('688'))] 
#d2 = d2[~(d2.index.str.startswith('000'))] 
#d2 = d2[~(d2.index.str.startswith('002'))] 
#d2 = d2[~(d2.index.str.startswith('300'))] 
#d2 = d2[~(d2.index.str.startswith('301'))] 

#不玩以下的股票
d2 = d2[~(d2.index.str.startswith('001'))] 
d2 = d2[~(d2.index.str.startswith('003'))] 
d2 = d2[~(d2.index.str.startswith('400'))] 
d2 = d2[~(d2.index.str.startswith('420'))] 
d2 = d2[~(d2.index.str.startswith('430'))] 
d2 = d2[~(d2.index.str.startswith('689'))] 
d2 = d2[~(d2.index.str.startswith('83'))] 
d2 = d2[~(d2.index.str.startswith('87'))] 
d2.columns
Index(['name'], dtype='object')
d2.index
Index(['000001', '000002', '000003', '000004', '000005', '000006', '000007',
       '000008', '000009', '000010',
       ...
       '688786', '688787', '688788', '688789', '688793', '688798', '688799',
       '688800', '688819', '688981'],
      dtype='object', name='code', length=4940)
# 本来想把退市的股票跟上市的股票一起整理来的
# 发现退市的股票都是400开头,则这里不再额外整理
#df_all = pd.concat([d1,d2],axis=0)
#df_all = df_all.sort_index()

# 需要生成         股票代码 股票名称 交易日期 开盘价 最高价 最低价 收盘价 前收盘价 成交量 成交额 流通市值 总市值
# 当前数据中有的   代码     名称              今开   最高   最低   最新价 昨收     成交量 成交额 流通市值 总市值

# 收盘后可以这样计算当前总股本数
#d3 = df_now.loc[df_now['代码'].isin(d2.index),['代码','名称','交易日期','开盘','收盘','昨收','流通市值','总市值']]
d3              = df_now.loc[df_now['代码'].isin(d2.index),['代码']]
d3['股票名称']  = df_now.loc[df_now['代码'].isin(d2.index),['名称']]
d3['交易日期']  = pd.Timestamp.today().strftime('%Y-%m-%d') #datetime.now()
d3['开盘价']    = df_now.loc[df_now['代码'].isin(d2.index),['今开']]
d3['收盘价']    = df_now.loc[df_now['代码'].isin(d2.index),['最新价']]
d3['昨收']      = df_now.loc[df_now['代码'].isin(d2.index),['昨收']]
d3['流通市值']  = df_now.loc[df_now['代码'].isin(d2.index),['流通市值']]
d3['总市值']    = df_now.loc[df_now['代码'].isin(d2.index),['总市值']]
                
col=['code','name','date_trade','open','close','close_yesterday','value_liquidity','value_total']
d3.columns=col
d3.set_index('code',inplace=True)
d3 = d3.sort_index()

#新加两列'股本'
d3['equity_liquidity'] = d3['value_liquidity'] / d3['close']
d3['equity_total'] = d3['value_total'] / d3['close']
d3
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_total
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10
000002万 科A2022-10-1017.5417.8317.151.732605e+112.073755e+119.717361e+091.163071e+10
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaN
000004ST国华2022-10-108.368.448.369.818123e+081.121237e+091.163285e+081.328480e+08
000005ST星源2022-10-101.671.681.671.777350e+091.778342e+091.057946e+091.058537e+09
..............................
688798艾为电子2022-10-1091.7390.4091.808.604724e+091.500640e+109.518500e+071.660000e+08
688799华纳药厂2022-10-1031.2431.4831.231.741253e+092.952824e+095.531300e+079.380000e+07
688800瑞可达2022-10-10136.00130.00136.009.227140e+091.471042e+107.097800e+071.131571e+08
688819天能股份2022-10-1034.1232.9034.514.279480e+093.198209e+101.300754e+089.721000e+08
688981中芯国际2022-10-1037.5137.7837.567.395067e+102.992704e+111.957403e+097.921399e+09

4940 rows × 9 columns

#处理NAN的数据
# 会看到 value_market(市值)为NaN,即当天没有市值,即已经退市的一些股票
# 这些股票的历史数据也是有意义的,所以股票代码保持全量,但是退市前的市值,股本取起来是个麻烦事情
# 有一些是退市的股票,有些是未上市股票
# 有昨收的是退市的,没昨收的是将上市的
# 有Nan的,总计198支,其中退市189,其中188只有昨收,000508 这只股票没有昨收但已经退市,即将上市9只
# 即将上市的股票代码取历史日线数据会出错
dnan = d3.loc[d3['value_total'].isnull()]
#dnan = dnan[~(dnan.index.str.startswith('000'))] 
#dnan = dnan[~(dnan.index.str.startswith('002'))] 
#dnan = dnan[~(dnan.index.str.startswith('300'))] 
#dnan = dnan[~(dnan.index.str.startswith('301'))] 
#dnan = dnan[~(dnan.index.str.startswith('600'))] 
#dnan = dnan[~(dnan.index.str.startswith('601'))] 
#dnan = dnan[~(dnan.index.str.startswith('603'))] 
#dnan = dnan[~(dnan.index.str.startswith('688'))] 
dnan
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_total
code
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaN
000013*ST石化A2022-10-10NaNNaN2.47NaNNaNNaNNaN
000015PT中浩A2022-10-10NaNNaN6.85NaNNaNNaNNaN
000018神城A退2022-10-10NaNNaN0.27NaNNaNNaNNaN
000024招商地产2022-10-10NaNNaN40.50NaNNaNNaNNaN
..............................
603996退市中新2022-10-10NaNNaN0.39NaNNaNNaNNaN
688152麒麟信安2022-10-10NaNNaNNaNNaNNaNNaNNaN
688291金橙子2022-10-10NaNNaNNaNNaNNaNNaNNaN
688372伟测科技2022-10-10NaNNaNNaNNaNNaNNaNNaN
688426康为世纪2022-10-10NaNNaNNaNNaNNaNNaNNaN

198 rows × 9 columns

#新上市股票代码
df_newstock = dnan[dnan['value_total'].isnull() & dnan['close_yesterday'].isnull()] 
#df_newstock = df_newstock[~df_newstock.index.str.startswith("000508")]

# PD的索引类型可以跟字符串比较是否相等,却不能跟时间类型直接比较
df_newstock = df_newstock[df_newstock.index != '000508'] 

df_newstock
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_total
code
301223中荣股份2022-10-10NaNNaNNaNNaNNaNNaNNaN
301230泓博医药2022-10-10NaNNaNNaNNaNNaNNaNNaN
301367怡和嘉业2022-10-10NaNNaNNaNNaNNaNNaNNaN
301379天山电子2022-10-10NaNNaNNaNNaNNaNNaNNaN
301389隆扬电子2022-10-10NaNNaNNaNNaNNaNNaNNaN
688152麒麟信安2022-10-10NaNNaNNaNNaNNaNNaNNaN
688291金橙子2022-10-10NaNNaNNaNNaNNaNNaNNaN
688372伟测科技2022-10-10NaNNaNNaNNaNNaNNaNNaN
688426康为世纪2022-10-10NaNNaNNaNNaNNaNNaNNaN
# 退市股票代码
# 这里不能分两步写,否则要用到conact
df_closed = dnan[(~dnan['close_yesterday'].isnull())|(dnan.index == '000508')]
df_closed
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_total
code
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaN
000013*ST石化A2022-10-10NaNNaN2.47NaNNaNNaNNaN
000015PT中浩A2022-10-10NaNNaN6.85NaNNaNNaNNaN
000018神城A退2022-10-10NaNNaN0.27NaNNaNNaNNaN
000024招商地产2022-10-10NaNNaN40.50NaNNaNNaNNaN
..............................
601268*ST二重2022-10-10NaNNaN2.35NaNNaNNaNNaN
601299中国北车2022-10-10NaNNaN29.98NaNNaNNaNNaN
601558退市锐电2022-10-10NaNNaN0.25NaNNaNNaNNaN
603157退市拉夏2022-10-10NaNNaN0.59NaNNaNNaNNaN
603996退市中新2022-10-10NaNNaN0.39NaNNaNNaNNaN

189 rows × 9 columns

# 取出子集,包括了退市的189支+4742支上市的,合计4931支
# 不包含新股票9只
d4 = d3.loc[~d3.index.isin(df_newstock.index)]
d4 = d4.sort_index()
d4
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_total
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10
000002万 科A2022-10-1017.5417.8317.151.732605e+112.073755e+119.717361e+091.163071e+10
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaN
000004ST国华2022-10-108.368.448.369.818123e+081.121237e+091.163285e+081.328480e+08
000005ST星源2022-10-101.671.681.671.777350e+091.778342e+091.057946e+091.058537e+09
..............................
688798艾为电子2022-10-1091.7390.4091.808.604724e+091.500640e+109.518500e+071.660000e+08
688799华纳药厂2022-10-1031.2431.4831.231.741253e+092.952824e+095.531300e+079.380000e+07
688800瑞可达2022-10-10136.00130.00136.009.227140e+091.471042e+107.097800e+071.131571e+08
688819天能股份2022-10-1034.1232.9034.514.279480e+093.198209e+101.300754e+089.721000e+08
688981中芯国际2022-10-1037.5137.7837.567.395067e+102.992704e+111.957403e+097.921399e+09

4931 rows × 9 columns

#增加一列,是否退市的标记
# 这可以说是一份基本完整的快照数据了
df_all = d4
df_all['is_closed'] = False
df_all['is_closed'] = df_all['value_total'].isnull()
df_all
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10False
000002万 科A2022-10-1017.5417.8317.151.732605e+112.073755e+119.717361e+091.163071e+10False
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaNTrue
000004ST国华2022-10-108.368.448.369.818123e+081.121237e+091.163285e+081.328480e+08False
000005ST星源2022-10-101.671.681.671.777350e+091.778342e+091.057946e+091.058537e+09False
.................................
688798艾为电子2022-10-1091.7390.4091.808.604724e+091.500640e+109.518500e+071.660000e+08False
688799华纳药厂2022-10-1031.2431.4831.231.741253e+092.952824e+095.531300e+079.380000e+07False
688800瑞可达2022-10-10136.00130.00136.009.227140e+091.471042e+107.097800e+071.131571e+08False
688819天能股份2022-10-1034.1232.9034.514.279480e+093.198209e+101.300754e+089.721000e+08False
688981中芯国际2022-10-1037.5137.7837.567.395067e+102.992704e+111.957403e+097.921399e+09False

4931 rows × 10 columns

# 找出三个典型例子观察下
df_all.loc[df_all.index.isin(['000001','000003','000508'])] # 三种情况:正常,退市,000508这个特殊的额存在
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10False
000003PT金田A2022-10-10NaNNaN2.71NaNNaNNaNNaNTrue
000508琼民源A2022-10-10NaNNaNNaNNaNNaNNaNNaNTrue
# 因为显式索引为code,那么直接使用df_all[0]会报错
# 根据数组下标(隐式索引),获得股票代码(显式索引)
df_all.index[0]
'000001'
#带上列取值
df_all.loc[df_all.index[0],'name']
'平安银行'
# 按照数组下标取得一行则为 
# 注意 dataframe 的 loc 后面跟的是[]
df_all.loc[df_all.index[0]]
name                              平安银行
date_trade                  2022-10-10
open                             11.87
close                            11.84
close_yesterday                  11.86
value_liquidity         229761675888.0
value_total             229766071464.0
equity_liquidity         19405546950.0
equity_total        19405918197.972973
is_closed                        False
Name: 000001, dtype: object
#df_all.loc[df_all.index[0],'close_yesterday']
df_all.iloc[0]['close_yesterday']
11.86
# 把收盘价补回来(目前只有一个000508)
# 这里有个取单元格(close_yesterday)的值得方法(想了俺半天)
# 注意看打印
for i in range(0,len(df_all)):    
    if pd.isna(df_all.iloc[i]['close_yesterday']):
        
            # 从另一个接口,取出所有的历史日线,放入 df_day
            code_full = 'sz'+ df_all.index[i]
            df_day = ak.stock_zh_index_daily(symbol=code_full)  
            df_day.sort_values(by='date')
            print(df_day.sort_values(by='date').tail(3))
            print(df_all.iloc[i]['close_yesterday'])
            
            
            # df_day 最后一个的收盘价用来赋值
            df_all.loc[df_all.index[i],'close_yesterday'] = df_day.sort_values(by='date').tail(1)['close'].iloc[0]
            print(df_all.iloc[i]['close_yesterday'])
            
            #df_all.loc[df_all.index[i],'close_yesterday'] = 23.5            
            # 这里是个谜,只能用loc这个热方法来赋值,目前还不清楚iloc方法不能赋值问题出在哪里
            #df_all.iloc[i]['close_yesterday']              = df_day.sort_values(by='date').tail(1)['close'].iloc[0]
            #df_all.iloc[i]['close_yesterday']              = 23.5
            
        
#df_all[~df_all['close_yesterday'].isnull()]
           date   open   high    low  close    volume
937  1997-02-26  24.15  25.48  24.12  25.41  10165400
938  1997-02-27  26.00  26.18  24.90  25.22  10688600
939  1997-02-28  24.80  24.80  22.70  23.50  56362000
nan
23.5
df_all.loc['000508']
d_test = df_all.loc[df_closed.index]
#d_test = df_all.loc[df_closed.index,['name','close_yesterday']]
#d_test = df_all.loc[df_closed.index,'close_yesterday'] #换成这一行会报错

# 这里还发现iloc 的另外一个问题,当只有一列的时候,会报错
d_test.iloc[0]['close_yesterday'] 
2.71
# 针对已经退市的股票,想对比一下
# 从实时行情得到的昨收df_all['close_yesterday']
# 从各支股票最后一条数据的收盘价
# 是否一样
d_test = df_all.loc[df_closed.index]
for i in range(0,len(d_test)):
    code_now = d_test.index[i]
    code_full = ''
    if code_now.startswith('6'):
        code_full = 'sh' + code_now
    else:
        code_full = 'sz' + code_now 
    
    df_day = ak.stock_zh_index_daily(symbol=code_full)
    if(d_test.loc[d_test.index[i]]['close_yesterday'] != df_day.sort_values(by='date').tail(1)['close'].iloc[0]):
        print(d_test.loc[d_test.index[i]])
    #else:
        #print(d_test.iloc[i])    
print('Nice!')

#运行这模块要等待一段时间,毕竟请求了189次股票的数据
#验证完毕这里的数据都是对的
Nice!
#网易的数据接口,没有复权,有总市值

#sz000003 这只退市的股票为例,请求为
#http://quotes.money.163.com/service/chddata.html?code=1000003&start=19910103&end=20020426&fields=TCLOSE;HIGH;LOW;TOPEN;LCLOSE;CHG;PCHG;TURNOVER;VOTURNOVER;VATURNOVER;TCAP;MCAP
#http://quotes.money.163.com/service/chddata.html?code=1000003

#函数:网易数据接口获得某只股票的历史日线(行情)数据
def get_daily_163(code,start='19900101',end=''):
    if code.startswith('6'):
        code = '0'+code
    else:
        code = '1'+code
    url_mod="http://quotes.money.163.com/service/chddata.html?code=%s&start=%s&end=%s"
    url=url_mod%(code,start,end)
    df=pd.read_csv(url, encoding = 'gb2312')
    
    #修复数据,上市第一天,前开盘价肯定是1,原始数据为0
    df.loc[df.index[-1],['前收盘']] = 1
    
    #赋值的老疑惑问题,以下两句有警告
    #df.tail(1)['前收盘'] = 1
    #df.iloc[-1]['前收盘'] = 1
    
    # 这里还是一定要转换成时间类型的
    # 否则用字符串类型作为索引的话很多赋值切片工作无法完成
    df.index = pd.to_datetime(df.日期)    
    df.sort_index() # 这里排序很重要哦,关系到下面的数据填充
    df = df[['股票代码','名称','日期','开盘价','收盘价','前收盘','流通市值','总市值']]    
    df['股票代码'] = code[1:]
    df['流通股本'] = df['流通市值'] / df['收盘价']
    df['总股本']   = df['总市值']   / df['收盘价']
    df['未开张']   =~((df['开盘价'] > 0) & (df['收盘价'] > 0)) #针对某只股票当前是指它是否退市,针对某只股票某天它是否交易

    #print(~df['未开张'])
    #向下填充,处理未开市的日子
    #df.replace(to_replace=np.inf,value=np.nan) #为什么这里用replace不起作用?搞不懂
    df.loc[df['未开张'],'流通股本'] = np.nan
    df.loc[df['未开张'],'总股本'] = np.nan
    df = df.fillna(method='ffill')    
    
    df = df.rename(columns={'名称':'股票名称'})    
    df = df.rename(columns={'前收盘':'前收盘价'})
    df = df.sort_index()
        
    df.rename(columns={'股票代码':'code',
                      '股票名称':'name',
                      '日期'    :'date_trade',
                      '开盘价'  :'open',
                      '收盘价'  :'close',
                      '前收盘价':'close_before',
                      '流通市值':'value_liquidity',
                      '总市值'  :'value_total',
                      '流通股本':'equity_liquidity',
                      '总股本'  :'equity_total',
                      '未开张'    :'is_closed'},
                      inplace=True)
    return df
#一只股票为例,处理数据
df_his = get_daily_163('000003')
df_his
codenamedate_tradeopencloseclose_beforevalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
日期
1991-01-02000003深金田A1991-01-02189.66189.661.001.147986e+101.894926e+106.052864e+079.991174e+07False
1991-01-03000003深金田A1991-01-03188.25188.25189.661.139452e+101.880839e+106.052864e+079.991174e+07False
1991-01-04000003深金田A1991-01-04187.31187.31188.251.133762e+101.871447e+106.052864e+079.991174e+07False
1991-01-09000003深金田A1991-01-090.000.00187.311.133762e+101.871447e+106.052864e+079.991174e+07True
1991-01-10000003深金田A1991-01-100.000.00187.311.133762e+101.871447e+106.052864e+079.991174e+07True
....................................
2002-04-22000003PT金田A2002-04-220.000.002.584.953879e+086.687277e+081.920108e+082.591968e+08True
2002-04-23000003PT金田A2002-04-230.000.002.584.953879e+086.687277e+081.920108e+082.591968e+08True
2002-04-24000003PT金田A2002-04-240.000.002.584.953879e+086.687277e+081.920108e+082.591968e+08True
2002-04-25000003PT金田A2002-04-250.000.002.584.953879e+086.687277e+081.920108e+082.591968e+08True
2002-04-26000003PT金田A2002-04-262.712.712.585.203493e+087.024233e+081.920108e+082.591968e+08False

2770 rows × 11 columns

# 做一个空的df,存放所有退市的股票的,最后一个交易日(历史数据中)的数据
#df_all.drop(df_all.index,axis=0,inplace=True)  #两句的效果应该是一样的
df_snapshot = df_all.iloc[:0]
df_snapshot
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
code
#获得所有退市的股票的总市值,流通市值数据(历史数据的最后一行)
for i in range(0,len(df_closed)):   
    d = get_daily_163(df_closed.index[i])
    
    d = d.loc[~d['is_closed']].tail(1)
    #print(d)
    
    d.set_index('code',inplace=True)    
    #print(d)
    df_snapshot = pd.concat([df_snapshot,d])    
# 这里请求了189次数据,运算需要一定的时间
df_snapshot['is_closed'] = True
df_snapshot = df_snapshot.sort_index()
df_snapshot
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closedclose_before
code
000003PT金田A2002-04-262.712.71NaN5.203493e+087.024233e+081.920108e+082.591968e+08True2.58
000013*ST石化A2004-04-282.452.47NaN1.267703e+086.683696e+085.132400e+072.705950e+08True2.50
000015PT中浩A2001-06-086.856.85NaN1.798988e+089.273079e+082.626260e+071.353734e+08True6.80
000018神城A退2020-01-060.270.27NaN3.721804e+084.585262e+081.378446e+091.698245e+09True0.27
000024招商地产2015-12-0740.6040.50NaN4.158946e+101.043260e+111.026900e+092.575951e+09True39.50
....................................
601268*ST二重2014-04-282.222.35NaN3.971500e+095.389606e+091.690000e+092.293450e+09True2.24
601299中国北车2015-05-0632.8829.98NaN3.035800e+113.675482e+111.012608e+101.225978e+10True32.60
601558退市锐电2020-06-230.250.25NaN1.507650e+091.507650e+096.030600e+096.030600e+09True0.25
603157退市拉夏2022-05-170.650.59NaN1.962358e+083.231263e+083.326030e+085.476716e+08True0.64
603996退市中新2022-05-170.400.39NaN1.170585e+081.170585e+083.001500e+083.001500e+08True0.39

189 rows × 11 columns

# 用快照填充,当日K线中,这些退市的股票的,市值,股本相关的数据
df_all.loc[df_snapshot.index] = df_snapshot
df_all
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10False
000002万 科A2022-10-1017.5417.8317.151.732605e+112.073755e+119.717361e+091.163071e+10False
000003PT金田A2002-04-262.712.71NaN5.203493e+087.024233e+081.920108e+082.591968e+08True
000004ST国华2022-10-108.368.448.369.818123e+081.121237e+091.163285e+081.328480e+08False
000005ST星源2022-10-101.671.681.671.777350e+091.778342e+091.057946e+091.058537e+09False
.................................
688798艾为电子2022-10-1091.7390.4091.808.604724e+091.500640e+109.518500e+071.660000e+08False
688799华纳药厂2022-10-1031.2431.4831.231.741253e+092.952824e+095.531300e+079.380000e+07False
688800瑞可达2022-10-10136.00130.00136.009.227140e+091.471042e+107.097800e+071.131571e+08False
688819天能股份2022-10-1034.1232.9034.514.279480e+093.198209e+101.300754e+089.721000e+08False
688981中芯国际2022-10-1037.5137.7837.567.395067e+102.992704e+111.957403e+097.921399e+09False

4931 rows × 10 columns

# 查看一下快照中的几个有特点的值,集合是乱序的,结果是按照index(代码)排序的
df_all.loc[df_all.index.isin(['000001','000003','000508','000015','603157','300264'])]
namedate_tradeopencloseclose_yesterdayvalue_liquidityvalue_totalequity_liquidityequity_totalis_closed
code
000001平安银行2022-10-1011.8711.8411.862.297617e+112.297661e+111.940555e+101.940592e+10False
000003PT金田A2002-04-262.712.71NaN5.203493e+087.024233e+081.920108e+082.591968e+08True
000015PT中浩A2001-06-086.856.85NaN1.798988e+089.273079e+082.626260e+071.353734e+08True
000508琼民源A1997-02-2824.8023.50NaN4.404452e+091.314976e+101.874235e+085.595642e+08True
300264佳创视讯2022-10-104.984.904.981.746294e+092.024190e+093.563866e+084.131000e+08False
603157退市拉夏2022-05-170.650.59NaN1.962358e+083.231263e+083.326030e+085.476716e+08True
#函数:akshare新浪接口获得某一只股票的历史日线(行情)数据
#没有股本,没有市值
def get_daily_sina(code):
    code_full = ''
    if code.startswith('6'):
        code_full = 'sh' + code
    else:
        code_full = 'sz' + code

    df_day = ak.stock_zh_index_daily(symbol=code_full)
    df_day['date'] = pd.to_datetime(df_day['date'])
    df_day.set_index('date',inplace=True)
    df_day = df_day.sort_index()
    #path_file = './'+code_full+'.csv'
    #df_day.to_csv(path_file)    
    return df_day
# 数据比对任务(有关复权的处理练习)
# 1、用当天的行情数据的,总市值,流通市值,最新价(收盘价),计算总股本,流通股本
# 2、获得有转增、送股的 分红信息
# 3、跟历史的行情数据中的对比(总市值,流通市值,收盘价,计算总股本,流通股本)
# 4、主要对比 股本变化前日,当日的历史数据,以及根据快照计算的数据,两者是否一致
# 5、股本变化后上市的价格是复权后的价格,所以这里的市值计算对比,一定要处理复权

#pandas中pd.NaT表示 not a time。
#如果要判断一个时间是不是pd.NaT可以使用pd.isna()、pd.notna()等方法。

#pandas中pd.NaN表示不是一个数字
# 去掉 有 nan 的索引项
#print(s1.dropna())

# 是否为空 pd.isnull notnull
# 是否为空字符串 == ''
# 是否为0 == 0

# 以一只股票为例
code = '000003' 
df_fenhong = ak.stock_history_dividend_detail(symbol=code)
df_fenhong
公告日期送股转增派息进度除权除息日股权登记日红股上市日
01996-07-10200实施1996-07-271996-07-261996-07-31
11995-07-28201实施1995-08-211995-08-18NaT
21994-05-06401实施1994-05-201994-05-19NaT
df_fenhong = df_fenhong[~((df_fenhong['送股'] == 0) & (df_fenhong['转增'] == 0))]

#df_fenhong[pd.notna(df_fenhong['除权除息日'])]
#df_fenhong[pd.isna(df_fenhong['红股上市日'])].index

# 本来,想将所有没有红股上市日的,都填写为 除权除息日,结果发现根本不行
# 以000003 的第一条为例
i = df_fenhong[pd.isna(df_fenhong['红股上市日'])].index
print(i)
df_fenhong.loc[i,'红股上市日'] = df_fenhong.loc[i,'除权除息日'] #稍作处理统一用红股上市日
df_fenhong = df_fenhong.sort_values(by=['红股上市日'],ascending=[False])
df_fenhong
Int64Index([1, 2], dtype='int64')
公告日期送股转增派息进度除权除息日股权登记日红股上市日
01996-07-10200实施1996-07-271996-07-261996-07-31
11995-07-28201实施1995-08-211995-08-181995-08-21
21994-05-06401实施1994-05-201994-05-191994-05-20
d_compare_a = pd.DataFrame()
d_compare_a['日期']        = df_fenhong['红股上市日']
d_compare_a['股票代码']    = code
d_compare_a['股票名称']    = ''
d_compare_a['送股']        = df_fenhong['送股']
d_compare_a['转增']        = df_fenhong['转增']

d_compare_a['收盘价']      = 0
d_compare_a['前收盘价']    = 0
d_compare_a['流通市值'] = 0 #查,根据股票代码,时间,直接查
d_compare_a['总市值']   = 0 
d_compare_a['流通股本']    = 0
d_compare_a['总股本']    = 0 

#df = df.drop(labels='日期', axis=1)
#d_compare_a.index = pd.to_datetime(df_fenhong['红股上市日'])
d_compare_a.set_index('日期',inplace=True)
d_compare_a
股票代码股票名称送股转增收盘价前收盘价流通市值总市值流通股本总股本
日期
1996-07-3100000320000000
1995-08-2100000320000000
1994-05-2000000340000000
code = '000003'
df_his = get_daily_163(code)
print(type(d_compare_a.index))
print(type(df_his.index))
print(d_compare_a.index)
print(df_his.index)

#DatetimeIndex 还是要必须的,要不后面处理数据好麻烦
<class 'pandas.core.indexes.base.Index'>
<class 'pandas.core.indexes.datetimes.DatetimeIndex'>
Index([1996-07-31, 1995-08-21, 1994-05-20], dtype='object', name='日期')
DatetimeIndex(['1991-01-02', '1991-01-03', '1991-01-04', '1991-01-09',
               '1991-01-10', '1991-01-11', '1991-01-14', '1991-01-15',
               '1991-01-16', '1991-01-17',
               ...
               '2002-04-15', '2002-04-16', '2002-04-17', '2002-04-18',
               '2002-04-19', '2002-04-22', '2002-04-23', '2002-04-24',
               '2002-04-25', '2002-04-26'],
              dtype='datetime64[ns]', name='日期', length=2770, freq=None)
#查出来的一只股票在配股转增当日的情况
d_compare_a['股票名称']    = df_his.loc[d_compare_a.index,'name']
d_compare_a['收盘价']      = df_his.loc[d_compare_a.index,'close']
d_compare_a['前收盘价']    = df_his.loc[d_compare_a.index,'close_before']
d_compare_a['流通市值']    = df_his.loc[d_compare_a.index,'value_liquidity']
d_compare_a['总市值']      = df_his.loc[d_compare_a.index,'value_total']
d_compare_a['流通股本']    = df_his.loc[d_compare_a.index,'equity_liquidity']
d_compare_a['总股本']      = df_his.loc[d_compare_a.index,'equity_total']
d_compare_a
股票代码股票名称送股转增收盘价前收盘价流通市值总市值流通股本总股本
日期
1996-07-31000003深金田A205.906.181.131883e+091.529261e+09191844499.0259196782.0
1995-08-21000003深金田A204.425.554.710848e+086.773085e+08106580275.0153237208.0
1994-05-20000003深金田A407.8211.164.733339e+087.813098e+0860528637.099911741.0
# 第0行  :根据df_all(快照)得到的股本数 跟日期最近的一条是否一致
# 总股本数一定是一致的,流通股本数有可能会不一致哦
# 其他行 : 根据上一行的送股、转增方案,计算得来
for j in range(len(d_compare_a)):
    row = d_compare_a.iloc[j]
    if j == 0:        
        print( (df_all.loc[row['股票代码'],'equity_total'] - row['总股本']) <= 0.000001)
        #print( df_all.loc[row['股票代码'],'equity_liquidity'] -row['流通股本'] <= 0.000001)
    else:
        last = d_compare_a.iloc[j-1]
        print(row['总股本'] - last['总股本']/(1+last['送股']/10+last['转增']/10) <= 0.000001)  
True
True
True

#关于复权,这里看一个问题

其中的第一条,日期为 1996-07-31的数据如下:

日期: 1996-07-31
收盘价: 5.9
流通市值:1131882544.1
总市值: 1529261013.8 //经过计算得到下面两组数据
流动股本:192010804.0
总股本: 259196782.0

我们来计算一下1995-08-21 这天的数据
看看查出来的数据跟算出来的数据是否一样呢?
1996-07-31做了10 送2 在这之后,再就没查到分红配股信息了
我们认为这之后的股本总数是不变的,则分红前:
流动股本:192010804.0 / (1+送股/10+转增/10)= 192010804.0 / 1.2= 160009003.33333334
总股本:259196782.0/ (1+送股/10+转增/10)= 259196782.0/ 1.2= 215997318.33333337
计算 1995-08-21的 收盘价为 4.42 则
流动市值 = 4.42160009003.33333334 = 707239794.7333333
总市值 = 4.42
215997318.33333337 = 954708147.0333335
整理如下:

日期: 1995-08-21
收盘价: 4.42
流通市值:707239794.73
总市值: 954708147.03
流动股本:160009003.33
总股本: 215997318.33

这个跟表中查询出来的结果相差也太多了(流通市值4.710848e+08,总市值:6.773085e+08)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用中的描述,市值因子因子投资中的一个重要指标之一。市值因子考虑了股票的市值大小,用来衡量公司的规模。较大的市值通常被认为与相对较低的风险和较稳定的回报相关联。因此,在因子投资中,根据股票的市值大小进行排序是一种常见的策略。 引用中提到了高容量因子指数,这是一种考虑了因子暴露和股票自身市值大小的指数构建方法。这种方法可以使投资者在投资市值因子时获得更好的流动性和可行性。 因此,对市值因子进行排序时,可以考虑使用高容量因子指数或其他基于市值大小的排序方法。通过将股票按照市值从大到小进行排序,投资者可以选择在投资组合中包含市值较大的股票,以获得更稳定的回报和较低的风险。123 #### 引用[.reference_title] - *1* [量化投资中的因子逻辑与多因子选股的概念](https://blog.csdn.net/weixin_37726222/article/details/123281554)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] - *2* *3* [【笔记】因子投资:方法与实践](https://blog.csdn.net/food_for_thought/article/details/112965367)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值