背景

backtrader 已经比较完善了,我想要借鉴量化投资框架中其他项目的优势,继续改进优化 backtrader。

任务

  1. 阅读研究分析 backtrader 这个项目的源代码,了解这个项目。

  2. 阅读研究分析/Users/yunjinqi/Documents/量化交易框架/thOth

  3. 借鉴这个新项目的优点和功能,给 backtrader 优化改进提供新的建议

  4. 写需规文档和设计文档放到这个文档的最下面,方便后续借鉴

thOth 项目简介

thOth 是一个 C++量化金融库,类似于 QuantLib 的设计,具有以下核心特点:

  • C++实现: 高性能 C++实现

  • 金融数学: 丰富的金融数学模型

  • 定价模型: 衍生品定价模型

  • 时间序列: 时间序列分析工具

  • 日期处理: 完善的日期和日历处理

  • 数值方法: 数值计算方法库

重点借鉴方向

  1. 金融模型: 金融数学模型实现

  2. 定价引擎: 衍生品定价引擎

  3. 时间序列: 时间序列分析

  4. 日期日历: 日期和交易日历

  5. 数值方法: 数值计算方法

  6. C++设计: C++设计模式借鉴


架构对比分析

Backtrader 核心特点

  • 优势:*

  1. 成熟的 Line 系统: 基于循环缓冲区的高效时间序列数据管理

  2. 完整的回测引擎: Cerebro 统一管理策略、数据、经纪商、分析器

  3. 丰富的技术指标: 60+内置技术指标

  4. 性能优化: 支持向量化(once 模式)和事件驱动(next 模式)双执行模式

  5. Cython 加速: 关键路径使用 Cython 优化

  6. 多市场支持: 支持股票、期货、加密货币等多种市场

  7. Python 优先: 纯 Python 实现,易于扩展和定制

  • 局限:*

  1. 事件系统简单: 缺少完整的观察者模式实现

  2. 日历系统简陋: 只有简单的交易日历

  3. 惰性计算缺失: 指标每次都重新计算

  4. Excel 集成: 缺少 Excel 集成

  5. 日期处理: 日期处理功能有限

  6. 动态更新: 策略更新需要重新创建

thOth 核心特点

  • 优势:*

  1. 观察者模式: 完整的 Observable/Observer 模式实现

  2. 可重链接句柄: 支持动态策略更新

  3. 惰性对象: 按需计算和结果缓存

  4. 日历系统: 桥接模式的日历系统

  5. 工作日惯例: 支持多种工作日调整惯例

  6. Excel 集成: 内置 Excel 日期转换

  7. 时间序列: 模板化的时间序列容器

  8. C++性能: 高性能 C++实现

  • 局限:*

  1. 语言门槛: C++开发门槛高

  2. 生态较小: 相比 Python 生态不够成熟

  3. 文档较少: 英文文档为主

  4. GUI 绑定: 与 MFC 绑定,跨平台受限


需求规格文档

1. 观察者模式增强 (优先级: 高)

  • 需求描述:*

引入完整的观察者模式,改进事件分发机制。

  • 功能需求:*

  1. Observable 基类: 可观察对象基类

  2. Observer 接口: 观察者接口

  3. 自动通知: 数据变化自动通知观察者

  4. 双向注册: 观察者与被观察者双向管理

  5. 异常安全: 通知过程中的异常处理

  • 非功能需求:*

  1. 不影响现有性能

  2. 向后兼容现有代码

2. 惰性计算系统 (优先级: 高)

  • 需求描述:*

引入惰性计算模式,缓存计算结果避免重复计算。

  • 功能需求:*

  1. LazyObject: 惰性计算对象基类

  2. 计算缓存: 缓存计算结果

  3. 失效机制: 数据变化时使缓存失效

  4. 冻结/解冻: 手动控制计算时机

  5. 性能监控: 计算次数统计

  • 非功能需求:*

  1. 内存占用可控

  2. 不影响实时性要求高的场景

3. 增强日历系统 (优先级: 中)

  • 需求描述:*

