使用 Python 获取A股新增投资者数据

散户死因.jpg

本文有视频教程,感兴趣的朋友可以点击链接观看。
【Python教程】30分钟DIY一个A股情绪监控器

前言

当前国内的经济环境一般,股市已经长期处于熊市之中,与牛市相比,现在几乎听不到有人讨论股市了。这是非常典型的直线思维:当股市在上涨的牛市中,人们的投资意愿就变强,如果股市低迷了一段时间,很多都都倾向于变现,不再追加投资,甚至离场不玩了。据说在熊市的时候,电视台的财经股评节目,收视率会不断创新低。

可是,经济周期的更迭,是必然的事件。有熊市也就必定有牛市,那么如果能比其他人更早察觉到牛熊转换的时机,显然能让我们更接近财富。

判断牛熊转换,有一个比较简单的方法,就是通过看新增投资者的开户数,一般而言,前一周股市涨的多,下一周的开户数就会暴增,如果股市暴跌,那开户数也会暴跌。有人甚至研究过美国股市,分析了1871年到2001年接近30年的数据,发现也有这个规律的存在。

我们可以在 东方财富网 | 数据中心 找到中国股票账户统计数据。

中国股票开户数据.png

然而,这种周期性的更迭,往往来的比较缓慢,我们对于这种缓慢变化的东西通常都是不那么敏感的。因此,如果我们能通过 Python 把这些数据爬去下来,保存好,然后通过程序去检查、对比数据,达到某个阈值就产生预警给我们提示,那肯定会比想起来才去查数据显得更有效。

本文一下将介绍如何使用 Python 获取中国股票开户数据信息。

利用 Python 爬虫抓取数据

想要保存数据,并且方便日后用以数据分析,那么最简单粗暴的方法就是用 Python 将页面的数据爬取下来保存。

编写爬虫程序,一般的步骤如下:
① 分页页面,选取所需的数据
② 分析页面数据呈现方式,编写抓取代码
③ 整合程序,运行调试测试

分析页面,选取数据

我们首先需要做的,就是分析页面,看我们需要爬取哪些数据以及看页面上的数据是如何呈现的,大致定下爬取的方法。

我们可以观察上面给出的页面截图,不难发现,这个网站所提供的数据,后面的几列,数据的质量并不高,其实有用的也就是统计时段的新增投资者数。而什么历史峰值、投资者总数,都可以通过计算获得。因此,我们这里只需要爬取统计时间和每周新增投资者数就可以了。

我们使用 Chrome 的开发者工具,在 Network 板块下可以找到网站返回我们所需数据的 url,这个 urlhttp://data.eastmoney.com/DataCenter_V3/Chart/cjsj/weeklystockaccountsnew.ashx?isxml=false,这个地址返回的事从 2015 年到最近的所有日期和数据,其中 X 标签中的数据是日期,Y 标签里的数据是新增开户数。有了这个接口连接,我们抓取数据就变得非常简单了。

程序编写

我们这一次爬虫所需要的 Python 库如下:
① requests
② json
③ pandas
在开始编写代码前,先安装好所需要的库。

首先,我们需要先使用 request 库来获取内容。我们获取的数据是以 str 的形式呈现的,为了方便我们的后续处理,我们还需要将其转换为 dict 的形式,这里我们需要用到 json 库。详细代码如下:

BASE_URL = 'http://data.eastmoney.com/DataCenter_V3/Chart/cjsj/weeklystockaccountsnew.ashx?isxml=true'
response = requests.get(BASE_URL)
raw_date = json.loads(response.text)

为了方便我们后续使用 pandas 整合数据,我们还需进一步对数据进行处理,我们要将其分成两个列表,一个是时间日期标签,另一个是新增开户数的数据。这里有一个坑需要注意一下,这里的开户数据是文本形式的,将来我们是需要对这个数据进行相关计算操作,因此需要将其转换为浮点的形式,详细代码如下:

date = raw_date['X'].split(',')
increment = list(map(float,raw_date['Y'][0].split(',')))
data_dict = {
   
   'date': date, 'increment': increment}

最后,我们只要使用 pandas 将其整合成一组 Series 即可,具体代码如下:

ts = pd.Series(data_dict['increment'], index=pd.to_datetime(data_dict['date']))

到这里,我们就可以对这一个序列进行进一步的数据操作了。

程序整合

这里,我整合了针对开户数的基本操作,具体可以参考以下的完整代码:

import requests
import pandas as pd
import json

BASE_URL = 'http://data.eastmoney.com/DataCenter_V3/Chart/cjsj/weeklystockaccountsnew.ashx?isxml=true'


def get_raw_data():
    response = requests.get(BASE_URL)
    raw_date = json.loads(response.text)
    date = raw_date['X'].split(',')
    increment = list(map(float,raw_date['Y'][0].split(',')))
    return {
   
   'date': date, 'increment': increment}

def generate_ts(data_dict):
    ts = pd.Series(data_dict['increment'], index=pd.to_datetime(data_dict['date']))
    return ts

