基于 4433 和高被选原则的基金选取(python 实现)

文章目录

  • 基于 4433 和高被选原则的基金选取(python 实现)
    • 前言
    • 程序实现
      • 导入所需要的包
      • 获取基金数据
      • 基金原数据预处理
      • 整理或者基金数据表
      • 使用4433原则挑选基金
      • 获得各个基金的前几持仓数据和股票集合
      • 统计最受欢迎的n大股票
      • 计算出持仓最吻合最受欢迎股票的基金
    • UI 人机界面制作
    • 使用 pyinstaller 封装为 exe

前言

从前大家朋友圈都在晒美食,晒旅游,晒玩乐,现在翻来朋友圈一看,竟然有很多人在晒炒股。这是一个好现象,说明人民日益增长的美好生活需要,已经从温饱休息,变成了投资和理财。股票和基金等似乎依然还是大众眼中新鲜和高级的事物,买过股票,涨涨跌跌,也值得网上凡尔赛一番。

在通货膨胀的时代,钱放着就是在贬值。如果你有余钱且有些许碎片化时间的话,投资和理财是很有必要的。股票对于大部分散户来说,无疑是坐等着被割韭菜。所以,比起股票,对于散户,我更建议买一些基金。当然,若是真的钟情于股票,倒是可以花一些无关紧要丢了也罢的小钱玩一玩。

经常会听到别人喜欢给人推荐股票,这种人都是新手。因为真正经历了股海沉浮的人,是不敢给人推荐股票的,这句话懂的人都懂。每一个炒股的人,都应该有自己的选股系统,否则,你凭别人推荐赢得的钱,迟早会凭自己的无知输掉。

我想了想,花了一天的时间,爬了些数据,写了两个基金推荐的程序。一个是网上流行的 4433 法则,另外一个我自己想的,基于最受欢迎股票的持仓稳合度。我不买基金。需要我推荐基金的可以找我。去年来行情那么好,投资回报只做到 30% 的,都算是差的。

不妨和大家分享一下我的选股和选基金的思路。简单来说就是“抄作业”。

作为专业投资机构,基金公司选择股票都有特定的程序,一般基金公司有自己的研究人员,研究人员把自己的研究结果汇总给基金经理,基金公司也会从券商的研究机构那里付费买研究报告,另外,基金公司的研究团队还经常到上市企业实地考察,以便了解第一手资料。基金经理根据汇总过来的资料和自己的经验判断大盘走势、板块趋势及个股存在的机会,然后有的还要经过开会讨论,集思广益。最后才让操盘人员买卖股票。

作为普通人,我们大概率是比不上这些机构的。那么我们应该怎么做?我们可以抄基金公司的作业呀,把别人的成果据为己有,站在巨人的肩膀上看问题,不香么。现在问题来了,根据法律规定基金公司在特定时间,只会公布上一个季度的持仓数据,那么它的作业就是老作业,布置了新作业,却交上一次的作业,肯定是不行的。那有什么办法呢?有。就是多抄几分作业,用频率来替代概率。我的程序可以抄所有基金公司的作业,把它整合成一个作业,虽然不那么完美,但是总归是不错的。怎么样把七千多份作业抄成一份,这就是我的卖点所在。我不懂选股,但是我希望能站在基金这个巨人的肩膀上看问题,总是不会错的。

学数据科学的应该清楚,数据分析的三板斧,其实非常有用的一招就是“count”(数数),小学就会的,最简单的,也是非常有效的。

下面是我的程序实现与软件制作。除了本体程序,我还制作了 GUI 用户交互界面,并且封装成了 exe,主要是考虑到那些没有运行环境的用户。不多加解释,直接看代码言简意赅。结果的话,我就不展示了,自己跑一跑把,会有惊喜的。

程序实现

导入所需要的包

# encoding=utf-8
import pandas as pd
import requests
from lxml import etree
import re
import collections

获取基金数据

ft 表示基金的类型,包含全部(all)、股票型(gp)、混合型(hh)、债券型(zq)、指数型(zs)、QDII(qdii)、LOF(lof)、FOF(fof)。

sc 表示排序类别,包括代码(dm)、简称(jc)、截止日期(jzrq)、单位净值(dwjz)、累计净值(ljjz)、日增长率(rzdf)、近一周(zzf)、近一月(1yzf)、近三月(3yzf)、近六月(6yzf)、近一年(1nzf)、近二年(2nzf)、近三年(3nzf)、今年来(jnzf)、成立以来(lnzf)、自定义时间内(qjzf)。

st 表示排序方式,包括降序(desc)和升序(asc)。

dx 表示是否可购,包括可购买(1)和不可购(0)。

