Ashare - 完整学习教程
Ashare - 完整学习教程
教程级别: 从零到一 预计学习时间: 2-3 小时 前置知识: Python 基础(变量、函数、import)、pandas 基本操作(DataFrame 查看)、A 股市场基本概念(股票代码、K 线)
环境搭建指南
系统要求
- 操作系统:Windows / macOS / Linux(任意)
- Python 版本:3.6 及以上
- 依赖项:pandas、requests(安装 Ashare 时自动安装)
安装步骤
方式一:通过 pip 安装(推荐)
# 使用 pip 安装 ashares 包
pip install ashares
# 如果下载速度慢,可以使用清华镜像源
pip install ashares -i https://pypi.tuna.tsinghua.edu.cn/simple
方式二:直接下载源码文件
# 克隆 GitHub 仓库
git clone https://github.com/mpquant/Ashare.git
# 进入目录
cd Ashare
# 将 Ashare.py 复制到你的项目目录即可使用
cp Ashare.py /你的项目路径/
基于官方 README(master 分支,2025-12-24)
验证安装
# 在 Python 交互环境中验证
from Ashare import *
import pandas as pd
# 验证 get_price 函数可用
print(get_price.__module__)
Ashare
如果输出 Ashare 说明安装成功。如果报错 ModuleNotFoundError,请检查安装方式是否正确。
第一部分:入门篇
1.1 第一次获取股票数据
概念讲解:
Ashare 的核心设计理念是"一个函数解决所有问题"。整个库只暴露一个函数 get_price(),它接受股票代码和查询参数,返回标准的 pandas DataFrame 格式数据。
get_price() 函数签名如下:
get_price(code, end_date='', count=10, frequency='1d', fields=[])
参数说明:
- code:股票代码(必填),支持多种格式(详见 1.2 节)
- end_date:结束日期(可选),默认为空表示取最新数据
- count:获取的数据条数(可选),默认为 10
- frequency:数据周期(可选),默认为 '1d'(日线)
- fields:字段筛选(可选),当前版本未使用该参数
返回值是一个 pandas DataFrame,包含以下列:
- open:开盘价
- close:收盘价
- high:最高价
- low:最低价
- volume:成交量
行索引为日期时间(DatetimeIndex)。
代码示例:
# 基于官方 README(master 分支,2025-12-24)
from Ashare import *
# 获取上证指数最近 10 个交易日的日线数据
df = get_price('sh000001', frequency='1d', count=10)
print('上证指数最近 10 日行情:')
print(df)
print()
# 查看数据类型
print('数据类型:')
print(df.dtypes)
print()
# 查看索引类型
print('索引类型:', type(df.index))
执行结果:
上证指数最近 10 日行情:
open close high low volume
2025-12-11 3432.56 3450.12 3465.78 3428.90 3.245670e+08
2025-12-12 3451.23 3445.67 3458.90 3440.12 2.987650e+08
2025-12-15 3446.78 3468.34 3475.56 3442.23 3.123450e+08
2025-12-16 3467.89 3456.78 3472.34 3450.67 2.876540e+08
2025-12-17 3455.67 3478.90 3485.12 3452.34 3.345670e+08
2025-12-18 3480.12 3462.45 3488.56 3458.78 3.098760e+08
2025-12-19 3460.34 3485.67 3492.34 3456.12 3.234560e+08
2025-12-22 3486.78 3490.12 3498.56 3482.34 3.156780e+08
2025-12-23 3488.90 3475.67 3495.23 3470.89 2.945670e+08
2025-12-24 3476.23 3482.56 3488.90 3472.12 3.012340e+08
数据类型:
open float64
close float64
high float64
low float64
volume float64
dtype: object
索引类型: <class 'pandas.core.indexes.datetimes.DatetimeIndex'>
注:以上输出为模拟结果,实际数据取决于查询时的市场行情。基于官方 README 及源码(master 分支,2025-12-24)
练习题:
1. 获取贵州茅台(代码 sh600519)最近 20 个交易日的日线数据,并打印出来。
2. 获取平安银行(代码 sz000001)最近 5 个交易日的日线数据,并查看收盘价的最大值。
1.2 股票代码格式
概念讲解:
中国 A 股市场的股票代码由 6 位数字组成,但在不同的量化平台中,代码格式有所不同。Ashare 支持以下两种主流格式:
| 格式类型 | 示例 | 适用平台 |
|---|---|---|
| 通达信格式 | sh600519、sz000001 |
通达信、东方财富等 |
| 同花顺/聚宽格式 | 600519.XSHG、000001.XSHE |
同花顺、聚宽(JoinQuant) |
格式规则:
- 上海证券交易所:前缀 sh 或后缀 .XSHG,代码以 6 开头(如 600519 贵州茅台)
- 深圳证券交易所:前缀 sz 或后缀 .XSHE,代码以 0 或 3 开头(如 000001 平安银行、300750 宁德时代)
Ashare 在内部自动完成格式转换,用户无需手动处理。转换逻辑:
- 600519.XSHG → 去掉 .XSHG → 600519 → 加上 sh → sh600519
- 000001.XSHE → 去掉 .XSHE → 000001 → 加上 sz → sz000001
- sh600519 → 保持不变
代码示例:
# 基于源码 Ashare.py(master 分支,2025-12-24)
from Ashare import *
# 三种格式获取同一只股票(贵州茅台)的数据,结果完全一致
# 格式一:通达信格式(推荐,最简洁)
df1 = get_price('sh600519', frequency='1d', count=5)
print('通达信格式获取结果:')
print(df1)
print()
# 格式二:同花顺/聚宽格式
df2 = get_price('600519.XSHG', frequency='1d', count=5)
print('同花顺/聚宽格式获取结果:')
print(df2)
print()
# 验证两种格式返回的数据是否一致
print('两种格式的收盘价是否一致:', df1['close'].equals(df2['close']))
执行结果:
通达信格式获取结果:
open close high low volume
2025-12-18 1520.00 1535.56 1540.23 1515.67 1.234567e+07
2025-12-19 1536.78 1542.34 1548.90 1530.12 1.345678e+07
2025-12-22 1543.45 1538.90 1550.23 1535.67 1.456789e+07
2025-12-23 1539.12 1545.67 1552.34 1536.78 1.234567e+07
2025-12-24 1546.23 1550.12 1556.78 1542.34 1.345678e+07
同花顺/聚宽格式获取结果:
open close high low volume
2025-12-18 1520.00 1535.56 1540.23 1515.67 1.234567e+07
2025-12-19 1536.78 1542.34 1548.90 1530.12 1.345678e+07
2025-12-22 1543.45 1538.90 1550.23 1535.67 1.456789e+07
2025-12-23 1539.12 1545.67 1552.34 1536.78 1.234567e+07
2025-12-24 1546.23 1550.12 1556.78 1542.34 1.345678e+07
两种格式的收盘价是否一致: True
注:以上输出为模拟结果。基于源码 Ashare.py(master 分支,2025-12-24)
练习题: 1. 分别使用通达信格式和聚宽格式获取宁德时代(300750)最近 10 个交易日的日线数据。 2. 获取上证指数(sh000001)和深证成指(sz399001)最近 5 个交易日的日线数据,对比两个指数的涨跌情况。
1.3 多周期行情数据
概念讲解:
Ashare 支持 8 种数据周期,覆盖了量化分析中最常用的时间维度。通过 frequency 参数指定周期:
| 参数值 | 周期 | 数据源 | 典型用途 |
|---|---|---|---|
'1d' |
日线 | 新浪(主)+ 腾讯(备) | 中长期趋势分析 |
'1w' |
周线 | 新浪(主)+ 腾讯(备) | 中期趋势确认 |
'1M' |
月线 | 新浪(主)+ 腾讯(备) | 长期趋势判断 |
'60m' |
60 分钟线 | 新浪(主)+ 腾讯(备) | 日内波段分析 |
'30m' |
30 分钟线 | 新浪(主)+ 腾讯(备) | 短线交易参考 |
'15m' |
15 分钟线 | 新浪(主)+ 腾讯(备) | 短线交易参考 |
'5m' |
5 分钟线 | 新浪(主)+ 腾讯(备) | 日内策略 |
'1m' |
1 分钟线 | 仅腾讯 | 超短线策略 |
注意:1 分钟线仅由腾讯数据源提供,其他周期支持新浪+腾讯双数据源热备。
代码示例:
# 基于官方 README 及源码(master 分支,2025-12-24)
from Ashare import *
# 日线数据(默认周期)
df_day = get_price('sh600519', frequency='1d', count=10)
print('=== 日线数据(最近 10 日)===')
print(df_day)
print()
# 周线数据
df_week = get_price('sh600519', frequency='1w', count=5)
print('=== 周线数据(最近 5 周)===')
print(df_week)
print()
# 月线数据
df_month = get_price('sh600519', frequency='1M', count=6)
print('=== 月线数据(最近 6 个月)===')
print(df_month)
执行结果:
=== 日线数据(最近 10 日)===
open close high low volume
2025-12-15 1532.45 1540.23 1545.67 1528.90 1.234567e+07
...(共 10 行)
=== 周线数据(最近 5 周)===
open close high low volume
2025-11-21 1500.00 1525.67 1530.45 1495.23 5.678900e+07
...(共 5 行)
=== 月线数据(最近 6 个月)===
open close high low volume
2025-07 1450.23 1520.56 1535.78 1445.12 2.345678e+08
...(共 6 行)
注:以上输出为模拟结果,实际数据取决于查询时的市场行情。基于官方 README 及源码(master 分支,2025-12-24)
练习题: 1. 获取比亚迪(sz002594)的日线、周线、月线数据各 10 条,观察不同周期下数据的时间跨度。 2. 获取某只股票的 5 分钟线和 60 分钟线数据,对比不同分钟线的精度差异。
第二部分:进阶篇
2.1 使用 end_date 参数获取历史数据
概念讲解:
在入门篇中,我们获取的都是最新数据(end_date 为空)。但在实际量化分析中,经常需要获取特定时间段的历史数据,例如回测某个策略在 2024 年的表现。
end_date 参数的工作原理:
1. 对于日线/周线/月线:Ashare 会计算 end_date 到当前日期的天数差,额外增加请求数据量,然后截取 end_date 之前的 count 条数据
2. end_date 可以是字符串格式(如 '2025-12-20')或 datetime.date 对象
3. 如果 end_date 正好是当天,Ashare 会将其置空,获取最新数据
代码示例:
# 基于源码 Ashare.py(master 分支,2025-12-24)
from Ashare import *
# 获取截至 2025-12-20 的最近 10 个交易日日线数据
df = get_price('sh600519', end_date='2025-12-20', count=10, frequency='1d')
print('截至 2025-12-20 的最近 10 日行情:')
print(df)
print()
# 使用 datetime 对象作为 end_date
import datetime
end = datetime.date(2025, 11, 30)
df2 = get_price('sh600519', end_date=end, count=5, frequency='1d')
print('截至 2025-11-30 的最近 5 日行情:')
print(df2)
执行结果:
截至 2025-12-20 的最近 10 日行情:
open close high low volume
2025-12-05 1510.23 1520.45 1525.67 1505.89 1.123456e+07
2025-12-08 1521.34 1518.90 1528.45 1515.23 1.234567e+07
2025-12-09 1519.56 1525.78 1530.12 1516.45 1.345678e+07
2025-12-10 1526.23 1532.45 1538.90 1522.34 1.456789e+07
2025-12-11 1533.12 1528.67 1535.45 1525.12 1.234567e+07
2025-12-12 1527.89 1535.23 1540.56 1524.78 1.345678e+07
2025-12-15 1536.45 1542.67 1548.90 1532.34 1.456789e+07
2025-12-16 1543.12 1538.90 1545.67 1535.23 1.234567e+07
2025-12-17 1539.56 1545.23 1550.78 1536.45 1.345678e+07
2025-12-18 1546.23 1550.12 1556.78 1542.34 1.234567e+07
截至 2025-11-30 的最近 5 日行情:
open close high low volume
2025-11-24 1490.12 1498.56 1505.23 1485.67 1.123456e+07
...(共 5 行)
注:以上输出为模拟结果。基于源码 Ashare.py(master 分支,2025-12-24)
注意事项:
- end_date 参数仅对日线('1d')、周线('1w')、月线('1M')有效。分钟线('5m' 等)的 end_date 参数会被传递但不影响新浪接口的返回结果。
- 如果 end_date 指定的日期不是交易日(如周末、节假日),Ashare 会返回该日期之前最近一个交易日的数据。
- 获取很早的历史数据时,由于新浪 API 的 datalen 参数限制,count 值不宜过大(建议不超过 1000)。
练习题:
1. 获取贵州茅台 2025 年 6 月到 2025 年 12 月的月线数据(end_date='2025-12-31', count=7, frequency='1M')。
2. 获取某只股票在 2025-10-08 到 2025-10-31 之间的日线数据。
2.2 分钟线数据获取
概念讲解:
分钟线数据是量化短线策略的重要基础。Ashare 支持 5 种分钟周期:1 分钟、5 分钟、15 分钟、30 分钟和 60 分钟。
分钟线的内部机制与日线不同:
- 1 分钟线('1m'):仅由腾讯数据源提供,通过 get_price_min_tx() 函数获取
- 其他分钟线('5m'/'15m'/'30m'/'60m'):主力为新浪接口,备用为腾讯接口
分钟线数据有一个特殊处理:腾讯分钟线返回的最后一根 K 线的收盘价会通过实时行情(qt)接口进行修正,确保最新价格准确。
代码示例:
# 基于官方 README 及源码(master 分支,2025-12-24)
from Ashare import *
# 获取 5 分钟线数据(最近 20 条)
df_5m = get_price('sh600519', frequency='5m', count=20)
print('=== 5 分钟线数据(最近 20 条)===')
print(df_5m)
print()
# 获取 60 分钟线数据(最近 10 条)
df_60m = get_price('sh600519', frequency='60m', count=10)
print('=== 60 分钟线数据(最近 10 条)===')
print(df_60m)
print()
# 获取 1 分钟线数据(最近 10 条,仅腾讯支持)
df_1m = get_price('sh600519', frequency='1m', count=10)
print('=== 1 分钟线数据(最近 10 条)===')
print(df_1m)
执行结果:
=== 5 分钟线数据(最近 20 条)===
open close high low volume
2025-12-24 14:30:00 1548.23 1550.45 1552.67 1546.12 23456.0
2025-12-24 14:35:00 1550.67 1548.90 1553.45 1547.23 19876.0
...(共 20 行)
=== 60 分钟线数据(最近 10 条)===
open close high low volume
2025-12-23 10:30:00 1540.12 1545.67 1548.90 1538.45 123456.0
...(共 10 行)
=== 1 分钟线数据(最近 10 条)===
open close high low volume
2025-12-24 14:51:00 1549.23 1550.12 1550.56 1548.89 3456.0
...(共 10 行)
注:以上输出为模拟结果。分钟线数据仅在交易时段有效。基于官方 README 及源码(master 分支,2025-12-24)
注意事项:
- 分钟线数据仅在交易时段内有效。非交易时段调用可能返回上一个交易日或不完整的数据。
- 分钟线的 count 参数建议不超过 500,过大的值可能导致请求超时。
- 1 分钟线仅由腾讯提供,如果腾讯接口异常,1 分钟线将无法获取(无备用数据源)。
- 分钟线的时间索引包含时分秒信息(如 2025-12-24 14:30:00),日线的时间索引仅包含日期(如 2025-12-24)。
练习题: 1. 分别获取贵州茅台的 5 分钟线和 60 分钟线各 30 条,对比两种周期下同一时间段内的 K 线数量。 2. 尝试获取 1 分钟线数据,验证时间索引的格式是否包含时分秒。
2.3 DataFrame 数据处理技巧
概念讲解:
Ashare 返回的是标准的 pandas DataFrame,因此可以直接使用 pandas 的全部功能进行数据处理和分析。本节介绍几个常用的数据处理模式。
代码示例:
# 基于官方 README 及源码(master 分支,2025-12-24)
from Ashare import *
# 获取 30 日日线数据
df = get_price('sh600519', frequency='1d', count=30)
# 1. 计算涨跌幅
df['pct_change'] = df['close'].pct_change() * 100
print('=== 最近 5 日涨跌幅 ===')
print(df[['close', 'pct_change']].tail(5))
print()
# 2. 计算移动平均线
df['ma5'] = df['close'].rolling(window=5).mean()
df['ma10'] = df['close'].rolling(window=10).mean()
print('=== 最近 5 日收盘价与均线 ===')
print(df[['close', 'ma5', 'ma10']].tail(5))
print()
# 3. 计算波动率(20 日标准差)
df['volatility'] = df['pct_change'].rolling(window=20).std()
print('=== 最近波动率 ===')
print(f"20 日波动率: {df['volatility'].iloc[-1]:.4f}%")
print()
# 4. 筛选涨幅超过 2% 的交易日
big_up_days = df[df['pct_change'] > 2]
print(f'涨幅超过 2% 的交易日数量: {len(big_up_days)}')
执行结果:
=== 最近 5 日涨跌幅 ===
close pct_change
2025-12-18 1550.12 0.32
2025-12-19 1542.34 -0.50
2025-12-22 1538.90 -0.22
2025-12-23 1545.67 0.44
2025-12-24 1550.12 0.29
=== 最近 5 日收盘价与均线 ===
close ma5 ma10
2025-12-18 1550.12 1542.67 1535.23
2025-12-19 1542.34 1543.45 1536.78
2025-12-22 1538.90 1543.12 1537.90
2025-12-23 1545.67 1543.78 1539.12
2025-12-24 1550.12 1545.43 1540.56
=== 最近波动率 ===
20 日波动率: 1.2345%
涨幅超过 2% 的交易日数量: 3
注:以上输出为模拟结果。基于 pandas 标准用法及 Ashare 返回格式
练习题: 1. 获取某只股票 60 日日线数据,计算 20 日均线和 60 日均线,找出"金叉"(短期均线从下方穿越长期均线)的日期。 2. 计算某只股票最近 30 日的日均成交量和成交量的标准差。
第三部分:高级篇
3.1 双数据源热备机制详解
概念讲解:
Ashare 的核心创新是内置了新浪财经和腾讯股票两个数据源,通过 try-except 机制实现自动故障切换。理解这个机制有助于排查数据获取问题和选择合适的参数。
切换策略总结:
| frequency | 主力数据源 | 备用数据源 | 切换机制 |
|---|---|---|---|
'1d'/'1w'/'1M' |
新浪 get_price_sina() |
腾讯 get_price_day_tx() |
try-except 自动切换 |
'5m'/'15m'/'30m'/'60m' |
新浪 get_price_sina() |
腾讯 get_price_min_tx() |
try-except 自动切换 |
'1m' |
腾讯 get_price_min_tx() |
无 | 无备用 |
用户无法控制使用哪个数据源,也无法在切换时得到通知。这意味着在极端情况下,同一参数的两次调用可能返回来自不同数据源的数据。
代码示例:
# 基于源码 Ashare.py(master 分支,2025-12-24)
# 演示如何手动模拟双数据源行为
from Ashare import *
# 日线数据:先尝试新浪,失败自动切换腾讯
df = get_price('sh600519', frequency='1d', count=10)
print('日线数据获取成功(来源:新浪或腾讯):')
print(df.head(3))
print()
# 1 分钟线:仅腾讯支持
df_min = get_price('sh600519', frequency='1m', count=10)
print('1 分钟线数据获取成功(来源:仅腾讯):')
print(df_min.head(3))
执行结果:
日线数据获取成功(来源:新浪或腾讯):
open close high low volume
2025-12-18 1546.23 1550.12 1556.78 1542.34 1.345678e+07
2025-12-19 1548.56 1542.34 1552.12 1540.23 1.234567e+07
2025-12-22 1543.12 1538.90 1548.56 1536.45 1.456789e+07
1 分钟线数据获取成功(来源:仅腾讯):
open close high low volume
2025-12-24 14:51:00 1549.23 1550.12 1550.56 1548.89 3456.0
2025-12-24 14:52:00 1550.34 1549.78 1551.12 1549.23 3123.0
2025-12-24 14:53:00 1549.56 1550.45 1550.89 1549.12 2890.0
注:以上输出为模拟结果。基于源码 Ashare.py(master 分支,2025-12-24)
注意事项: - 用户无法感知当前使用的是哪个数据源。如果需要确认数据来源,可以通过检查 DataFrame 的列顺序来推断(新浪返回的列顺序是 day/open/high/low/close/volume,腾讯日线是 time/open/close/high/low/volume)。 - 双数据源返回的数据可能存在微小差异(如复权方式不同),在对精度要求高的场景下需要注意。 - 新浪接口使用 HTTP(非 HTTPS),数据传输未加密。腾讯部分接口也是 HTTP。
3.2 批量获取多只股票数据
概念讲解:
Ashare 每次调用只获取一只股票的数据。在实际量化分析中,通常需要同时获取多只股票的数据。本节介绍如何通过循环批量获取,以及相关的注意事项。
代码示例:
# 基于 Ashare API 设计及 Python 标准库
from Ashare import *
import time
# 定义要获取的股票列表(通达信格式)
stocks = {
'sh600519': '贵州茅台',
'sz000001': '平安银行',
'sz002594': '比亚迪',
'sh601318': '中国平安',
'sz300750': '宁德时代'
}
# 批量获取日线数据
results = {}
for code, name in stocks.items():
try:
df = get_price(code, frequency='1d', count=30)
results[code] = df
# 计算最近 30 日涨跌幅
latest = df['close'].iloc[-1]
earliest = df['close'].iloc[0]
change_pct = (latest - earliest) / earliest * 100
print(f'{name}({code}):30 日涨跌幅 {change_pct:+.2f}%')
# 每次请求后短暂等待,避免触发上游 API 的频率限制
time.sleep(0.5)
except Exception as e:
print(f'{name}({code})获取失败: {e}')
print()
# 对比所有股票的最近收盘价
print('=== 各股票最新收盘价 ===')
for code, name in stocks.items():
if code in results:
print(f'{name}({code}): {results[code]["close"].iloc[-1]:.2f}')
执行结果:
贵州茅台(sh600519):30 日涨跌幅 +3.45%
平安银行(sz000001):30 日涨跌幅 -1.23%
比亚迪(sz002594):30 日涨跌幅 +5.67%
中国平安(sh601318):30 日涨跌幅 +2.34%
宁德时代(sz300750):30 日涨跌幅 -0.89%
=== 各股票最新收盘价 ===
贵州茅台(sh600519): 1550.12
平安银行(sz000001): 15.23
比亚迪(sz002594): 265.45
中国平安(sh601318): 52.67
宁德时代(sz300750): 198.34
注:以上输出为模拟结果。基于 Ashare API 设计
注意事项:
- 必须添加 time.sleep():Ashare 底层访问的是公开 API,连续高频请求可能触发频率限制或 IP 封禁。建议每次请求间隔至少 0.3 秒。
- 异常处理不可省略:网络波动、上游接口变更等都可能导致单只股票获取失败。使用 try-except 确保一只股票失败不会中断整个批量任务。
- 不建议单次批量超过 50 只股票:过多的请求可能导致 IP 被临时封禁。如需获取全市场数据,建议使用 Tushare 或 AKShare。
3.3 数据质量验证与缓存
概念讲解:
Ashare 返回的数据未经过完整性校验。在实际使用中,建议对返回数据做基本的质量验证,并对频繁使用的数据添加缓存机制,避免重复请求。
代码示例:
# 基于 Ashare API 设计及 Python 标准库
from Ashare import *
import pandas as pd
import time
def get_price_safe(code, end_date='', count=10, frequency='1d', max_retries=3):
"""
带重试和数据验证的安全获取函数。
参数:
code: 股票代码
end_date: 结束日期
count: 数据条数
frequency: 数据周期
max_retries: 最大重试次数
"""
for attempt in range(max_retries):
try:
df = get_price(code, end_date=end_date, count=count, frequency=frequency)
# 验证 1:检查是否为空
if df.empty:
print(f'警告:{code} 返回空数据,重试 {attempt + 1}/{max_retries}')
time.sleep(1)
continue
# 验证 2:检查必需列是否存在
required_cols = ['open', 'close', 'high', 'low', 'volume']
missing_cols = [col for col in required_cols if col not in df.columns]
if missing_cols:
print(f'警告:{code} 缺少列 {missing_cols}')
continue
# 验证 3:检查缺失值
if df[required_cols].isnull().any().any():
null_count = df[required_cols].isnull().sum().sum()
print(f'警告:{code} 存在 {null_count} 个缺失值')
# 验证 4:检查价格合理性(收盘价应在最高价和最低价之间)
price_invalid = (df['close'] > df['high']) | (df['close'] < df['low'])
if price_invalid.any():
print(f'警告:{code} 存在 {price_invalid.sum()} 条价格异常数据')
return df
except Exception as e:
print(f'错误:{code} 第 {attempt + 1} 次请求失败: {e}')
if attempt < max_retries - 1:
time.sleep(2)
print(f'错误:{code} 获取失败,已达最大重试次数 {max_retries}')
return pd.DataFrame()
# 简单内存缓存
_cache = {}
def get_price_cached(code, end_date='', count=10, frequency='1d'):
"""
带缓存的数据获取函数。同一参数组合只请求一次。
注意:缓存是内存级别的,进程退出后失效。
"""
cache_key = f'{code}_{end_date}_{count}_{frequency}'
if cache_key in _cache:
return _cache[cache_key]
df = get_price_safe(code, end_date=end_date, count=count, frequency=frequency)
if not df.empty:
_cache[cache_key] = df
return df
# 使用示例
df = get_price_cached('sh600519', count=30, frequency='1d')
print(f'获取到 {len(df)} 条数据')
print(f'日期范围:{df.index[0]} 至 {df.index[-1]}')
执行结果:
获取到 30 条数据
日期范围:2025-11-12 00:00:00 至 2025-12-24 00:00:00
注:以上输出为模拟结果。基于 Ashare API 设计
注意事项:
- 重试间隔应逐步增加:生产环境中建议使用指数退避策略(如 1s、2s、4s),避免在接口故障时造成雪崩效应。
- 缓存的有效期:股票数据是实时变化的,日线数据的缓存可以保留到当日收盘后,分钟线数据缓存有效期应很短(如 5 分钟)。
- 价格验证逻辑:close <= high and close >= low 是最基本的合理性检查,更严格的验证可以包括成交量是否为正、涨跌停判断等。
第四部分:实战项目
项目需求
构建一个"多股票技术分析面板"脚本,综合运用以下知识点: 1. 多周期数据获取(知识点 1.3):同时获取日线和周线数据 2. 多股票批量获取(知识点 3.2):获取多只股票的数据 3. DataFrame 数据处理(知识点 2.3):计算技术指标(均线、涨跌幅、波动率) 4. 数据质量验证(知识点 3.3):对获取的数据进行基本验证
功能要求: - 输入一组股票代码,自动获取日线数据 - 计算 5 日均线、10 日均线、涨跌幅和波动率 - 生成汇总报告,按涨跌幅排序 - 对异常数据进行标记
项目设计
stock_analysis_panel.py
│
├── get_stock_data() # 批量获取股票数据
├── calc_indicators() # 计算技术指标
├── validate_data() # 数据验证
├── generate_report() # 生成汇总报告
└── main() # 主函数
完整实现代码
# 基于 Ashare API 设计、pandas 标准用法及源码(master 分支,2025-12-24)
from Ashare import *
import pandas as pd
import time
# ===== 配置区域 =====
# 要分析的股票列表(通达信格式)
STOCKS = {
'sh600519': '贵州茅台',
'sz000001': '平安银行',
'sz002594': '比亚迪',
'sh601318': '中国平安',
'sz300750': '宁德时代',
'sh600036': '招商银行',
'sz000858': '五粮液',
'sh601012': '隆基绿能',
}
# 分析参数
DATA_COUNT = 30 # 获取的交易日数量
REQUEST_INTERVAL = 0.5 # 请求间隔(秒)
def validate_data(df, code):
"""
数据验证函数。
检查数据的完整性和合理性。
参数:
df: pandas DataFrame,Ashare 返回的行情数据
code: str,股票代码
返回:
list: 异常信息列表,空列表表示数据正常
"""
issues = []
# 检查是否为空
if df.empty:
issues.append(f'{code}: 返回数据为空')
return issues
# 检查数据行数是否足够
if len(df) < 10:
issues.append(f'{code}: 数据行数不足(仅 {len(df)} 行)')
# 检查缺失值
required_cols = ['open', 'close', 'high', 'low', 'volume']
null_count = df[required_cols].isnull().sum().sum()
if null_count > 0:
issues.append(f'{code}: 存在 {null_count} 个缺失值')
# 检查价格合理性
price_invalid = (df['close'] > df['high']) | (df['close'] < df['low'])
if price_invalid.any():
issues.append(f'{code}: 存在 {price_invalid.sum()} 条价格异常数据')
# 检查成交量是否为负
if (df['volume'] < 0).any():
issues.append(f'{code}: 存在负成交量')
return issues
def calc_indicators(df):
"""
计算技术指标。
包括:5 日均线、10 日均线、涨跌幅、20 日波动率。
参数:
df: pandas DataFrame,Ashare 返回的行情数据
返回:
pandas DataFrame:添加了技术指标列的数据
"""
df = df.copy()
# 计算涨跌幅(百分比)
df['pct_change'] = df['close'].pct_change() * 100
# 计算移动平均线
df['ma5'] = df['close'].rolling(window=5).mean()
df['ma10'] = df['close'].rolling(window=10).mean()
# 计算 20 日波动率(涨跌幅的标准差)
df['volatility'] = df['pct_change'].rolling(window=20).std()
return df
def get_stock_data(stocks, count=30):
"""
批量获取股票数据并进行验证。
参数:
stocks: dict,股票代码到名称的映射
count: int,获取的交易日数量
返回:
dict: 股票代码到(DataFrame, 验证信息)的映射
"""
results = {}
for code, name in stocks.items():
try:
# 获取日线数据
df = get_price(code, frequency='1d', count=count)
# 数据验证
issues = validate_data(df, code)
if issues:
for issue in issues:
print(f' [警告] {issue}')
# 计算技术指标
if not df.empty:
df = calc_indicators(df)
results[code] = {
'name': name,
'data': df,
'issues': issues
}
print(f' {name}({code})获取成功,{len(df)} 条数据')
except Exception as e:
print(f' {name}({code})获取失败: {e}')
results[code] = {
'name': name,
'data': pd.DataFrame(),
'issues': [f'{code}: 获取失败 - {e}']
}
# 请求间隔,避免触发频率限制
time.sleep(REQUEST_INTERVAL)
return results
def generate_report(results):
"""
生成汇总分析报告。
参数:
results: dict,get_stock_data() 的返回值
返回:
pandas DataFrame:汇总报告表
"""
report_data = []
for code, info in results.items():
df = info['data']
name = info['name']
if df.empty:
report_data.append({
'代码': code,
'名称': name,
'最新价': None,
'涨跌幅(%)': None,
'MA5': None,
'MA10': None,
'20日波动率(%)': None,
'30日涨跌幅(%)': None,
'日均成交量': None,
'状态': '获取失败'
})
continue
latest = df.iloc[-1]
first = df.iloc[0]
# 判断均线趋势
ma_status = ''
if pd.notna(latest['ma5']) and pd.notna(latest['ma10']):
if latest['ma5'] > latest['ma10']:
ma_status = '多头'
else:
ma_status = '空头'
# 计算 30 日总涨跌幅
total_change = (latest['close'] - first['close']) / first['close'] * 100
report_data.append({
'代码': code,
'名称': name,
'最新价': round(latest['close'], 2),
'涨跌幅(%)': round(latest.get('pct_change', 0), 2) if pd.notna(latest.get('pct_change')) else None,
'MA5': round(latest['ma5'], 2) if pd.notna(latest['ma5']) else None,
'MA10': round(latest['ma10'], 2) if pd.notna(latest['ma10']) else None,
'20日波动率(%)': round(latest['volatility'], 2) if pd.notna(latest['volatility']) else None,
'30日涨跌幅(%)': round(total_change, 2),
'日均成交量': round(df['volume'].mean(), 0),
'状态': ma_status
})
report_df = pd.DataFrame(report_data)
# 按 30 日涨跌幅降序排列
report_df = report_df.sort_values('30日涨跌幅(%)', ascending=False)
return report_df
def main():
"""
主函数:执行完整的多股票技术分析流程。
"""
print('=' * 60)
print('多股票技术分析面板')
print('=' * 60)
print()
# 第一步:批量获取数据
print('[1/3] 正在获取股票数据...')
results = get_stock_data(STOCKS, count=DATA_COUNT)
print()
# 第二步:生成报告
print('[2/3] 正在生成分析报告...')
report = generate_report(results)
print()
# 第三步:输出结果
print('[3/3] 分析结果:')
print('=' * 60)
print(report.to_string(index=False))
print('=' * 60)
# 输出统计摘要
valid_report = report.dropna(subset=['30日涨跌幅(%)'])
if not valid_report.empty:
print()
print('=== 统计摘要 ===')
print(f'分析股票数量:{len(report)}')
print(f'获取成功:{len(valid_report)}')
print(f'获取失败:{len(report) - len(valid_report)}')
best = valid_report.iloc[0]
worst = valid_report.iloc[-1]
print(f'30 日涨幅最大:{best["名称"]}({best["30日涨跌幅(%)"]:+.2f}%)')
print(f'30 日跌幅最大:{worst["名称"]}({worst["30日涨跌幅(%)"]:+.2f}%)')
if __name__ == '__main__':
main()
代码解析
知识点运用说明:
-
多周期数据获取(1.3 节):
get_price(code, frequency='1d', count=count)使用日线周期获取数据。frequency='1d'是默认值,确保获取的是日线数据。 -
多股票批量获取(3.2 节):
get_stock_data()函数通过循环遍历股票列表,每次调用get_price()获取一只股票的数据,并在每次请求后使用time.sleep(REQUEST_INTERVAL)控制请求频率。 -
DataFrame 数据处理(2.3 节):
calc_indicators()函数使用 pandas 的pct_change()计算涨跌幅、rolling().mean()计算移动平均线、rolling().std()计算波动率。 -
数据质量验证(3.3 节):
validate_data()函数检查数据是否为空、行数是否足够、是否存在缺失值、价格是否合理(收盘价在最高价和最低价之间)、成交量是否为负。
扩展挑战
-
增加更多技术指标:在
calc_indicators()中添加 MACD(指数平滑移动平均线)、RSI(相对强弱指标)、布林带等常用技术指标的计算。提示:可以使用 mpquant 开源的 MyTT 库(https://github.com/mpquant/MyTT),它与 Ashare 出自同一作者。 -
增加数据导出功能:将分析报告导出为 CSV 文件或 Excel 文件,方便后续查看和分享。提示:使用
df.to_csv()或df.to_excel()方法。 -
增加可视化功能:使用 matplotlib 或 plotly 绘制 K 线图和均线图。提示:搜索结果中掘金文章的
plot_draw_kline函数是一个参考起点。
第五部分:常见问题与排查指南
常见错误及解决方案
| 错误信息 | 原因 | 解决方案 |
|---|---|---|
ModuleNotFoundError: No module named 'Ashare' |
未安装 ashares 包,或安装了错误的包名 | 执行 pip install ashares(注意包名是 ashares,不是 ashare) |
JSONDecodeError: Expecting value |
新浪或腾讯 API 返回了非 JSON 内容(如 HTML 错误页面) | 检查网络连接;如果持续出现可能是 API 接口变更,关注 GitHub Issues |
KeyError: 'qfqday' |
腾讯 API 对指数和股票返回不同的字段名 | 这是 Ashare 内部已处理的问题。如果仍然出现,说明你使用的版本较旧,更新到最新版即可 |
Empty DataFrame |
传入的股票代码格式不正确,或该股票已退市 | 确认股票代码格式正确(如 sh600519,不是 600519);检查股票是否仍在交易 |
ConnectionError |
网络无法连接到新浪或腾讯的 API 服务器 | 检查网络连接;如果在国内使用代理,确认代理配置正确 |
返回的数据行数少于请求的 count |
count 超过了上游 API 的最大返回限制,或该股票上市时间不够长 |
减小 count 值;对于次新股,先查询上市日期再确定合理的 count |
get_price('600519') 返回空数据 |
股票代码缺少交易所前缀 | 使用 sh600519(上海)或 sz000001(深圳)格式,或使用 600519.XSHG 格式 |
| 分钟线数据与实际行情不一致 | 腾讯分钟线返回的最后一根 K 线使用了实时行情修正 | 这是正常行为。Ashare 会用 qt(实时行情)接口的收盘价覆盖最后一根 K 线 |
基于 Ashare 源码分析(master 分支,2025-12-24)及社区常见问题
调试技巧
- 直接检查 API 返回:如果
get_price()返回异常数据,可以直接在浏览器中访问底层 API 来检查原始返回。例如: - 新浪日线:
http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sh600519&scale=240&ma=5&datalen=10 - 腾讯日线:
http://web.ifzq.gtimg.cn/appstock/app/fqkline/get?param=sh600519,day,,2025-12-24,10,qfq -
如果浏览器能正常返回 JSON 数据但 Ashare 获取失败,说明是 Python 环境或网络问题。
-
使用 try-except 捕获详细错误:Ashare 内部的 try-except 会吞掉异常(裸
except:),建议在外层包裹自己的异常捕获,打印完整的错误堆栈:python import traceback try: df = get_price('sh600519', frequency='1d', count=10) except Exception: traceback.print_exc() -
检查请求延迟:如果获取数据非常慢(超过 5 秒),可能是网络问题或 API 限流。可以使用以下代码测量请求时间:
python import time start = time.time() df = get_price('sh600519', frequency='1d', count=10) elapsed = time.time() - start print(f'请求耗时:{elapsed:.2f} 秒')
第六部分:学习路线推荐
官方文档推荐阅读顺序
由于 Ashare 没有独立的文档站点,学习资源主要集中在以下位置:
- GitHub README - 重点关注安装方式和基本用法示例
- 地址:https://github.com/mpquant/Ashare
-
重点:
get_price()的参数说明和代码示例 -
Ashare.py 源码 - 重点关注数据流和 API 调用逻辑
- 地址:https://github.com/mpquant/Ashare/blob/main/Ashare.py
-
重点:双数据源切换逻辑(
get_price()函数)、频率参数映射、股票代码格式转换 -
GitHub Issues - 重点关注常见问题和用户反馈
- 地址:https://github.com/mpquant/Ashare/issues
- 重点:接口变更通知、数据源失效报告
推荐进阶资源
- mpquant/MyTT(通达信技术指标 Python 移植库):https://github.com/mpquant/MyTT
- 同一作者开发的通达信技术指标库,包含 MACD、KDJ、RSI、布林带等 50+ 个指标
-
与 Ashare 天然兼容,可以直接基于 Ashare 获取的数据计算技术指标
-
从0开始学量化:使用Ashare获取A股数据 — 知乎专栏
- https://zhuanlan.zhihu.com/p/2590244600
-
从零开始的量化数据获取教程,包含与聚宽平台的集成示例
-
AKShare、baostock、Ashare和Pytdx获取股票行情数据的完全指南 — 百度开发者社区
- https://developer.baidu.com/article/details/2794524
- 多库对比使用指南,帮助理解何时选择 Ashare、何时需要更强大的工具
进阶方向建议
完成本教程后,建议按以下方向深入学习:
- 从 Ashare 迁移到 AKShare:当项目需要更多数据类型(财务报表、指数估值、基金数据等)时,学习 AKShare 的 API
- 技术指标计算:结合 MyTT 库,在 Ashare 数据基础上构建完整的技术分析系统
- 量化策略回测:学习 backtrader 或 vnpy 等回测框架,将 Ashare 作为数据源进行策略验证
信息来源与版本说明
- 教程基于版本: 源码 master 分支(2025-12-24 最后更新),无正式版本号
- 信息获取日期: 2026-04-13
- 信息来源列表:
- GitHub 仓库 mpquant/Ashare
- Ashare 源码 Ashare.py
- 从0开始学量化:使用Ashare获取A股数据 — 知乎
- AKShare、baostock、Ashare和Pytdx获取股票行情数据的完全指南 — 百度开发者社区
- 使用Python下载A股行情的几种方法 — 博客园
- matplotlib K线绘制示例 — 稀土掘金