# positionbt
**Repository Path**: xin123123/positionbt
## Basic Information
- **Project Name**: positionbt
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-04-17
- **Last Updated**: 2026-04-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# PositionBT
PositionBT 是一个专注于基于仓位数据进行策略回测的 Python 库。这个库的设计理念是"简单即是美",致力于提供一个轻量级但功能强大的回测框架。
> 注意:当前版本仅支持单个交易品种的回测。多品种回测功能正在开发中,将在未来版本中推出。
## 特点
* 简单易用
- 有别于传统回测框架需要处理繁琐的订单、手续费和滑点模型,PositionBT 采用规范化的仓位数据进行回测,大幅简化了使用流程。
- 仓位采用标准化设计,从 -1(满仓做空)到 1(满仓做多)的直观刻度,让策略评估更加清晰明确。
- 专注于策略核心逻辑的验证,避免在交易执行细节上耗费过多精力,提升策略研发效率。
* 高性能
- 基于 Polars 构建,提供极速的数据处理能力。
- 优化计算流程,避免重复计算,提高回测效率。
* 可视化
- 集成 `plotly` 打造专业的可视化模块,提供丰富的交互式分析功能。
- 支持多种查看方式:可通过浏览器实时预览回测报告,或导出为 HTML 文件便于分享与存档。
* 可扩展性
- 灵活的指标系统:支持自定义性能评估指标。
- 丰富的可视化选项:支持自定义图表类型,可实现策略绩效曲线、回撤分析、持仓分布等多维度分析展示。
- 开放的接口设计:便于用户扩展和集成自己的分析工具,打造个性化的回测分析流程。
## 性能测试
为了展示 PositionBT 的性能表现,我们使用了一个真实的大规模数据集进行测试:
### 测试数据集
* 文件:data/btc_ohlcv_1m.parquet
* 时间范围:2017年8月17日 至 2024年12月22日
* 数据类型:1分钟K线数据
* 数据量:2,682,218条记录
### 测试环境
* 硬件:Mac Mini (M4芯片)
* 内存:16 GB
* 硬盘:256 GB
### 性能结果
* 回测耗时:0.14 秒
* 数据处理速度:19,158,700 条/秒
这个测试结果表明,PositionBT 能够高效处理大规模的历史数据,为策略验证提供快速的反馈。即使面对数百万级别的数据量,其性能表现依然保持稳定。
> 注:测试结果可能会因硬件配置和数据特征而有所差异。
## 安装
```bash
pip install positionbt
```
## 快速开始
### 买入持有策略示例
#### 代码
下面展示了一个简单的策略回测示例:在整个回测期间保持 BTC 满仓多头持仓。这个示例演示了 PositionBT 的基本用法,包括数据加载、回测执行和结果可视化的完整流程。
```python
import polars as pl
from examples.data_loader import load_close_data
from positionbt import BacktestVisualizer, PositionBacktester
# Load BTC close data
close_df = load_close_data()
# Generate position data
position_df = close_df.select(pl.col("time")).with_columns(pl.lit(1).alias("position"))
# Initialize backtester with parameters
backtester = PositionBacktester(
close_df=close_df,
commission_rate=0.001, # 0.1% commission rate
annual_trading_days=365, # Use 365 trading days per year
indicators="all", # Calculate all available indicators
)
# Run backtest
backtest_result = backtester.run(position_df)
# Print backtest results in tabular format
backtest_result.print()
# Create visualizer and show results in browser
visualizer = BacktestVisualizer()
visualizer.show_in_browser(backtest_result, backtester.params)
```
#### 结果
回测结果:

回测报告:

### 自定义指标示例
#### 代码
PositionBT 支持自定义指标,用户可以根据需要添加自己的指标进行回测。打印回测结果,或者输出回测报告时,自定义指标会直接显示。
```python
import polars as pl
from examples.data_loader import load_close_data
from positionbt import BaseIndicator, PositionBacktester, indicator_registry
class MonthlyReturn(BaseIndicator):
"""Monthly return indicator"""
@property
def name(self) -> str:
return "monthly_return"
@property
def requires(self) -> set[str]:
# Depends on annual return
return {"annual_return"}
def calculate(self, cache: dict) -> float:
"""Calculate monthly return
Calculation method:
1. Convert from annual return
2. Using formula: (1 + r_annual)^(1/12) - 1
Args:
cache: Dictionary containing calculation cache
Returns:
Monthly return value
"""
if "monthly_return" not in cache:
annual_return = cache["annual_return"]
monthly_return = (1 + annual_return) ** (1 / 12) - 1
cache["monthly_return"] = monthly_return
return cache["monthly_return"]
def format(self, value: float) -> str:
"""Format monthly return value as percentage
Args:
value: Monthly return value
Returns:
Formatted string with percentage
"""
return f"{value:.2%}"
# Register custom indicator
indicator_registry.register(MonthlyReturn())
# Load close data
close_df = load_close_data()
# Generate position data
position_df = close_df.select(pl.col("time")).with_columns(pl.lit(1).alias("position"))
# Create backtester instance (using all indicators including the newly registered monthly return)
backtester = PositionBacktester(
close_df=close_df,
commission_rate=0.001, # 0.1% commission rate
annual_trading_days=365, # Use 365 trading days per year
indicators=["monthly_return"], # Use all registered indicators
)
# Run backtest
results = backtester.run(position_df)
# Print results
results.print()
```
#### 结果
回测结果:

