目录

class 卑微码农:
def __init__(self):
self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
self.发量 = 100 # 初始发量
self.咖啡因耐受度 = '极限'
def 修Bug(self, bug):
try:
# 试图用玄学解决问题
if bug.严重程度 == '离谱':
print("这一定是环境问题!")
else:
print("让我看看是谁又没写注释...哦,是我自己。")
except Exception as e:
# 如果try块都救不了,那就...
print("重启一下试试?")
self.发量 -= 1 # 每解决一个bug,头发-1
# 实例化一个我
我 = 卑微码农()
引言
如果你是股票投资者,可能曾有过这样的困惑:
- 手动分析几十只股票的历史走势,耗时又容易遗漏关键信号;
- 听说 “均线交叉”“动量策略” 能赚钱,却不知道怎么验证效果;
- 想自动化跟踪股价、计算指标,却被复杂的编程门槛劝退。

其实,用 Python 的三个 “神器”——yfinance(数据获取)、Pandas(数据处理)、Matplotlib(可视化),就能从零搭建一套量化交易系统:免费获取股票数据、自动计算技术指标、回测交易策略、可视化分析结果,全程代码可复用,新手也能快速上手。
上述三个工具说明,请参考之前的博客。
Python pandas 实战:从数据处理到分析可视化,搞定数据分析核心技能-优快云博客
用 Python yfinance 玩转金融数据:从股票爬取到分析可视化的实战指南-优快云博客
Python Matplotlib 可视化全攻略:从基础图表到交互可视化,搞定数据呈现核心技能-优快云博客
本文从实际场景出发,通过 “数据获取→指标计算→策略构建→回测分析” 的完整流程,手把手教你用这三个库实现量化交易,附可直接运行的代码和详细注释,帮你避开 90% 的新手坑。
一、为什么这三个库是量化交易的 “黄金组合”?

量化交易的核心流程是 “数据→分析→决策→验证”,而 Pandas、yfinance、Matplotlib 恰好分别对应这一流程的关键环节:
- yfinance:解决 “数据从哪来” 的问题。免费获取全球股票、指数、加密货币的历史价格、财务数据,无需 API 密钥,一行代码就能下载 10 年日线数据,比付费接口更适合个人用户。
- Pandas:解决 “数据怎么处理” 的问题。作为 Python 数据处理 “瑞士军刀”,能轻松清洗数据、计算技术指标(均线、MACD、RSI)、生成交易信号,让复杂的时间序列分析变得简单。
- Matplotlib:解决 “结果怎么展示” 的问题。将枯燥的数字转化为直观的图表(价格走势、策略信号、回测收益),帮你快速理解策略效果,发现潜在问题。
这三个库的组合优势在于:免费开源、生态兼容、门槛低。无需懂复杂的金融工程,只要会基础 Python,就能搭建起属于自己的量化系统。
二、环境搭建:3 分钟配齐量化工具包

在开始前,需要安装三个核心库,推荐搭配 Python 3.8 及以上版本(兼容性更好)。
2.1 安装命令
# 基础安装(推荐用pip)
pip install pandas yfinance matplotlib
# 安装指定版本(避免版本兼容问题)
pip install pandas==2.1.4 yfinance==0.2.31 matplotlib==3.8.2
2.2 验证安装
打开 Python 环境(推荐用 Jupyter Notebook,方便分步运行),输入以下代码,无报错则安装成功:
import pandas as pd # 数据处理
import yfinance as yf # 数据获取
import matplotlib.pyplot as plt # 可视化
# 查看版本(确保与示例兼容)
print(f"pandas版本:{pd.__version__}")
print(f"yfinance版本:{yf.__version__}")
print(f"matplotlib版本:{plt.__version__}")
2.3 准备工作:了解股票代码格式
用 yfinance 获取数据需要股票代码,不同市场的代码格式不同(可在雅虎财经官网查询):
- 美股:直接用代码(如苹果 AAPL、微软 MSFT);
- A 股:上交所加
.SS(如贵州茅台 600519.SS),深交所加.SZ(如宁德时代 300750.SZ); - 指数:标普 500 是
^GSPC,沪深 300 是000300.SS。
三、数据获取:用 yfinance 批量下载股票数据

