
为什么用Python搞股票数据
散户想验证一个交易想法,手动翻K线图太慢。用Python写几行代码,几秒钟就能拉出十年的日线数据,还能自动算好均线、RSI、MACD。免费、灵活、可复现,这是量化交易的入门基本功。
准备工作:安装三个库
打开命令行,敲下这行命令:
pip install yfinance pandas ta
yfinance负责从雅虎财经拉数据,pandas负责表格处理,ta负责技术指标计算。三个库都是纯免费,不需要注册任何账号。

下载股票历史数据
import yfinance as yf
# 下载苹果公司2020年1月1日到2023年12月31日的日线数据
df = yf.download('AAPL', start='2020-01-01', end='2023-12-31')
print(df.head())
运行后你会看到一张表格,包含开盘价、最高价、最低价、收盘价、成交量和调整后收盘价。yfinance自动处理了拆股和分红,数据可以直接用于回测。
A股数据怎么办?yfinance也支持,代码改成yf.download('600519.SS', start='2020-01-01', end='2023-12-31'),600519.SS代表上海证券交易所的贵州茅台。深圳股票用.SZ后缀。
想批量下载多只股票?传入列表即可:
tickers = ['AAPL', 'MSFT', 'GOOG']
df_multi = yf.download(tickers, start='2020-01-01', end='2023-12-31')
返回的是多层列索引,用df_multi['Close']['AAPL']就能取到苹果的收盘价序列。
计算常用技术指标
拿到数据后,用ta库算指标,几行代码搞定。
移动平均线
import pandas as pd
from ta.trend import SMAIndicator
# 计算20日和60日简单移动平均
df['SMA_20'] = SMAIndicator(df['Close'], window=20).sma_indicator()
df['SMA_60'] = SMAIndicator(df['Close'], window=60).sma_indicator()
SMA_20上穿SMA_60,俗称金叉,传统技术分析视为买入信号。反过来叫死叉。
相对强弱指数RSI
from ta.momentum import RSIIndicator
df['RSI'] = RSIIndicator(df['Close'], window=14).rsi()
RSI高于70通常认为超买,低于30认为超卖。震荡市里这个指标很管用,单边趋势里容易钝化,别死守一个阈值。
MACD
from ta.trend import MACD
macd = MACD(df['Close'])
df['MACD'] = macd.macd()
df['MACD_signal'] = macd.macd_signal()
df['MACD_diff'] = macd.macd_diff()
MACD_diff是柱状图,由负转正代表短期动能增强。很多量化策略用MACD_diff上穿零轴作为开仓条件。
数据清洗与缺失值处理
yfinance返回的数据偶尔有缺失,比如停牌日没有成交量。用pandas直接处理:
df = df.dropna() # 删掉空值行
df = df[df['Volume'] > 0] # 过滤掉零成交量的异常日
如果要做日内回测,需要分钟级数据。yfinance支持interval='1m',但只能取最近7天的数据。历史分钟数据要花钱买,免费方案里yfinance算够用的。
简单回测:双均线策略
把信号写出来,统计一下历史表现。
df['Signal'] = 0
df.loc[df['SMA_20'] > df['SMA_60'], 'Signal'] = 1
df.loc[df['SMA_20'] <= df['SMA_60'], 'Signal'] = 0
df['Position'] = df['Signal'].shift(1) # 避免未来函数
df['Returns'] = df['Close'].pct_change()
df['Strategy_Returns'] = df['Position'] * df['Returns']
cumulative_strategy = (1 + df['Strategy_Returns']).cumprod()
cumulative_market = (1 + df['Returns']).cumprod()
print(f"策略累计收益: {cumulative_strategy.iloc[-1]:.2f}")
print(f"买入持有收益: {cumulative_market.iloc[-1]:.2f}")
这段代码把每天的信号滞后一天执行,防止用到未来数据。cumprod()计算复利累计收益。跑完你会发现,双均线在趋势行情里能跑赢大盘,震荡市里反复打脸。
期货数据也能这么玩
期货主力连续合约在yfinance里代码不同,比如原油是CL=F,黄金是GC=F,标普500期货是ES=F。下载方式和股票一模一样。
cl = yf.download('CL=F', start='2020-01-01', end='2023-12-31')
期货数据没有调整后收盘价,直接用收盘价算指标就行。注意期货有换月跳空,yfinance返回的连续合约已经做了前复权处理,回测时不用额外调整。
可视化检查
画个图,肉眼确认指标和价格的关系。
import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8))
ax1.plot(df.index, df['Close'], label='Close')
ax1.plot(df.index, df['SMA_20'], label='SMA 20')
ax1.plot(df.index, df['SMA_60'], label='SMA 60')
ax1.legend()
ax1.set_title('Price and Moving Averages')
ax2.plot(df.index, df['RSI'])
ax2.axhline(70, color='r', linestyle='--')
ax2.axhline(30, color='g', linestyle='--')
ax2.set_title('RSI')
plt.tight_layout()
plt.show()
图表能帮你快速发现指标在哪些阶段失效。比如2022年苹果的RSI长期在30到50之间徘徊,超卖信号根本不准。
保存数据到本地
每次跑都联网下载太慢,存成CSV文件。
df.to_csv('AAPL_with_indicators.csv')
# 下次直接读取
df = pd.read_csv('AAPL_with_indicators.csv', index_col='Date', parse_dates=True)
index_col和parse_dates保证日期列被正确解析为时间索引,方便后续按时间切片。
避坑指南
yfinance偶尔会抽风,返回空数据。加个重试逻辑:
import time
def download_with_retry(ticker, start, end, retries=3):
for i in range(retries):
try:
data = yf.download(ticker, start=start, end=end)
if not data.empty:
return data
except Exception as e:
print(f"第{i+1}次失败: {e}")
time.sleep(2)
raise ValueError(f"无法下载{ticker}的数据")
免费数据源有延迟,日线数据当天收盘后几小时才更新。做实时交易得用券商API,那是另一个话题了。
下一步可以做什么
把上面的代码拼起来,你已经有了一个能跑通的数据管道。接下来可以加更多指标,比如布林带、ATR,或者把策略改成多因子打分。回测框架推荐backtrader或vectorbt,比手动算收益规范得多。期货数据注意合约乘数和保证金,股票回测不涉及这些,但期货杠杆会放大盈亏,代码里要算清楚。
整套流程下来,从拉数据到出策略信号,半小时足够。动手敲一遍,比看十篇文章管用。