← Files EdgePilot ResearchARCHIVED FILE

backtest_core_src/edgepilot_backtest_core/presets.py

3.11 KB · Oct 2, 2026 · 00:31 UTC

↓ Download file

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

from edgepilot_backtest_core.discovery import StrategyDescriptor, instantiate_config_class


def preset_names(root: Path, strategy: StrategyDescriptor) -> list[str]:
    path = root / strategy.name / "configs"
    return sorted(item.stem for item in path.glob("*.json")) if path.exists() else []


def load_preset(root: Path, strategy: StrategyDescriptor, name: str | None) -> tuple[str | None, dict[str, Any]]:
    available = preset_names(root, strategy)
    selected = "default" if name is None and "default" in available else name
    if selected is None:
        return None, {}
    path = root / strategy.name / "configs" / f"{selected}.json"
    if not path.exists():
        raise FileNotFoundError(f"Unknown preset {selected!r} for {strategy.name}; available: {available}")
    values = json.loads(path.read_text(encoding="utf-8"))
    if not isinstance(values, dict):
        raise TypeError(f"Strategy preset must contain a JSON object: {path}")
    return selected, values


def resolve_strategy_parameters(strategy: StrategyDescriptor, values: dict[str, Any]) -> dict[str, Any]:
    return json.loads(instantiate_config_class(strategy.config_cls, values).json())


def preset_strategy_values(preset: dict[str, Any]) -> dict[str, Any]:
    values = preset.get("strategy", preset)
    if not isinstance(values, dict):
        raise TypeError("Preset 'strategy' must be a JSON object")
    return dict(values)


def preset_backtest_values(preset: dict[str, Any]) -> dict[str, Any]:
    values = preset.get("backtest", {})
    if not isinstance(values, dict):
        raise TypeError("Preset 'backtest' must be a JSON object")
    return dict(values)


def preset_markets(preset: dict[str, Any]) -> list[dict[str, Any]]:
    values = preset_backtest_values(preset).get("markets")
    if not isinstance(values, list) or not values:
        raise ValueError("Preset backtest.markets must be a non-empty array")
    result = []
    for market in values:
        if not isinstance(market, dict):
            raise TypeError("Each backtest market must be an object")
        missing = {"instrument_id", "bar_type", "venue"} - market.keys()
        if missing:
            raise ValueError(f"Market is missing required fields: {sorted(missing)}")
        result.append(dict(market))
    return result


def preset_venues(preset: dict[str, Any]) -> dict[str, dict[str, Any]]:
    values = preset_backtest_values(preset).get("venues")
    if not isinstance(values, dict) or not values:
        raise ValueError("Preset backtest.venues must be a non-empty object")
    result = {}
    for name, settings in values.items():
        if not isinstance(settings, dict):
            raise TypeError(f"Venue settings for {name} must be an object")
        result[str(name).upper()] = dict(settings)
    return result


def public_adapter_options(values: dict[str, Any]) -> dict[str, Any]:
    secrets = ("api_key", "api_secret", "passphrase", "password", "private_key", "secret", "token")
    return {key: value for key, value in values.items() if not any(part in key.lower() for part in secrets)}

SHA-256: 2aba99293aebf0b973b2fa8f9f46bef1e084872bf57b1764b22e95455089fbee