找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

460

积分

0

好友

58

主题
发表于 12 小时前 | 查看: 0| 回复: 0

上一篇,我们使用Dash实现了一个轮动策略Web版交互界面。本篇将在其基础上,把功能强大的 Backtrader 回测框架深度集成到系统中,让你能够利用真实历史数据对轮动策略进行验证和优化。

动量策略轮动系统主界面
策略回测参数设置界面
策略回测结果概览界面

搭建思路与目标

这个系列旨在从零开始,用 Python 一步步搭建出一套完整的ETF量化交易系统。选择ETF作为标的,是因为对普通交易者而言,它相比选股难度更小,且没有退市风险。通过跟随整个实现路径,你可以系统性地学习量化系统构建的方法论。

掌握了核心方法后,你完全可以将其迁移至期货、比特币或美股等不同市场,并在实战中持续迭代和完善自己的系统。

系统架构与核心集成

整体架构:前端采用Dash构建响应式Web界面,通过Bootstrap进行现代化UI设计;后端核心是Backtrader量化回测引擎,通过回调函数与前端交互;数据层使用AKShare从新浪财经获取实时ETF历史数据,形成清晰的三层架构。

技术栈:Dash(前端框架)+ Backtrader(量化回测)+ AKShare(数据获取)+ Pandas(数据处理)+ Plotly(数据可视化),形成了一套完整的量化策略研发工具链。

数据流:用户在Web界面设置参数 → 点击回测按钮触发Dash回调 → Backtrader引擎加载ETF历史数据 → 执行动量轮动策略 → 生成交易记录和绩效指标 → 结果返回前端可视化展示。

Backtrader策略核心实现 (MomentumRotationStrategy)

策略的核心在于动量轮动逻辑:定期计算所有ETF在一定周期内的动量(收益率),卖出不在前列的持仓,并买入动量最强的几只ETF。

class MomentumRotationStrategy(bt.Strategy):
    """
    动量轮动策略的核心实现
    继承自Backtrader的bt.Strategy基类
    """
    params = (
        ('momentum_period', 5),     # 动量计算周期
        ('rebalance_period', 5),    # 调仓周期
        ('hold_num', 2),            # 持有标的数量
        ('min_momentum', 0),        # 最小动量阈值
        ('position_size', 0.4),     # 单个标的仓位比例
        ('printlog', True),         # 日志开关
    )

参数说明

  • momentum_period: 计算动量(收益率)的回顾周期
  • rebalance_period: 调仓间隔天数
  • hold_num: 每次持有表现最好的ETF数量
  • min_momentum: 动量过滤阈值,避免买入弱势标的
  • position_size: 每个ETF的最大仓位比例

__init__() - 初始化方法

    def __init__(self):
        # 为每个ETF计算动量指标
        self.momentum = {
            data: bt.indicators.Momentum(data.close, period=self.p.momentum_period) 
            for data in self.datas
        }
        # 存储ETF排序结果
        self.rankings = list(self.datas)
        # 调仓计数器
        self.rebalance_day = 0
        # 订单字典,管理未完成订单
        self.order_dict = {}

next() - 逐日执行方法

每个交易日调用一次,当计数器达到预设的调仓周期时,触发调仓逻辑。

    def next(self):
        self.rebalance_day += 1
        # 到达调仓日时执行调仓
        if self.rebalance_day >= self.p.rebalance_period:
            self.rebalance_portfolio()
            self.rebalance_day = 0

rebalance_portfolio() - 核心调仓逻辑

这是策略的“大脑”,包含了排序、卖出、买入和仓位控制的全过程。

    def rebalance_portfolio(self):
        """执行调仓:卖出不在前列的,买入排名前列的"""
        # 1. 按动量值排序(从高到低)
        self.rankings.sort(key=lambda d: self.momentum[d][0], reverse=True)
        # 2. 卖出不在前hold_num名的持仓
        for data in self.datas:
            pos = self.getposition(data).size
            if pos > 0 and data not in self.rankings[:self.p.hold_num]:
                self.close(data=data)  # 平仓
        # 3. 买入排名前hold_num且动量达标的标的
        for i in range(min(self.p.hold_num, len(self.rankings))):
            data = self.rankings[i]
            pos = self.getposition(data).size
            momentum_value = self.momentum[data][0]
            if pos == 0 and momentum_value > self.p.min_momentum and data not in self.order_dict:
                # 计算买入数量
                target_value = self.broker.getvalue() * self.p.position_size
                size = int(target_value / data.close[0] / 100) * 100  # 按手数取整
                if size > 0:
                    self.order_dict[data] = self.buy(data=data, size=size)