### 自定义可视化示例
#### 代码
PositionBT 支持自定义可视化,用户可以根据需要添加自己的可视化模块。
```python
import plotly.graph_objects as go
import polars as pl
from examples.data_loader import load_close_data
from positionbt import (
BacktestVisualizer,
BaseFigure,
PositionBacktester,
figure_registry,
)
class DrawdownFigure(BaseFigure):
"""Drawdown visualization figure"""
@property
def name(self) -> str:
return "drawdown"
@property
def title(self) -> str:
return "Strategy Drawdown"
def create(self) -> go.Figure:
"""Create drawdown figure
Returns:
Plotly figure object containing drawdown visualization
"""
# Calculate cumulative maximum of equity curve
cummax = self.equity_curve.get_column("equity_curve").cum_max()
# Calculate drawdown as percentage from peak
drawdown = (self.equity_curve.get_column("equity_curve") - cummax) / cummax
# Add drawdown trace to figure
self._fig.add_trace(
go.Scatter(
x=self.equity_curve.get_column("time"),
y=drawdown,
fill="tozeroy", # Fill area from line to zero
name="drawdown",
line=dict(color="red"),
)
)
# Update layout with percentage formatting
self._fig.update_layout(
yaxis=dict(
tickformat=".1%", # Format y-axis ticks as percentages
hoverformat=".2%", # Format hover text as percentages
),
)
return self._fig
# Register custom figure
figure_registry.register(DrawdownFigure)
# Load close data
close_df = load_close_data()
# Generate position data
position_df = close_df.select(pl.col("time")).with_columns(pl.lit(1).alias("position"))
# Initialize backtester
backtester = PositionBacktester(
close_df=close_df,
commission_rate=0.001, # 0.1% commission rate
annual_trading_days=365, # Use 365 trading days per year
indicators="all", # Calculate all available indicators
)
# Run backtest
backtest_result = backtester.run(position_df)
# Create visualizer and show results in browser
visualizer = BacktestVisualizer(figures=["drawdown"])
visualizer.show_in_browser(backtest_result, backtester.params)
```
#### 结果
回测报告:

