第25章 迷你实战:从零搭建双均线策略Agent系统

第25章 迷你实战:从零搭建双均线策略Agent系统

本章顾问:龙马(技术落地)、沈飞(策略逻辑)
预估时长:4小时
本章前置检查

  • □ 已完成第24章的数据治理体系,能获取并清洗Tushare数据
  • □ 熟悉OpenClaw和Hermes的基础配置(第1-12章)
  • □ 理解双Agent协作的基本模式(第15章)

本章难点提示

  • 25.2节的回测函数虽然简单,但包含了未来函数检查、滑点模拟等关键细节,不要跳过。
  • 25.3节的Agent配置是本章核心,建议按顺序逐个配置并测试,不要一次性全部部署。
  • 25.4节的观察阶段至少运行一周模拟盘,不要急于实盘。

🎯 本章教学目标:从零搭建一个完整的双均线策略Agent系统,涵盖数据获取、信号生成、模拟交易、风控监控全流程,理解量化策略Agent化的核心模式,并为后续多因子策略扩展打下基础。

图片[1]-从零跑通量化回测:双均线策略开发+绩效评估+调优全流程

25.1 策略简介:双均线金叉死叉

🎯 本节目标:理解双均线策略的逻辑、参数选择及其在量化交易中的地位。

预计时长:0.5小时

25.1.1 策略逻辑

双均线策略是最经典、最简单的趋势跟踪策略之一。它通过两条不同周期的移动平均线来判断趋势方向:

  • 金叉(买入信号):短期均线从下方上穿长期均线,表示上升趋势开始
  • 死叉(卖出信号):短期均线从上方下穿长期均线,表示下降趋势开始

核心代码逻辑

python

def generate_signals(df, short_window=5, long_window=20):
    df['short_ma'] = df['close'].rolling(window=short_window).mean()
    df['long_ma'] = df['close'].rolling(window=long_window).mean()
    df['signal'] = 0
    df.loc[df['short_ma'] > df['long_ma'], 'signal'] = 1   # 持仓
    df.loc[df['short_ma'] <= df['long_ma'], 'signal'] = 0  # 空仓
    df['position'] = df['signal'].diff()  # 仓位变化:+1买入,-1卖出
    return df

沈飞注:双均线策略虽然简单,但它体现了趋势跟踪的核心思想——截断亏损,让利润奔跑。即使专业量化机构,也会用类似方法作为基础过滤器。不要因为它简单就轻视,实盘中它能避开震荡市的大部分亏损。

25.1.2 参数选择与敏感性

参数组合适用场景优缺点
(5, 20)中短期交易敏感,信号多,易震荡
(10, 30)中期趋势平衡
(20, 60)中长期滞后,信号少,但更稳定

龙马注:参数优化的陷阱在于“过度拟合”。本章先用固定参数(5,20),后续扩展中再讨论参数优化和过拟合防范。

🛠️ 实践任务(本节):在纸上画出金叉和死叉的示意图,标出买卖点。

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

25.2 数据获取与回测准备

🎯 本节目标:使用Tushare获取历史数据,编写轻量级回测函数,验证策略有效性。

预计时长:1小时

25.2.1 数据获取(复用第24章清洗流程)

python

import tushare as ts
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

# 初始化Tushare
pro = ts.pro_api('你的token')  # 请替换为实际token

# 获取贵州茅台历史日线数据(后复权)
df = pro.daily(ts_code='600519.SH', start_date='20200101', end_date='20231231')
df['trade_date'] = pd.to_datetime(df['trade_date'])
df = df.sort_values('trade_date')

# 计算后复权收盘价(复权因子已在Tushare返回中)
df['adj_close'] = df['close'] * df['adj_factor']

print(df.head())

25.2.2 轻量级回测函数(不使用复杂框架)

python

