Initial public release

This commit is contained in:
sinmb79
2026-03-30 13:19:11 +09:00
commit 92a692b63c
116 changed files with 5822 additions and 0 deletions

87
hydra/backtest/result.py Normal file
View File

@@ -0,0 +1,87 @@
# hydra/backtest/result.py
from dataclasses import dataclass, field
@dataclass
class Trade:
market: str
symbol: str
entry_price: float
exit_price: float
qty: float
pnl_usd: float
pnl_pct: float
entry_ts: int
exit_ts: int
entry_reason: str
exit_reason: str
@dataclass
class BacktestResult:
market: str
symbol: str
timeframe: str
since: int
until: int
initial_capital: float
final_equity: float
trades: list[Trade] = field(default_factory=list)
equity_curve: list[dict] = field(default_factory=list)
metrics: dict = field(default_factory=dict)
def compute_metrics(
trades: list[Trade],
equity_curve: list[dict],
initial_capital: float,
final_equity: float,
) -> dict:
total_return_pct = (final_equity - initial_capital) / initial_capital * 100
total_trades = len(trades)
if total_trades == 0:
return {
"total_return_pct": round(total_return_pct, 4),
"total_trades": 0,
"win_rate": 0.0,
"max_drawdown_pct": 0.0,
"sharpe_ratio": 0.0,
"avg_pnl_usd": 0.0,
}
wins = sum(1 for t in trades if t.pnl_usd > 0)
win_rate = wins / total_trades * 100
avg_pnl_usd = sum(t.pnl_usd for t in trades) / total_trades
# Max drawdown from equity curve
max_drawdown_pct = 0.0
if equity_curve:
peak = equity_curve[0]["equity"]
for point in equity_curve:
eq = point["equity"]
if eq > peak:
peak = eq
dd = (peak - eq) / peak * 100 if peak > 0 else 0.0
if dd > max_drawdown_pct:
max_drawdown_pct = dd
# Sharpe ratio (annualized, trade-based)
sharpe_ratio = 0.0
if total_trades >= 2:
import math
pnls = [t.pnl_usd for t in trades]
mean = sum(pnls) / len(pnls)
variance = sum((p - mean) ** 2 for p in pnls) / (len(pnls) - 1)
std = math.sqrt(variance)
if std > 0:
sharpe_ratio = round((mean / std) * math.sqrt(252), 4)
return {
"total_return_pct": round(total_return_pct, 4),
"total_trades": total_trades,
"win_rate": round(win_rate, 2),
"max_drawdown_pct": round(max_drawdown_pct, 4),
"sharpe_ratio": sharpe_ratio,
"avg_pnl_usd": round(avg_pnl_usd, 4),
}