基于大数据技术对基金分析-python

提示:本文为个人原创,仅供技术探讨与交流,对实际投资并不造成建议。


前言

在当下热销的基金市场中,有着茫茫多的基金,本文希望能以科学的角度,以数据作为依托,更好地挑选基金
本文共用到以下技术:Python爬虫、SQL分析


本文切入角度:
1.希望做到在相对低的净值买入值得长期持有的基金并定投
2.通过已有的数据了解到当下及未来3个月市场热门的板块(抱团)
3.通过基金的表现及近期情况判断市场方向
基金是T+1交易制度,存在明显的市场时间滞后,不适合像股票一样频繁操作。

一、数据获取:python爬虫

1).从天天基金数据接口获取数据

接入天天基金数据接口(所有基金名称列表代码):http://fund.eastmoney.com/js/fundcode_search.js
部分数据截图:
在这里插入图片描述
从图中数据可以看出,js文件中的数据以列表格式存放,且按照 => (编号、拼音缩写、基金名称、基金类型、拼音 )的顺序排列,因为信息并不完善,所以还需要再爬取每个基金的详细信息

2).爬虫前期准备

通过观察,天天基金的robots规则为:
在这里插入图片描述
每个基金详情页面为
http://fund.eastmoney.com/+基金代号,如下图:
在这里插入图片描述

3).爬虫具体实现

获取唯一编号列表

import requests

def get_req_data(url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:100.0) Gecko/20100101 Firefox/100.0',
    }
    res = requests.get(url=url, headers=headers)
    res.encoding = 'utf-8'
    return res.text

def get_code():
    data = get_req_data('http://fund.eastmoney.com/js/fundcode_search.js')
    data_list = data.replace("var r = [", "").replace("];", "").replace("],", "];").split(";")
    mf_codes = []
    for a in data_list:
        mf_list = a.split(",")
        mf_code = mf_list[0].replace("[", "").replace("\"", "")
        mf_codes.append(mf_code)
    return mf_codes

二、数据清洗及计算指标

1.过滤数据

据观察,数据中存在已终止基金或已不更新数据的基金 仅保留:昨日涨跌幅、近一月涨跌幅、近三月涨跌幅、近六月涨跌幅、近一年涨跌幅、近三年涨跌幅%、成立以来涨跌幅 共7个字段中为 “–”(基金运作时间未久会以“–”表示,为正常)和存在“%”的数据

2.数据字段格式统一

(便于后续SQL查询)金额字段统一为:仅保留数值(以亿元为单位)

(便于后续SQL查询)统一涨幅字段:百分比 => double小数,“–” => 0.0

3.计算得出字段now_down、all_win

all_win:将3个月、半年、一年、三年、历史总涨幅为正的基金标记为1 => 从数据层面上看,该基金中长期正收益,值得长期持有并定投
now_down:将同时满足昨日涨跌幅<0,仅一月涨跌幅<0,近半年涨跌幅>0,仅一年涨跌幅>0的基金标记,并计算出昨日跌幅+ 仅一月跌幅作为参数 => 数据层面上判断:该基金长期持有为正收益且当前属于回撤调整期,属于相对低值可入手
在这里插入图片描述

4.数据清洗具体实现