def backtest_dma(df, short=5, long=20, slippage=0.001, commission=0.0003):
    """
    双均线策略回测
    slippage: 滑点(单边0.1%)
    commission: 手续费(双边0.03%)
    """
    df = df.copy()
    # 生成信号
    df['short_ma'] = df['adj_close'].rolling(window=short).mean()
    df['long_ma'] = df['adj_close'].rolling(window=long).mean()
    df['signal'] = 0
    df.loc[df['short_ma'] > df['long_ma'], 'signal'] = 1
    df.loc[df['short_ma'] <= df['long_ma'], 'signal'] = 0
    df['position'] = df['signal'].diff()
    
    # 模拟交易
    df['entry_price'] = df['adj_close']
    df['trade_cost'] = 0.0
    # 买入时支付滑点+佣金
    buy_mask = df['position'] == 1
    df.loc[buy_mask, 'trade_cost'] = df['entry_price'] * (slippage + commission)
    # 卖出时支付滑点+佣金
    sell_mask = df['position'] == -1
    df.loc[sell_mask, 'trade_cost'] = df['entry_price'] * (slippage + commission)
    
    # 计算每日收益
    df['returns'] = df['adj_close'].pct_change() * df['signal'].shift(1)
    df['net_returns'] = df['returns'] - df['trade_cost'] / df['entry_price']
    df['cum_returns'] = (1 + df['net_returns']).cumprod()
    
    # 绩效指标
    total_return = df['cum_returns'].iloc[-1] - 1
    annual_return = (1 + total_return) ** (252 / len(df)) - 1
    sharpe = df['net_returns'].mean() / df['net_returns'].std() * np.sqrt(252)
    max_drawdown = (df['cum_returns'] / df['cum_returns'].cummax() - 1).min()
    
    print(f"总收益率: {total_return:.2%}")
    print(f"年化收益率: {annual_return:.2%}")
    print(f"夏普比率: {sharpe:.2f}")
    print(f"最大回撤: {max_drawdown:.2%}")
    return df

25.2.3 运行回测并可视化

python

result = backtest_dma(df, short=5, long=20)

# 绘制净值曲线
plt.figure(figsize=(12, 6))
plt.plot(result['trade_date'], result['cum_returns'], label='策略净值')
plt.plot(result['trade_date'], result['adj_close'] / result['adj_close'].iloc[0], label='买入持有')
plt.legend()
plt.title('双均线策略回测 (贵州茅台, 2020-2023)')
plt.show()

龙马注:回测函数中的滑点和手续费设置非常重要。很多新手忽略这些成本,导致回测看起来很美,实盘却亏损。本章设为单边0.1%滑点+双边0.03%佣金,是比较现实的估计。

🛠️ 实践任务(本节)

  1. 获取至少两只股票的历史数据(如茅台+五粮液),分别运行回测。
  2. 调整均线参数,观察绩效变化,记录最优参数。

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

25.3 Agent配置:一个迷你团队

🎯 本节目标:将回测逻辑拆解为四个Agent,搭建可扩展的量化Agent团队。

预计时长:1.5小时

25.3.1 团队结构回顾

第23.5节我们定义了一人量化公司的核心Agent团队(6个Agent)。本章我们实现其中三个核心Agent的简化版:

Agent类型职责本章实现内容
数据AgentOpenClaw定时拉取最新行情Cron任务 + 数据清洗
策略AgentHermes计算均线信号,记录策略逻辑Skill + ACP委托
交易执行AgentOpenClaw模拟下单审批流程 + 模拟盘
风控AgentHermes(独立)监控回撤,触发暂停独立ACP服务 + 共享记忆

25.3.2 数据Agent配置(OpenClaw Cron)

创建Cron任务,每天收盘后自动拉取最新数据:

bash

openclaw cron add --name "fetch_daily_data" \
  --cron "30 15 * * 1-5" --tz Asia/Shanghai \
  --message "从Tushare获取沪深300成分股最新日线数据,清洗后存入Parquet文件" \
  --session isolated

对应的Skill或脚本(fetch_and_clean.py)应实现:调用Tushare API,执行第24章的清洗流程,保存到data/daily/目录。

25.3.3 策略Agent配置(Hermes Skill)

创建Hermes Skill用于生成交易信号。

目录~/.hermes/skills/dma_strategy/

SKILL.md

markdown

---
name: dma_strategy
description: 双均线策略信号生成器,根据最新数据计算金叉/死叉信号
---

## 触发器
- 用户请求“计算最新信号”
- 数据Agent更新后自动触发(通过ACP)