header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36','Referer': 'http://fund.eastmoney.com/data/fundranking.html','Cookie':'st_si=74949607860286; st_asi=delete; ASP.NET_SessionId=gekyucnll0wte0wrks2rr23b; _adsame_fullscreen_18503=1; EMFUND1=null; EMFUND2=null; EMFUND3=null; EMFUND4=null; EMFUND5=null; EMFUND6=null; EMFUND7=null; EMFUND8=null; EMFUND0=null; EMFUND9=02-07 16:37:21@#$%u521B%u91D1%u5408%u4FE1%u5DE5%u4E1A%u5468%u671F%u80A1%u7968A@%23%24005968; st_pvi=90009717841707; st_sp=2021-02-07%2012%3A14%3A29; st_inirUrl=https%3A%2F%2Fwww.baidu.com%2Flink; st_sn=21; st_psi=2021020716562364-0-0372414431'
}
sample = '1500';
ft = 'gp'
sc = '6yzf'
dx = '1'
st = 'desc'
url = 'http://fund.eastmoney.com/data/rankhandler.aspx?op=ph&dt=kf&ft='+ft+'&rs=&gs=0&sc='+sc+'&st='+st+'&sd=2021-01-07&ed=2021-02-07&qdii=&tabSubtype=,,,,,&pi=1&pn='+sample+'&dx='+dx+'&v=0.2692835962833908'
response = requests.get(url=url, headers=header)
text = response.text

基金原数据预处理

data = text.split('=')[1]#使用等号分开去后面一部分
compile_data = re.findall("{datas:\\[(.*)\\],allRecords", str(data))[0]#取datas和allRecords中的所有内容
strip_data = str(compile_data).strip('[').strip(']')#移除字符串头尾的中括号
replace_quta = strip_data.replace('"', "")#双引号替换为空
quota_arrays = replace_quta.split(",")#使用逗号转为列表

整理或者基金数据表

intervals = [[i * 25, (i + 1) * 25] for i in range(15000)]#生成10000个区间,每个区间长度为25
narrays = []
for k in intervals:start, end = k[0], k[1]line = quota_arrays[start:end]#将条目25个分为一组,表示一只基金narrays.append(line)
header = ["基金代码", "基金简称", "基金条码", "日期","单位净值", "累计净值", "日增长率", "近1周", "近1月", "近3月", "近半年", "近1年", "近2年", "近3年","今年来", "成立来", "其他1", "其他2", "其他3", "其他4", "其他5", "其他6", "其他7", "其他8", "其他9"]
df = pd.DataFrame(narrays, columns=header)#生成pd数据结构
df.dropna()
total = df.count()[0]
print("共有{}支基金!".format(total))
df = df.head(total)
df_part = df[["基金代码", "基金简称", "日增长率", "近1周", "近1月", "近3月", "近半年", "近1年", "近2年", "近3年","今年来", "成立来"]]#挑选部分感兴趣的条目
df.to_csv("./选取的全部基金数据.csv", encoding="utf_8_sig")

使用4433原则挑选基金

4433原则,第一个4,近一年前1/4,第二个4,近两年,近三年,今年来前1/4,第一个3,近3个月前1/3,第二个3,近6个月前1/3。

# 4433原则,第一个4,近一年前1/4,第二个4,近两年,近三年,今年来前1/4,第一个3,近3个月前1/3,第二个3,近6个月前1/3
total_quarter = int(total*0.25)
total_third = int(total*1/3)
df_picked_part = df_part
for sc in ["近1年","近2年","近3年","今年来"]:#print(sc)df_tmp = df_part.sort_values(by=[sc], ascending=False, axis=0)df_tmp = df_tmp.head(total_quarter)df_picked_part = pd.merge(df_picked_part,df_tmp,how='inner')
for sc in ["近3月","近半年"]:#print(sc)df_tmp = df_part.sort_values(by=[sc], ascending=False, axis=0)df_tmp = df_tmp.head(total_third)df_picked_part = pd.merge(df_picked_part,df_tmp,how='inner')
print(df_picked_part)
df_picked_part.to_csv("./4433法则挑选出的基金.csv", encoding="utf_8_sig")

获得各个基金的前几持仓数据和股票集合

