"""
AssetAllocation API namespace.

AUTO-GENERATED by scripts/generate_sdk.py - DO NOT EDIT MANUALLY!
Regenerate with: python scripts/generate_sdk.py --category asset_allocation
"""
from __future__ import annotations

from typing import Any, Dict, List, Optional

from ._base import AsyncBaseAPI, BaseAPI


class AssetAllocationAPI(BaseAPI):
    """AssetAllocation namespace: backtest, compare, decompose, drift, frontier, optimize, risk_profile, stress, suggest_securities, validate."""

    def backtest(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        rebalance_frequency: Optional[str] = None,
        return_method: Optional[str] = "twr",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Backtest model

        Backtest model using portfolio returns engine.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        rebalance_frequency: monthly|quarterly|annual|weekly
        return_method: twr|mwr|modified_dietz"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if rebalance_frequency is not None:
            params["rebalance_frequency"] = rebalance_frequency
        if return_method is not None:
            params["return_method"] = return_method
        return self._call("asset_allocation.backtest", params=params, options=options, context=context, response_format=response_format)

    def compare(
        self,
        *,
        models: List[Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        metrics: Optional[List[Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Compare multiple models

        Backtest and compare multiple asset allocation models.

        Args:
        models: List of asset allocation models
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        metrics: Metrics to include in comparison"""
        params: Dict[str, Any] = {}
        params["models"] = models
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if metrics is not None:
            params["metrics"] = metrics
        return self._call("asset_allocation.compare", params=params, options=options, context=context, response_format=response_format)

    def decompose(
        self,
        *,
        portfolio_id: str,
        model: Optional[Dict[str, Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Decompose portfolio by asset class

        Map portfolio securities into asset classes (or model classes).

        Args:
        portfolio_id: Portfolio ID
        model: Optional model for class mapping"""
        params: Dict[str, Any] = {}
        params["portfolio_id"] = portfolio_id
        if model is not None:
            params["model"] = model
        return self._call("asset_allocation.decompose", params=params, options=options, context=context)

    def drift(
        self,
        *,
        model: Dict[str, Any],
        portfolio_id: str,
        tolerance: Optional[float] = 0.05,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Calculate model drift

        Compare current portfolio weights vs model target allocation.

        Args:
        model: Asset allocation model
        portfolio_id: Portfolio ID
        tolerance: Absolute drift threshold"""
        params: Dict[str, Any] = {}
        params["model"] = model
        params["portfolio_id"] = portfolio_id
        if tolerance is not None:
            params["tolerance"] = tolerance
        return self._call("asset_allocation.drift", params=params, options=options, context=context)

    def frontier(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        points: Optional[int] = 50,
        cov_method: Optional[str] = "ledoit_wolf",
        rf: Optional[float] = 0.0,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Efficient frontier

        Compute efficient frontier from model class proxies.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        points: Number of frontier points
        cov_method: sample|ledoit_wolf|oas|ewma
        rf: Risk-free rate"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if points is not None:
            params["points"] = points
        if cov_method is not None:
            params["cov_method"] = cov_method
        if rf is not None:
            params["rf"] = rf
        return self._call("asset_allocation.frontier", params=params, options=options, context=context, response_format=response_format)

    def optimize(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        objective: Optional[str] = "max_sharpe",
        target_return: Optional[float] = None,
        rf: Optional[float] = 0.0,
        cov_method: Optional[str] = "ledoit_wolf",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Optimize model allocation

        Run a single optimization for model classes and bounds.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        objective: max_sharpe|min_risk|target_return|risk_parity
        target_return: Target return for target_return objective
        rf: Risk-free rate
        cov_method: sample|ledoit_wolf|oas|ewma"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if objective is not None:
            params["objective"] = objective
        if target_return is not None:
            params["target_return"] = target_return
        if rf is not None:
            params["rf"] = rf
        if cov_method is not None:
            params["cov_method"] = cov_method
        return self._call("asset_allocation.optimize", params=params, options=options, context=context)

    def risk_profile(
        self,
        *,
        risk_level: int,
        currency: Optional[str] = "EUR",
        include_proxies: Optional[bool] = True,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Get risk profile template

        Return static model template for MiFID SRI 1-7.

        Args:
        risk_level: MiFID SRI risk level 1-7
        currency: Model currency
        include_proxies: Include suggested proxy TepiloraCodes"""
        params: Dict[str, Any] = {}
        params["risk_level"] = risk_level
        if currency is not None:
            params["currency"] = currency
        if include_proxies is not None:
            params["include_proxies"] = include_proxies
        return self._call("asset_allocation.risk_profile", params=params, options=options, context=context)

    def stress(
        self,
        *,
        model: Dict[str, Any],
        scenarios: Optional[Any] = None,
        start_date: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Stress test model

        Apply deterministic class-level scenarios to model weights.

        Args:
        model: Asset allocation model
        scenarios: Scenario names or custom definitions; accepts list and dict custom shocks
        start_date: Start date (YYYY-MM-DD)"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if scenarios is not None:
            params["scenarios"] = scenarios
        if start_date is not None:
            params["start_date"] = start_date
        return self._call("asset_allocation.stress", params=params, options=options, context=context)

    def suggest_securities(
        self,
        *,
        model: Dict[str, Any],
        class_name: Optional[str] = None,
        filters: Optional[Dict[str, Any]] = None,
        limit: Optional[int] = 5,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Suggest securities by class

        Suggest securities for one or all model classes via securities.search.

        Args:
        model: Asset allocation model
        class_name: Specific class name
        filters: Optional filters for securities.search
        limit: Max suggestions per class"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if class_name is not None:
            params["class_name"] = class_name
        if filters is not None:
            params["filters"] = filters
        if limit is not None:
            params["limit"] = limit
        return self._call("asset_allocation.suggest_securities", params=params, options=options, context=context)

    def validate(
        self,
        *,
        model: Dict[str, Any],
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Validate asset allocation model

        Validate structure, weights, and proxy availability in D_full.parquet.

        Args:
        model: Asset allocation model"""
        params: Dict[str, Any] = {}
        params["model"] = model
        return self._call("asset_allocation.validate", params=params, options=options, context=context)



class AsyncAssetAllocationAPI(AsyncBaseAPI):
    """AssetAllocation namespace: backtest, compare, decompose, drift, frontier, optimize, risk_profile, stress, suggest_securities, validate."""

    async def backtest(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        rebalance_frequency: Optional[str] = None,
        return_method: Optional[str] = "twr",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Backtest model

        Backtest model using portfolio returns engine.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        rebalance_frequency: monthly|quarterly|annual|weekly
        return_method: twr|mwr|modified_dietz"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if rebalance_frequency is not None:
            params["rebalance_frequency"] = rebalance_frequency
        if return_method is not None:
            params["return_method"] = return_method
        return await self._call("asset_allocation.backtest", params=params, options=options, context=context, response_format=response_format)

    async def compare(
        self,
        *,
        models: List[Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        metrics: Optional[List[Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Compare multiple models

        Backtest and compare multiple asset allocation models.

        Args:
        models: List of asset allocation models
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        metrics: Metrics to include in comparison"""
        params: Dict[str, Any] = {}
        params["models"] = models
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if metrics is not None:
            params["metrics"] = metrics
        return await self._call("asset_allocation.compare", params=params, options=options, context=context, response_format=response_format)

    async def decompose(
        self,
        *,
        portfolio_id: str,
        model: Optional[Dict[str, Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Decompose portfolio by asset class

        Map portfolio securities into asset classes (or model classes).

        Args:
        portfolio_id: Portfolio ID
        model: Optional model for class mapping"""
        params: Dict[str, Any] = {}
        params["portfolio_id"] = portfolio_id
        if model is not None:
            params["model"] = model
        return await self._call("asset_allocation.decompose", params=params, options=options, context=context)

    async def drift(
        self,
        *,
        model: Dict[str, Any],
        portfolio_id: str,
        tolerance: Optional[float] = 0.05,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Calculate model drift

        Compare current portfolio weights vs model target allocation.

        Args:
        model: Asset allocation model
        portfolio_id: Portfolio ID
        tolerance: Absolute drift threshold"""
        params: Dict[str, Any] = {}
        params["model"] = model
        params["portfolio_id"] = portfolio_id
        if tolerance is not None:
            params["tolerance"] = tolerance
        return await self._call("asset_allocation.drift", params=params, options=options, context=context)

    async def frontier(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        points: Optional[int] = 50,
        cov_method: Optional[str] = "ledoit_wolf",
        rf: Optional[float] = 0.0,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Efficient frontier

        Compute efficient frontier from model class proxies.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        points: Number of frontier points
        cov_method: sample|ledoit_wolf|oas|ewma
        rf: Risk-free rate"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if points is not None:
            params["points"] = points
        if cov_method is not None:
            params["cov_method"] = cov_method
        if rf is not None:
            params["rf"] = rf
        return await self._call("asset_allocation.frontier", params=params, options=options, context=context, response_format=response_format)

    async def optimize(
        self,
        *,
        model: Dict[str, Any],
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        objective: Optional[str] = "max_sharpe",
        target_return: Optional[float] = None,
        rf: Optional[float] = 0.0,
        cov_method: Optional[str] = "ledoit_wolf",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Optimize model allocation

        Run a single optimization for model classes and bounds.

        Args:
        model: Asset allocation model
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        objective: max_sharpe|min_risk|target_return|risk_parity
        target_return: Target return for target_return objective
        rf: Risk-free rate
        cov_method: sample|ledoit_wolf|oas|ewma"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if start_date is not None:
            params["start_date"] = start_date
        if end_date is not None:
            params["end_date"] = end_date
        if objective is not None:
            params["objective"] = objective
        if target_return is not None:
            params["target_return"] = target_return
        if rf is not None:
            params["rf"] = rf
        if cov_method is not None:
            params["cov_method"] = cov_method
        return await self._call("asset_allocation.optimize", params=params, options=options, context=context)

    async def risk_profile(
        self,
        *,
        risk_level: int,
        currency: Optional[str] = "EUR",
        include_proxies: Optional[bool] = True,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Get risk profile template

        Return static model template for MiFID SRI 1-7.

        Args:
        risk_level: MiFID SRI risk level 1-7
        currency: Model currency
        include_proxies: Include suggested proxy TepiloraCodes"""
        params: Dict[str, Any] = {}
        params["risk_level"] = risk_level
        if currency is not None:
            params["currency"] = currency
        if include_proxies is not None:
            params["include_proxies"] = include_proxies
        return await self._call("asset_allocation.risk_profile", params=params, options=options, context=context)

    async def stress(
        self,
        *,
        model: Dict[str, Any],
        scenarios: Optional[Any] = None,
        start_date: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Stress test model

        Apply deterministic class-level scenarios to model weights.

        Args:
        model: Asset allocation model
        scenarios: Scenario names or custom definitions; accepts list and dict custom shocks
        start_date: Start date (YYYY-MM-DD)"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if scenarios is not None:
            params["scenarios"] = scenarios
        if start_date is not None:
            params["start_date"] = start_date
        return await self._call("asset_allocation.stress", params=params, options=options, context=context)

    async def suggest_securities(
        self,
        *,
        model: Dict[str, Any],
        class_name: Optional[str] = None,
        filters: Optional[Dict[str, Any]] = None,
        limit: Optional[int] = 5,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Suggest securities by class

        Suggest securities for one or all model classes via securities.search.

        Args:
        model: Asset allocation model
        class_name: Specific class name
        filters: Optional filters for securities.search
        limit: Max suggestions per class"""
        params: Dict[str, Any] = {}
        params["model"] = model
        if class_name is not None:
            params["class_name"] = class_name
        if filters is not None:
            params["filters"] = filters
        if limit is not None:
            params["limit"] = limit
        return await self._call("asset_allocation.suggest_securities", params=params, options=options, context=context)

    async def validate(
        self,
        *,
        model: Dict[str, Any],
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Validate asset allocation model

        Validate structure, weights, and proxy availability in D_full.parquet.

        Args:
        model: Asset allocation model"""
        params: Dict[str, Any] = {}
        params["model"] = model
        return await self._call("asset_allocation.validate", params=params, options=options, context=context)