## 执行步骤
1. 读取最新清洗后的数据文件(Parquet)
2. 计算5日均线和20日均线
3. 判断是否金叉(短期上穿长期)或死叉(短期下穿长期)
4. 输出信号:买入/卖出/持有
5. 将信号和理由写入共享记忆(Redis)

## 输出格式
{
  "signal": "BUY/SELL/HOLD",
  "reason": "5日均线(价格)上穿20日均线(价格),形成金叉",
  "timestamp": "2025-01-01"
}

手动测试Skill

bash

hermes -c "使用dma_strategy技能,基于今天的日线数据生成信号"

25.3.4 交易执行Agent配置(OpenClaw + 审批)

模拟下单需要审批,避免实盘风险。

AGENTS.md(在OpenClaw中创建trade_executor Agent):

markdown

---
name: trade_executor
role: 交易执行员
type: default
---

## 职责
- 接收策略Agent的信号
- 模拟下单(输出日志),实盘需审批
- 记录成交记录

## 工作流
1. 从共享记忆读取最新信号
2. 如果是BUY/SELL,生成模拟订单
3. 调用审批工具,等待确认
4. 确认后记录到交易日志
5. 更新持仓状态

## 约束
- 单笔交易金额不超过10%(模拟)
- 每日总交易次数不超过3次

审批配置openclaw.json):

json

{
  "agents": {
    "list": [{
      "id": "trade_executor",
      "tools": {
        "requireApproval": ["execute_trade"]
      }
    }]
  }
}

25.3.5 风控Agent配置(独立Hermes)

风控Agent必须独立运行,不与交易Agent共享记忆。它监控回撤,超限时触发暂停。

SKILL.md

markdown

---
name: risk_monitor
description: 监控账户回撤,当超过阈值时发出告警并建议暂停
---

## 触发器
- 每5分钟运行一次(Cron)
- 交易后触发

## 执行步骤
1. 读取账户净值曲线(从共享记忆的只读区域)
2. 计算当前回撤(当前净值 / 历史最高净值 - 1)
3. 如果回撤 < -5%,发出告警
4. 如果回撤 < -8%,建议暂停所有交易
5. 将告警写入共享记忆的告警队列

## 输出
{
  "drawdown": -0.06,
  "alert_level": "warning",
  "action": "reduce_position"
}

Cron任务

bash

hermes cron add --name "risk_check" --every "5m" \
  --message "执行风控检查,读取共享记忆中的净值,判断回撤是否超限"

25.3.6 协作流程总览(注:由于图表形式在本网页上显示错位,本节用纯文本和表格描述四个Agent之间的协作关系。)

协作流程步骤说明

  1. 数据采集
    数据Agent(OpenClaw Cron)在每日收盘后自动运行,从Tushare获取最新日线数据,执行清洗(复权、去极值、填充缺失),然后将处理后的数据写入共享记忆(Redis或共享文件)。写入的键名例如 daily_data:600519
  2. 信号生成
    策略Agent(Hermes Skill)被Cron定时触发或由数据Agent通过ACP唤醒。它从共享记忆读取最新的日线数据,计算5日与20日均线,判断金叉或死叉。将生成的信号(BUY、SELL或HOLD)以及简要理由写入共享记忆,键名例如 signal:latest
  3. 交易执行
    交易Agent(OpenClaw)监听共享记忆中signal:latest的变化。一旦发现有新信号且为BUY或SELL,它根据信号方向和最新价格生成模拟订单。随后交易Agent调用审批工具,通过飞书发送审批请求(例如:“是否执行买入茅台100股?”)。你审批通过后,交易Agent将订单记录写入共享记忆(orders键),并更新持仓和净值曲线(equity_curve键)。
  4. 风控监控
    风控Agent(独立Hermes)每5分钟由Cron唤醒一次。它从共享记忆读取最近一段时间的净值曲线,计算当前回撤(最高净值到当前净值的跌幅)。如果回撤超过-5%,风控Agent写入一条警告信息到共享记忆的alerts键,并发送飞书告警。如果回撤超过-8%,则额外发送“暂停交易”指令给交易Agent(通过ACP或直接修改共享记忆中的pause_trading标志)。