量化的第一步是获取高质量数据。yfinance 能轻松获取历史价格、实时报价、分红拆股等信息,我们以 “特斯拉(TSLA)” 为例,演示核心用法。
3.1 获取单只股票的历史价格
用Ticker.history()方法获取历史数据,支持自定义时间范围和周期(日线、周线等):
# 1. 创建特斯拉的Ticker对象
tsla = yf.Ticker("TSLA")
# 2. 获取2020-2023年的日线数据(包含开盘价、最高价、最低价、收盘价、成交量)
# period:时间范围(1y=1年,5y=5年,max=全部历史)
# interval:周期(1d=日线,1wk=周线,1mo=月线)
tsla_hist = tsla.history(period="5y", interval="1d", auto_adjust=True)
# 3. 查看数据结构(pandas DataFrame格式,索引为日期)
print("数据形状:", tsla_hist.shape) # 输出(1258, 5),表示1258行数据,5列指标
print("\n前5行数据:")
print(tsla_hist.head())
输出结果中,Open(开盘价)、High(最高价)、Low(最低价)、Close(收盘价)、Volume(成交量)是量化分析的核心指标。auto_adjust=True表示启用后复权(处理分红拆股导致的价格断层),推荐始终开启。
3.2 批量获取多只股票数据
分析多只股票(如对比科技巨头)时,用yf.download()更高效:
# 1. 定义要分析的股票列表(苹果、微软、谷歌、亚马逊)
tickers = ["AAPL", "MSFT", "GOOGL", "AMZN"]
# 2. 批量获取2023年数据
multi_stocks = yf.download(
tickers=tickers,
start="2023-01-01",
end="2023-12-31",
interval="1d",
auto_adjust=True
)
# 3. 查看数据结构(多层索引:第一层是指标,第二层是股票代码)
print("数据列名:", multi_stocks.columns.names) # 输出['Price', 'Ticker']
print("\n收盘价子表前5行:")
print(multi_stocks["Close"].head()) # 提取所有股票的收盘价
3.3 获取关键财务数据(辅助基本面分析)
除了价格数据,yfinance 还能获取市盈率、市值等基本面指标,用于筛选股票:
# 获取苹果公司的基本信息(返回字典)
aapl = yf.Ticker("AAPL")
aapl_info = aapl.info
# 提取关键基本面指标
print(f"公司名称:{aapl_info['longName']}")
print(f"市值(美元):{aapl_info['marketCap'] / 1e9:.2f}亿") # 转换为亿
print(f"动态市盈率:{aapl_info['trailingPE']:.2f}")
print(f"股息率(%):{aapl_info['dividendYield'] * 100:.2f}")
print(f"52周最高价:{aapl_info['fiftyTwoWeekHigh']:.2f}美元")
四、数据处理:用 Pandas 计算量化指标

