From c32ea21d0e29a0894fe94ecc4236145541bce3ab Mon Sep 17 00:00:00 2001 From: TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> Date: Thu, 2 Apr 2026 09:50:47 +0900 Subject: refactor: dead code cleanup - Remove placeholder 'backtest report' command (no stored results) - Connect walk-forward analysis to CLI: 'trading backtest walk-forward' - Update test for renamed command --- cli/src/trading_cli/commands/backtest.py | 79 +++++++++++++++++++++++++++++--- cli/tests/test_cli_backtest.py | 7 +-- 2 files changed, 77 insertions(+), 9 deletions(-) diff --git a/cli/src/trading_cli/commands/backtest.py b/cli/src/trading_cli/commands/backtest.py index b9e3c1b..01fe092 100644 --- a/cli/src/trading_cli/commands/backtest.py +++ b/cli/src/trading_cli/commands/backtest.py @@ -102,9 +102,76 @@ def run(strategy, symbol, timeframe, balance, output_format, file_path): asyncio.run(_run()) -@backtest.command() -@click.option("--id", "backtest_id", required=True, help="Backtest run ID") -def report(backtest_id): - """Show a backtest report by ID.""" - click.echo(f"Showing backtest report for ID: {backtest_id}...") - click.echo("(Not yet implemented - requires stored backtest results)") +@backtest.command("walk-forward") +@click.option("--strategy", required=True, help="Strategy name") +@click.option("--symbol", required=True, help="Trading symbol") +@click.option("--timeframe", default="1h", show_default=True, help="Candle timeframe") +@click.option("--balance", default=10000.0, show_default=True, help="Initial balance") +@click.option("--windows", default=5, show_default=True, help="Number of walk-forward windows") +def walk_forward(strategy, symbol, timeframe, balance, windows): + """Run walk-forward analysis to detect overfitting.""" + try: + from strategy_engine.plugin_loader import load_strategies + from backtester.walk_forward import WalkForwardEngine + from shared.db import Database + from shared.config import Settings + from shared.models import Candle + except ImportError as e: + click.echo(f"Error: Could not import required modules: {e}", err=True) + sys.exit(1) + + strategies_dir = _ROOT / "services" / "strategy-engine" / "strategies" + strategies = load_strategies(strategies_dir) + matched = [s for s in strategies if s.name == strategy] + if not matched: + click.echo(f"Error: Strategy '{strategy}' not found.", err=True) + sys.exit(1) + + strategy_cls = type(matched[0]) + + async def _run(): + settings = Settings() + db = Database(settings.database_url) + await db.connect() + try: + rows = await db.get_candles(symbol, timeframe, limit=2000) + if not rows: + click.echo(f"Error: No candles found for {symbol} {timeframe}", err=True) + sys.exit(1) + + candles = [ + Candle( + symbol=r["symbol"], + timeframe=r["timeframe"], + open_time=r["open_time"], + open=r["open"], + high=r["high"], + low=r["low"], + close=r["close"], + volume=r["volume"], + ) + for r in reversed(rows) + ] + + param_grid = [{}] # Default params — extend as needed + engine = WalkForwardEngine( + strategy_factory=strategy_cls, + param_grid=param_grid, + initial_balance=Decimal(str(balance)), + num_windows=windows, + ) + result = engine.run(candles) + + click.echo(f"Walk-Forward Analysis: {result.strategy_name}") + click.echo(f"Windows: {result.num_windows}") + click.echo(f"In-sample profit: {result.in_sample_profit_pct:.2f}%") + click.echo(f"Out-of-sample profit: {result.out_of_sample_profit_pct:.2f}%") + click.echo(f"Efficiency ratio: {result.efficiency_ratio:.2f}") + if result.efficiency_ratio > 0.5: + click.echo("-> Strategy appears robust (ratio > 0.5)") + else: + click.echo("-> WARNING: Possible overfitting (ratio < 0.5)") + finally: + await db.close() + + asyncio.run(_run()) diff --git a/cli/tests/test_cli_backtest.py b/cli/tests/test_cli_backtest.py index 80f516c..adf19d3 100644 --- a/cli/tests/test_cli_backtest.py +++ b/cli/tests/test_cli_backtest.py @@ -13,8 +13,9 @@ def test_backtest_run_help(): assert "--balance" in result.output -def test_backtest_report_help(): +def test_backtest_walk_forward_help(): runner = CliRunner() - result = runner.invoke(cli, ["backtest", "report", "--help"]) + result = runner.invoke(cli, ["backtest", "walk-forward", "--help"]) assert result.exit_code == 0 - assert "--id" in result.output + assert "--strategy" in result.output + assert "--windows" in result.output -- cgit v1.2.3