deltaforge-real-time-cross-.../deltaforge/backtester.py

51 lines
1.9 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import Dict, List, Any
@dataclass
class BacktestResult:
pnl: float
trades: int
timestamp: datetime
def backtest(plan_delta: dict, initial_capital: float = 100000.0) -> BacktestResult:
# Very simple deterministic replay: PnL proportional to sum of absolute deltas
total_delta = sum(abs(v) for v in (plan_delta or {}).values())
pnl = initial_capital * 0.0001 * total_delta # toy PnL model
return BacktestResult(pnl=pnl, trades=len(plan_delta or {}), timestamp=datetime.utcnow())
class Backtester:
def __init__(self, initial_cash: float = 0.0, seed: int | None = None):
self.initial_cash = initial_cash
self.seed = seed
def apply(self, signals: List[Any], plan) -> float:
# Deterministic, minimal cash-impact calculation based on plan.deltas or plan.delta
total_cost = 0.0
deltas: List[Any] = []
if plan is not None:
if getattr(plan, "deltas", None):
deltas = plan.deltas # type: ignore
elif getattr(plan, "delta", None):
deltas = plan.delta # type: ignore
for item in deltas:
if isinstance(item, dict):
s = item.get("size", 0.0)
p = item.get("price", 0.0)
total_cost += abs(float(s)) * float(p)
# If item is a StrategyDelta, accumulate its delta_positions if provided
elif hasattr(item, "delta_positions") and isinstance(item.delta_positions, dict): # type: ignore
# Without explicit prices, assume no cost from these in this toy model
pass
return float(self.initial_cash) - total_cost
def replay(self, signals: List[Any], plan) -> float:
# Alias for compatibility with tests that call replay
return self.apply(signals, plan)