def parse(codes):
    t = len(codes)
    for i in range(0, t, 1000):
        sqlInfo, end = [], i + 1000
        if end > t:
            end = t
        for j in range(i, end):
            url = 'http://fund.eastmoney.com/'+str(codes[j])+'.html'
            response = etree.HTML(get_req_data(url))
            mf_name =response.xpath('//div[@class="fundDetail-tit"]/div[1]/text()')
            check_day = response.xpath('//dl[@class="dataItem02"]/dd[1]/span[1]/text()')
            if len(mf_name) == 0 or len(check_day) == 0:
                continue
            mf_name, mf_num = mf_name[0], codes[j]
            mf_type = response.xpath('//td[contains(text(),"基金类型")]/a/text()')[0]
            mf_money = check_data(response.xpath('//td[contains(text(),"亿元")]/text()')[0].replace(":", "").split("亿")[0])
            mf_manager = response.xpath('//td[contains(text(),"基金经理")]/a/text()')[0]
            mf_all = response.xpath('//div[@class="dataOfFund"]/dl[3]/dd[3]/span[2]/text()')
            worth, rate, day7, all_win, now_down = 0.0, 0.0, 0.0, 0, 0.0
            if len(mf_all) != 0:
                worth = check_data(check_day[0])
                if(worth == 0.0):
                    continue
                rate = check_data(response.xpath('//dl[@class="dataItem02"]/dd[1]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon1 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[1]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon3 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[2]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon6 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[3]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon12 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[1]/dd[3]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon36 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[2]/dd[3]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon_all = check_data(mf_all[0].replace("%", "")) * 0.01
            else:
                day7 = check_data(check_day[0].replace("%", "")) * 0.01
                mon1 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[1]/dd[1]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon3 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[2]/dd[1]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon6 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[3]/dd[1]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon12 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[1]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon36 = check_data(response.xpath('//div[@class="dataOfFund"]/dl[2]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
                mon_all = check_data(response.xpath('//div[@class="dataOfFund"]/dl[3]/dd[2]/span[2]/text()')[0].replace("%", "")) * 0.01
            # all_win:将3个月、半年、一年、三年、历史总涨幅为正的基金标记为1 => 从数据层面上看,该基金中长期正收益,值得长期持有并定投
            if mon3 > 0.0 and mon6 > 0.0 and mon12 > 0.0 and mon36 > 0.0 and mon_all > 0.0:
                all_win = 1
            # now_down:将同时满足昨日涨跌幅 < 0,仅一月涨跌幅 < 0,近半年涨跌幅 > 0, 仅一年涨跌幅 > 0
            # 的基金标记,并计算出昨日跌幅 + 仅一月跌幅作为参数 => 数据层面上判断:该基金长期持有为正收益且当前属于回撤调整期,属于相对低值可入手
            if rate < 0.0 and mon1 < 0.0 and mon6 > 0.0 and mon12 > 0.0 and mon36 > 0.0:
                now_down = (rate + mon1) * 0.01
            sqlInfo.append((mf_name, mf_num, mf_type, float(mf_money), mf_manager, worth, rate, day7, mon1, mon3, mon6, mon12, mon36, mon_all, all_win, now_down))
            print(sqlInfo[-1])
        insert_data(sqlInfo)
      
def check_data(mf):
    if mf == "--":
        mf = 0.0
    return float(mf)

4.保存数据库

def insert_data(sqlInfo):
    # 批量写入数据库, 打开数据库连接
    conn = pymysql.connect(host='127.0.0.1', port=3306, user='root', passwd='123456', db='fund_money', charset='utf8')
    sql = 'INSERT INTO `fund`(mf_name, mf_num, mf_type, mf_money, mf_manager, mf_worth, mf_rate, mf_day7, mf_mon1 , mf_mon3 , mf_mon6 , mf_mon12, mf_mon36, mf_all, all_win, now_down) ' \
          'VALUES(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)'

    # 使用 cursor() 方法创建一个游标对象 cursor
    cursor = conn.cursor()
    cursor.executemany(sql, sqlInfo)
    conn.commit()  # 提交
    cursor.close()
    conn.close()

创建数据库

CREATE TABLE fund (
  `fund_id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `mf_name` varchar(50) NOT NULL DEFAULT '' COMMENT '基金名称', 
  `mf_num` varchar(20) NOT NULL DEFAULT '' COMMENT '基金代码', 
  `mf_type` varchar(20) NOT NULL DEFAULT '' COMMENT '基金类型', 
  `mf_money` float NOT NULL DEFAULT 0.0 COMMENT '基金规模(亿元)', 
  `mf_manager` varchar(20) NOT NULL DEFAULT '' COMMENT '基金经理', 
  `mf_day7` float NOT NULL DEFAULT 0.0 COMMENT '七日年化率%', 
  `mf_worth` float NOT NULL DEFAULT 0.0 COMMENT '单位净值', 
  `mf_rate` float NOT NULL DEFAULT 0.0 COMMENT '昨日涨跌幅%', 
  `mf_mon1` float NOT NULL DEFAULT 0.0 COMMENT '近一月涨跌幅%', 
  `mf_mon3` float NOT NULL DEFAULT 0.0 COMMENT '近三月涨跌幅%', 
  `mf_mon6` float NOT NULL DEFAULT 0.0 COMMENT '近六月涨跌幅%', 
  `mf_mon12` float NOT NULL DEFAULT 0.0 COMMENT '近一年涨跌幅%', 
  `mf_mon36` float NOT NULL DEFAULT 0.0 COMMENT '近三年涨跌幅%', 
  `mf_all` float NOT NULL DEFAULT 0.0 COMMENT '成立以来涨跌幅%', 
  `all_win` integer NOT NULL DEFAULT 0 COMMENT '0:其他 1:长期正收益', 
  `now_down` float NOT NULL DEFAULT 0.0 COMMENT '回撤调整期涨跌幅%', 
  PRIMARY KEY (`fund_id`)
)ENGINE=InnoDB COMMENT='基金基础数据表';

三、数据分析:SQL

1.昨日涨跌幅、近一月涨跌幅、近一年涨幅、仅三年涨幅 top20 => 当前主题行情分析

2.金额总值top50=> 截至2023-6-29最热门抱团方向

在这里插入图片描述

3. 3月份后涨跌幅为“- -” => 新发基金封闭期3个月=> 当前基金机构看好的行业板块方向 => 未来抱团方向(?)

4.now_down最小前20 => 数值越小,跌幅越大

SELECT * FROM `fund` ORDER BY now_down, mf_mon1 LIMIT 20;

在这里插入图片描述

5.all_win =>中长期正收益,值得长期持有

总结

完整代码
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

百里 Jess

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值