python量化交易--因子选股策略

Fama-French三因子选股策略,三因子分别为  市场因子(股指)、市值因子、账面市值比因子

三因子模型的具体步骤:

1.对股票按照市值和账面市值比分组,共计六组,市值按大小市值各50%分,账面市值比按3:4:3=H:M:L分配(因为账面市值比的作用更强,所以分得更细一点)

2.计算股票市场每天的SMB、HML,按日期循环生成

3.找出个股的涨跌幅(如茅台)以及股指的涨跌幅

4.按日期合并以上数据

5.OLS线性拟合,得出个股收益率的三因子表达式,选出常数项小于0的股票

具体实施:最初想用tushare的api来导出股票的详情数据,但是由于积分权限限制(我的只有120积分.......)只能用daily,导致像市净率、市值、市盈率等重要指标都导不出来,所以我选择了去东方财富网爬虫,但这里爬虫我不知道怎么爬每支股票历史每天收盘的市净率、市值、市盈率等,只爬了当天。所以在后面分组之后的步骤发生了变化。

代码实现具体步骤

1.利用selenium和xpath爬虫沪指300成分股数据、东方财富网股票数据。

2.按市值分组,按账面市值比分组。

3.选择小市值和大账面市值比的公司研究。

4.利用市盈率进行第二次筛选PE∈(0,20]的股票。

5.爬虫股票的ROE数据,利用ROE进行第三次筛选,取最大的前10个ROE。

6.最后得到的10支股票再手动剔除掉银行类,保险类,证券类。(因为此类股票的市盈率是失真的)。

7.对最终选出的股票再结合当前形势判断是否能够买入。(如当下的教培类【中公教育类型的除外】和地产类的不值得入手)运行之后得到的10支股票是:绿地控股、浙江龙盛、成都银行、中国人保、长沙银行、阳光城、渝农商行、五矿资本、荣盛发展、东吴证券,排除掉银行证券保险地产后,只剩下了浙江龙盛,然后仔细看了下该股的数据,市盈率目前8.6,市值小,BM大。到时可再根据MACD图的金叉死叉来看看买入和卖出时机。

我的个人微信,对python量化有同样兴趣的朋友可以加我探讨

python量化交易--因子选股策略_第1张图片

源代码

import pandas as pd
import tushare
import numpy as np
from lxml import html
import requests
import re
import time
import pymongo
import mplfinance as mpf
import matplotlib.pyplot as plt
import talib
import matplotlib
from pyecharts.charts import Grid
import datetime
from selenium import webdriver
token='61ade75f85bcd95167232260ab892339bf0e6ff276b1a127e97bc3ed'
pro=tushare.pro_api(token)
#沪深300指数成分股
hs300_code_list=[]
hs300_name_list=[]
market_value_list=[]
BM_list=[]#账面市值比列表
dict_list=[]
pct_chg_list=[]
wb=webdriver.Chrome()
def getcode(url):
    headers={'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36 Edg/90.0.818.66'}
    response=requests.get(url,headers=headers).content.decode('gbk')
    for i in range(1,301):
        etree1=html.etree.HTML(response)
        etree2=etree1.xpath('//*[@id="senfe"]/tr[{}]/td[2]/text()'.format(i))[0]
        etree3=etree1.xpath('//*[@id="senfe"]/tr[{}]/td[3]/a[1]/text()'.format(i))[0]
        hs300_name_list.append(etree3)
        if (str(etree2)[0])==str(0):
            daihao='sz'+str(etree2)
            code=str(etree2)+'.SZ'
        if (str(etree2)[0])==str(6):
            daihao='sh'+str(etree2)
            code=str(etree2)+'.SH'
        if (str(etree2)[0])==str(3):
            daihao='sz'+str(etree2)
            code=str(etree2)+'.SZ'
        hs300_code_list.append(code)
        url1='http://quote.eastmoney.com/{}.html'.format(daihao)
        wb.get(url1)
        #流通市值计算
        try:
            market_value=wb.find_element_by_xpath('//*[@id="gt14"]').text
            market_value = int(re.search(r'\d+', str(market_value)).group(0))
            print(market_value)
        except:
            market_value=wb.find_element_by_xpath('//*[@id="gt117"]').text#澜起科技页面布局不一样
            market_value = int(re.search(r'\d+', str(market_value)).group(0))
            print(market_value)
        market_value=int(re.search(r'\d+', str(market_value)).group(0))
        #市净率
        try:
            PBR=float(wb.find_element_by_xpath('//*[@id="gt13"]').text)
        #账面市值比:1/市净率  BM
        except:
            PBR=float(wb.find_element_by_xpath('//*[@id="gt167"]').text)#传音控股页面布局不一样
        BM=1/PBR
        if BM<0:
            print('小于0')
        market_value_list.append(market_value)
        BM_list.append(BM)
        dataframe=pro.daily(ts_code=code,start_date='20180101',end_date='20210824')
        pct_chg=(dataframe.loc[dataframe.index[-1],'close']-dataframe.loc[dataframe.index[0],'open'])/dataframe.loc[dataframe.index[0],'open']
        pct_chg_list.append(pct_chg)
    dict_list={'股票名称':hs300_name_list,'股票代号':hs300_code_list,'股票涨跌幅':pct_chg_list,'股票市值':market_value_list,'股票账面市值比':BM_list}
    dataframe2=pd.DataFrame(dict_list)
    dataframe2.to_csv(r'C:\Users\asus\Desktop\沪深300股票信息.csv',mode='w',encoding='utf-8')
