diff options
Diffstat (limited to 'services/backtester/src')
| -rw-r--r-- | services/backtester/src/backtester/main.py | 51 |
1 files changed, 27 insertions, 24 deletions
diff --git a/services/backtester/src/backtester/main.py b/services/backtester/src/backtester/main.py index c9b3890..0a2b47d 100644 --- a/services/backtester/src/backtester/main.py +++ b/services/backtester/src/backtester/main.py @@ -1,36 +1,41 @@ """Main entry point for the backtester service.""" - +import asyncio +import importlib import os import sys from decimal import Decimal +from pathlib import Path -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 +# Resolve strategies directory from env or relative path +_STRATEGIES_DIR = Path(os.environ.get( + "STRATEGIES_DIR", + str(Path(__file__).resolve().parents[4] / "strategy-engine" / "strategies") +)) +if _STRATEGIES_DIR.parent not in [Path(p) for p in sys.path]: + sys.path.insert(0, str(_STRATEGIES_DIR.parent)) -# Allow importing strategies from the strategy-engine service -_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.""" config = BacktestConfig() - # Import strategy dynamically (requires strategy-engine in sys.path) try: - from strategies.base import BaseStrategy # noqa: F401 - - # Try to import concrete strategy by name - module_name = config.strategy_name - import importlib - - mod = importlib.import_module(f"strategies.{module_name}") - strategy_cls = getattr(mod, "Strategy") + mod = importlib.import_module(f"strategies.{config.strategy_name}") + # Find the first BaseStrategy subclass + from strategies.base import BaseStrategy + strategy_cls = None + for attr_name in dir(mod): + obj = getattr(mod, attr_name) + if isinstance(obj, type) and issubclass(obj, BaseStrategy) and obj is not BaseStrategy: + strategy_cls = obj + break + if strategy_cls is None: + raise RuntimeError(f"No strategy class found in {config.strategy_name}") strategy = strategy_cls() strategy.configure({}) except Exception as exc: @@ -41,7 +46,7 @@ async def run_backtest() -> str: try: rows = await db.get_candles(config.symbol, config.timeframe, config.candle_limit) candles = [Candle(**row) for row in rows] - candles = list(reversed(candles)) # oldest first for strategy processing + candles = list(reversed(candles)) finally: await db.close() @@ -51,7 +56,5 @@ async def run_backtest() -> str: if __name__ == "__main__": - import asyncio - report = asyncio.run(run_backtest()) print(report) |