改进交易日历系统,支持更多市场和工作日惯例。

  • 功能需求:*

  1. 日历基类: 抽象日历接口

  2. 多市场支持: 不同市场的交易日历

  3. 工作日惯例: following/preceding/modified 等

  4. 节假日管理: 支持添加/移除节假日

  5. 周末处理: 灵活的周末定义

  • 非功能需求:*

  1. 保持现有 API 兼容

  2. 支持自定义日历

4. 可重链接句柄 (优先级: 中)

  • 需求描述:*

引入句柄系统,支持策略组件动态替换。

  • 功能需求:*

  1. Handle 类: 可重链接的句柄

  2. 动态更新: 运行时更换策略组件

  3. 引用追踪: 自动追踪所有句柄引用

  4. 通知传播: 更新后自动通知观察者

  • 非功能需求:*

  1. 类型安全

  2. 内存安全

5. Excel 集成 (优先级: 低)

  • 需求描述:*

提供 Excel 集成功能,方便数据分析。

  • 功能需求:*

  1. 日期转换: Excel 日期序列号转换

  2. 数据导出: 导出为 Excel 格式

  3. UDF 支持: Excel 用户自定义函数

  4. 实时更新: 支持 Excel 实时数据更新

6. 时间序列增强 (优先级: 低)

  • 需求描述:*

改进时间序列数据管理。

  • 功能需求:*

  1. 观察者支持: 时间序列变化自动通知

  2. 高效查找: 基于日期的高效查找

  3. 插入通知: 新数据插入自动通知

  4. 类型安全: 模板化的类型安全


设计文档

1. 观察者模式设计

1.1 观察者基类


# backtrader/observer/base.py

from typing import Set, List, Optional, Callable
from abc import ABC, abstractmethod

class Observer(ABC):
    """
    观察者基类

    接收来自被观察对象的更新通知
    """

    def __init__(self):
        self._observables: Set['Observable'] = set()

    def register_with(self, observable: 'Observable') -> bool:
        """
        注册到被观察对象

        Args:
            observable: 被观察对象

        Returns:
            是否成功注册
        """
        if observable not in self._observables:
            success = observable.register_observer(self)
            if success:
                self._observables.add(observable)
                return True
        return False

    def unregister_from(self, observable: 'Observable') -> bool:
        """
        从被观察对象注销

        Args:
            observable: 被观察对象

        Returns:
            是否成功注销
        """
        if observable in self._observables:
            count = observable.unregister_observer(self)
            if count > 0:
                self._observables.discard(observable)
                return True
        return False

    def unregister_from_all(self) -> None:
        """从所有被观察对象注销"""
        for observable in list(self._observables):
            self.unregister_from(observable)

    @abstractmethod
    def update(self, observable: 'Observable', event=None) -> None:
        """
        接收更新通知

        Args:
            observable: 发送通知的被观察对象
            event: 事件数据
        """
        raise NotImplementedError


class Observable:
    """
    被观察对象基类

    管理观察者并发送更新通知
    """

    def __init__(self):
        self._observers: Set[Observer] = set()

    def register_observer(self, observer: Observer) -> bool:
        """
        注册观察者

        Args:
            observer: 观察者对象

        Returns:
            是否是新注册的观察者
        """
        if observer not in self._observers:
            self._observers.add(observer)
            return True
        return False

    def unregister_observer(self, observer: Observer) -> int:
        """
        注销观察者

        Args:
            observer: 观察者对象

        Returns:
            剩余观察者数量
        """
        self._observers.discard(observer)
        return len(self._observers)

    def notify_observers(self, event=None) -> None:
        """
        通知所有观察者

        Args:
            event: 事件数据
        """

# 创建观察者列表副本,避免通知过程中修改
        observers = list(self._observers)

        for observer in observers:
            try:
                observer.update(self, event)
            except Exception:

# 观察者异常不影响其他观察者
                pass

    @property
    def observer_count(self) -> int:
        """获取观察者数量"""
        return len(self._observers)

```bash

#### 1.2 在现有类中集成观察者模式

```python