数据流向与依赖关系表

步骤发起者所需读取的共享数据写入的共享数据触发/通知对象
1数据Agent无(直接从Tushare获取)daily_data:<股票代码>策略Agent(间接,通过Cron或ACP)
2策略Agentdaily_data:<股票代码>signal:latestsignal_history交易Agent(通过共享记忆监听)
3交易Agentsignal:latest,账户信息ordersequity_curvepositions风控Agent(通过净值更新间接触发)
4风控Agentequity_curve,风控阈值alertspause_trading交易Agent(读取暂停标志)

文字时序描述(模拟一次完整循环):

  • 15:30 数据Agent运行 → 写入daily_data:600519
  • 15:35 策略Agent运行 → 读取daily_data:600519 → 计算得出BUY信号 → 写入signal:latest
  • 15:36 交易Agent监听到新信号 → 读取signal:latest → 生成模拟订单 → 飞书发送审批请求 → 你点击“批准” → 交易Agent写入ordersequity_curve
  • 15:40 风控Agent运行 → 读取equity_curve → 计算回撤为-3%(未超限)→ 无操作。
  • (次日)如果市场下跌导致回撤达到-6%,风控Agent会写入alerts并发送告警;若达到-9%,则写入pause_trading: true,交易Agent将拒绝后续信号直至你手动解除。

龙马注:这个迷你团队已经具备了量化系统的最小闭环。你可以先手动触发各个环节验证,然后再设置Cron自动化。建议先单独测试策略Agent是否正确生成信号,再集成交易Agent。

🛠️ 实践任务(本节)

  1. 按照上述配置,创建数据Agent的Cron任务并手动运行一次
  2. 创建策略Agent Skill并测试信号生成
  3. 配置交易Agent的审批流程,模拟一次买入信号

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

25.4 运行与观察

🎯 本节目标:运行系统一周模拟盘,记录结果,分析Agent协作表现。

预计时长:0.5小时

25.4.1 启动系统

  1. 启动OpenClaw Gateway:openclaw gateway start
  2. 启动Hermes Gateway(可选,用于渠道推送):hermes gateway start
  3. 确保Cron任务已启用:openclaw cron list

25.4.2 模拟盘运行一周

  • 每天收盘后数据Agent自动拉取数据
  • 策略Agent生成信号(可通过飞书/Telegram接收推送)
  • 交易Agent根据信号模拟下单,需你审批
  • 风控Agent每5分钟检查回撤

观察要点

  • 数据是否准时更新
  • 信号是否合理(对比手动计算)
  • 审批流程是否流畅
  • 风控告警是否及时

25.4.3 记录日志与复盘

建议在飞书群中配置一个专用频道,接收所有Agent的日志推送。例如:

bash

openclaw cron add --name "daily_summary" --cron "0 16 * * 1-5" \
  --message "汇总今日信号、交易、风控状态" \
  --deliver feishu:oc_群ID

沈飞注:模拟盘至少运行一个月,经历至少一次完整的买卖周期。不要因为一周没信号就急躁。双均线策略在震荡市可能长期无信号,这正是它的风控价值。

🛠️ 实践任务(本节)

  1. 配置飞书群接收Agent日志
  2. 运行模拟盘至少一周,截图关键日志
  3. 记录遇到的任何异常(如数据丢失、信号延迟)及解决方案

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

25.5 扩展讨论:如何将双均线升级为多因子模型

🎯 本节目标:理解从双均线到多因子策略的扩展路径,为第27章做铺垫。

预计时长:0.3小时

扩展方向

扩展维度双均线多因子模型所需新增Agent
信号来源单一均线多个因子(动量、价值、质量等)因子挖掘Agent
信号合成简单金叉死叉加权打分、机器学习因子合成Agent
风险控制简单回撤监控因子暴露控制、行业中性风险模型Agent
资产配置单一资产多资产组合优化资产配置Agent

代码扩展示例

python

# 多因子打分框架(伪代码)
def multi_factor_score(df, factors):
    """
    factors: 字典,键为因子名称,值为因子值Series
    """
    scores = pd.DataFrame()
    for name, factor in factors.items():
        # 因子标准化(Z-score)
        scores[name] = (factor - factor.mean()) / factor.std()
    # 等权合成
    total_score = scores.mean(axis=1)
    # 选择得分最高的10%股票买入
    return total_score