获取数据后,需要用 Pandas 计算技术指标(如均线、收益率),这是生成交易信号的基础。我们以特斯拉数据为例,演示核心操作。
4.1 数据清洗(处理缺失值和异常值)
原始数据可能存在缺失(如节假日休市),需要先清洗:
# 1. 检查缺失值
print("缺失值数量:\n", tsla_hist.isnull().sum())
# 2. 处理缺失值:用前一天的数据填充(适合时间序列)
tsla_clean = tsla_hist.fillna(method="ffill")
# 3. 检查异常值:收盘价不可能为负
tsla_clean = tsla_clean[tsla_clean["Close"] > 0]
print("清洗后数据形状:", tsla_clean.shape)
4.2 计算核心技术指标
技术指标是量化策略的 “信号源”,以下是最常用的 4 个指标计算方法:
4.2.1 均线(MA):判断趋势
均线是某段时间内收盘价的平均值,5 日均线反映短期趋势,20 日均线反映中期趋势:
# 计算5日均线和20日均线
tsla_clean["MA5"] = tsla_clean["Close"].rolling(window=5).mean() # 前5天收盘价的均值
tsla_clean["MA20"] = tsla_clean["Close"].rolling(window=20).mean()
# 查看结果(只显示收盘价和均线列)
print(tsla_clean[["Close", "MA5", "MA20"]].tail())
4.2.2 日收益率:衡量波动
日收益率 =(当日收盘价 - 前一日收盘价)/ 前一日收盘价,反映单日涨跌幅度:
# 计算日收益率(shift(1)表示取前一行数据)
tsla_clean["Daily_Return"] = (tsla_clean["Close"] - tsla_clean["Close"].shift(1)) / tsla_clean["Close"].shift(1)
# 查看结果(前几行可能为NaN,因为没有前一天数据)
print(tsla_clean[["Close", "Daily_Return"]].head())
4.2.3 相对强弱指数(RSI):判断超买超卖
RSI 取值 0-100,通常 > 70 视为超买(可能下跌),<30 视为超卖(可能上涨):
def calculate_rsi(data, window=14):
"""计算RSI指标"""
# 计算价格变动
delta = data["Close"].diff(1)
# 区分上涨和下跌
gain = delta.where(delta > 0, 0) # 上涨幅度(下跌时记为0)
loss = -delta.where(delta < 0, 0) # 下跌幅度(上涨时记为0)
# 计算平均涨跌幅
avg_gain = gain.rolling(window=window).mean()
avg_loss = loss.rolling(window=window).mean()
# 计算RSI
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
return rsi
# 计算14天RSI
tsla_clean["RSI14"] = calculate_rsi(tsla_clean)
print(tsla_clean[["Close", "RSI14"]].tail())
4.2.4 移动平均收敛散度(MACD):判断趋势强度
MACD 由快线(DIF)、慢线(DEA)、柱状线(MACD)组成,交叉信号常用于判断买入卖出点:
def calculate_macd(data, fast_period=12, slow_period=26, signal_period=9):
"""计算MACD指标"""
# 计算快慢线
ema_fast = data["Close"].ewm(span=fast_period, adjust=False).mean() # 12日指数移动平均
ema_slow = data["Close"].ewm(span=slow_period, adjust=False).mean() # 26日指数移动平均
data["MACD_DIF"] = ema_fast - ema_slow # 快线
data["MACD_DEA"] = data["MACD_DIF"].ewm(span=signal_period, adjust=False).mean() # 慢线
data["MACD_Bar"] = data["MACD_DIF"] - data["MACD_DEA"] # 柱状线
return data
# 计算MACD
tsla_clean = calculate_macd(tsla_clean)
print(tsla_clean[["Close", "MACD_DIF", "MACD_DEA", "MACD_Bar"]].tail())
4.3 保存处理后的数据(方便复用)
处理好的数据可保存为 CSV,避免重复下载:
# 保存为CSV(索引为日期,保留)
tsla_clean.to_csv("tsla_5y_data.csv")
# 后续可直接读取
# tsla_clean = pd.read_csv("tsla_5y_data.csv", index_col=0, parse_dates=True)
五、可视化分析:用 Matplotlib 展示数据与指标

光有数据和指标不够直观,用 Matplotlib 绘制图表,能快速发现趋势和信号。
5.1 绘制价格与均线走势
# 设置中文显示(避免乱码)
plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"]
plt.rcParams["axes.unicode_minus"] = False # 解决负号显示问题
# 1. 创建画布
fig, ax = plt.subplots(figsize=(12, 6))
# 2. 绘制收盘价和均线
ax.plot(tsla_clean.index, tsla_clean["Close"], label="收盘价", alpha=0.7, linewidth=1)
ax.plot(tsla_clean.index, tsla_clean["MA5"], label="5日均线", color="orange", linewidth=2)
ax.plot(tsla_clean.index, tsla_clean["MA20"], label="20日均线", color="green", linewidth=2)
# 3. 添加标题和标签
ax.set_title("特斯拉股价与均线走势(2019-2024)", fontsize=15)
ax.set_xlabel("日期")
ax.set_ylabel("价格(美元)")
# 4. 添加网格和图例
ax.grid(alpha=0.3)
ax.legend()
# 5. 自动调整日期标签(避免重叠)
fig.autofmt_xdate()
plt.show()
从图中可直观看到:当 5 日均线上穿 20 日均线(金叉),股价往往上涨;下穿(死叉)则可能下跌 —— 这就是均线策略的核心逻辑。
5.2 绘制 RSI 指标(判断超买超卖)
# 创建上下两个子图(共享x轴)
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 8), sharex=True, gridspec_kw={"height_ratios": [3, 1]})
# 上子图:收盘价
ax1.plot(tsla_clean.index, tsla_clean["Close"], label="收盘价", color="blue")
ax1.set_title("特斯拉股价与RSI指标", fontsize=15)
ax1.legend(loc="upper left")
ax1.grid(alpha=0.3)
# 下子图:RSI
ax2.plot(tsla_clean.index, tsla_clean["RSI14"], label="RSI(14)", color="purple")
ax2.axhline(70, color="red", linestyle="--", alpha=0.5) # 超买线
ax2.axhline(30, color="green", linestyle="--", alpha=0.5) # 超卖线
ax2.set_ylabel("RSI值")
ax2.legend(loc="upper left")
ax2.grid(alpha=0.3)
# 调整布局
plt.tight_layout()
plt.show()
图中红色虚线(70)和绿色虚线(30)是关键阈值:当 RSI 突破 70 后回落,可能是下跌信号;跌破 30 后回升,可能是上涨信号。
5.3 绘制多股票收益率对比
# 1. 提取2023年四只科技股的收盘价
close_prices = multi_stocks["Close"]
# 2. 计算累计收益率(以第一天为基准,标准化为100)
normalized = (close_prices / close_prices.iloc[0] * 100)
# 3. 绘制收益率曲线
plt.figure(figsize=(12, 6))
for stock in normalized.columns:
plt.plot(normalized.index, normalized[stock], label=stock, linewidth=2)
plt.title("2023年科技股累计收益率对比(初始值=100)", fontsize=15)
plt.xlabel("日期")
plt.ylabel("累计收益(初始100)")
plt.legend()
plt.grid(alpha=0.3)
fig.autofmt_xdate()
plt.show()
通过收益率曲线,能快速看出哪只股票表现更好(如 2023 年英伟达涨幅远超其他科技股)。
六、策略构建与回测:用三剑客实现双均线策略