## 支持的指标
| 指标名称 | 说明 | 计算方法 | 展示格式 | 指标ID |
|---------|------|---------|----------|---------|
| 总收益率 (Total Return) | 策略整体收益表现 | 最终净值/初始净值 - 1 | 百分比 (xx.xx%) | total_return |
| 年化收益率 (Annual Return) | 收益率年化后的表现 | (1 + 总收益率)^(365/实际天数) - 1 | 百分比 (xx.xx%) | annual_return |
| 波动率 (Volatility) | 收益率的年化标准差 | 收益率标准差 * √(年化周期) | 百分比 (xx.xx%) | volatility |
| 夏普比率 (Sharpe Ratio) | 风险调整后收益指标 | 年化收益率/年化波动率 | 小数 (xx.xx) | sharpe_ratio |
| 最大回撤 (Max Drawdown) | 最大净值回撤幅度 | (历史最高点 - 当前净值)/历史最高点 的最大值 | 百分比 (xx.xx%) | max_drawdown |
| 最大回撤持续期 (Max Drawdown Duration) | 最大回撤的持续时间 | 最大回撤期间的天数 | xx 天 | max_drawdown_duration |
| 胜率 (Win Rate) | 盈利交易占比 | 盈利交易次数/总交易次数 | 百分比 (xx.xx%) | win_rate |
| 平均回撤 (Avg Drawdown) | 回撤的平均值 | 所有非零回撤的算术平均值 | 百分比 (xx.xx%) | avg_drawdown |
| 盈亏比 (Profit Loss Ratio) | 平均盈利与平均亏损之比 | \|平均盈利\|/\|平均亏损\| | 小数 (xx.xx) 或 ∞ | profit_loss_ratio |
> 注:所有百分比指标均保留两位小数,比率指标保留两位小数。
## 支持的可视化
## 回测报告组件
### 图表组件
| 图表名称 | 组件ID | 说明 | 主要特点 |
|---------|--------|------|----------|
| 交易表现图 | trading_performance | 展示策略整体交易表现 | - 包含三个子图:净值曲线、收盘价和回撤
- 在净值曲线和收盘价图上标注交易点位
- 使用不同颜色和形状标记多空交易
- 支持交互式缩放查看 |
| 月度收益分布图 | monthly_returns | 展示策略月度收益分布 | - 使用柱状图展示每月收益
- 红绿双色区分盈亏
- 支持收益率精确查看
- 清晰展示月度收益的分布情况 |
| 周度收益热力图 | weekly_returns_heatmap | 展示策略周度收益分布 | - 类似 GitHub 贡献图的热力图展示
- 使用红蓝色系表示盈亏
- 支持周度收益的精确查看
- 直观展示收益的时间分布特征 |
| 仓位分析图 | position_analysis | 分析策略仓位特征 | - 包含三个子图:仓位频率分布、仓位收益率分布、仓位价格收益率分布
- 使用柱状图展示不同仓位区间的特征
- 支持交互式查看详细数据
- 帮助分析仓位与收益的关系 |
### 信息面板
| 面板类型 | 展示内容 | 说明 |
|---------|---------|------|
| 回测参数信息 | - 手续费率
- 年化交易天数
- 使用的指标 | 展示回测的基本设置参数 |
| 数据信息 | - 起始日期
- 结束日期
- 总天数
- 数据点数
- 数据频率 | 展示回测数据的基本信息 |
| 绩效指标 | - 总收益率
- 年化收益率
- 夏普比率
- 最大回撤
- 其他核心指标 | 以卡片形式展示策略的关键绩效指标 |
> 注:所有图表组件都支持交互式操作,可以放大、缩小、平移和导出图片。报告以 HTML 格式生成,可以通过浏览器直接查看或保存成 HTML 文件。
## API 参考
### 核心类
#### PositionBacktester
回测引擎的主类,用于执行策略回测。
```python
PositionBacktester(
close_df: pl.DataFrame,
commission_rate: float = 0.0,
annual_trading_days: int = 252,
indicators: Union[str, list[str]] = "all"
)
```
**参数说明:**
- `close_df`: 包含 `time` 和 `close` 列的 Polars DataFrame
- `commission_rate`: 交易手续费率,默认 0.0%
- `annual_trading_days`: 年化天数,默认 252
- `indicators`: 需要计算的指标,可以是 "all" 或指标名称列表
**主要方法:**
- `run(position_df: pl.DataFrame) -> BacktestResult`: 执行回测并返回结果
#### BacktestResult
回测结果的数据类,包含回测的所有结果数据。
**主要属性:**
- `equity_curve`: 净值曲线数据
- `indicator_values`: 指标计算结果
- `formatted_indicator_values`: 格式化后的指标值
**主要方法:**
- `print()`: 以表格形式打印回测结果
#### BacktestVisualizer
回测结果可视化器,用于生成交互式回测报告。
```python
BacktestVisualizer(
figures: Optional[list[str]] = None
)
```
**参数说明:**
- `figures`: 需要展示的图表列表(可选)
**主要方法:**
- `show_in_browser(results: BacktestResult, params: dict, notes: Optional[str] = None)`: 在浏览器中展示回测报告
- `generate_html_report(results: BacktestResult, params: dict, output_path: str, notes: Optional[str] = None)`: 生成 HTML 格式的回测报告
### 基类
#### BaseIndicator
指标计算的基类,用于自定义新的性能指标。
**必须实现的方法:**
- `name(self) -> str`: 返回指标名称
- `calculate(self, cache: dict) -> float`: 计算指标值
- `format(self, value: float) -> str`: 格式化指标值
**非必须实现的方法:**
* `requires(self) -> set[str]`: 依赖的指标
#### BaseFigure
可视化图表的基类,用于自定义新的图表类型。
**必须实现的方法:**
- `name(self) -> str`: 返回图表唯一标识符(需使用 @property 装饰器)
- `title(self) -> str`: 返回图表显示标题(需使用 @property 装饰器)
- `create(self) -> go.Figure`: 创建并返回 Plotly 图表对象
**初始化参数:**
- `results`: BacktestResult 对象,包含回测结果数据
**可用属性:**
- `results`: 回测结果对象
- `equity_curve`: 净值曲线数据
- `_fig`: 基础图表对象(包含默认布局设置)
### 注册器
#### indicator_registry
指标注册器,用于管理和获取可用的性能指标。
**主要方法:**
- `register(indicator_cls: Type[BaseIndicator])`: 注册新的指标
- `get(name: str) -> Type[BaseIndicator]`: 获取指标类
- `available_indicators`: 获取所有可用指标列表
#### figure_registry
图表注册器,用于管理和获取可用的可视化图表。
**主要方法:**
- `register(figure_cls: Type[BaseFigure])`: 注册新的图表
- `get(name: str) -> Type[BaseFigure]`: 获取图表类
- `available_figures`: 获取所有可用图表列表