龙马注:双均线是单因子,多因子就是多个单因子的组合。你当前的数据Agent、策略Agent、交易Agent、风控Agent架构完全兼容多因子——只需将策略Agent改为调用多个因子Skill并合成信号即可。

🛠️ 实践任务(本节):在双均线策略代码基础上,尝试增加一个波动率因子(如ATR),当波动率过高时降低仓位。

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

25.6 🚨 常见误解:双均线策略简单 = 没有价值

🎯 本节目标:纠正对简单策略的偏见,理解其在实盘中的价值。

预计时长:0.2小时

误解

“双均线是人尽皆知的简单策略,用它肯定赚不到钱。”

真相

  • 趋势跟踪的有效性:双均线捕捉大趋势,在牛熊市中都能获利。
  • 过滤器作用:即使不作为主策略,也可作为其他策略的“开关”(只在均线多头时开仓)。
  • 稳健性:参数不敏感,不易过拟合。
  • 实盘案例:许多CTA策略的核心就是双均线或其变种。

沈飞注:我在实盘中见过用双均线跑商品期货的团队,年化收益20%+,最大回撤10%以内。简单不等于无效,复杂不等于有效。关键是纪律执行——双均线在震荡市会连续亏损,但很少有人能坚持下来。

🛠️ 实践任务(本节):思考你所在的领域,有哪些“简单但有效”的规则值得Agent化?

💭 本节总结(不看书写3行):
1.
2.
3.

📊 用时记录:计划____min → 实际____min → 偏差原因:________

第25章 参考资料与扩展阅读

  1. Tushare Pro日线行情接口 https://tushare.pro/document/2?doc_id=27
  2. 双均线策略原理与实现(聚宽社区) https://www.joinquant.com/view/community/detail/xxxx
  3. 滑点与手续费对回测的影响 https://www.quantstart.com/articles/Slippage-and-Commission-in-Backtesting
  4. OpenClaw Cron任务配置 https://docs.openclaw.ai/zh-CN/automation/cron-jobs
  5. Hermes Skill开发最佳实践 https://hermes-agent.nousresearch.com/docs/skills/best-practices

第五篇综合任务(第25章完成后)

任务:完成以下所有检查项。

  • 成功获取并清洗至少一只股票的历史日线数据
  • 运行双均线回测,输出绩效指标,并保存净值曲线图
  • 配置数据Agent的Cron任务,手动触发一次成功
  • 创建策略Agent Skill,测试信号生成
  • 配置交易Agent审批流程,模拟一次下单
  • (可选)运行模拟盘一周,记录日志

完成后,保存回测脚本和Agent配置文件,命名为chapter25_dual_ma_agents.zip

顾问审校意见

沈飞:

“第25章的双均线策略虽然简单,但麻雀虽小五脏俱全——它完整演示了量化系统的四个核心Agent:数据、策略、交易、风控。这对于初学者建立系统思维非常有帮助。

需要提醒的是:双均线在震荡市会连续亏损,这是策略本身的特点,不是Bug。实盘中很多人因为无法忍受连续的小亏损而放弃,这恰恰是最大的错误。因此,本章特别强调‘模拟盘至少运行一个月’——让读者亲身体验震荡期的煎熬,比任何说教都有效。”

龙马:

“本章的Agent配置已经可以跑通。我补充两个工程细节:

共享记忆推荐使用Redis,可以设置自动过期(如信号保留7天)。配置简单,适合个人量化。

策略Agent的SKILL.md中,读取数据时建议使用绝对路径,避免相对路径在不同上下文中出错。或者通过环境变量配置数据目录。

另外,建议读者在回测函数中加入future_check,确保没有用到未来数据。虽然Tushare的数据本身是安全的,但自己写代码处理时容易出错。”

下一章预告:第26章 量化投资公司的Agent化映射:从岗位到Agent —— 我们将系统化地将第23章的真实岗位映射为Agent角色,给出完整的映射表和协作设计,为第27章的Skill开发打下基础。

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容