rank_codes = df_part['基金代码'].values.tolist()
#len_codes = len(rank_codes)
stocks_array = []
stock_funds = []
total_part = int(total/100) #每百分之一报一次进度
for index, code in enumerate(rank_codes):
#    if index < 1:
#        print("<" * 30 + "所有基金的股票池前10情况" + ">" * 30)
#    print(code)if index%total_part==0:print("<" * 30 + "获得各个基金的前几持仓数据和股票集合中:"+str(index)+"/"+str(total)+ ">" * 30)url = "http://fundf10.eastmoney.com/FundArchivesDatas.aspx?type=jjcc&code={}&topline=10&year=&month=&rt=0.5032668912422176".format(code)head = {"Cookie": "EMFUND1=null; EMFUND2=null; EMFUND3=null; EMFUND4=null; EMFUND5=null; EMFUND6=null; EMFUND7=null; EMFUND8=null; EMFUND0=null; st_si=44023331838789; st_asi=delete; EMFUND9=08-16 22:04:25@#$%u4E07%u5BB6%u65B0%u5229%u7075%u6D3B%u914D%u7F6E%u6DF7%u5408@%23%24519191; ASP.NET_SessionId=45qdofapdlm1hlgxapxuxhe1; st_pvi=87492384111747; st_sp=2020-08-16%2000%3A05%3A17; st_inirUrl=http%3A%2F%2Ffund.eastmoney.com%2Fdata%2Ffundranking.html; st_sn=12; st_psi=2020081622103685-0-6169905557","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36"}response = requests.get(url, headers=head)text = response.textdiv = re.findall('content:\\"(.*)\\",arryear', text)[0]html_body = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>test</title></head><body>%s</body></html>' % (div)#构造网页html = etree.HTML(html_body)#将传进去的字符串转变成_Element对象stock_info = html.xpath('//div[1]/div/table/tbody/tr/td/a')#  stock_money = html.xpath('//div[1]/div/table/tbody/tr/td')stock_one_fund = []for i in range(0,len(stock_info)):stock = stock_info[i]tmp = stock.text.split('.')[0]if stock.text and (tmp.isdigit() or (tmp.isupper() and tmp.isalnum())):
#        if stock.text and stock.text.isdigit():# list_tmp = [stock.text,stock_info[i+1].text]stock_one_fund.append(stock_info[i+1].text)
#            print(stock_info[i+1].text)if len(stock_one_fund)>1:#      print("基金代码:{}".format(code), "基金持有前10股票池", stock_one_fund)stock_funds.append([code,stock_one_fund])if len(stock_one_fund) > 1 and stock_one_fund:stocks_array.extend(stock_one_fund)
print("<" * 30 + "获得各个基金的前几持仓数据和股票集合中:done!!!"+ ">" * 30)
pd.DataFrame(stock_funds).to_csv("./基金的股票持仓情况统计.csv", encoding="utf_8_sig")

统计最受欢迎的n大股票

rank = 10
count_each_stock = collections.Counter(stocks_array) #各个股票计数
df_stock=pd.DataFrame.from_dict(count_each_stock,orient='index',columns=["持有该股基金数目"])
df_stock=df_stock.reset_index().rename(columns={"index":"股票简称"})
df_stock=df_stock.sort_values(by="持有该股基金数目",ascending=False)
df_stock_head = df_stock.head(rank)
print(df_stock_head)
df_stock.to_csv("./股票的归属基金数目统计.csv", encoding="utf_8_sig")

计算出持仓最吻合最受欢迎股票的基金

funds_stocks_count = []
for st_funds in stock_funds:df_stock_funds = pd.DataFrame(st_funds[1],columns=['股票简称'])
#    print(df_stock_funds)count = pd.merge(df_stock_head['股票简称'],df_stock_funds,how='inner').iloc[:,0].sizejc_tmp = df_part[df_part['基金代码']==st_funds[0]].iloc[0,1]funds_stocks_count.append([jc_tmp,count])
df_funds_stock_count = pd.DataFrame(funds_stocks_count,columns = ['基金简称','优仓数目'])
df_funds_stock_count = df_funds_stock_count.sort_values(by=["优仓数目"], ascending=False, axis=0)
df_funds_stock_count = pd.merge(df_funds_stock_count,df_part,how='inner',on='基金简称')
df_funds_stock_count.to_csv("./基金持有优仓数目统计.csv", encoding="utf_8_sig")
df_funds_stock_count.head(10)

UI 人机界面制作