notify_order() - 订单状态回调

负责处理订单状态变化,记录交易日志并清理已完成订单。

    def notify_order(self, order):
        """处理订单状态变化"""
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'买入执行 {order.data._name}, 价格:{order.executed.price:.2f}')
            elif order.issell():
                self.log(f'卖出执行 {order.data._name}, 价格:{order.executed.price:.2f}')
            self.order_dict.pop(order.data, None)  # 移除已完成的订单

数据获取与回测引擎配置

获取ETF历史数据并转换为Backtrader需要的格式。

def get_etf_data(etf_code, start_date='2023-01-01', end_date='2023-12-31'):
    """
    从新浪财经获取ETF历史数据
    返回格式:DataFrame with columns: ['open', 'high', 'low', 'close', 'volume']
    """
    # 市场代码转换:沪市51开头,深市15开头
    symbol = f'sh{etf_code}' if etf_code.startswith('51') else f'sz{etf_code}'
    # 使用AKShare获取数据
    df = ak.fund_etf_hist_sina(symbol=symbol)
    # 数据清洗和格式化
    df['date'] = pd.to_datetime(df['date'])
    df.set_index('date', inplace=True)
    df = df[(df.index >= start_date) & (df.index <= end_date)]
    return df

数据格式转换:

# Backtrader需要PandasData格式
data = bt.feeds.PandasData(
    dataname=df,           # 原始DataFrame
    name=etf_code,         # 数据名称(用于识别)
    datetime=None,         # 使用索引作为日期
    open=0, high=1,        # 列索引映射
    low=2, close=3, 
    volume=4,              # 成交量列
    openinterest=-1        # 无持仓量数据
)

回测引擎的初始化与执行函数 run_backtest 封装了创建引擎、设置参数、添加数据与策略、运行回测并返回结果的完整流程。

Dash回调函数集成:打通前后端

关键一步是将Backtrader回测逻辑嵌入到Dash的回调函数中。当用户在前端点击“开始回测”按钮时,会触发一个复杂的回调函数 run_real_backtest。这个函数负责:

  1. 从前端组件获取用户设置的所有参数(日期、资金、策略参数)。
  2. 调用数据获取函数,为ETF池中的每个标的获取历史数据。
  3. 动态创建并配置Backtrader的Cerebro引擎。
  4. 将数据和策略添加到引擎中,并附加各类绩效分析器。
  5. 执行回测,并从结果中提取总收益率、夏普比率、最大回撤、交易详情等指标。
  6. 处理回测中的时间序列收益,生成可视化的净值曲线图。
  7. 将所有结果格式化,返回给前端的各个显示组件进行更新。

这一设计实现了从数据获取、策略执行到绩效分析与可视化的完整闭环。系统执行时,会在控制台输出详细的调仓日志,例如:

2024-04-23 | 📅 调仓日期: 2024-04-23
2024-04-23 | 💰 当前总资产: 1000000.00
2024-04-23 | 📊 ETF动量排名 (周期=20天):
2024-04-23 |    1. 159562      动量: +0.09 
2024-04-23 |    2. 159652      动量: +0.04 
2024-04-23 | 📥 买入清单 (2只):
2024-04-23 |   ✔ 159562: 312000股 (动量: +0.09)
2024-04-23 |   ✔ 159652: 447900股 (动量: +0.04)

为什么选择Dash?

对于量化研究者和数据科学家而言,Dash极大地降低了构建交互式Web应用的门槛。它允许你完全使用Python来定义前端布局和交互逻辑,无需接触HTML、CSS或JavaScript。这意味着你可以将全部精力集中在核心的策略和数据逻辑上,快速将想法转化为可展示、可交互的产品。

