"""Dynamic plugin loader for strategy modules.""" import importlib.util import sys from pathlib import Path import yaml from strategies.base import BaseStrategy def load_strategies(strategies_dir: Path) -> list[BaseStrategy]: """Scan strategies_dir for *.py files and load all BaseStrategy subclasses.""" loaded: list[BaseStrategy] = [] config_dir = strategies_dir / "config" for path in sorted(strategies_dir.glob("*.py")): # Skip dunder files and base if path.name.startswith("__") or path.name == "base.py": continue module_name = f"_strategy_plugin_{path.stem}" spec = importlib.util.spec_from_file_location(module_name, path) if spec is None or spec.loader is None: continue module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module spec.loader.exec_module(module) for attr_name in dir(module): obj = getattr(module, attr_name) if isinstance(obj, type) and issubclass(obj, BaseStrategy) and obj is not BaseStrategy: instance = obj() yaml_path = config_dir / f"{path.stem}.yaml" if yaml_path.exists(): with open(yaml_path) as f: params = yaml.safe_load(f) if params: instance.configure(params) loaded.append(instance) return loaded