# backtrader/lineseries.py 中添加观察者支持

from backtrader.observer.base import Observable

class LineSeries(Observable):
    """
    带观察者支持的 LineSeries

    数据变化时自动通知观察者
    """

    def __init__(self):
        super().__init__()
        self._last_notified_len = 0

    def home(self) -> None:
        """将当前点设为基准点"""
        super().home()

# 通知观察者数据已重置
        self.notify_observers(event={'type': 'home'})

    def advance(self) -> None:
        """前进一步"""
        super().advance()

# 只通知新增的数据点
        if len(self) > self._last_notified_len:
            self.notify_observers(event={
                'type': 'advance',
                'from': self._last_notified_len,
                'to': len(self)
            })
            self._last_notified_len = len(self)

```bash

### 2. 惰性计算系统设计

```python

# backtrader/lazy/base.py

from typing import Dict, Any
from datetime import datetime

class LazyObject:
    """
    惰性计算对象基类

    只有在需要时才计算结果,并缓存计算结果
    """

    def __init__(self):
        self._calculated = False
        self._frozen = False
        self._result = None
        self._calc_count = 0  # 计算次数统计

    def calculate(self) -> Any:
        """
        执行计算(如果需要)

        Returns:
            计算结果
        """
        if not self._calculated and not self._frozen:
            self._perform_calculation()
            self._calculated = True
            self._calc_count += 1

        return self._result

    def freeze(self) -> None:
        """冻结对象,停止自动计算"""
        self._frozen = True

    def unfreeze(self) -> None:
        """解冻对象,清除缓存"""
        self._frozen = False
        self._calculated = False
        self._result = None

    def is_calculated(self) -> bool:
        """是否已计算"""
        return self._calculated

    @property
    def calculation_count(self) -> int:
        """获取计算次数"""
        return self._calc_count

    def _perform_calculation(self) -> None:
        """
        执行实际计算

        子类实现此方法
        """
        raise NotImplementedError

    def _set_result(self, result: Any) -> None:
        """设置计算结果"""
        self._result = result

    def _invalidate(self) -> None:
        """使缓存失效"""
        self._calculated = False
        self._result = None


class LazyIndicator(LazyObject):
    """
    惰性计算指标

    基于现有 Indicator 添加惰性计算支持
    """

    def __init__(self, indicator):
        super().__init__()
        self._indicator = indicator
        self._data_len_snapshot = 0

    def _perform_calculation(self) -> None:
        """执行指标计算"""

# 使用原始指标计算
        result = []
        for i in range(len(self._indicator)):
            result.append(self._indicator[i])
        self._set_result(result)
        self._data_len_snapshot = len(self._indicator)

    def is_stale(self) -> bool:
        """
        检查数据是否已过期

        Returns:
            如果底层数据长度变化则返回 True
        """
        return len(self._indicator) != self._data_len_snapshot

    def calculate_if_needed(self) -> Any:
        """仅在需要时计算"""
        if self.is_stale():
            self.unfreeze()  # 清除缓存
        return self.calculate()

```bash

### 3. 增强日历系统设计

```python

# backtrader/calendar/base.py

from typing import Set, List, Optional
from datetime import date, datetime, timedelta
from enum import Enum

class BusinessDayConvention(Enum):
    """工作日调整惯例"""
    FOLLOWING = "following"              # 顺延到下一个工作日
    MODIFIED_FOLLOWING = "modified_following"  # 修正顺延
    PRECEDING = "preceding"              # 提前到上一个工作日
    MODIFIED_PRECEDING = "modified_preceding"  # 修正提前
    UNADJUSTED = "unadjusted"            # 不调整


