summaryrefslogtreecommitdiff
path: root/services/backtester/src
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:24:30 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2026-04-01 16:24:30 +0900
commit100aa624ad3f8ad466a95f9da8af30f31f77cc9c (patch)
treeef81b9f37872ed462a1f84ea238a130f758782d2 /services/backtester/src
parent73eaf704584e5bf3c4499ccdd574af87304e1e5f (diff)
fix: resolve lint issues and final integration fixes
- Fix ambiguous variable name in binance_rest.py - Remove unused volumes variable in volume_profile_strategy.py - Fix import ordering in backtester main.py and test_metrics.py - Auto-format all files with ruff
Diffstat (limited to 'services/backtester/src')
-rw-r--r--services/backtester/src/backtester/config.py1
-rw-r--r--services/backtester/src/backtester/engine.py5
-rw-r--r--services/backtester/src/backtester/main.py25
-rw-r--r--services/backtester/src/backtester/metrics.py23
-rw-r--r--services/backtester/src/backtester/reporter.py1
-rw-r--r--services/backtester/src/backtester/simulator.py1
6 files changed, 34 insertions, 22 deletions
diff --git a/services/backtester/src/backtester/config.py b/services/backtester/src/backtester/config.py
index bfbc196..5a912f3 100644
--- a/services/backtester/src/backtester/config.py
+++ b/services/backtester/src/backtester/config.py
@@ -1,4 +1,5 @@
"""Configuration for the backtester service."""
+
from pydantic_settings import BaseSettings
diff --git a/services/backtester/src/backtester/engine.py b/services/backtester/src/backtester/engine.py
index 386309b..0441011 100644
--- a/services/backtester/src/backtester/engine.py
+++ b/services/backtester/src/backtester/engine.py
@@ -1,4 +1,5 @@
"""Backtesting engine that runs strategies against historical candle data."""
+
from __future__ import annotations
from dataclasses import dataclass, field
@@ -98,9 +99,7 @@ class BacktestEngine:
)
for t in simulator.trades
]
- detailed = compute_detailed_metrics(
- trade_records, self._initial_balance, final_balance
- )
+ detailed = compute_detailed_metrics(trade_records, self._initial_balance, final_balance)
return BacktestResult(
strategy_name=self._strategy.name,
diff --git a/services/backtester/src/backtester/main.py b/services/backtester/src/backtester/main.py
index ab69ee1..c9b3890 100644
--- a/services/backtester/src/backtester/main.py
+++ b/services/backtester/src/backtester/main.py
@@ -1,22 +1,21 @@
"""Main entry point for the backtester service."""
-import sys
+
import os
+import sys
from decimal import Decimal
+from shared.db import Database # noqa: E402
+from shared.models import Candle # noqa: E402
+
+from backtester.config import BacktestConfig # noqa: E402
+from backtester.engine import BacktestEngine # noqa: E402
+from backtester.reporter import format_report # noqa: E402
+
# Allow importing strategies from the strategy-engine service
-_STRATEGY_ENGINE_PATH = os.path.join(
- os.path.dirname(__file__), "../../../../strategy-engine"
-)
+_STRATEGY_ENGINE_PATH = os.path.join(os.path.dirname(__file__), "../../../../strategy-engine")
if _STRATEGY_ENGINE_PATH not in sys.path:
sys.path.insert(0, _STRATEGY_ENGINE_PATH)
-from shared.db import Database
-from shared.models import Candle
-
-from backtester.config import BacktestConfig
-from backtester.engine import BacktestEngine
-from backtester.reporter import format_report
-
async def run_backtest() -> str:
"""Load strategy, fetch candles, run backtest, and return a formatted report."""
@@ -35,9 +34,7 @@ async def run_backtest() -> str:
strategy = strategy_cls()
strategy.configure({})
except Exception as exc:
- raise RuntimeError(
- f"Failed to load strategy '{config.strategy_name}': {exc}"
- ) from exc
+ raise RuntimeError(f"Failed to load strategy '{config.strategy_name}': {exc}") from exc
db = Database(config.database_url)
await db.connect()
diff --git a/services/backtester/src/backtester/metrics.py b/services/backtester/src/backtester/metrics.py
index 15be0e6..caf8477 100644
--- a/services/backtester/src/backtester/metrics.py
+++ b/services/backtester/src/backtester/metrics.py
@@ -1,4 +1,5 @@
"""Detailed backtest metrics: Sharpe, Sortino, drawdown, and more."""
+
from __future__ import annotations
import math
@@ -87,7 +88,9 @@ def compute_detailed_metrics(
)
pairs = _pair_trades(trades)
- total_return = float(final_balance - initial_balance) / float(initial_balance) if initial_balance else 0.0
+ total_return = (
+ float(final_balance - initial_balance) / float(initial_balance) if initial_balance else 0.0
+ )
if not pairs:
return DetailedMetrics(
@@ -114,7 +117,9 @@ def compute_detailed_metrics(
gross_profit = sum(p["pnl"] for p in wins)
gross_loss = abs(sum(p["pnl"] for p in losses))
- profit_factor = gross_profit / gross_loss if gross_loss > 0 else float("inf") if gross_profit > 0 else 0.0
+ profit_factor = (
+ gross_profit / gross_loss if gross_loss > 0 else float("inf") if gross_profit > 0 else 0.0
+ )
avg_win = gross_profit / winning_trades if winning_trades else 0.0
avg_loss = gross_loss / losing_trades if losing_trades else 0.0
@@ -123,7 +128,11 @@ def compute_detailed_metrics(
# Holding periods
holding_periods = [p["holding_period"] for p in pairs]
- avg_holding = sum(holding_periods, timedelta(0)) / len(holding_periods) if holding_periods else timedelta(0)
+ avg_holding = (
+ sum(holding_periods, timedelta(0)) / len(holding_periods)
+ if holding_periods
+ else timedelta(0)
+ )
# Build equity curve from pairs
init_bal = float(initial_balance)
@@ -153,7 +162,11 @@ def compute_detailed_metrics(
max_dd = dd
# Duration: use pair exit times
if i <= len(pairs) and dd_start_idx < len(pairs):
- start_time = pairs[dd_start_idx]["exit_time"] if dd_start_idx < len(pairs) else pairs[0]["entry_time"]
+ start_time = (
+ pairs[dd_start_idx]["exit_time"]
+ if dd_start_idx < len(pairs)
+ else pairs[0]["entry_time"]
+ )
end_time = pairs[i - 1]["exit_time"]
max_dd_duration = end_time - start_time if end_time > start_time else timedelta(0)
@@ -171,7 +184,7 @@ def compute_detailed_metrics(
if len(returns) > 1:
mean_r = sum(returns) / len(returns)
downside = [min(r, 0.0) for r in returns]
- downside_var = sum(d ** 2 for d in downside) / (len(downside) - 1)
+ downside_var = sum(d**2 for d in downside) / (len(downside) - 1)
downside_std = math.sqrt(downside_var)
sortino = (mean_r / downside_std * math.sqrt(365)) if downside_std > 0 else 0.0
else:
diff --git a/services/backtester/src/backtester/reporter.py b/services/backtester/src/backtester/reporter.py
index e9e9936..cc5d67b 100644
--- a/services/backtester/src/backtester/reporter.py
+++ b/services/backtester/src/backtester/reporter.py
@@ -1,4 +1,5 @@
"""Report formatting for backtest results."""
+
from __future__ import annotations
import csv
diff --git a/services/backtester/src/backtester/simulator.py b/services/backtester/src/backtester/simulator.py
index b897c5a..33eeb76 100644
--- a/services/backtester/src/backtester/simulator.py
+++ b/services/backtester/src/backtester/simulator.py
@@ -1,4 +1,5 @@
"""Simulated order executor for backtesting."""
+
from dataclasses import dataclass, field
from datetime import datetime, timezone
from decimal import Decimal