
为什么需要批量获取周线历史数据
做股票回测,周线数据比日线更干净。日线噪音多,一个消息就能跳空,周线过滤掉短期情绪,趋势信号更稳。期货跨品种套利也需要周线判断大方向。手动从行情软件导出?一只只点,累到手酸,而且每次更新都要重来。Python能一次性抓全市场5000多只股票的周线,存成CSV,随用随取。
选哪个数据源不折腾
免费抓A股数据,常用三个库:tushare需要积分,baostock速度慢,akshare最省事。akshare封装了东方财富、新浪等接口,不需要注册,代码两行就能跑。周线数据直接支持,返回的是pandas DataFrame,列名是中文,改个名字就能用。
安装一行命令:

pip install akshare pandas
核心函数长什么样
akshare里抓A股历史行情的函数叫stock_zh_a_hist。它接收股票代码、周期、开始日期、结束日期、复权方式。周期填weekly就是周线。复权方式选qfq前复权,回测时价格连续,不会因为分红除权产生假跳空。
先看单只股票怎么抓:
import akshare as ak
df = ak.stock_zh_a_hist(symbol="000001", period="weekly", start_date="20200101", end_date="20241231", adjust="qfq")
print(df.head())
返回的列有日期、开盘、收盘、最高、最低、成交量、成交额、振幅、涨跌幅、涨跌额、换手率。日期列是字符串,转成datetime方便后续处理。
怎么拿到全部股票代码
抓全市场之前,先要一份股票列表。akshare提供stock_info_a_code_name,返回所有A股代码和名称。
stock_list = ak.stock_info_a_code_name()
codes = stock_list['code'].tolist()
print(len(codes)) # 大约5000多只
注意:这个列表包含北交所、科创板、创业板,也包含ST股。回测时可以根据需要过滤掉ST和上市不足半年的新股。
批量下载并保存到本地
写一个循环,每只股票抓周线,存成单独CSV文件。文件名用股票代码,方便后续读取。
import os
import time
import pandas as pd
import akshare as ak
output_dir = "stock_weekly_data"
os.makedirs(output_dir, exist_ok=True)
stock_list = ak.stock_info_a_code_name()
codes = stock_list['code'].tolist()
for i, code in enumerate(codes):
file_path = os.path.join(output_dir, f"{code}.csv")
if os.path.exists(file_path):
continue # 已经下载过就跳过
try:
df = ak.stock_zh_a_hist(symbol=code, period="weekly", start_date="20150101", end_date="20241231", adjust="qfq")
if df.empty:
continue
df.to_csv(file_path, index=False, encoding="utf-8_sig")
print(f"{i+1}/{len(codes)} {code} 完成")
except Exception as e:
print(f"{code} 失败: {e}")
time.sleep(0.3) # 别把服务器打崩
几个细节:
time.sleep(0.3)是礼貌爬虫,太快会被封IP。文件编码用
utf-8_sig,Excel打开不乱码。跳过已存在的文件,支持断点续传。
开始日期设到2015年,覆盖一轮完整牛熊。
抓下来的数据怎么用
读完CSV,把日期设成索引,就能做周线策略。比如双均线:
df = pd.read_csv("stock_weekly_data/000001.csv", parse_dates=['日期'])
df.set_index('日期', inplace=True)
df['ma20'] = df['收盘'].rolling(20).mean()
df['ma60'] = df['收盘'].rolling(60).mean()
df['signal'] = 0
df.loc[df['ma20'] > df['ma60'], 'signal'] = 1
df.loc[df['ma20'] < df['ma60'], 'signal'] = -1
print(df[['收盘', 'ma20', 'ma60', 'signal']].tail())
期货周线数据用akshare的futures_zh_weekly,逻辑一样。跨品种套利时,把两个品种的周线收盘价对齐,算价差Z-score,超过2倍标准差就开仓。
常见坑和解决办法
接口超时:东方财富服务器偶尔抽风。加try-except重试三次,间隔2秒。
股票代码带前缀:akshare的stock_zh_a_hist不需要前缀,直接传6位数字。如果从其他源拿到sh600000,用code.replace('sh','').replace('sz','')去掉。
停牌股票返回空:正常,跳过就行。
数据量太大:5000只股票,每只约500周,总共250万行。存CSV占硬盘约2GB,用SQLite或Parquet压缩到500MB。
周线日期是周五:akshare返回的周线日期是每周最后一个交易日,可能是周四或周五。做时间序列对齐时注意用resample('W-FRI')统一。
进阶做法
需要每天更新数据?把脚本挂到定时任务,每天收盘后跑增量。先读本地CSV,取最新日期,只抓之后的周线,合并再存回去。
数据量再大,用多进程。把股票代码分成4份,开4个进程同时抓,速度翻三倍。注意每个进程独立sleep,避免并发过高。
想要更全的期货周线?akshare支持futures_main_sina拿主力连续合约,周期参数改weekly。商品期货和股指期货都能抓,配合股票数据做跨市场策略。
别犯的错
不要用adjust=""不复权。除权那天价格直接腰斩,均线完全失效。前复权qfq最适合回测,后复权hfq适合算真实收益率。
不要忽略停牌。连续停牌几周的股票,周线会出现空白,rolling计算会错位。用df = df.asfreq('W-FRI')补全,再fillna(method='ffill')填充价格。
不要把成交量直接加总。周线成交量是日线累加,但换手率要重新算,不是简单平均。
数据抓下来只是第一步。真正赚钱的是策略逻辑和风控。周线数据给你更干净的信号,但仓位管理、止损规则、品种分散才是长期活下来的关键。