class TradingCalendar:
    """
    交易日历基类

    管理交易日和节假日
    """

    def __init__(self, name: str = "default"):
        self.name = name
        self._weekend_days: Set[int] = set()  # 0=周一, 6=周日
        self._holidays: Set[date] = set()
        self._added_holidays: Set[date] = set()
        self._removed_holidays: Set[date] = set()

    def is_weekend(self, dt: date) -> bool:
        """
        检查是否是周末

        Args:
            dt: 日期

        Returns:
            是否是周末
        """
        return dt.weekday() in self._weekend_days

    def is_holiday(self, dt: date) -> bool:
        """
        检查是否是节假日

        Args:
            dt: 日期

        Returns:
            是否是节假日
        """
        if dt in self._removed_holidays:
            return False
        if dt in self._added_holidays:
            return True
        return dt in self._holidays

    def is_business_day(self, dt: date) -> bool:
        """
        检查是否是工作日

        Args:
            dt: 日期

        Returns:
            是否是工作日
        """
        return not (self.is_weekend(dt) or self.is_holiday(dt))

    def add_holiday(self, dt: date) -> None:
        """添加节假日"""
        self._added_holidays.add(dt)

    def remove_holiday(self, dt: date) -> None:
        """移除节假日"""
        self._removed_holidays.add(dt)

    def adjust(self, dt: date,
               convention: BusinessDayConvention = BusinessDayConvention.FOLLOWING) -> date:
        """
        调整到工作日

        Args:
            dt: 日期
            convention: 调整惯例

        Returns:
            调整后的日期
        """
        if convention == BusinessDayConvention.UNADJUSTED:
            return dt

        if self.is_business_day(dt):
            return dt

        if convention == BusinessDayConvention.FOLLOWING:
            return self._next_business_day(dt)
        elif convention == BusinessDayConvention.PRECEDING:
            return self._prev_business_day(dt)
        elif convention == BusinessDayConvention.MODIFIED_FOLLOWING:
            next_day = self._next_business_day(dt)
            if next_day.month != dt.month:
                return self._prev_business_day(dt)
            return next_day
        elif convention == BusinessDayConvention.MODIFIED_PRECEDING:
            prev_day = self._prev_business_day(dt)
            if prev_day.month != dt.month:
                return self._next_business_day(dt)
            return prev_day

        return dt

    def _next_business_day(self, dt: date) -> date:
        """获取下一个工作日"""
        next_dt = dt + timedelta(days=1)
        while not self.is_business_day(next_dt):
            next_dt += timedelta(days=1)
        return next_dt

    def _prev_business_day(self, dt: date) -> date:
        """获取上一个工作日"""
        prev_dt = dt - timedelta(days=1)
        while not self.is_business_day(prev_dt):
            prev_dt -= timedelta(days=1)
        return prev_dt

    def business_days_between(self, start: date, end: date) -> List[date]:
        """
        获取两个日期之间的所有工作日

        Args:
            start: 开始日期
            end: 结束日期

        Returns:
            工作日列表
        """
        if start > end:
            start, end = end, start

        days = []
        current = start
        while current <= end:
            if self.is_business_day(current):
                days.append(current)
            current += timedelta(days=1)
        return days

    def n_business_days(self, start: date, end: date) -> int:
        """计算工作日数量"""
        return len(self.business_days_between(start, end))


class UnitedStatesCalendar(TradingCalendar):
    """美国交易日历"""

    def __init__(self, market: str = "NYSE"):
        super().__init__(f"US-{market}")
        self.market = market

# 周末是周六(5)和周日(6)
        self._weekend_days = {5, 6}

# 常见美国节假日(需要每年更新)
        self._setup_holidays()

    def _setup_holidays(self) -> None:
        """设置美国节假日"""

# 新年

# 马丁路德金日

# 总统日

# 阵亡将士纪念日

# 独立日

# 劳动节

# 哥伦布日

# 退伍军人日

# 感恩节

# 圣诞节
        pass


class ChinaCalendar(TradingCalendar):
    """中国交易日历"""

    def __init__(self):
        super().__init__("CN")

# 周末是周六(5)和周日(6)
        self._weekend_days = {5, 6}

# 中国节假日(春节、清明、劳动节、端午、中秋、国庆)
        self._setup_holidays()

    def _setup_holidays(self) -> None:
        """设置中国节假日"""

# 需要每年更新
        pass

```bash

### 4. 可重链接句柄设计

```python

