From 100aa624ad3f8ad466a95f9da8af30f31f77cc9c Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Wed, 1 Apr 2026 16:24:30 +0900 Subject: 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 --- services/backtester/src/backtester/config.py | 1 + services/backtester/src/backtester/engine.py | 5 ++--- services/backtester/src/backtester/main.py | 25 +++++++++++-------------- services/backtester/src/backtester/metrics.py | 23 ++++++++++++++++++----- services/backtester/src/backtester/reporter.py | 1 + services/backtester/src/backtester/simulator.py | 1 + services/backtester/tests/test_engine.py | 4 ++-- services/backtester/tests/test_metrics.py | 17 ++++++++--------- services/backtester/tests/test_reporter.py | 1 + services/backtester/tests/test_simulator.py | 4 ++-- 10 files changed, 47 insertions(+), 35 deletions(-) (limited to 'services/backtester') 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 diff --git a/services/backtester/tests/test_engine.py b/services/backtester/tests/test_engine.py index 1a25e1c..6962477 100644 --- a/services/backtester/tests/test_engine.py +++ b/services/backtester/tests/test_engine.py @@ -1,13 +1,13 @@ """Tests for the BacktestEngine.""" + from datetime import datetime, timezone from decimal import Decimal from unittest.mock import MagicMock -import pytest from shared.models import Candle, Signal, OrderSide -from backtester.engine import BacktestEngine, BacktestResult +from backtester.engine import BacktestEngine def make_candle(symbol: str, price: float, timeframe: str = "1h") -> Candle: diff --git a/services/backtester/tests/test_metrics.py b/services/backtester/tests/test_metrics.py index b222b8a..68bc0b5 100644 --- a/services/backtester/tests/test_metrics.py +++ b/services/backtester/tests/test_metrics.py @@ -1,4 +1,6 @@ """Tests for detailed backtest metrics.""" + +import math from datetime import datetime, timedelta, timezone from decimal import Decimal @@ -21,9 +23,9 @@ def test_compute_metrics_basic(): """Two round-trip trades: 1 win, 1 loss. Verify counts and win_rate.""" trades = [ _make_trade("BUY", "100", 0), - _make_trade("SELL", "120", 10), # win: +20 + _make_trade("SELL", "120", 10), # win: +20 _make_trade("BUY", "130", 20), - _make_trade("SELL", "110", 30), # loss: -20 + _make_trade("SELL", "110", 30), # loss: -20 ] metrics = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10000")) @@ -37,9 +39,9 @@ def test_compute_metrics_profit_factor(): """Verify profit_factor = gross_profit / gross_loss.""" trades = [ _make_trade("BUY", "100", 0), - _make_trade("SELL", "150", 10), # win: +50 + _make_trade("SELL", "150", 10), # win: +50 _make_trade("BUY", "150", 20), - _make_trade("SELL", "130", 30), # loss: -20 + _make_trade("SELL", "130", 30), # loss: -20 ] metrics = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10030")) @@ -51,9 +53,9 @@ def test_compute_metrics_max_drawdown(): """Max drawdown should be > 0 when there is a losing trade after a peak.""" trades = [ _make_trade("BUY", "100", 0), - _make_trade("SELL", "150", 10), # win: equity goes up + _make_trade("SELL", "150", 10), # win: equity goes up _make_trade("BUY", "150", 20), - _make_trade("SELL", "120", 30), # loss: equity drops + _make_trade("SELL", "120", 30), # loss: equity drops ] metrics = compute_detailed_metrics(trades, Decimal("10000"), Decimal("10020")) @@ -91,6 +93,3 @@ def test_compute_metrics_empty_trades(): assert metrics.calmar_ratio == 0.0 assert metrics.max_drawdown == 0.0 assert metrics.monthly_returns == {} - - -import math diff --git a/services/backtester/tests/test_reporter.py b/services/backtester/tests/test_reporter.py index aef3fc6..2ea49c0 100644 --- a/services/backtester/tests/test_reporter.py +++ b/services/backtester/tests/test_reporter.py @@ -1,4 +1,5 @@ """Tests for the report formatter.""" + import json from datetime import timedelta from decimal import Decimal diff --git a/services/backtester/tests/test_simulator.py b/services/backtester/tests/test_simulator.py index 9d8b23e..e8c80ec 100644 --- a/services/backtester/tests/test_simulator.py +++ b/services/backtester/tests/test_simulator.py @@ -1,9 +1,9 @@ """Tests for the OrderSimulator.""" + from decimal import Decimal -import pytest -from shared.models import Signal, OrderSide, OrderType +from shared.models import Signal, OrderSide from backtester.simulator import OrderSimulator -- cgit v1.2.3