制作的效果如下:
制作过程如下:

  • 首先安装 PyQt,并打开 Qt designer,如果找不到 designer 在哪,推荐查找神器 everything。
  • 新建 Dialog 窗体,拖入布局控件,拖入需要用到的控件,排好位置,给每个对象设置好默认值和属性等,起一个好记的名字。
  • 给“确定”按钮编辑信号/槽,指向窗体空白处,设置为clicked()->accept()。如图:
  • 保存 ui 文件。使用 pyuic5 或者 pyuic4 工具转 ui 为 py 文件,pyuic5 -o test.py test.ui。生成 py 代码的 Dialog.setObjectName 是用来定义窗体名称的,可修改。
  • 将生成的 GUI 代码和原来的基金选取代码进行融合即可。
    # -*- coding: utf-8 -*-
    """
    Created on Mon Feb  8 16:12:40 2021@author: Administrator
    """
    # -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'fund_pick.ui'
    #
    # Created by: PyQt5 UI code generator 5.15.2
    #
    # WARNING: Any manual changes made to this file will be lost when pyuic5 is
    # run again.  Do not edit this file unless you know what you are doing.from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_Dialog(object):def setupUi(self, Dialog):Dialog.setObjectName("Dialog")Dialog.resize(1071, 486)self.textBrowser = QtWidgets.QTextBrowser(Dialog)self.textBrowser.setGeometry(QtCore.QRect(50, 440, 981, 41))self.textBrowser.setObjectName("textBrowser")self.textBrowser_2 = QtWidgets.QTextBrowser(Dialog)self.textBrowser_2.setGeometry(QtCore.QRect(400, 30, 631, 411))self.textBrowser_2.setObjectName("textBrowser_2")self.gridLayoutWidget = QtWidgets.QWidget(Dialog)self.gridLayoutWidget.setGeometry(QtCore.QRect(60, 30, 311, 331))self.gridLayoutWidget.setObjectName("gridLayoutWidget")self.gridLayout_2 = QtWidgets.QGridLayout(self.gridLayoutWidget)self.gridLayout_2.setContentsMargins(0, 0, 0, 0)self.gridLayout_2.setObjectName("gridLayout_2")self.ft_input = QtWidgets.QComboBox(self.gridLayoutWidget)self.ft_input.setObjectName("ft_input")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.ft_input.addItem("")self.gridLayout_2.addWidget(self.ft_input, 1, 2, 1, 1)self.dx_input = QtWidgets.QComboBox(self.gridLayoutWidget)self.dx_input.setObjectName("dx_input")self.dx_input.addItem("")self.dx_input.addItem("")self.gridLayout_2.addWidget(self.dx_input, 4, 2, 1, 1)self.st_input = QtWidgets.QComboBox(self.gridLayoutWidget)self.st_input.setObjectName("st_input")self.st_input.addItem("")self.st_input.addItem("")self.gridLayout_2.addWidget(self.st_input, 3, 2, 1, 1)self.sc_input = QtWidgets.QComboBox(self.gridLayoutWidget)self.sc_input.setObjectName("sc_input")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.sc_input.addItem("")self.gridLayout_2.addWidget(self.sc_input, 2, 2, 1, 1)self.label_3 = QtWidgets.QLabel(self.gridLayoutWidget)self.label_3.setObjectName("label_3")self.gridLayout_2.addWidget(self.label_3, 1, 0, 1, 1)self.label_4 = QtWidgets.QLabel(self.gridLayoutWidget)self.label_4.setObjectName("label_4")self.gridLayout_2.addWidget(self.label_4, 2, 0, 1, 1)self.label = QtWidgets.QLabel(self.gridLayoutWidget)self.label.setObjectName("label")self.gridLayout_2.addWidget(self.label, 3, 0, 1, 1)self.label_2 = QtWidgets.QLabel(self.gridLayoutWidget)self.label_2.setObjectName("label_2")self.gridLayout_2.addWidget(self.label_2, 4, 0, 1, 1)self.pushButton = QtWidgets.QPushButton(Dialog)self.pushButton.setGeometry(QtCore.QRect(150, 380, 150, 46))self.pushButton.setObjectName("pushButton")self.retranslateUi(Dialog)self.pushButton.clicked.connect(Dialog.accept)QtCore.QMetaObject.connectSlotsByName(Dialog)def retranslateUi(self, Dialog):_translate = QtCore.QCoreApplication.translateDialog.setWindowTitle(_translate("Dialog", "Dialog"))self.textBrowser.setHtml(_translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
    "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
    "p, li { white-space: pre-wrap; }\n"
    "</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-weight:600;\">作者:lusongcool@163.com  制作日期:2021.02.08  版权所有,偷盗必究</span></p></body></html>"))self.textBrowser_2.setHtml(_translate("Dialog", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
    "<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
    "p, li { white-space: pre-wrap; }\n"
    "</style></head><body style=\" font-family:\'SimSun\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">ft 表示基金的类型,包含全部(all)、股票型(gp)、混合型(hh)、债券型(zq)、指数型(zs)、QDII(qdii)、LOF(lof)、FOF(fof)。</p>\n"
    "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n"
    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">sc 表示排序类别,包括代码(dm)、简称(jc)、截止日期(jzrq)、单位净值(dwjz)、累计净值(ljjz)、日增长率(rzdf)、近一周(zzf)、近一月(1yzf)、近三月(3yzf)、近六月(6yzf)、近一年(1nzf)、近二年(2nzf)、近三年(3nzf)、今年来(jnzf)、成立以来(lnzf)、自定义时间内(qjzf)。</p>\n"
    "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n"
    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">st 表示排序方式,包括降序(desc)和升序(asc)。</p>\n"
    "<p style=\"-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><br /></p>\n"
    "<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">dx 表示是否可购,包括可购买(1)和不可购(0)。</p></body></html>"))self.ft_input.setItemText(0, _translate("Dialog", "all"))self.ft_input.setItemText(1, _translate("Dialog", "gp"))self.ft_input.setItemText(2, _translate("Dialog", "hh"))self.ft_input.setItemText(3, _translate("Dialog", "zq"))self.ft_input.setItemText(4, _translate("Dialog", "zs"))self.ft_input.setItemText(5, _translate("Dialog", "qdii"))self.ft_input.setItemText(6, _translate("Dialog", "lof"))self.ft_input.setItemText(7, _translate("Dialog", "fof"))self.dx_input.setItemText(0, _translate("Dialog", "1"))self.dx_input.setItemText(1, _translate("Dialog", "0"))self.st_input.setItemText(0, _translate("Dialog", "desc"))self.st_input.setItemText(1, _translate("Dialog", "asc"))self.sc_input.setItemText(0, _translate("Dialog", "dm"))self.sc_input.setItemText(1, _translate("Dialog", "jc"))self.sc_input.setItemText(2, _translate("Dialog", "jzrq"))self.sc_input.setItemText(3, _translate("Dialog", "dwjz"))self.sc_input.setItemText(4, _translate("Dialog", "ljjz"))self.sc_input.setItemText(5, _translate("Dialog", "rzdf"))self.sc_input.setItemText(6, _translate("Dialog", "zzf"))self.sc_input.setItemText(7, _translate("Dialog", "1yzf"))self.sc_input.setItemText(8, _translate("Dialog", "3yzf"))self.sc_input.setItemText(9, _translate("Dialog", "6yzf"))self.sc_input.setItemText(10, _translate("Dialog", "lnzf"))self.sc_input.setItemText(11, _translate("Dialog", "2nzf"))self.sc_input.setItemText(12, _translate("Dialog", "3nzf"))self.sc_input.setItemText(13, _translate("Dialog", "jnzf"))self.sc_input.setItemText(14, _translate("Dialog", "lnzf"))self.sc_input.setItemText(15, _translate("Dialog", "qjzf"))self.label_3.setText(_translate("Dialog", "ft"))self.label_4.setText(_translate("Dialog", "sc"))self.label.setText(_translate("Dialog", "st"))self.label_2.setText(_translate("Dialog", "dx"))self.pushButton.setText(_translate("Dialog", "确定"))from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import QInputDialog, QLineEdit, QDialog
    from PyQt5.QtWidgets import QApplication
    import sys
    #import dlg
    class TestDialog(QDialog,Ui_Dialog):  def __init__(self,parent=None):  super(TestDialog,self).__init__(parent)  self.setupUi(self)app=QApplication(sys.argv)
    dialog=TestDialog()
    dialog.show()
    app.exec_()ft = dialog.ft_input.currentText()
    sc = dialog.sc_input.currentText()
    st = dialog.st_input.currentText()
    dx = dialog.dx_input.currentText() #!/usr/bin/env python
    # coding: utf-8# # 基于4433法则和高被选原则的基金选取# Author:lusong@lsec.cc.ac.cn
    # Date:2021.2.7# ### 导入所需要的包# In[ ]:# encoding=utf-8
    import pandas as pd
    import requests
    from lxml import etree
    import re
    import collections# ### 获取基金数据
    # ft 表示基金的类型,包含全部(all)、股票型(gp)、混合型(hh)、债券型(zq)、指数型(zs)、QDII(qdii)、LOF(lof)、FOF(fof)。
    #
    # sc 表示排序类别,包括代码(dm)、简称(jc)、截止日期(jzrq)、单位净值(dwjz)、累计净值(ljjz)、日增长率(rzdf)、近一周(zzf)、近一月(1yzf)、近三月(3yzf)、近六月(6yzf)、近一年(1nzf)、近二年(2nzf)、近三年(3nzf)、今年来(jnzf)、成立以来(lnzf)、自定义时间内(qjzf)。
    #
    # st 表示排序方式,包括降序(desc)和升序(asc)。
    #
    # dx 表示是否可购,包括可购买(1)和不可购(0)。# In[ ]:header = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36','Referer': 'http://fund.eastmoney.com/data/fundranking.html','Cookie':'st_si=74949607860286; st_asi=delete; ASP.NET_SessionId=gekyucnll0wte0wrks2rr23b; _adsame_fullscreen_18503=1; EMFUND1=null; EMFUND2=null; EMFUND3=null; EMFUND4=null; EMFUND5=null; EMFUND6=null; EMFUND7=null; EMFUND8=null; EMFUND0=null; EMFUND9=02-07 16:37:21@#$%u521B%u91D1%u5408%u4FE1%u5DE5%u4E1A%u5468%u671F%u80A1%u7968A@%23%24005968; st_pvi=90009717841707; st_sp=2021-02-07%2012%3A14%3A29; st_inirUrl=https%3A%2F%2Fwww.baidu.com%2Flink; st_sn=21; st_psi=2021020716562364-0-0372414431'
    }
    sample = '15000';
    #ft = 'qdii'
    #sc = '6yzf'
    #dx = '1'
    #st = 'desc'
    url = 'http://fund.eastmoney.com/data/rankhandler.aspx?op=ph&dt=kf&ft='+ft+'&rs=&gs=0&sc='+sc+'&st='+st+'&sd=2021-01-07&ed=2021-02-07&qdii=&tabSubtype=,,,,,&pi=1&pn='+sample+'&dx='+dx+'&v=0.2692835962833908'
    response = requests.get(url=url, headers=header)
    text = response.text# ### 基金原数据预处理# In[ ]:data = text.split('=')[1]#使用等号分开去后面一部分
    compile_data = re.findall("{datas:\\[(.*)\\],allRecords", str(data))[0]#取datas和allRecords中的所有内容
    strip_data = str(compile_data).strip('[').strip(']')#移除字符串头尾的中括号
    replace_quta = strip_data.replace('"', "")#双引号替换为空
    quota_arrays = replace_quta.split(",")#使用逗号转为列表# ### 整理或者基金数据表# In[ ]:intervals = [[i * 25, (i + 1) * 25] for i in range(15000)]#生成10000个区间,每个区间长度为25
    narrays = []
    for k in intervals:start, end = k[0], k[1]line = quota_arrays[start:end]#将条目25个分为一组,表示一只基金narrays.append(line)
    header = ["基金代码", "基金简称", "基金条码", "日期","单位净值", "累计净值", "日增长率", "近1周", "近1月", "近3月", "近半年", "近1年", "近2年", "近3年","今年来", "成立来", "其他1", "其他2", "其他3", "其他4", "其他5", "其他6", "其他7", "其他8", "其他9"]
    df = pd.DataFrame(narrays, columns=header)#生成pd数据结构
    df.dropna()
    total = df.count()[0]
    print("共有{}支基金!".format(total))
    df = df.head(total)
    df_part = df[["基金代码", "基金简称", "日增长率", "近1周", "近1月", "近3月", "近半年", "近1年", "近2年", "近3年","今年来", "成立来"]]#挑选部分感兴趣的条目
    df.to_csv("./选取的全部基金数据.csv", encoding="utf_8_sig")# ### 使用4433原则挑选基金
    # 4433原则,第一个4,近一年前1/4,第二个4,近两年,近三年,今年来前1/4,第一个3,近3个月前1/3,第二个3,近6个月前1/3# In[ ]:# 4433原则,第一个4,近一年前1/4,第二个4,近两年,近三年,今年来前1/4,第一个3,近3个月前1/3,第二个3,近6个月前1/3
    total_quarter = int(total*0.25)
    total_third = int(total*1/3)
    df_picked_part = df_part
    for sc in ["近1年","近2年","近3年","今年来"]:#print(sc)df_tmp = df_part.sort_values(by=[sc], ascending=False, axis=0)df_tmp = df_tmp.head(total_quarter)df_picked_part = pd.merge(df_picked_part,df_tmp,how='inner')
    for sc in ["近3月","近半年"]:#print(sc)df_tmp = df_part.sort_values(by=[sc], ascending=False, axis=0)df_tmp = df_tmp.head(total_third)df_picked_part = pd.merge(df_picked_part,df_tmp,how='inner')# In[ ]:print(df_picked_part)
    df_picked_part.to_csv("./4433法则挑选出的基金.csv", encoding="utf_8_sig")# ### 获得各个基金的前几持仓数据和股票集合# In[ ]:rank_codes = df_part['基金代码'].values.tolist()
    #len_codes = len(rank_codes)
    stocks_array = []
    stock_funds = []
    total_part = int(total/100) #每百分之一报一次进度
    for index, code in enumerate(rank_codes):
    #    if index < 1:
    #        print("<" * 30 + "所有基金的股票池前10情况" + ">" * 30)
    #    print(code)if index%total_part==0:print("<" * 30 + "获得各个基金的前几持仓数据和股票集合中:"+str(index)+"/"+str(total)+ ">" * 30)url = "http://fundf10.eastmoney.com/FundArchivesDatas.aspx?type=jjcc&code={}&topline=10&year=&month=&rt=0.5032668912422176".format(code)head = {"Cookie": "EMFUND1=null; EMFUND2=null; EMFUND3=null; EMFUND4=null; EMFUND5=null; EMFUND6=null; EMFUND7=null; EMFUND8=null; EMFUND0=null; st_si=44023331838789; st_asi=delete; EMFUND9=08-16 22:04:25@#$%u4E07%u5BB6%u65B0%u5229%u7075%u6D3B%u914D%u7F6E%u6DF7%u5408@%23%24519191; ASP.NET_SessionId=45qdofapdlm1hlgxapxuxhe1; st_pvi=87492384111747; st_sp=2020-08-16%2000%3A05%3A17; st_inirUrl=http%3A%2F%2Ffund.eastmoney.com%2Fdata%2Ffundranking.html; st_sn=12; st_psi=2020081622103685-0-6169905557","User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36"}response = requests.get(url, headers=head)text = response.textdiv = re.findall('content:\\"(.*)\\",arryear', text)[0]html_body = '<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>test</title></head><body>%s</body></html>' % (div)#构造网页html = etree.HTML(html_body)#将传进去的字符串转变成_Element对象stock_info = html.xpath('//div[1]/div/table/tbody/tr/td/a')#  stock_money = html.xpath('//div[1]/div/table/tbody/tr/td')stock_one_fund = []for i in range(0,len(stock_info)):stock = stock_info[i]tmp = stock.text.split('.')[0]if stock.text and (tmp.isdigit() or (tmp.isupper() and tmp.isalnum())):
    #        if stock.text and stock.text.isdigit():# list_tmp = [stock.text,stock_info[i+1].text]stock_one_fund.append(stock_info[i+1].text)
    #            print(stock_info[i+1].text)if len(stock_one_fund)>1:#      print("基金代码:{}".format(code), "基金持有前10股票池", stock_one_fund)stock_funds.append([code,stock_one_fund])if len(stock_one_fund) > 1 and stock_one_fund:stocks_array.extend(stock_one_fund)
    print("<" * 30 + "获得各个基金的前几持仓数据和股票集合中:done!!!"+ ">" * 30)
    pd.DataFrame(stock_funds).to_csv("./基金的股票持仓情况统计.csv", encoding="utf_8_sig")# ### 统计最受欢迎的n大股票# In[ ]:rank = 10
    count_each_stock = collections.Counter(stocks_array) #各个股票计数
    df_stock=pd.DataFrame.from_dict(count_each_stock,orient='index',columns=["持有该股基金数目"])
    df_stock=df_stock.reset_index().rename(columns={"index":"股票简称"})
    df_stock=df_stock.sort_values(by="持有该股基金数目",ascending=False)
    df_stock_head = df_stock.head(rank)
    print(df_stock_head)
    df_stock.to_csv("./股票的归属基金数目统计.csv", encoding="utf_8_sig")# ### 计算出持仓最吻合最受欢迎股票的基金# In[ ]:funds_stocks_count = []
    for st_funds in stock_funds:df_stock_funds = pd.DataFrame(st_funds[1],columns=['股票简称'])
    #    print(df_stock_funds)count = pd.merge(df_stock_head['股票简称'],df_stock_funds,how='inner').iloc[:,0].sizejc_tmp = df_part[df_part['基金代码']==st_funds[0]].iloc[0,1]funds_stocks_count.append([jc_tmp,count])
    df_funds_stock_count = pd.DataFrame(funds_stocks_count,columns = ['基金简称','优仓数目'])
    df_funds_stock_count = df_funds_stock_count.sort_values(by=["优仓数目"], ascending=False, axis=0)
    df_funds_stock_count = pd.merge(df_funds_stock_count,df_part,how='inner',on='基金简称')
    df_funds_stock_count.to_csv("./基金持有优仓数目统计.csv", encoding="utf_8_sig")
    df_funds_stock_count.head(10)# In[ ]:

    上面的融合,补充的核心部分代码是:

    from PyQt5.QtGui import *
    from PyQt5.QtCore import *
    from PyQt5.QtWidgets import QInputDialog, QLineEdit, QDialog
    from PyQt5.QtWidgets import QApplication
    import sys
    #import dlg
    class TestDialog(QDialog,Ui_Dialog):  def __init__(self,parent=None):  super(TestDialog,self).__init__(parent)  self.setupUi(self)app=QApplication(sys.argv)
    dialog=TestDialog()
    dialog.show()
    app.exec_()
    

使用 pyinstaller 封装为 exe

如果你使用的是 Anaconda,为保证生成的 exe 足够小,请安装虚拟机,虚拟机安装相应的系统和 Python 环境,保证一个纯净的转化环境。

使用 pyinstaller 命令进行封装。-F 参数可以封装为单文件。封装出来的 exe 使用命令行进行测试,缺什么包补装什么包,之后重新封装,知道成功。

基于 python 的股票和基金选取 程序设计相关推荐

  1. 基于python的股票程序化交易论文_基于Python工具的股票量化投资策略研究

    2019 年第 07 期 20 世 纪 80 年代, 一 些 投 资 者 开 始 利用 计 算 机 研究金 融 数据 , 并 初显 成 效 . 20 世 纪 末 , 投 资 者 把 计 算 机 技术 ...

  2. 基于Python的旅游管理系统微信小程序设计与实现毕业论文+项目源码及数据库

     源码获取:我的博客资源页面可以下载!!!! 项目名称 基于Python的旅游管理系统微信小程序设计与实现毕业论文+项目源码及数据库 系统说明 本商业旅游系统可以分为三个部分,即微信小程序的手机客户端 ...

  3. 基于python的股票程序化交易软件_tushare开源股票交易接口基于python实现技术

    tushare开源股票交易接口基于python实现技术 怎样在tushare中完成股票实盘交易 其实,如何使用实盘交易功能接口,与通过tushare获取数据一样简单,先看一下几个关键接口的使用方法: ...

  4. 基于python 的股票行情查询系统开发(一)

    基于python 的股市行情查询系统开发(一) 一.前言 1.开发背景 二.开发计划 1.开发语言 2.数据api获取 3.后续计划 今日进度 1.前期准备 2.获取股票代码 一.前言 1.开发背景 ...

  5. 基于 Python 监控股票涨停情况

    前言 偶然一次打开炒股软件,发现了这么一个下面这么一个区域 我的第一反应是:天呐,竟然还能这么玩?简单粗暴!所以我立马想到写一个涨停板监控程序,一旦监控到股票涨停并且有大量买单则立马通知我,当然还可以 ...

  6. 3 Python获取股票、基金、期货数据,好用的库efinance

    efinance 是由个人打造的用于获取股票.基金.期货数据的免费开源 Python 库,你可以使用它很方便地获取数据以便更好地服务于个人的交易系统需求. 范例 Stock 获取股票历史日 K 线数 ...

  7. 基于python的股票程序化交易软件_程序化交易(三):基于 Python 的股票程序化交易/量化框架 easyquant...

    续前贴,在前面的基础上弄了一个简单的程序化交易框架 easyquant 开源在 github 上,欢迎大家 star & fork.下面是简单介绍: 交易模块 easytrader 支持 华泰 ...

  8. 基于python的股票客户流失数据分析模型

    目录 1.案例背景 2 2. 读取数据 2 3. 划分特征变量和目标变量 3 4. 模型的搭建和使用 3 5. 模型的使用 4 6. ROC曲线对模型的评估 7 7.总结 10 8.参考文献 10 9 ...

  9. python股票策略_基于python的股票自动盯盘程序

    不是每个人都有时间时刻盯盘的,而且股票那么多,往往挂一漏万,错过很多好的股票和买入机会.笔者尝试用python实现了一个可以自动盯盘的程序,调用了一个免费的股票数据接口baostock提供的历史行情数 ...

  10. 基于python的股票数据的读取及可视化(K线图)

    文章目录 1.读取数据 2.绘制股票走势图 3.绘制K线图 1.读取数据 TuShare是一个免费.开源的python财经数据接口包.主要实现对股票等金融数据从数据采集.清洗加工 到 数据存储的过程, ...

最新文章

  1. C#中static静态变量的用法
  2. String类型转date
  3. C语言a+++b的问题
  4. 托管数据中心之间的PUE比较(下)
  5. VTK:可视化之MovableAxes
  6. (转)为什么人生气时说话用喊的?
  7. NSArray创建和使用
  8. java8根据某个id删选_Java 8可选
  9. Docker中安装Jenkins实时发布.net core 项目(二)
  10. 【c++leetcode】判断一个数是否是2的幂、3的幂、4的幂
  11. 非连续内存区缺页异常处理
  12. idea全局主题_2020年最新-IDEA最详细配置(配图文收藏版配置)
  13. arm中用c语言编写的程序 出现数组的最后一行调用不到,C语言函数指针数组在ARM中断中的应用...
  14. 系统软件内部测试报告模板,软件系统测试报告模板-20210316091936.pdf-原创力文档...
  15. Flarum正式版 简体中文语言包
  16. Python走心的42个代码例子
  17. 程序员应如何提高系统分析能力(转)
  18. 使用Python 对ENVI SPECTRAL LIBRARY(.sli)进行读取
  19. 【opencv源码剖析】背景建模mog2
  20. 金山WPS软件测试笔试题目总结

热门文章

  1. 计算方法(三)分段线性插值和Hermite插值
  2. ​新型冠状病毒是对未来自我隔离的预演?
  3. 零管理费的基金你见过吗?基金行业价格战预演
  4. CSS Sprite、CSS雪碧图应用实例
  5. 按键精灵定时后台点击
  6. iPhone 与 Mac 怎么同步?同步有什么用
  7. 企业如何选择短信平台
  8. xlwings 冻结窗口格 / 冻结首行/ FreezePanes
  9. 计算机管理能看到移动硬盘,无法识别移动硬盘并且不显示磁盘图标.
  10. BMVC2020 Best Paper: Delving Deeper into Anti-aliasing in ConvNets论文解读