有了数据、指标和可视化基础,我们来构建一个经典的 “双均线策略”,并回测其效果。
6.1 策略逻辑
双均线策略是量化入门的经典策略,逻辑简单且有效:
- 买入信号:短期均线(如 5 日均线)上穿长期均线(如 20 日均线)—— 金叉;
- 卖出信号:短期均线下穿长期均线 —— 死叉;
- 持仓规则:发出买入信号时全仓买入,卖出信号时清仓,不考虑止损。
6.2 生成交易信号
用 Pandas 标记买入(1)和卖出(-1)信号:
# 1. 复制数据(避免修改原始数据)
strategy_data = tsla_clean[["Close", "MA5", "MA20"]].copy()
# 2. 生成信号:金叉=买入(1),死叉=卖出(-1)
# 先判断前一天的均线位置关系(避免未来函数)
strategy_data["MA5_prev"] = strategy_data["MA5"].shift(1)
strategy_data["MA20_prev"] = strategy_data["MA20"].shift(1)
# 金叉:今天MA5 > MA20,且昨天MA5 <= MA20
strategy_data["Buy_Signal"] = ((strategy_data["MA5"] > strategy_data["MA20"]) &
(strategy_data["MA5_prev"] <= strategy_data["MA20_prev"])).astype(int)
# 死叉:今天MA5 < MA20,且昨天MA5 >= MA20
strategy_data["Sell_Signal"] = ((strategy_data["MA5"] < strategy_data["MA20"]) &
(strategy_data["MA5_prev"] >= strategy_data["MA20_prev"])).astype(int)
# 合并为交易信号(1=买入,-1=卖出,0=无操作)
strategy_data["Signal"] = strategy_data["Buy_Signal"] - strategy_data["Sell_Signal"]
# 查看信号示例(筛选有信号的行)
print(strategy_data[strategy_data["Signal"] != 0][["Close", "MA5", "MA20", "Signal"]].tail())
6.3 回测策略收益
计算策略的累计收益,并与 “买入持有” 策略对比:
# 1. 初始化持仓和资金
strategy_data["Position"] = 0 # 持仓状态:0=空仓,1=满仓
strategy_data["Cash"] = 100000 # 初始资金10万
strategy_data["Shares"] = 0 # 持有股数
strategy_data["Total_Asset"] = 100000 # 总资产(现金+股票市值)
# 2. 遍历每一天,执行交易
for i in range(1, len(strategy_data)):
# 获取当前和前一天的数据
prev = strategy_data.iloc[i-1]
current = strategy_data.iloc[i]
# 继承前一天的持仓和资产
strategy_data.at[strategy_data.index[i], "Position"] = prev["Position"]
strategy_data.at[strategy_data.index[i], "Cash"] = prev["Cash"]
strategy_data.at[strategy_data.index[i], "Shares"] = prev["Shares"]
# 买入信号且空仓:用全部现金买入
if current["Signal"] == 1 and prev["Position"] == 0:
# 计算可买股数(取整数,不考虑手续费)
shares = int(prev["Cash"] / current["Close"])
cost = shares * current["Close"]
# 更新状态
strategy_data.at[strategy_data.index[i], "Shares"] = shares
strategy_data.at[strategy_data.index[i], "Cash"] = prev["Cash"] - cost
strategy_data.at[strategy_data.index[i], "Position"] = 1
# 卖出信号且满仓:清仓
elif current["Signal"] == -1 and prev["Position"] == 1:
# 计算卖出收益
cash = prev["Cash"] + prev["Shares"] * current["Close"]
# 更新状态
strategy_data.at[strategy_data.index[i], "Shares"] = 0
strategy_data.at[strategy_data.index[i], "Cash"] = cash
strategy_data.at[strategy_data.index[i], "Position"] = 0
# 计算总资产
total_asset = strategy_data.at[strategy_data.index[i], "Cash"] + \
strategy_data.at[strategy_data.index[i], "Shares"] * current["Close"]
strategy_data.at[strategy_data.index[i], "Total_Asset"] = total_asset
# 3. 计算买入持有策略的收益(第一天买入,持有至最后)
first_price = strategy_data["Close"].iloc[0]
last_price = strategy_data["Close"].iloc[-1]
hold_shares = int(100000 / first_price)
hold_asset = 100000 - hold_shares * first_price + hold_shares * last_price
strategy_data["Hold_Asset"] = hold_asset # 买入持有策略的最终资产(保持不变)
print(f"策略最终总资产:{strategy_data['Total_Asset'].iloc[-1]:.2f}美元")
print(f"买入持有最终资产:{hold_asset:.2f}美元")
6.4 可视化回测结果
plt.figure(figsize=(12, 6))
# 绘制总资产和买入持有资产
plt.plot(strategy_data.index, strategy_data["Total_Asset"], label="双均线策略", color="blue")
plt.plot(strategy_data.index, strategy_data["Hold_Asset"], label="买入持有", color="gray", linestyle="--")
# 标记买入和卖出点
buy_signals = strategy_data[strategy_data["Signal"] == 1]
sell_signals = strategy_data[strategy_data["Signal"] == -1]
plt.scatter(buy_signals.index, buy_signals["Total_Asset"], marker="^", color="green", label="买入", s=100)
plt.scatter(sell_signals.index, sell_signals["Total_Asset"], marker="v", color="red", label="卖出", s=100)
plt.title("双均线策略与买入持有收益对比", fontsize=15)
plt.xlabel("日期")
plt.ylabel("总资产(美元)")
plt.legend()
plt.grid(alpha=0.3)
fig.autofmt_xdate()
plt.show()
6.5 策略评价指标
光看总资产不够,还需计算以下指标评估策略优劣:
def evaluate_strategy(data):
"""计算策略评价指标"""
# 1. 总收益率
total_return = (data["Total_Asset"].iloc[-1] / data["Total_Asset"].iloc[0] - 1) * 100
# 2. 年化收益率(假设一年252个交易日)
days = len(data)
annual_return = ((1 + total_return / 100) ** (252 / days) - 1) * 100
# 3. 胜率(盈利交易次数 / 总交易次数)
trades = data[(data["Signal"] == 1) | (data["Signal"] == -1)]
if len(trades) == 0:
win_rate = 0
else:
# 简化计算:每次买入后下次卖出为一次完整交易
buy_points = data[data["Signal"] == 1].index
sell_points = data[data["Signal"] == -1].index
profitable = 0
for b, s in zip(buy_points, sell_points):
if data.loc[s, "Close"] > data.loc[b, "Close"]:
profitable += 1
win_rate = (profitable / len(buy_points)) * 100 if len(buy_points) > 0 else 0
# 4. 最大回撤(历史最高点到最低点的跌幅)
rolling_max = data["Total_Asset"].cummax() # 累计最大值
drawdown = (data["Total_Asset"] - rolling_max) / rolling_max # 回撤率
max_drawdown = drawdown.min() * 100 # 最大回撤(负的)
return {
"总收益率(%)": round(total_return, 2),
"年化收益率(%)": round(annual_return, 2),
"胜率(%)": round(win_rate, 2),
"最大回撤(%)": round(max_drawdown, 2)
}
# 计算并打印评价指标
metrics = evaluate_strategy(strategy_data)
print("策略评价指标:")
for key, value in metrics.items():
print(f"{key}: {value}")
指标解读:
- 总收益率:策略期间的整体收益;
- 年化收益率:将收益标准化到一年,方便跨周期对比;
- 胜率:盈利交易占比,越高说明策略越稳定;
- 最大回撤:历史上从最高点下跌的最大幅度,越小说明风险越低。
七、实战案例:A 股股票筛选与策略回测
前面以美股为例,现在用 A 股数据实战:筛选出符合 “低市盈率 + 高动量” 的股票,并用双均线策略回测。
7.1 筛选股票(结合基本面和技术面)
# 1. 定义A股股票池(茅台、宁德时代、比亚迪、招商银行)
a股_tickers = ["600519.SS", "300750.SZ", "002594.SZ", "600036.SS"]
names = ["贵州茅台", "宁德时代", "比亚迪", "招商银行"]
# 2. 批量获取基本面数据,筛选低市盈率(<30)的股票
filtered = []
for ticker, name in zip(a股_tickers, names):
stock = yf.Ticker(ticker)
info = stock.info
pe = info.get("trailingPE", float("inf")) # 动态市盈率
if pe < 30: # 筛选市盈率<30的股票
filtered.append((ticker, name, pe))
print("低市盈率股票筛选结果:")
for t, n, p in filtered:
print(f"{n}({t}):市盈率={p:.2f}")
# 3. 从筛选结果中,选择近3个月涨幅最高的股票(高动量)
best_stock = None
max_return = -float("inf")
for t, n, p in filtered:
# 获取近3个月数据
hist = yf.download(t, period="3mo", auto_adjust=True)
# 计算涨幅
return_rate = (hist["Close"].iloc[-1] / hist["Close"].iloc[0] - 1) * 100
print(f"{n}近3个月涨幅:{return_rate:.2f}%")
if return_rate > max_return:
max_return = return_rate
best_stock = (t, n)
print(f"\n最终选择:{best_stock[1]}({best_stock[0]}),近3个月涨幅{max_return:.2f}%")
7.2 回测选中股票的双均线策略
# 1. 获取选中股票的5年数据
ticker, name = best_stock
a股_data = yf.download(ticker, period="5y", auto_adjust=True)
# 2. 计算均线
a股_data["MA5"] = a股_data["Close"].rolling(5).mean()
a股_data["MA20"] = a股_data["Close"].rolling(20).mean()
# 3. 生成信号(复用前面的逻辑)
a股_data["MA5_prev"] = a股_data["MA5"].shift(1)
a股_data["MA20_prev"] = a股_data["MA20"].shift(1)
a股_data["Buy_Signal"] = ((a股_data["MA5"] > a股_data["MA20"]) &
(a股_data["MA5_prev"] <= a股_data["MA20_prev"])).astype(int)
a股_data["Sell_Signal"] = ((a股_data["MA5"] < a股_data["MA20"]) &
(a股_data["MA5_prev"] >= a股_data["MA20_prev"])).astype(int)
a股_data["Signal"] = a股_data["Buy_Signal"] - a股_data["Sell_Signal"]
# 4. 回测(复用前面的回测逻辑)
a股_data["Position"] = 0
a股_data["Cash"] = 100000
a股_data["Shares"] = 0
a股_data["Total_Asset"] = 100000
for i in range(1, len(a股_data)):
prev = a股_data.iloc[i-1]
current = a股_data.iloc[i]
a股_data.at[a股_data.index[i], "Position"] = prev["Position"]
a股_data.at[a股_data.index[i], "Cash"] = prev["Cash"]
a股_data.at[a股_data.index[i], "Shares"] = prev["Shares"]
if current["Signal"] == 1 and prev["Position"] == 0:
shares = int(prev["Cash"] / current["Close"])
cost = shares * current["Close"]
a股_data.at[a股_data.index[i], "Shares"] = shares
a股_data.at[a股_data.index[i], "Cash"] = prev["Cash"] - cost
a股_data.at[a股_data.index[i], "Position"] = 1
elif current["Signal"] == -1 and prev["Position"] == 1:
cash = prev["Cash"] + prev["Shares"] * current["Close"]
a股_data.at[a股_data.index[i], "Shares"] = 0
a股_data.at[a股_data.index[i], "Cash"] = cash
a股_data.at[a股_data.index[i], "Position"] = 0
total_asset = a股_data.at[a股_data.index[i], "Cash"] + \
a股_data.at[a股_data.index[i], "Shares"] * current["Close"]
a股_data.at[a股_data.index[i], "Total_Asset"] = total_asset
# 5. 可视化结果
plt.figure(figsize=(12, 6))
plt.plot(a股_data.index, a股_data["Total_Asset"], label="双均线策略", color="blue")
buy_signals = a股_data[a股_data["Signal"] == 1]
sell_signals = a股_data[a股_data["Signal"] == -1]
plt.scatter(buy_signals.index, buy_signals["Total_Asset"], marker="^", color="green", label="买入", s=100)
plt.scatter(sell_signals.index, sell_signals["Total_Asset"], marker="v", color="red", label="卖出", s=100)
plt.title(f"{name}双均线策略回测结果", fontsize=15)
plt.xlabel("日期")
plt.ylabel("总资产(人民币)")
plt.legend()
plt.grid(alpha=0.3)
fig.autofmt_xdate()
plt.show()
# 6. 打印评价指标
a股_metrics = evaluate_strategy(a股_data)
print(f"\n{name}策略评价指标:")
for key, value in a股_metrics.items():
print(f"{key}: {value}")
八、避坑指南:量化新手常踩的 6 个坑
-
数据复权问题:未复权的数据会因分红拆股出现价格断层(如股价突然从 100 元跌到 20 元),导致指标计算错误。解决:获取数据时始终设置
auto_adjust=True。 -
未来函数陷阱:用当天数据计算前一天的信号(如用今天的均线判断昨天是否买入),会导致回测收益虚高。解决:计算信号时用
shift(1)取前一天数据。 -
过度优化参数:为了让回测结果好看,反复调整均线周期(如把 5 日和 20 日改成 7 日和 19 日),导致策略 “拟合历史” 但未来失效。解决:用样本外数据验证(如用前 3 年数据优化,后 2 年数据测试)。
-
忽略交易成本:回测时不考虑手续费、滑点(买卖价差),导致实际收益远低于预期。解决:在回测中加入成本(如每次交易扣除 0.1% 的手续费)。
-
数据频率错误:用日线数据回测日内策略,或用分钟线数据计算周线指标,逻辑矛盾。解决:确保数据频率与策略周期匹配(如日线策略用日线数据)。
-
单只股票回测偏见:只回测一只股票就判定策略有效,可能是运气。解决:多股票、多周期回测(如在 10 只股票上测试,且至少 3 年数据)。
九、进阶方向:从入门到实战的升级路径
掌握基础后,可从以下方向进阶:
-
策略升级:结合更多指标(如 MACD+RSI 组合信号)、加入止损止盈(如亏损 10% 强制止损)、尝试选股策略(如多因子模型)。
-
工具扩展:学习专业回测框架(如 Backtrader、VectorBT),支持更复杂的策略逻辑;用 TA-Lib 库快速计算技术指标(替代手动编写的 RSI、MACD 函数)。
-
自动化交易:对接券商 API(如富途、雪球),实现策略自动下单;用定时任务(如
schedule库)每日自动获取数据并生成信号。 -
风险管理:学习仓位管理(如每只股票持仓不超过总资金的 10%)、分散投资(同时持有多只不相关股票),降低单一风险。
-
量化思维培养:理解 “概率思维”—— 量化策略不是 100% 赚钱,而是通过多次交易让盈利概率大于亏损概率;接受 “回测≠未来”,市场变化会导致策略失效,需持续优化。
十、总结:量化交易的核心不是代码,而是逻辑
用 Pandas、yfinance、Matplotlib 实现量化的过程,本质是 “将交易逻辑转化为可执行的代码”。这三个库只是工具,真正重要的是:
- 你能否清晰定义策略的买入卖出规则(避免模糊的 “感觉”);
- 你能否用数据验证策略的有效性(而非凭直觉判断);
- 你能否接受策略的局限性(没有永远赚钱的策略,只有适应市场的策略)。
从本文的双均线策略开始,尝试修改参数(如换成 10 日和 30 日均线)、添加新指标、测试不同股票,逐步积累经验。记住:量化交易的门槛不在编程,而在 “用数据说话” 的思维方式。
注意:本文只是技术切磋,请勿盲目跟随!
1391

被折叠的 条评论
为什么被折叠?