url='http://www.shdjt.com/flsort.asp?lb=993505'
#getcode1=getcode(url)
dataframe2=pd.read_csv(r'C:\Users\asus\Desktop\沪深300股票信息.csv')
market_value_list2=dataframe2['股票市值'].sort_values()
#市值分组
for i in range(dataframe2.shape[0]):
    A=int(dataframe2.loc[dataframe2.index[i],'股票市值'])
    B=int(market_value_list2.loc[market_value_list2.index[150]])
    if A0.7:
        dataframe2.loc[dataframe2.index[i],'BM']='H'
    else:
        if dataframe2.loc[dataframe2.index[i],'股票账面市值比']<0.3:
            dataframe2.loc[dataframe2.index[i],'BM']='L'
        else:
            dataframe2.loc[dataframe2.index[i],'BM']='M'
#按2*3的维度分组
df_SL=dataframe2[(dataframe2['B&S']=='S')&(dataframe2['BM']=='L')]
df_SH=dataframe2[(dataframe2['B&S']=='S')&(dataframe2['BM']=='H')]
df_SM=dataframe2[(dataframe2['B&S']=='S')&(dataframe2['BM']=='M')]
df_BL=dataframe2[(dataframe2['B&S']=='B')&(dataframe2['BM']=='L')]
df_BH=dataframe2[(dataframe2['B&S']=='B')&(dataframe2['BM']=='H')]
df_BM=dataframe2[(dataframe2['B&S']=='B')&(dataframe2['BM']=='M')]
S_L=((df_SL['股票涨跌幅']*df_SL['股票市值']).sum())/df_SL['股票市值'].sum()
S_H=((df_SH['股票涨跌幅']*df_SH['股票市值']).sum())/df_SH['股票市值'].sum()
S_M=((df_SM['股票涨跌幅']*df_SM['股票市值']).sum())/df_SM['股票市值'].sum()
B_L=((df_BL['股票涨跌幅']*df_BL['股票市值']).sum())/df_BL['股票市值'].sum()
B_H=((df_BH['股票涨跌幅']*df_BH['股票市值']).sum())/df_BH['股票市值'].sum()
B_M=((df_BM['股票涨跌幅']*df_BM['股票市值']).sum())/df_BM['股票市值'].sum()
SMB=(1/3)*(S_H+S_M+S_L-B_H-B_L-B_M)
HML=(1/2)*(S_H+B_H-S_L-B_L)


#利用账面市值比和市值大小做第一次筛选,得到df_SH
print(df_SH)#找出市值小于650亿且账面市值比大于0.7的股票,49个
end=time.localtime(time.time())
end=time.strftime('%Y%m%d',end)
end_list=[]
for i in range(df_SH.shape[0]):
    end_list.append(end)
dict_value={'日期':end_list,'股票代码':df_SH['股票代号'],'今日市值':df_SH['股票市值'],'今日股票账面市值比':df_SH['股票账面市值比']}
dataframe3=pd.DataFrame(dict_value)
#dataframe3.to_csv(r'C:\Users\asus\Desktop\股票市值和BM.csv',mode='a',encoding='utf-8')
end=time.localtime(time.time())
end=time.strftime('%Y%m%d',end)
start=int(end)-10000

#for i in range(df_SH.shape[0]):
    #dataframe4=pro.daily(ts_code=df_SH.loc[df_SH.index[i],'股票代号'],start_date=start,end_date=end)
    #print(dataframe4)

#第二次筛选
daihao_list=[]
PE_list=[]
for i in range(df_SH.shape[0]):
    daihao=re.search(r'\d+',df_SH.loc[df_SH.index[i],'股票代号']).group(0)
    houzhui=re.search(r'\D+',df_SH.loc[df_SH.index[i],'股票代号']).group(0)
    if houzhui=='.SH':
        daihao=str('sh')+daihao
    if houzhui=='.SZ':
        daihao=str('sz')+daihao
    url2='http://quote.eastmoney.com/{}.html'.format(daihao)
    wb.get(url2)
    try:
        PE=wb.find_element_by_xpath('//*[@id="gt6"]').text#市盈率爬虫
        PE_list.append(PE)
        daihao_list.append(daihao)
    except:
        print('网站结构不对,请调整xpath')
dict_PE={'股票代号':daihao_list,'股票市盈率':PE_list}
dataframe5=pd.DataFrame(dict_PE)
daihao_good_list=[]
PE_good_list=[]
for i in range(dataframe5.shape[0]):
    if float(dataframe5.loc[dataframe5.index[i],'股票市盈率'])<=20:
        if float(dataframe5.loc[dataframe5.index[i],'股票市盈率'])>0:
            daihao_good_list.append(dataframe5.loc[dataframe5.index[i],'股票代号'])
            PE_good_list.append(dataframe5.loc[dataframe5.index[i],'股票市盈率'])
dict_PE_good={'股票代号':daihao_good_list,'股票市盈率':PE_good_list}
dataframe6=pd.DataFrame(dict_PE_good)
print(dataframe6)#剩下35个

#第三次筛选
ROE_list=[]
for i in range(dataframe6.shape[0]):
    url3='http://quote.eastmoney.com/{}.html'.format(dataframe6.loc[dataframe6.index[i],'股票代号'])
    wb.get(url3)
    try:
        ROE=wb.find_element_by_xpath('//*[@id="cwzbDataBox"]/tr[1]/td[9]').text
        ROE_list.append(ROE)
    except:
        print('网页结构不对,请调整xpath')
dataframe6['ROE']=ROE_list
dataframe6=dataframe6.sort_values(by='ROE',ascending=False)
dataframe7=dataframe6.head(10)#取ROE最大的前10
print(dataframe7)

####剔除银行类,保险类,证券类
####再分析当前形势,例如地产类和教育类不碰

你可能感兴趣的:(python)