# backtrader/handle/base.py

from typing import Optional, Callable
from weakref import WeakRef

class Handle:
    """
    可重链接句柄

    允许动态替换底层对象而不需要更新所有引用
    """

    def __init__(self, target=None):
        """
        初始化句柄

        Args:
            target: 目标对象
        """
        self._target = target
        self._observers: List[Callable] = []

    def relink(self, new_target) -> None:
        """
        重链接到新目标

        Args:
            new_target: 新的目标对象
        """
        old_target = self._target
        self._target = new_target

# 通知观察者
        for observer in self._observers:
            observer(old_target, new_target)

    def get(self):
        """获取当前目标"""
        return self._target

    def __call__(self):
        """使句柄可调用"""
        return self._target

    def subscribe(self, callback: Callable) -> None:
        """
        订阅重链接事件

        Args:
            callback: 回调函数,接收(old_target, new_target)
        """
        self._observers.append(callback)

    def unsubscribe(self, callback: Callable) -> None:
        """取消订阅"""
        if callback in self._observers:
            self._observers.remove(callback)

    @property
    def is_empty(self) -> bool:
        """是否为空句柄"""
        return self._target is None


class StrategyHandle(Handle):
    """
    策略句柄

    允许在运行时动态替换策略
    """

    def __init__(self, strategy=None):
        super().__init__(strategy)
        self._active_params = {}

    def relink(self, new_strategy) -> None:
        """重链接到新策略"""

# 保存当前参数
        if self._target is not None:
            self._active_params = self._target.params._getpairs()
        else:
            self._active_params = {}

        super().relink(new_strategy)

# 恢复参数到新策略
        if new_strategy is not None:
            for key, value in self._active_params.items():
                setattr(new_strategy.params, key, value)

    def update_params(self, **params) -> None:
        """更新策略参数"""
        if self._target is not None:
            for key, value in params.items():
                setattr(self._target.params, key, value)
            self._active_params.update(params)

# 触发策略重新计算
            self._target.params recalculated = True

    @property
    def strategy(self):
        """获取当前策略"""
        return self._target

```bash

### 5. Excel 集成设计

```python

# backtrader/excel/utils.py

from datetime import datetime, date
import pandas as pd

class ExcelDateConverter:
    """
    Excel 日期转换器

    支持 Excel 日期序列号与 Python 日期互转
    """

# Excel 基准日期: 1900 年 1 月 1 日 (实际上 Excel 错误地认为 1900 是闰年)
    EXCEL_EPOCH = date(1899, 12, 30)
    SECONDS_PER_DAY = 86400

    @classmethod
    def date_to_excel(cls, dt: date) -> float:
        """
        转换日期为 Excel 日期序列号

        Args:
            dt: Python 日期

        Returns:
            Excel 日期序列号

        Excel 日期序列号是从 1899-12-30 开始计算的天数
        """
        if isinstance(dt, datetime):
            dt = dt.date()

        delta = dt - cls.EXCEL_EPOCH
        return float(delta.days)

    @classmethod
    def excel_to_date(cls, excel_date: float) -> date:
        """
        转换 Excel 日期序列号为 Python 日期

        Args:
            excel_date: Excel 日期序列号

        Returns:
            Python 日期
        """
        return cls.EXCEL_EPOCH + timedelta(days=int(excel_date))

    @classmethod
    def datetime_to_excel(cls, dt: datetime) -> float:
        """
        转换日期时间为 Excel 日期序列号

        Args:
            dt: Python 日期时间

        Returns:
            Excel 日期序列号(带小数部分表示时间)
        """
        date_part = cls.date_to_excel(dt.date())
        time_part = (dt.hour *3600 + dt.minute*60 + dt.second) / cls.SECONDS_PER_DAY
        return date_part + time_part

    @classmethod
    def excel_to_datetime(cls, excel_date: float) -> datetime:
        """
        转换 Excel 日期序列号为 Python 日期时间

        Args:
            excel_date: Excel 日期序列号

        Returns:
            Python 日期时间
        """
        date_part = int(excel_date)
        time_part = excel_date - date_part

        base_date = cls.excel_to_date(date_part)
        seconds = int(time_part* cls.SECONDS_PER_DAY)

        hour = seconds // 3600
        minute = (seconds % 3600) // 60
        second = seconds % 60

        return datetime.combine(base_date, datetime.min.time()) + timedelta(
            hours=hour, minutes=minute, seconds=second
        )

    @classmethod
    def datetime_to_sql(cls, dt: datetime, microseconds: bool = False) -> str:
        """
        转换为 SQL 日期时间格式

        Args:
            dt: 日期时间
            microseconds: 是否包含微秒

        Returns:
            SQL 格式的日期时间字符串
        """
        if microseconds:
            return dt.strftime("%Y-%m-%d %H:%M:%S.%f")
        else:
            return dt.strftime("%Y-%m-%d %H:%M:%S")

    @classmethod
    def sql_to_datetime(cls, sql_str: str) -> datetime:
        """
        从 SQL 格式解析日期时间

        Args:
            sql_str: SQL 格式的日期时间字符串

        Returns:
            Python 日期时间
        """

