本文你将得到什么:
痛点:为什么均线交叉不值得手动翻
很多做趋势跟踪的朋友,每天开盘前会干一件事:把自选股逐个打开,看看 MA5 有没有上穿 MA10、MA20 有没有拐头。十几只票翻下来,半小时没了,还经常看花眼。
更麻烦的是,等你肉眼确认"金叉成立了",价格往往已经跑了一段。技术指标的时效性很强,自动化是必经之路。
本文用不到 50 行核心代码,把"拉数据 → 算均线 → 找交叉 → 画出来 → 简单回测"整条链路跑通。
环境准备
pip install mairui pandas numpy matplotlib
第一步:拉取日线数据
from mairui import Client
# 演示证书(明文写入方便复制运行;实际项目建议放配置文件)
client = Client("LICENCE-66D8-9F96-0C7F0FBCD073")
bars = client.stock_history(code="600519", period="d", dividend="f")
print(f"获取 {len(bars)} 条 K 线")
print(f"日期范围: {bars[0]['t']} ~ {bars[–1]['t']}")
返回的 bars 是字典列表,每条含 t(日期)、o(开)、h(高)、l(低)、c(收)、v(量)。
第二步:计算移动平均线
import pandas as pd
df = pd.DataFrame(bars)
df = df.rename(columns={"t": "date", "o": "o", "h": "h", "l": "l", "c": "c", "v": "v"})
df = df.sort_values("date").reset_index(drop=True)
closes = df["c"].astype(float)
# 计算 MA5/MA10/MA20
df["ma5"] = closes.rolling(window=5, min_periods=5).mean()
df["ma10"] = closes.rolling(window=10, min_periods=10).mean()
df["ma20"] = closes.rolling(window=20, min_periods=20).mean()
print(f"MA5 最新: {df['ma5'].iloc[–1]:.2f}")
print(f"MA10 最新: {df['ma10'].iloc[–1]:.2f}")
print(f"MA20 最新: {df['ma20'].iloc[–1]:.2f}")
输出示例(演示数据):
MA5 最新: 11.03
MA10 最新: 11.15
MA20 最新: 11.15
注意:本文使用演示证书,返回的是固定样例数据。换成你的正式证书后,即为真实行情,代码无需任何修改。
第三步:检测金叉与死叉
交叉的定义很简单:
- 金叉:前一天 short < long,当天 short > long
- 死叉:前一天 short > long,当天 short < long
def find_crossover(df):
signals = []
for i in range(1, len(df)):
prev = df.iloc[i – 1]
curr = df.iloc[i]
if prev["ma5"] < prev["ma10"] and curr["ma5"] > curr["ma10"]:
signals.append((curr["date"], "golden", curr["c"]))
elif prev["ma5"] > prev["ma10"] and curr["ma5"] < curr["ma10"]:
signals.append((curr["date"], "death", curr["c"]))
return signals
signals = find_crossover(df)
for date, typ, price in signals:
label = "金叉" if typ == "golden" else "死叉"
print(f"{date} {label} @ {price:.2f}")
输出示例:
2025-10-16 死叉 @ 10.74
2025-10-20 金叉 @ 11.42
2025-10-28 死叉 @ 10.66
2025-11-10 金叉 @ 11.45
2025-11-21 死叉 @ 10.79
第四步:可视化——把信号画在图上
import matplotlib.pyplot as plt
plt.rcParams["font.sans-serif"] = ["SimHei", "Microsoft YaHei"]
plt.rcParams["axes.unicode_minus"] = False
fig, ax = plt.subplots(figsize=(12, 6))
x = range(len(df))
ax.plot(x, closes, label="收盘价", color="black", linewidth=0.8)
ax.plot(x, df["ma5"], label="MA5", color="orange", linewidth=1)
ax.plot(x, df["ma10"], label="MA10", color="blue", linewidth=1)
ax.plot(x, df["ma20"], label="MA20", color="purple", linewidth=1)
# 标记信号
for idx, row in df.iterrows():
for date, typ, price in signals:
if row["date"] == date:
color = "red" if typ == "golden" else "green"
marker = "^" if typ == "golden" else "v"
ax.scatter([idx], [price], color=color, marker=marker, s=100, zorder=5)
ax.set_title("600519 移动平均线与交叉信号")
ax.set_ylabel("价格")
ax.legend()
ax.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("ma_cross.png", dpi=150)
图中红色三角为金叉买入点,绿色倒三角为死叉卖出点,一目了然。
第五步:简单回测——金叉买、死叉卖
有了信号,自然想验证"按均线交叉交易到底赚不赚钱"。下面是一个最简回测:金叉满仓买入,死叉清仓卖出。
def backtest(df, signals, initial=100000):
position = 0
cash = initial
trades = []
nav = []
for idx, row in df.iterrows():
price = row["c"]
for date, typ, _ in signals:
if row["date"] == date:
if typ == "golden" and position == 0:
position = 1
trades.append((date, "BUY", price))
elif typ == "death" and position == 1:
if trades:
buy_price = trades[–1][2]
shares = initial / buy_price
cash = shares * price
position = 0
trades.append((date, "SELL", price))
current_nav = cash if position == 0 else (initial / trades[–1][2] * price if trades else initial)
nav.append(current_nav)
return trades, nav
trades, nav = backtest(df, signals)
print(f"交易次数: {len(trades)}")
for t in trades:
print(f" {t[0]} {t[1]} @ {t[2]:.2f}")
final = nav[–1]
ret = (final – 100000) / 100000 * 100
buyhold = (closes.iloc[–1] – closes.iloc[0]) / closes.iloc[0] * 100
print(f"策略收益: {ret:.2f}%")
print(f"买入持有: {buyhold:.2f}%")
输出示例:
交易次数: 6
2025-10-20 BUY @ 11.42
2025-10-28 SELL @ 10.66
2025-11-10 BUY @ 11.45
2025-11-21 SELL @ 10.79
2025-11-24 BUY @ 11.07
2025-11-26 SELL @ 10.82
策略收益: -2.26%
买入持有: -6.74%
在这个演示数据区间,策略虽然也是负收益,但跑赢了买入持有约 4.5 个百分点,说明均线交叉在震荡市中起到了一定的避险作用。当然,这只是单只票、单段时间的演示,不代表任何确定性结论。
常见坑与注意
小结
本文用 50 行核心代码完成了:
- 自动拉取日线
- 计算 MA5/MA10/MA20
- 检测金叉/死叉
- 可视化标注
- 简单回测验证
下一步,你可以把这套逻辑扩展到多只股票批量扫描,或者把均线交叉和 MACD、KDJ 等指标叠加使用——后者正是本系列下一篇的主题。
免责声明
本文仅为技术教学,不构成任何投资建议。文中使用的股票代码仅作演示,不代表推荐。投资有风险,入市需谨慎。
代码与文档:https://github.com/MaiRuiApi