一个最简单的Dash应用结构清晰:

  1. 创建应用对象app = dash.Dash(__name__)
  2. 定义布局:使用 html.Div, dcc.Input, dcc.Graph 等组件构建页面。
  3. 定义回调:使用 @app.callback 装饰器,指定输入(哪些组件的变化会触发函数)和输出(函数结果更新哪些组件),编写交互逻辑函数。
  4. 运行服务器app.run_server(debug=True)

在这个最简例程的基础上,你可以轻松地添加图表、多页面标签(Tabs),并连接真实的数据库或API,从而构建出像本文介绍的这样功能复杂的量化交易管理平台。

框架功能模块详解

本系统采用侧边栏导航结合主内容区的经典布局,通过Dash的回调机制实现各功能页面的平滑切换。主要功能模块如下:

1. 我的轮动池

提供ETF池管理功能,支持添加、筛选、排序以构建个性化轮动池。核心是动量排名的可视化,实时计算并展示各ETF的动量分数及排名变化,策略状态一目了然。
动量轮动策略核心逻辑

  • 每20天定期调仓
  • 选择动量排名前2的ETF持有
  • 动量分数基于20日涨幅计算
  • 实现“强者恒强”的轮动效应

我的轮动池管理界面

2. 我的账户

提供资产全景视角,展示总资产、持仓市值、可用资金及累计收益。通过交互式资产配置饼图直观展示持仓分布,并配有动态收益曲线追踪账户净值变化。

我的账户资产概览界面

3. 策略回测

构建参数化回测系统,支持灵活设置回测周期、初始资金、调仓频率等。以绩效指标矩阵和净值对比曲线图全面评估策略历史表现。

策略回测设置与结果界面

4. 参数配置

集中管理所有策略参数,分为策略参数、交易参数和风险参数三类,形成从策略逻辑、交易执行到风险管控的完整配置闭环。

系统参数配置界面

5. 实盘明细

提供交易全流程监控,支持多维度筛选交易记录,完整展示每笔交易的详情并自动计算盈亏。

实盘交易明细界面

6. 数据管理

实现一体化数据管理,支持自动更新计划配置,监控多数据源状态,并提供手动更新控制。

数据管理界面

7. 系统监控

保障系统稳定运行,实时展示服务器、数据库、策略引擎等核心组件状态,监控资源使用率,并追踪关键操作日志。

系统监控界面

8. 策略文档

构建知识沉淀体系,包含策略原理说明、详细操作指南、最佳实践分享和技术支持通道。

策略文档界面

部署与运行

# 安装核心依赖
pip install dash plotly pandas numpy akshare backtrader

# 开发环境运行
python app.py

# 生产环境部署建议使用Gunicorn
gunicorn -w 4 -b 0.0.0.0:8050 app:server

应用启动后,在浏览器中访问 http://localhost:8050 即可使用。

总结与展望

Dash框架让数据科学家能够专注于业务逻辑,高效构建专业级Web应用。本系统所实现的Web版轮动策略框架,采用了界面与功能架构先行的策略。当前版本已完成所有交互界面和模块逻辑,展示数据为模拟与真实数据结构相结合。

关键在于,后续所有数据接口、回调函数和计算模块均采用标准化设计。这意味着,使用者只需将现有的模拟数据源替换为真实的行情API(如券商接口),并将策略逻辑的核心计算函数替换为最终的实盘算法,即可在不改动任何界面代码的情况下,快速将本演示系统升级为一套完整的、可用于生产环境的交易平台。这种设计充分体现了 开源实战 项目中模块化与可扩展性的重要思想,为个人量化交易者提供了一个极佳的开发起点。通过 云栈社区 这样的平台,开发者可以交流类似项目的经验,共同推动量化工具生态的发展。




上一篇:Swoole 6.2引入io_uring:异步IO性能超Golang 3倍、Node.js 4.4倍
下一篇:深入理解C/C++结构体对齐:从原理到实战优化内存布局
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-18 16:30 , Processed in 0.230314 second(s), 43 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表