# 尝试多种格式
        formats = [
            "%Y-%m-%d %H:%M:%S.%f",
            "%Y-%m-%d %H:%M:%S",
            "%Y-%m-%d",
            "%Y-%m-%dT%H:%M:%S",
            "%Y-%m-%dT%H:%M:%S.%f",
        ]

        for fmt in formats:
            try:
                return datetime.strptime(sql_str, fmt)
            except ValueError:
                continue

        raise ValueError(f"无法解析日期时间: {sql_str}")


class ExcelExporter:
    """
    Excel 导出器

    将 backtrader 结果导出为 Excel 格式
    """

    def __init__(self, cerebro):
        self.cerebro = cerebro
        self.converter = ExcelDateConverter()

    def export_to_dataframe(self) -> pd.DataFrame:
        """
        导出为 DataFrame

        Returns:
            包含策略结果的数据框
        """
        strategies = self.cerebro.runstrats
        if not strategies:
            return pd.DataFrame()

        strat = strategies[0]

# 获取时间序列数据
        data = {}

# 获取日期数据
        dates = list(strat.datas[0].datetime.date())
        data['date'] = dates
        data['excel_date'] = [self.converter.date_to_excel(d) for d in dates]

# 获取净值曲线
        if hasattr(strat, 'stats'):
            data['value'] = strat.stats.broker.getvalue()

        return pd.DataFrame(data)

    def export_to_excel(self, filename: str) -> None:
        """
        导出到 Excel 文件

        Args:
            filename: 输出文件名
        """
        try:
            import openpyxl
            from openpyxl.utils.dataframe import dataframe_to_rows
        except ImportError:
            raise ImportError("需要安装 openpyxl: pip install openpyxl")

        df = self.export_to_dataframe()

        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = "Strategy Results"

# 写入数据
        for row in dataframe_to_rows(df, index=False, header=True):
            ws.append(row)

        wb.save(filename)

    @staticmethod
    def export_pandas_to_excel(df: pd.DataFrame, filename: str, sheet_name: str = "Sheet1") -> None:
        """
        导出 DataFrame 到 Excel

        Args:
            df: 数据框
            filename: 文件名
            sheet_name: 工作表名
        """
        try:
            import openpyxl
        except ImportError:
            raise ImportError("需要安装 openpyxl: pip install openpyxl")

        wb = openpyxl.Workbook()
        ws = wb.active
        ws.title = sheet_name

# 写入标题
        for col_idx, column in enumerate(df.columns, 1):
            ws.cell(row=1, column=col_idx, value=column)

# 写入数据
        for row_idx, (_, row) in enumerate(df.iterrows(), 2):
            for col_idx, value in enumerate(row, 1):
                ws.cell(row=row_idx, column=col_idx, value=value)

        wb.save(filename)

```bash

### 6. 使用示例

```python
import backtrader as bt
from backtrader.observer.base import Observer, Observable
from backtrader.lazy.base import LazyIndicator
from backtrader.calendar.base import TradingCalendar, BusinessDayConvention, UnitedStatesCalendar