def get_account_increment():
    data = get_raw_data()
    return generate_ts(data)

if __name__ == '__main__':
    account_increment = get_account_increment()
    # 打印所有数据
    print(account_increment)
    # 计算标准差
    print(account_increment.std())
    # 计算最小值
    print(account_increment.min())
    # 计算最大值
    print(account_increment.max())
    # 计算均值
    print(account_increment.mean())

更深入的探究

我们真正需要的,当然不仅仅只是获取数据。如果只是要获取数据,直接登录网站查看即可。那么,更有用的数据分析应该如何做呢?以下有两个比较简单、基础的应用:
① 数据跟踪报告
② 市场情绪监测

① 数据跟踪报告
针对这种每周更新的数据,最常见的问题恐怕是经常会忘记去查看。而最简单的方法,就是把这个数据抓取的程序放到定期任务中,可以通过定期发邮件或者借助 itchat 等工具发微信来推送给自己即可,当然,也可以和其他数据一并整合推送。

② 市场情绪监测
我们在文章的开头,提到了可以通过开户数来判断当前的市场环境。在实践层面,我们可以通过计算这一组数据的均值、方差,然后划分几个不同的区间,来定位不同的市场情绪。然后根据这个划分,输出当前的市场情绪状态来给我们提供一个简要的判断。

为实现上述两个功能,我将上面的代码进行了进一步的封装,详细代码如下:


import requests
import pandas as pd
import json
import interval

class RetailMonitoring():

    __BASE_URL = 'http://data.eastmoney.com/DataCenter_V3/Chart/cjsj/weeklystockaccountsnew.ashx?isxml=true'
    __MARKET_EMOTION_ZH = ['极度悲观', '悲观', '乐观', '极度乐观', '疯狂']
    __MARKET_EMOTION_EN = ['Extreme Pessimism', 'Pessimism', 'Optimistic', 'Extreme Optimistic', 'Crazy']

    def __init__(self):
        # Load data
        data = self._get_raw_date()
        self._data = self._generate_ts(data)
        # current data
        self._current_data = self._data[-1]
        # set mean
        self._mean = self._data.mean()
        # set std 
        self._std = self._data.std()
        # set min 
        self._min = self._data.min()
        # set max
        self._max = self._data.max()
        # pressimism section
        self._pessimism_section = interval.Interval(self._mean - self._std, self._mean)
        # extreme pressimism section
        self._extreme_pessimism_section = interval.Interval(self._mean - 3* self._std, self._mean - self._std)
        # optimistic section
        self._optimistic = interval.Interval(self._mean, self._mean + self._std)
        # extreme optimistic section
        self._extreme_optimistic = interval.Interval(self._mean + self._std, self._mean + 2 * self._std)
        # crazy
        self._crazy = interval.Interval(self._mean + 2 * self._std, self._mean + 3 * self._std)
        # emoton status

    def _get_raw_date(self):
        response = requests.get(self.__BASE_URL)
        raw_date = json.loads(response.text)
        date = raw_date['X'].split(',')
        increment = list(map(float,raw_date['Y'][0].split(',')))
        return {
   
   'date': date, 'increment': increment}

    def _generate_ts(self, data_dict):
        ts = pd.Series(data_dict['increment'], index=pd.to_datetime(data_dict['date']))
        return ts

    def _check_emotion_status(self, data, lang='ZH'):
        if lang == 'ZH':
            emotion_return = self.__MARKET_EMOTION_ZH
        else:
            emotion_return = self.__MARKET_EMOTION_EN
        if data in self._extreme_pessimism_section:
            return emotion_return[0]
        elif data in self._pessimism_section:
            return emotion_return[1]
        elif data in self._optimistic:
            return emotion_return[2]
        elif data in self._extreme_optimistic:
            return emotion_return[3]
        else:
            return emotion_return[4]

    def get_min(self):
        return self._min

    def get_max(self):
        return self._max

    def get_mean(self):
        return self._mean

    def get_current_data(self):
        return self._current_data

    def get_data(self):
        return self._data

    def get_current_emotion_status(self):
        return self._check_emotion_status(self._current_data)

    def get_emotion_status(self, data):
        return self._check_emotion_status(data)

if __name__ == '__main__':
    rm = RetailMonitoring()
    print('最近一周新增开户数: %s 万' % rm.get_current_data())
    print('当前情绪指数: %s' % rm.get_current_emotion_status())
    print('历史一周最多新增开户数: %s 万' % rm.get_max())
    print('历史一周最少新增开户数: %s 万' % rm.get_min())
    print(rm.get_data())

后记

投资不仅仅是技术,更多的还是需要理解人性。从更多的间接指标中攫取有用的信息,也许是未来量化交易投资的一个非常有潜力的方向。我们其实不仅仅能从新增开户数中获取市场情绪的指标,也许能从其他更多方面,如财经节目收视率等去分析研究。这里只是抛砖引玉

猜你喜欢

转载自blog.csdn.net/weixin_37272286/article/details/81263375