使用 Python 获取A股新增投资者数据
![](https://img.haomeiwen.com/i1638540/02d7794e026040c1.jpg)
前言
当前国内的经济环境一般,股市已经长期处于熊市之中,与牛市相比,现在几乎听不到有人讨论股市了。这是非常典型的直线思维:当股市在上涨的牛市中,人们的投资意愿就变强,如果股市低迷了一段时间,很多都都倾向于变现,不再追加投资,甚至离场不玩了。据说在熊市的时候,电视台的财经股评节目,收视率会不断创新低。
可是,经济周期的更迭,是必然的事件。有熊市也就必定有牛市,那么如果能比其他人更早察觉到牛熊转换的时机,显然能让我们更接近财富。
判断牛熊转换,有一个比较简单的方法,就是通过看新增投资者的开户数,一般而言,前一周股市涨的多,下一周的开户数就会暴增,如果股市暴跌,那开户数也会暴跌。有人甚至研究过美国股市,分析了1871年到2001年接近30年的数据,发现也有这个规律的存在。
我们可以在 东方财富网 | 数据中心 找到中国股票账户统计数据。
![](https://img.haomeiwen.com/i1638540/399d285c20449942.png)
然而,这种周期性的更迭,往往来的比较缓慢,我们对于这种缓慢变化的东西通常都是不那么敏感的。因此,如果我们能通过 Python 把这些数据爬去下来,保存好,然后通过程序去检查、对比数据,达到某个阈值就产生预警给我们提示,那肯定会比想起来才去查数据显得更有效。
本文一下将介绍如何使用 Python 获取中国股票开户数据信息。
利用 Python 爬虫抓取数据
想要保存数据,并且方便日后用以数据分析,那么最简单粗暴的方法就是用 Python 将页面的数据爬取下来保存。
编写爬虫程序,一般的步骤如下:
① 分页页面,选取所需的数据
② 分析页面数据呈现方式,编写抓取代码
③ 整合程序,运行调试测试
分析页面,选取数据
我们首先需要做的,就是分析页面,看我们需要爬取哪些数据以及看页面上的数据是如何呈现的,大致定下爬取的方法。
我们可以观察上面给出的页面截图,不难发现,这个网站所提供的数据,后面的几列,数据的质量并不高,其实有用的也就是统计时段的新增投资者数。而什么历史峰值、投资者总数,都可以通过计算获得。因此,我们这里只需要爬取统计时间和每周新增投资者数就可以了。
我们使用 Chrome 的开发者工具,在 Network 板块下可以找到网站返回我们所需数据的 url
,这个 url
是 http://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())
后记
投资不仅仅是技术,更多的还是需要理解人性。从更多的间接指标中攫取有用的信息,也许是未来量化交易投资的一个非常有潜力的方向。我们其实不仅仅能从新增开户数中获取市场情绪的指标,也许能从其他更多方面,如财经节目收视率等去分析研究。这里只是抛砖引玉