Python金融数据分析入门:用Tushare获取股票历史行情(附完整代码示例)

📅 发布时间:2026/7/9 4:53:45 👁️ 浏览次数:
Python金融数据分析入门:用Tushare获取股票历史行情(附完整代码示例)
Python金融数据分析入门用Tushare获取股票历史行情附完整代码示例对于刚接触金融数据分析的Python爱好者来说最令人兴奋又略带困惑的第一步往往就是如何获取可靠、结构化的市场数据。市面上充斥着各种数据源有的需要付费订阅有的界面复杂有的数据质量参差不齐。如果你渴望一种更“程序员友好”的方式——通过几行代码就能将海量历史行情数据拉取到本地进行自由的分析和建模那么Tushare这个工具库绝对值得你深入了解。它并非一个简单的数据下载器而是一个将金融数据API化的桥梁让你能够像调用普通函数一样获取从股票、基金到宏观经济等一系列金融数据。这篇文章我将从一个实践者的角度带你从零开始手把手掌握Tushare的核心用法并分享一些我实际使用中总结出的数据处理技巧和避坑指南。1. 环境准备与Tushare初探在开始编写任何代码之前一个稳定、隔离的Python环境是高效工作的基石。我强烈建议使用conda或venv创建独立的虚拟环境这能避免不同项目间的依赖冲突。假设你已经安装了Python建议3.7及以上版本那么环境搭建可以这样开始# 创建并激活一个名为‘finance’的虚拟环境以conda为例 conda create -n finance python3.9 conda activate finance # 安装核心依赖 pip install tushare pandas numpy matplotlib这里pandas和numpy是后续数据处理的左膀右臂matplotlib则用于基础的可视化。安装完成后你首先需要访问Tushare的官网进行注册以获取一个唯一的token。这个token是你的身份凭证所有数据请求都基于它。注册过程完全免费对于个人学习和研究来说获取基础数据如日线行情的权限已经足够。拿到token后我们进行初始化。不要把token硬编码在脚本里尤其是如果你打算将代码分享到GitHub等平台。一个更安全的做法是将其存储在环境变量中。import tushare as ts import pandas as pd import os # 方式一直接在代码中设置仅用于临时测试不推荐用于正式项目 ts.set_token(你的token字符串) # 方式二从环境变量读取推荐 # 假设你在终端中执行了 export TUSHARE_TOKEN你的token token os.getenv(TUSHARE_TOKEN) if token: ts.set_token(token) else: print(请设置环境变量 TUSHARE_TOKEN) exit() # 初始化Pro接口 pro ts.pro_api()初始化pro对象后你就拥有了打开金融数据宝库的钥匙。Tushare的数据通过不同的API函数提供每个函数对应一类数据。在开始调用前花几分钟浏览官网的数据字典了解有哪些数据可用以及每个API所需的参数这会让你后续的探索事半功倍。2. 核心API调用实战获取个股历史行情获取数据是第一步但如何高效、准确地获取所需数据里面有不少门道。Tushare Pro接口提供了daily、weekly、monthly等函数来获取不同周期的行情数据。我们以最常用的日线数据daily()为例。最基本的调用只需要股票代码和日期范围。A股股票的代码通常以.SZ深交所或.SH上交所结尾。# 获取贵州茅台600519.SH2023年全年的日线数据 df pro.daily(ts_code600519.SH, start_date20230101, end_date20231231) print(df.head()) print(f共获取到{len(df)}条数据)执行这段代码你会得到一个DataFrame包含日期、开盘价、最高价、最低价、收盘价、成交量等关键字段。但直接这样调用可能会遇到两个常见问题一是数据量很大时返回较慢二是默认的字段顺序可能不符合你的分析习惯。注意trade_date字段是整数格式如20230101在后续进行时间序列分析时需要将其转换为标准的datetime类型。一个更健壮、功能更丰富的调用示例应该包含错误处理和参数优化def fetch_stock_daily(ts_code, start_date, end_date, fieldsNone): 获取股票日线行情数据并做基础处理。 参数: ts_code: 股票代码如 000001.SZ start_date: 开始日期格式 YYYYMMDD end_date: 结束日期格式 YYYYMMDD fields: 指定返回的字段列表为None则返回所有字段 返回: 处理后的 pandas DataFrame try: # 调用API df pro.daily(ts_codets_code, start_datestart_date, end_dateend_date, fieldsfields) if df.empty: print(f未获取到股票 {ts_code} 在指定时间段的数据。) return df # 1. 将交易日期转换为datetime类型并设为索引 df[trade_date] pd.to_datetime(df[trade_date], format%Y%m%d) df.set_index(trade_date, inplaceTrue) df.sort_index(inplaceTrue) # 按时间升序排列 # 2. 重命名列使其更易读可选 column_mapping { open: 开盘价, high: 最高价, low: 最低价, close: 收盘价, pre_close: 前收盘价, change: 涨跌额, pct_chg: 涨跌幅(%), vol: 成交量(手), amount: 成交额(千元) } df.rename(columnscolumn_mapping, inplaceTrue) return df except Exception as e: print(f获取数据时发生错误: {e}) return pd.DataFrame() # 返回空DataFrame # 使用函数获取中国平安601318.SH2024年第一季度数据 pingan_df fetch_stock_daily(601318.SH, 20240101, 20240331) if not pingan_df.empty: print(pingan_df[[开盘价, 收盘价, 成交量(手)]].head())通过封装函数我们不仅实现了代码复用还内置了数据清洗和转换的步骤让获取到的数据立刻处于“分析就绪”状态。fields参数非常有用当你只需要其中几列数据时指定它可以减少网络传输的数据量提高效率。3. 进阶技巧批量获取与数据管理分析单只股票只是起点真正的力量在于对比和组合分析。这就需要我们批量获取多只股票的数据。直接写循环调用API虽然可行但效率不高且可能触发频率限制。更优雅的方式是利用Tushare支持的批量代码查询以及合理的缓存策略。批量获取同一时间段多只股票数据daily()接口的ts_code参数支持批量传入代码间用逗号分隔。# 一次性获取三只股票的数据 stock_codes 600519.SH,000858.SZ,300750.SZ batch_df pro.daily(ts_codestock_codes, start_date20240101, end_date20240331) print(batch_df[ts_code].unique()) # 查看包含哪些股票返回的DataFrame会包含所有股票的数据并通过ts_code列区分。为了方便后续分析我们经常需要将数据转换为面板数据格式即每个股票单独成一个DataFrame并以股票代码为键存储在字典中。# 将批量获取的数据按股票代码拆分成字典 panel_data {} for code in batch_df[ts_code].unique(): panel_data[code] batch_df[batch_df[ts_code] code].copy() # 对每个股票的数据进行同样的日期转换和索引设置 panel_data[code][trade_date] pd.to_datetime(panel_data[code][trade_date], format%Y%m%d) panel_data[code].set_index(trade_date, inplaceTrue) panel_data[code].sort_index(inplaceTrue) # 现在可以方便地访问任意一只股票的数据 if 600519.SH in panel_data: maotai panel_data[600519.SH] print(maotai[[close, vol]].tail())数据缓存与本地存储反复从网络请求相同的数据是低效的。对于历史数据一旦获取就应该保存到本地。我常用的策略是使用pickle或parquet格式存储DataFrame因为它们能很好地保留数据类型和索引。import os from pathlib import Path def save_stock_data(df, code, data_dir./stock_data): 将单只股票数据保存到本地 Path(data_dir).mkdir(parentsTrue, exist_okTrue) file_path Path(data_dir) / f{code}.parquet df.to_parquet(file_path) print(f数据已保存至: {file_path}) def load_stock_data(code, data_dir./stock_data): 从本地加载单只股票数据 file_path Path(data_dir) / f{code}.parquet if file_path.exists(): df pd.read_parquet(file_path) # 确保索引是datetime类型 if not isinstance(df.index, pd.DatetimeIndex): df.index pd.to_datetime(df.index) return df else: print(f本地文件 {file_path} 不存在。) return None # 使用示例先尝试从本地加载如果没有则从网络获取并保存 code 000001.SZ local_df load_stock_data(code) if local_df is None: print(本地无缓存从Tushare获取...) online_df fetch_stock_daily(code, 20230101, 20231231) if not online_df.empty: save_stock_data(online_df, code) local_df online_df建立这样的本地数据仓库后你的分析脚本启动速度会快很多并且对Tushare API的依赖也降低了在网络不稳定或API维护时仍能工作。4. 基础数据分析与可视化实战数据到手后真正的乐趣才开始。我们使用pandas进行快速的数据洞察和特征计算。假设我们已经有了df这个包含某股票日线数据的DataFrame且索引已是日期。计算简单技术指标移动平均线是最基础也最常用的指标之一。# 计算5日、20日、60日简单移动平均线SMA df[SMA_5] df[收盘价].rolling(window5).mean() df[SMA_20] df[收盘价].rolling(window20).mean() df[SMA_60] df[收盘价].rolling(window60).mean() # 计算每日收益率 df[日收益率] df[收盘价].pct_change() # 计算滚动波动率以20日为例 df[波动率_20d] df[日收益率].rolling(window20).std() * (20**0.5) # 年化波动率粗略估算制作一个简单的价格与均线图可视化能让我们直观感受趋势。这里使用matplotlib。import matplotlib.pyplot as plt plt.style.use(seaborn-v0_8-darkgrid) # 使用一个好看的样式 fig, (ax1, ax2) plt.subplots(2, 1, figsize(14, 10), sharexTrue) # 子图1价格与均线 ax1.plot(df.index, df[收盘价], label收盘价, linewidth1.5, alpha0.8) ax1.plot(df.index, df[SMA_20], label20日均线, linewidth1.5, linestyle--) ax1.plot(df.index, df[SMA_60], label60日均线, linewidth1.5, linestyle:) ax1.set_ylabel(价格 (元)) ax1.set_title(股票价格与移动平均线) ax1.legend() ax1.grid(True, alpha0.3) # 子图2成交量 ax2.bar(df.index, df[成交量(手)], colorskyblue, alpha0.7, label成交量) ax2.set_xlabel(日期) ax2.set_ylabel(成交量 (手)) ax2.set_title(成交量) ax2.legend() ax2.grid(True, alpha0.3) # 自动调整日期标签格式避免重叠 fig.autofmt_xdate() plt.tight_layout() plt.show()进行简单的数据汇总统计pandas的describe()函数可以快速给出分布概况但我们也可以自定义更贴合金融场景的统计。# 基础描述性统计 print(df[[收盘价, 日收益率, 成交量(手)]].describe()) # 计算一些关键金融统计量 annual_return df[日收益率].mean() * 252 # 粗略年化收益率 annual_volatility df[日收益率].std() * (252**0.5) # 年化波动率 sharpe_ratio annual_return / annual_volatility if annual_volatility ! 0 else None # 夏普比率无风险利率假设为0 stats_summary pd.DataFrame({ 统计量: [年平均收益率, 年化波动率, 夏普比率(零无风险利率)], 值: [f{annual_return:.2%}, f{annual_volatility:.2%}, f{sharpe_ratio:.3f} if sharpe_ratio else N/A] }) print(stats_summary)通过这几个步骤你已经完成了从数据获取、清洗、存储到基础分析和可视化的完整闭环。这为你后续进行更复杂的策略回测、因子分析或机器学习建模打下了坚实的基础。记住金融数据分析的核心在于提出正确的问题并用数据去验证或探索答案工具只是帮你更高效地完成这个过程。在接下来的探索中你可能会对Tushare的其他数据接口如财务数据、宏观经济数据产生兴趣也可以将pandas的威力发挥到更大结合scikit-learn或statsmodels等库进行预测模型构建。