# 1. 使用观察者模式

class MyObserver(Observer):
    def update(self, observable, event=None):
        print(f"收到更新通知: {observable.__class__.__name__}, 事件: {event}")

class MyStrategy(bt.Strategy, Observer):
    def __init__(self):
        super().__init__()

# 观察数据源
        self.data = self.datas[0]
        self.data.register_with(self)

    def next(self):

# 正常策略逻辑
        if len(self.data) > 20:
            if self.data.close[0] > self.data.close[-1]:
                self.buy()

    def update(self, observable, event=None):

# 接收数据更新通知
        if event and event.get('type') == 'advance':
            print(f"数据更新到: {event['to']}")

# 2. 使用惰性计算

class LazySMA(bt.Indicator):
    _forcecalculate = False

    def __init__(self, data, period):
        super().__init__()
        self.data = data
        self.period = period
        self.lazy_calc = LazyIndicator(self)

    def next(self):

# 只有在需要时才重新计算
        if self.lazy_calc.is_stale():
            self.lazy_calc.unfreeze()
            result = self.lazy_calc.calculate()
            self.line[0] = result[-1] if result else 0
        else:

# 使用缓存值
            pass

# 3. 使用交易日历

cerebro = bt.Cerebro()

# 设置美国交易日历

us_calendar = UnitedStatesCalendar(market="NYSE")

# 检查日期是否是工作日

test_date = date(2024, 1, 15)
print(f"是否工作日: {us_calendar.is_business_day(test_date)}")

# 调整到下一个工作日

adjusted = us_calendar.adjust(test_date, BusinessDayConvention.FOLLOWING)
print(f"调整后日期: {adjusted}")

# 4. 使用 Excel 导出

cerebro.addstrategy(MyStrategy)
cerebro.run()

# 导出到 Excel

from backtrader.excel.utils import ExcelExporter
exporter = ExcelExporter(cerebro)
exporter.export_to_excel("strategy_results.xlsx")

```bash

### 7. 实施路线图

#### 阶段 1: 观察者模式 (1-2 周)

- [ ] 实现 Observable 基类
- [ ] 实现 Observer 接口
- [ ]  LineSeries 中集成通知
- [ ] 单元测试

#### 阶段 2: 惰性计算 (1-2 周)

- [ ] 实现 LazyObject 基类
- [ ] 实现 LazyIndicator
- [ ] 缓存失效机制
- [ ] 性能测试

#### 阶段 3: 交易日历 (2 周)

- [ ] 实现 TradingCalendar 基类
- [ ] 实现 UnitedStatesCalendar
- [ ] 实现 ChinaCalendar
- [ ] 集成到 Cerebro

#### 阶段 4: 句柄系统 (1 周)

- [ ] 实现 Handle 基类
- [ ] 实现 StrategyHandle
- [ ] 参数管理
- [ ] 单元测试

#### 阶段 5: Excel 集成 (1 周)

- [ ] 实现 Excel 日期转换
- [ ] 实现 ExcelExporter
- [ ] 文档和示例

#### 阶段 6: 集成测试 (1 周)

- [ ] 端到端测试
- [ ] 性能对比
- [ ] 文档完善

- --

## 附录: 关键文件路径

### Backtrader 关键文件

- `cerebro.py`: 核心引擎
- `strategy.py`: Strategy 基类
- `lineseries.py`: LineSeries 基类
- `lineiterator.py`: LineIterator 基类
- `utils/`: 工具函数

### thOth 关键文件

- `thOth/pattern/observable.hpp`: 被观察对象
- `thOth/pattern/observer.hpp`: 观察者接口
- `thOth/pattern/lazyObject.hpp`: 惰性对象
- `thOth/time/calendar.hpp`: 日历基类
- `thOth/time/calendars/unitedStates.hpp`: 美国日历
- `thOth/time/timeSeries.hpp`: 时间序列
- `thOth/time/dateTime.hpp`: 日期时间