Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
- [x] `batch_equity_summary()` 已提供简单资金曲线摘要。
- [x] `margin_utilization_summary()` 已提供批量持仓保证金占用率统计。
- [x] `run_daily_position_mark()` 已提供单笔持仓逐日盯市与保证金估算。
- [ ] 在完整组合持仓/资金引擎中合并多笔持仓逐日保证金监控。
- [x] `portfolio_daily_margin()` 已支持多笔持仓逐日合并盯市与保证金监控。
- [ ] 在完整组合资金引擎中接入融资/资金费率与更多组合约束。
- [x] T+1 close 执行近似已加入 `backtest --t1-close`(仍非 open/settle,真实缺口待合约数据接入)。
- [x] `summarize_roll_costs()` 已提供合约级可量化换月 gap 成本统计。
- [x] 真实换月 gap 成本可作为 `--roll-cost-bps` 附加到 `backtest`/`evidence`。
Expand Down Expand Up @@ -71,4 +72,4 @@

当前测试:`PYTHONPATH=src python3 -m unittest discover -s tests -v`

当前通过:102 tests OK。
当前通过:103 tests OK。
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@
- `formal_v2.generate_v2_formal_report()`:协议 v2 正式验收前的可审计报告入口;
- `margin_utilization_summary()`:批量持仓保证金占用率统计;
- `formal` CLI:输出双因子 v2 正式验收前报告;
- `run_daily_position_mark()`:单笔持仓逐日盯市与保证金占用估算。
- `run_daily_position_mark()`:单笔持仓逐日盯市与保证金占用估算;
- `portfolio_daily_margin()`:多笔持仓逐日合并盯市与保证金监控。

## [0.1.0-rc1] - 2026-09-02

Expand Down
59 changes: 59 additions & 0 deletions src/goratio/margin.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,3 +299,62 @@ def run_daily_position_mark(
"rows": rows,
"note": "逐日盯市研究模拟,不构成交易建议",
}


def portfolio_daily_margin(
records,
positions,
*,
initial_capital: float = 100000.0,
) -> dict:
"""合并多笔持仓的逐日盯市与保证金占用。

positions: [{"instrument": "gold"/"oil", "entry_date": date,
"exit_date": date, "direction": 1/-1, "lots": int}]
"""
from collections import defaultdict
from datetime import date

daily_map = defaultdict(lambda: {"margin": 0.0, "pnl": 0.0, "count": 0})
rows_by_position = []
for position in positions:
result = run_daily_position_mark(
records,
instrument=position["instrument"],
entry_date=position["entry_date"],
exit_date=position["exit_date"],
direction=position["direction"],
lots=position["lots"],
)
rows_by_position.append(result)
for row in result["rows"]:
d = row["date"]
daily_map[d]["margin"] += row["margin_estimate"]
daily_map[d]["pnl"] += row["cumulative_pnl"]
daily_map[d]["count"] += 1
Comment on lines +315 to +334
daily_rows = []
peak = initial_capital
max_drawdown = 0.0
for d in sorted(daily_map):
record = daily_map[d]
equity = initial_capital + record["pnl"]
peak = max(peak, equity)
max_drawdown = max(max_drawdown, peak - equity)
daily_rows.append(
{
"date": d,
"total_margin": record["margin"],
"total_pnl": record["pnl"],
"equity": equity,
"position_count": record["count"],
}
)
return {
"initial_capital": initial_capital,
"day_count": len(daily_rows),
"daily_rows": daily_rows,
"final_equity": daily_rows[-1]["equity"] if daily_rows else initial_capital,
"max_drawdown": max_drawdown,
"rows_by_position": rows_by_position,
"note": "多笔持仓逐日合并盯市研究模拟,不构成交易建议",
}
42 changes: 42 additions & 0 deletions tests/test_margin.py
Original file line number Diff line number Diff line change
Expand Up @@ -193,5 +193,47 @@ def test_run_daily_position_mark_tracks_roll(self) -> None:
self.assertGreater(result["rows"][1]["margin_estimate"], 0)


def test_portfolio_daily_margin_aggregates(self) -> None:
from goratio.margin import portfolio_daily_margin

records = [
ContractRecord(
date=date(2024, 1, 2), instrument="gold", symbol="GC",
contract_month="2024-02", close=2000.0,
volume=100, open_interest=50,
),
ContractRecord(
date=date(2024, 1, 3), instrument="gold", symbol="GC",
contract_month="2024-02", close=2010.0,
volume=80, open_interest=40,
),
ContractRecord(
date=date(2024, 1, 3), instrument="gold", symbol="GC",
contract_month="2024-04", close=2020.0,
volume=200, open_interest=300,
),
ContractRecord(
date=date(2024, 1, 4), instrument="gold", symbol="GC",
contract_month="2024-04", close=2030.0,
volume=250, open_interest=400,
),
]
positions = [
{
"instrument": "gold",
"entry_date": date(2024, 1, 2),
"exit_date": date(2024, 1, 4),
"direction": 1,
"lots": 1,
}
]

summary = portfolio_daily_margin(records, positions)

self.assertEqual(summary["day_count"], 3)
self.assertGreater(summary["final_equity"], 100000.0)
self.assertGreater(summary["daily_rows"][0]["total_margin"], 0)
Comment on lines +221 to +235


if __name__ == "__main__":
unittest.main()