"""
Portfolio API namespace.

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

from typing import Any, Dict, List, Optional, Union

from ._base import AsyncBaseAPI, BaseAPI


class PortfolioAPI(BaseAPI):
    """Portfolio namespace: attribution, compare, contribution, costs, create, delete, drift, exposure, get, list, optimize, rebalance, returns, share, shares, stress, tearsheet, unshare, update."""

    def attribution(
        self,
        *,
        benchmark_weights: Optional[str] = None,
        currency: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Performance attribution

        Brinson attribution analysis.

        Args:
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        if benchmark_weights is not None:
            _payload["benchmark_weights"] = benchmark_weights
        if currency is not None:
            _payload["currency"] = currency
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        return self._call("portfolio.attribution", params=_payload, options=options, context=context, response_format=response_format)

    def compare(
        self,
        *,
        portfolios: List[Any],
        currency: Optional[str] = None,
        exposure_dimensions: Optional[str] = None,
        include_exposure: Optional[bool] = None,
        metrics: Optional[List[Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Compare portfolios

        Compare multiple portfolios.

        Args:
        portfolios: List of portfolio definitions (id or weights)
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["portfolios"] = portfolios
        if currency is not None:
            _payload["currency"] = currency
        if exposure_dimensions is not None:
            _payload["exposure_dimensions"] = exposure_dimensions
        if include_exposure is not None:
            _payload["include_exposure"] = include_exposure
        if metrics is not None:
            _payload["metrics"] = metrics
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        return self._call("portfolio.compare", params=_payload, options=options, context=context, response_format=response_format)

    def contribution(
        self,
        *,
        id: str,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        drifting: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Return contribution

        Contribution of each holding to portfolio return.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if drifting is not None:
            _payload["drifting"] = drifting
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        if weights is not None:
            _payload["weights"] = weights
        return self._call("portfolio.contribution", params=_payload, options=options, context=context, response_format=response_format)

    def costs(
        self,
        *,
        portfolio_value: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio costs

        TER and trading costs analysis."""
        _payload: Dict[str, Any] = {}
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if weights is not None:
            _payload["weights"] = weights
        return self._call("portfolio.costs", params=_payload, options=options, context=context, response_format=response_format)

    def create(
        self,
        *,
        name: str,
        input_type: str,
        allow_negative_cash: Optional[bool] = None,
        allow_short: Optional[bool] = None,
        auto_cash: Optional[str] = None,
        base_currency: Optional[str] = None,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        holdings: Optional[str] = None,
        initial_cash: Optional[str] = None,
        initial_weights: Optional[str] = None,
        trades: Optional[str] = None,
        values: Optional[str] = None,
        weights: Optional[Dict[str, Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        type_: Optional[str] = "Real",
        input_data: Optional[Dict[str, Any]] = None,
        benchmark: Optional[str] = None,
        description: Optional[str] = "",
        settings: Optional[Dict[str, Any]] = None,
        visibility: Optional[str] = "private",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Create portfolio

        Create a new portfolio.

        Args:
        name: Portfolio name
        input_type: fixed_weights|drifting_weights|holdings|values|trades
        weights: Portfolio weights {TepiloraCode: float}. Required for fixed_weights
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        type_: Real|Suggested|Simulation|Backtest|Model
        input_data: Input data (alternative to flat params). Format depends on input_type: holdings=[{date,positions}], trades=[{date,type,security,quantity,price}], values=[{date,security,value}]
        benchmark: Benchmark TepiloraCode
        description: Description
        settings: Portfolio settings
        visibility: private|shared"""
        _payload: Dict[str, Any] = {}
        _payload["name"] = name
        _payload["input_type"] = input_type
        if allow_negative_cash is not None:
            _payload["allow_negative_cash"] = allow_negative_cash
        if allow_short is not None:
            _payload["allow_short"] = allow_short
        if auto_cash is not None:
            _payload["auto_cash"] = auto_cash
        if base_currency is not None:
            _payload["base_currency"] = base_currency
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if holdings is not None:
            _payload["holdings"] = holdings
        if initial_cash is not None:
            _payload["initial_cash"] = initial_cash
        if initial_weights is not None:
            _payload["initial_weights"] = initial_weights
        if trades is not None:
            _payload["trades"] = trades
        if values is not None:
            _payload["values"] = values
        if weights is not None:
            _payload["weights"] = weights
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if type_ is not None:
            _payload["type"] = type_
        if input_data is not None:
            _payload["input_data"] = input_data
        if benchmark is not None:
            _payload["benchmark"] = benchmark
        if description is not None:
            _payload["description"] = description
        if settings is not None:
            _payload["settings"] = settings
        if visibility is not None:
            _payload["visibility"] = visibility
        return self._call("portfolio.create", params=_payload, options=options, context=context)

    def delete(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Delete portfolio

        Delete portfolio.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return self._call("portfolio.delete", params=_payload, options=options, context=context)

    def drift(
        self,
        *,
        compare_rebalanced: Optional[str] = None,
        currency: Optional[str] = None,
        end_date: Optional[str] = None,
        start_date: Optional[str] = None,
        target_weights: Optional[str] = None,
        threshold: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio drift

        Weight drift from target."""
        _payload: Dict[str, Any] = {}
        if compare_rebalanced is not None:
            _payload["compare_rebalanced"] = compare_rebalanced
        if currency is not None:
            _payload["currency"] = currency
        if end_date is not None:
            _payload["end_date"] = end_date
        if start_date is not None:
            _payload["start_date"] = start_date
        if target_weights is not None:
            _payload["target_weights"] = target_weights
        if threshold is not None:
            _payload["threshold"] = threshold
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        return self._call("portfolio.drift", params=_payload, options=options, context=context, response_format=response_format)

    def exposure(
        self,
        *,
        date: Optional[str] = None,
        dimensions: Optional[str] = None,
        dimension: Optional[str] = "sector",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio exposure

        Exposure by sector, country, currency, etc.

        Args:
        dimension: sector|country|currency|asset_class"""
        _payload: Dict[str, Any] = {}
        if date is not None:
            _payload["date"] = date
        if dimensions is not None:
            _payload["dimensions"] = dimensions
        if dimension is not None:
            _payload["dimension"] = dimension
        return self._call("portfolio.exposure", params=_payload, options=options, context=context, response_format=response_format)

    def get(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Get portfolio

        Get portfolio details.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return self._call("portfolio.get", params=_payload, options=options, context=context)

    def list(
        self,
        *,
        type_: Optional[str] = None,
        input_type: Optional[str] = None,
        search: Optional[str] = None,
        sort: Optional[str] = "createdAt",
        order: Optional[str] = "desc",
        limit: Optional[int] = 50,
        offset: Optional[int] = 0,
        include_shared: Optional[bool] = True,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """List portfolios

        List user's portfolios.

        Args:
        type_: Filter by type
        input_type: Filter by input type
        search: Search in name
        sort: Sort field
        order: Sort order: asc|desc
        limit: Maximum results
        offset: Pagination offset
        include_shared: Include shared portfolios"""
        _payload: Dict[str, Any] = {}
        if type_ is not None:
            _payload["type"] = type_
        if input_type is not None:
            _payload["input_type"] = input_type
        if search is not None:
            _payload["search"] = search
        if sort is not None:
            _payload["sort"] = sort
        if order is not None:
            _payload["order"] = order
        if limit is not None:
            _payload["limit"] = limit
        if offset is not None:
            _payload["offset"] = offset
        if include_shared is not None:
            _payload["include_shared"] = include_shared
        return self._call("portfolio.list", params=_payload, options=options, context=context)

    def optimize(
        self,
        *,
        identifiers: Optional[Union[str, List[str]]] = None,
        poll_interval: Optional[str] = None,
        securities_metadata: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[bool] = False,
        currency: Optional[str] = None,
        timeout: Optional[int] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Optimize portfolio

        Portfolio optimization (Julia backend). Pass identifiers for inline mode or id for saved portfolio.

        Args:
        identifiers: TepiloraCodes (for inline mode)
        settings: Optimizer settings (solver_mode, constraints, etc.)
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        total_return: Use total return prices
        currency: Base currency
        timeout: Optimization timeout (seconds)"""
        _payload: Dict[str, Any] = {}
        if identifiers is not None:
            _payload["identifiers"] = identifiers
        if poll_interval is not None:
            _payload["poll_interval"] = poll_interval
        if securities_metadata is not None:
            _payload["securities_metadata"] = securities_metadata
        if settings is not None:
            _payload["settings"] = settings
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if currency is not None:
            _payload["currency"] = currency
        if timeout is not None:
            _payload["timeout"] = timeout
        return self._call("portfolio.optimize", params=_payload, options=options, context=context)

    def rebalance(
        self,
        *,
        costs: Optional[str] = None,
        current_weights: Optional[str] = None,
        min_trade_value: Optional[str] = None,
        portfolio_value: Optional[str] = None,
        strategy: Optional[str] = None,
        target_weights: Optional[Dict[str, Any]] = None,
        threshold: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Rebalance portfolio

        Calculate rebalancing trades.

        Args:
        target_weights: Target weights"""
        _payload: Dict[str, Any] = {}
        if costs is not None:
            _payload["costs"] = costs
        if current_weights is not None:
            _payload["current_weights"] = current_weights
        if min_trade_value is not None:
            _payload["min_trade_value"] = min_trade_value
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if strategy is not None:
            _payload["strategy"] = strategy
        if target_weights is not None:
            _payload["target_weights"] = target_weights
        if threshold is not None:
            _payload["threshold"] = threshold
        return self._call("portfolio.rebalance", params=_payload, options=options, context=context, response_format=response_format)

    def returns(
        self,
        *,
        id: str,
        allow_negative_cash: Optional[bool] = None,
        allow_short: Optional[bool] = None,
        auto_cash: Optional[str] = None,
        base_currency: Optional[str] = None,
        borrow_cost: Optional[str] = None,
        borrow_spread_annual: Optional[str] = None,
        cash_yield: Optional[str] = None,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        drifting: Optional[str] = None,
        holdings: Optional[str] = None,
        initial_value: Optional[str] = None,
        max_stale_days: Optional[str] = None,
        Obs: Optional[str] = None,
        price_fill: Optional[str] = None,
        rebalance_dates: Optional[str] = None,
        rebalance_effective: Optional[str] = None,
        rebalance_frequency: Optional[str] = None,
        rebalance_on: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        stale_policy: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        return_method: Optional[str] = "twr",
        total_return: Optional[str] = None,
        trades: Optional[str] = None,
        user_prices: Optional[str] = None,
        values: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Get portfolio returns

        Time series of portfolio returns.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        return_method: twr|mwr|modified_dietz"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if allow_negative_cash is not None:
            _payload["allow_negative_cash"] = allow_negative_cash
        if allow_short is not None:
            _payload["allow_short"] = allow_short
        if auto_cash is not None:
            _payload["auto_cash"] = auto_cash
        if base_currency is not None:
            _payload["base_currency"] = base_currency
        if borrow_cost is not None:
            _payload["borrow_cost"] = borrow_cost
        if borrow_spread_annual is not None:
            _payload["borrow_spread_annual"] = borrow_spread_annual
        if cash_yield is not None:
            _payload["cash_yield"] = cash_yield
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if drifting is not None:
            _payload["drifting"] = drifting
        if holdings is not None:
            _payload["holdings"] = holdings
        if initial_value is not None:
            _payload["initial_value"] = initial_value
        if max_stale_days is not None:
            _payload["max_stale_days"] = max_stale_days
        if Obs is not None:
            _payload["Obs"] = Obs
        if price_fill is not None:
            _payload["price_fill"] = price_fill
        if rebalance_dates is not None:
            _payload["rebalance_dates"] = rebalance_dates
        if rebalance_effective is not None:
            _payload["rebalance_effective"] = rebalance_effective
        if rebalance_frequency is not None:
            _payload["rebalance_frequency"] = rebalance_frequency
        if rebalance_on is not None:
            _payload["rebalance_on"] = rebalance_on
        if settings is not None:
            _payload["settings"] = settings
        if stale_policy is not None:
            _payload["stale_policy"] = stale_policy
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if return_method is not None:
            _payload["return_method"] = return_method
        if total_return is not None:
            _payload["total_return"] = total_return
        if trades is not None:
            _payload["trades"] = trades
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        if values is not None:
            _payload["values"] = values
        if weights is not None:
            _payload["weights"] = weights
        return self._call("portfolio.returns", params=_payload, options=options, context=context, response_format=response_format)

    def share(
        self,
        *,
        id: str,
        target_apikey: str,
        permission: Optional[str] = "read",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Share portfolio

        Share portfolio with another user.

        Args:
        id: Portfolio ID
        target_apikey: Target user apikey
        permission: read|write"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        _payload["target_apikey"] = target_apikey
        if permission is not None:
            _payload["permission"] = permission
        return self._call("portfolio.share", params=_payload, options=options, context=context)

    def shares(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """List shares

        List users with access to portfolio.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return self._call("portfolio.shares", params=_payload, options=options, context=context)

    def stress(
        self,
        *,
        id: str,
        asset_class: Optional[str] = None,
        mode: Optional[str] = None,
        portfolio_value: Optional[str] = None,
        scenario: Optional[str] = None,
        scenario_name: Optional[str] = None,
        scenarios: Optional[List[Any]] = None,
        shock_range: Optional[str] = None,
        shocks: Optional[str] = None,
        steps: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Stress test

        Portfolio stress testing.

        Args:
        id: Portfolio ID
        scenarios: Custom scenarios"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if asset_class is not None:
            _payload["asset_class"] = asset_class
        if mode is not None:
            _payload["mode"] = mode
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if scenario is not None:
            _payload["scenario"] = scenario
        if scenario_name is not None:
            _payload["scenario_name"] = scenario_name
        if scenarios is not None:
            _payload["scenarios"] = scenarios
        if shock_range is not None:
            _payload["shock_range"] = shock_range
        if shocks is not None:
            _payload["shocks"] = shocks
        if steps is not None:
            _payload["steps"] = steps
        if weights is not None:
            _payload["weights"] = weights
        return self._call("portfolio.stress", params=_payload, options=options, context=context)

    def tearsheet(
        self,
        *,
        id: str,
        benchmark_id: Optional[str] = None,
        benchmark_name: Optional[str] = None,
        benchmark_weights: Optional[str] = None,
        currency: Optional[str] = None,
        name: Optional[str] = None,
        output_path: Optional[str] = None,
        risk_free_rate: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Portfolio tearsheet

        Comprehensive portfolio report.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if benchmark_id is not None:
            _payload["benchmark_id"] = benchmark_id
        if benchmark_name is not None:
            _payload["benchmark_name"] = benchmark_name
        if benchmark_weights is not None:
            _payload["benchmark_weights"] = benchmark_weights
        if currency is not None:
            _payload["currency"] = currency
        if name is not None:
            _payload["name"] = name
        if output_path is not None:
            _payload["output_path"] = output_path
        if risk_free_rate is not None:
            _payload["risk_free_rate"] = risk_free_rate
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        return self._call("portfolio.tearsheet", params=_payload, options=options, context=context)

    def unshare(
        self,
        *,
        id: str,
        target_apikey: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Unshare portfolio

        Revoke portfolio sharing.

        Args:
        id: Portfolio ID
        target_apikey: User to remove"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        _payload["target_apikey"] = target_apikey
        return self._call("portfolio.unshare", params=_payload, options=options, context=context)

    def update(
        self,
        *,
        id: str,
        name: Optional[str] = None,
        input_data: Optional[Dict[str, Any]] = None,
        benchmark: Optional[str] = None,
        description: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Update portfolio

        Update portfolio details.

        Args:
        id: Portfolio ID
        name: New name
        input_data: New holdings/weights
        benchmark: New benchmark
        description: New description
        settings: New settings"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if name is not None:
            _payload["name"] = name
        if input_data is not None:
            _payload["input_data"] = input_data
        if benchmark is not None:
            _payload["benchmark"] = benchmark
        if description is not None:
            _payload["description"] = description
        if settings is not None:
            _payload["settings"] = settings
        return self._call("portfolio.update", params=_payload, options=options, context=context)



class AsyncPortfolioAPI(AsyncBaseAPI):
    """Portfolio namespace: attribution, compare, contribution, costs, create, delete, drift, exposure, get, list, optimize, rebalance, returns, share, shares, stress, tearsheet, unshare, update."""

    async def attribution(
        self,
        *,
        benchmark_weights: Optional[str] = None,
        currency: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Performance attribution

        Brinson attribution analysis.

        Args:
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        if benchmark_weights is not None:
            _payload["benchmark_weights"] = benchmark_weights
        if currency is not None:
            _payload["currency"] = currency
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        return await self._call("portfolio.attribution", params=_payload, options=options, context=context, response_format=response_format)

    async def compare(
        self,
        *,
        portfolios: List[Any],
        currency: Optional[str] = None,
        exposure_dimensions: Optional[str] = None,
        include_exposure: Optional[bool] = None,
        metrics: Optional[List[Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Compare portfolios

        Compare multiple portfolios.

        Args:
        portfolios: List of portfolio definitions (id or weights)
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["portfolios"] = portfolios
        if currency is not None:
            _payload["currency"] = currency
        if exposure_dimensions is not None:
            _payload["exposure_dimensions"] = exposure_dimensions
        if include_exposure is not None:
            _payload["include_exposure"] = include_exposure
        if metrics is not None:
            _payload["metrics"] = metrics
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        return await self._call("portfolio.compare", params=_payload, options=options, context=context, response_format=response_format)

    async def contribution(
        self,
        *,
        id: str,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        drifting: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Return contribution

        Contribution of each holding to portfolio return.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if drifting is not None:
            _payload["drifting"] = drifting
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        if weights is not None:
            _payload["weights"] = weights
        return await self._call("portfolio.contribution", params=_payload, options=options, context=context, response_format=response_format)

    async def costs(
        self,
        *,
        portfolio_value: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio costs

        TER and trading costs analysis."""
        _payload: Dict[str, Any] = {}
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if weights is not None:
            _payload["weights"] = weights
        return await self._call("portfolio.costs", params=_payload, options=options, context=context, response_format=response_format)

    async def create(
        self,
        *,
        name: str,
        input_type: str,
        allow_negative_cash: Optional[bool] = None,
        allow_short: Optional[bool] = None,
        auto_cash: Optional[str] = None,
        base_currency: Optional[str] = None,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        holdings: Optional[str] = None,
        initial_cash: Optional[str] = None,
        initial_weights: Optional[str] = None,
        trades: Optional[str] = None,
        values: Optional[str] = None,
        weights: Optional[Dict[str, Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        type_: Optional[str] = "Real",
        input_data: Optional[Dict[str, Any]] = None,
        benchmark: Optional[str] = None,
        description: Optional[str] = "",
        settings: Optional[Dict[str, Any]] = None,
        visibility: Optional[str] = "private",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Create portfolio

        Create a new portfolio.

        Args:
        name: Portfolio name
        input_type: fixed_weights|drifting_weights|holdings|values|trades
        weights: Portfolio weights {TepiloraCode: float}. Required for fixed_weights
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        type_: Real|Suggested|Simulation|Backtest|Model
        input_data: Input data (alternative to flat params). Format depends on input_type: holdings=[{date,positions}], trades=[{date,type,security,quantity,price}], values=[{date,security,value}]
        benchmark: Benchmark TepiloraCode
        description: Description
        settings: Portfolio settings
        visibility: private|shared"""
        _payload: Dict[str, Any] = {}
        _payload["name"] = name
        _payload["input_type"] = input_type
        if allow_negative_cash is not None:
            _payload["allow_negative_cash"] = allow_negative_cash
        if allow_short is not None:
            _payload["allow_short"] = allow_short
        if auto_cash is not None:
            _payload["auto_cash"] = auto_cash
        if base_currency is not None:
            _payload["base_currency"] = base_currency
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if holdings is not None:
            _payload["holdings"] = holdings
        if initial_cash is not None:
            _payload["initial_cash"] = initial_cash
        if initial_weights is not None:
            _payload["initial_weights"] = initial_weights
        if trades is not None:
            _payload["trades"] = trades
        if values is not None:
            _payload["values"] = values
        if weights is not None:
            _payload["weights"] = weights
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if type_ is not None:
            _payload["type"] = type_
        if input_data is not None:
            _payload["input_data"] = input_data
        if benchmark is not None:
            _payload["benchmark"] = benchmark
        if description is not None:
            _payload["description"] = description
        if settings is not None:
            _payload["settings"] = settings
        if visibility is not None:
            _payload["visibility"] = visibility
        return await self._call("portfolio.create", params=_payload, options=options, context=context)

    async def delete(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Delete portfolio

        Delete portfolio.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return await self._call("portfolio.delete", params=_payload, options=options, context=context)

    async def drift(
        self,
        *,
        compare_rebalanced: Optional[str] = None,
        currency: Optional[str] = None,
        end_date: Optional[str] = None,
        start_date: Optional[str] = None,
        target_weights: Optional[str] = None,
        threshold: Optional[str] = None,
        total_return: Optional[str] = None,
        user_prices: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio drift

        Weight drift from target."""
        _payload: Dict[str, Any] = {}
        if compare_rebalanced is not None:
            _payload["compare_rebalanced"] = compare_rebalanced
        if currency is not None:
            _payload["currency"] = currency
        if end_date is not None:
            _payload["end_date"] = end_date
        if start_date is not None:
            _payload["start_date"] = start_date
        if target_weights is not None:
            _payload["target_weights"] = target_weights
        if threshold is not None:
            _payload["threshold"] = threshold
        if total_return is not None:
            _payload["total_return"] = total_return
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        return await self._call("portfolio.drift", params=_payload, options=options, context=context, response_format=response_format)

    async def exposure(
        self,
        *,
        date: Optional[str] = None,
        dimensions: Optional[str] = None,
        dimension: Optional[str] = "sector",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Portfolio exposure

        Exposure by sector, country, currency, etc.

        Args:
        dimension: sector|country|currency|asset_class"""
        _payload: Dict[str, Any] = {}
        if date is not None:
            _payload["date"] = date
        if dimensions is not None:
            _payload["dimensions"] = dimensions
        if dimension is not None:
            _payload["dimension"] = dimension
        return await self._call("portfolio.exposure", params=_payload, options=options, context=context, response_format=response_format)

    async def get(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Get portfolio

        Get portfolio details.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return await self._call("portfolio.get", params=_payload, options=options, context=context)

    async def list(
        self,
        *,
        type_: Optional[str] = None,
        input_type: Optional[str] = None,
        search: Optional[str] = None,
        sort: Optional[str] = "createdAt",
        order: Optional[str] = "desc",
        limit: Optional[int] = 50,
        offset: Optional[int] = 0,
        include_shared: Optional[bool] = True,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """List portfolios

        List user's portfolios.

        Args:
        type_: Filter by type
        input_type: Filter by input type
        search: Search in name
        sort: Sort field
        order: Sort order: asc|desc
        limit: Maximum results
        offset: Pagination offset
        include_shared: Include shared portfolios"""
        _payload: Dict[str, Any] = {}
        if type_ is not None:
            _payload["type"] = type_
        if input_type is not None:
            _payload["input_type"] = input_type
        if search is not None:
            _payload["search"] = search
        if sort is not None:
            _payload["sort"] = sort
        if order is not None:
            _payload["order"] = order
        if limit is not None:
            _payload["limit"] = limit
        if offset is not None:
            _payload["offset"] = offset
        if include_shared is not None:
            _payload["include_shared"] = include_shared
        return await self._call("portfolio.list", params=_payload, options=options, context=context)

    async def optimize(
        self,
        *,
        identifiers: Optional[Union[str, List[str]]] = None,
        poll_interval: Optional[str] = None,
        securities_metadata: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[bool] = False,
        currency: Optional[str] = None,
        timeout: Optional[int] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Optimize portfolio

        Portfolio optimization (Julia backend). Pass identifiers for inline mode or id for saved portfolio.

        Args:
        identifiers: TepiloraCodes (for inline mode)
        settings: Optimizer settings (solver_mode, constraints, etc.)
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        total_return: Use total return prices
        currency: Base currency
        timeout: Optimization timeout (seconds)"""
        _payload: Dict[str, Any] = {}
        if identifiers is not None:
            _payload["identifiers"] = identifiers
        if poll_interval is not None:
            _payload["poll_interval"] = poll_interval
        if securities_metadata is not None:
            _payload["securities_metadata"] = securities_metadata
        if settings is not None:
            _payload["settings"] = settings
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        if currency is not None:
            _payload["currency"] = currency
        if timeout is not None:
            _payload["timeout"] = timeout
        return await self._call("portfolio.optimize", params=_payload, options=options, context=context)

    async def rebalance(
        self,
        *,
        costs: Optional[str] = None,
        current_weights: Optional[str] = None,
        min_trade_value: Optional[str] = None,
        portfolio_value: Optional[str] = None,
        strategy: Optional[str] = None,
        target_weights: Optional[Dict[str, Any]] = None,
        threshold: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Rebalance portfolio

        Calculate rebalancing trades.

        Args:
        target_weights: Target weights"""
        _payload: Dict[str, Any] = {}
        if costs is not None:
            _payload["costs"] = costs
        if current_weights is not None:
            _payload["current_weights"] = current_weights
        if min_trade_value is not None:
            _payload["min_trade_value"] = min_trade_value
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if strategy is not None:
            _payload["strategy"] = strategy
        if target_weights is not None:
            _payload["target_weights"] = target_weights
        if threshold is not None:
            _payload["threshold"] = threshold
        return await self._call("portfolio.rebalance", params=_payload, options=options, context=context, response_format=response_format)

    async def returns(
        self,
        *,
        id: str,
        allow_negative_cash: Optional[bool] = None,
        allow_short: Optional[bool] = None,
        auto_cash: Optional[str] = None,
        base_currency: Optional[str] = None,
        borrow_cost: Optional[str] = None,
        borrow_spread_annual: Optional[str] = None,
        cash_yield: Optional[str] = None,
        components: Optional[str] = None,
        currency: Optional[str] = None,
        drifting: Optional[str] = None,
        holdings: Optional[str] = None,
        initial_value: Optional[str] = None,
        max_stale_days: Optional[str] = None,
        Obs: Optional[str] = None,
        price_fill: Optional[str] = None,
        rebalance_dates: Optional[str] = None,
        rebalance_effective: Optional[str] = None,
        rebalance_frequency: Optional[str] = None,
        rebalance_on: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        stale_policy: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        return_method: Optional[str] = "twr",
        total_return: Optional[str] = None,
        trades: Optional[str] = None,
        user_prices: Optional[str] = None,
        values: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
        response_format: Optional[str] = None,
    ) -> Any:
        """Get portfolio returns

        Time series of portfolio returns.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)
        return_method: twr|mwr|modified_dietz"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if allow_negative_cash is not None:
            _payload["allow_negative_cash"] = allow_negative_cash
        if allow_short is not None:
            _payload["allow_short"] = allow_short
        if auto_cash is not None:
            _payload["auto_cash"] = auto_cash
        if base_currency is not None:
            _payload["base_currency"] = base_currency
        if borrow_cost is not None:
            _payload["borrow_cost"] = borrow_cost
        if borrow_spread_annual is not None:
            _payload["borrow_spread_annual"] = borrow_spread_annual
        if cash_yield is not None:
            _payload["cash_yield"] = cash_yield
        if components is not None:
            _payload["components"] = components
        if currency is not None:
            _payload["currency"] = currency
        if drifting is not None:
            _payload["drifting"] = drifting
        if holdings is not None:
            _payload["holdings"] = holdings
        if initial_value is not None:
            _payload["initial_value"] = initial_value
        if max_stale_days is not None:
            _payload["max_stale_days"] = max_stale_days
        if Obs is not None:
            _payload["Obs"] = Obs
        if price_fill is not None:
            _payload["price_fill"] = price_fill
        if rebalance_dates is not None:
            _payload["rebalance_dates"] = rebalance_dates
        if rebalance_effective is not None:
            _payload["rebalance_effective"] = rebalance_effective
        if rebalance_frequency is not None:
            _payload["rebalance_frequency"] = rebalance_frequency
        if rebalance_on is not None:
            _payload["rebalance_on"] = rebalance_on
        if settings is not None:
            _payload["settings"] = settings
        if stale_policy is not None:
            _payload["stale_policy"] = stale_policy
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if return_method is not None:
            _payload["return_method"] = return_method
        if total_return is not None:
            _payload["total_return"] = total_return
        if trades is not None:
            _payload["trades"] = trades
        if user_prices is not None:
            _payload["user_prices"] = user_prices
        if values is not None:
            _payload["values"] = values
        if weights is not None:
            _payload["weights"] = weights
        return await self._call("portfolio.returns", params=_payload, options=options, context=context, response_format=response_format)

    async def share(
        self,
        *,
        id: str,
        target_apikey: str,
        permission: Optional[str] = "read",
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Share portfolio

        Share portfolio with another user.

        Args:
        id: Portfolio ID
        target_apikey: Target user apikey
        permission: read|write"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        _payload["target_apikey"] = target_apikey
        if permission is not None:
            _payload["permission"] = permission
        return await self._call("portfolio.share", params=_payload, options=options, context=context)

    async def shares(
        self,
        *,
        id: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """List shares

        List users with access to portfolio.

        Args:
        id: Portfolio ID"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        return await self._call("portfolio.shares", params=_payload, options=options, context=context)

    async def stress(
        self,
        *,
        id: str,
        asset_class: Optional[str] = None,
        mode: Optional[str] = None,
        portfolio_value: Optional[str] = None,
        scenario: Optional[str] = None,
        scenario_name: Optional[str] = None,
        scenarios: Optional[List[Any]] = None,
        shock_range: Optional[str] = None,
        shocks: Optional[str] = None,
        steps: Optional[str] = None,
        weights: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Stress test

        Portfolio stress testing.

        Args:
        id: Portfolio ID
        scenarios: Custom scenarios"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if asset_class is not None:
            _payload["asset_class"] = asset_class
        if mode is not None:
            _payload["mode"] = mode
        if portfolio_value is not None:
            _payload["portfolio_value"] = portfolio_value
        if scenario is not None:
            _payload["scenario"] = scenario
        if scenario_name is not None:
            _payload["scenario_name"] = scenario_name
        if scenarios is not None:
            _payload["scenarios"] = scenarios
        if shock_range is not None:
            _payload["shock_range"] = shock_range
        if shocks is not None:
            _payload["shocks"] = shocks
        if steps is not None:
            _payload["steps"] = steps
        if weights is not None:
            _payload["weights"] = weights
        return await self._call("portfolio.stress", params=_payload, options=options, context=context)

    async def tearsheet(
        self,
        *,
        id: str,
        benchmark_id: Optional[str] = None,
        benchmark_name: Optional[str] = None,
        benchmark_weights: Optional[str] = None,
        currency: Optional[str] = None,
        name: Optional[str] = None,
        output_path: Optional[str] = None,
        risk_free_rate: Optional[str] = None,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        total_return: Optional[str] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Portfolio tearsheet

        Comprehensive portfolio report.

        Args:
        id: Portfolio ID
        start_date: Start date (YYYY-MM-DD)
        end_date: End date (YYYY-MM-DD)"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if benchmark_id is not None:
            _payload["benchmark_id"] = benchmark_id
        if benchmark_name is not None:
            _payload["benchmark_name"] = benchmark_name
        if benchmark_weights is not None:
            _payload["benchmark_weights"] = benchmark_weights
        if currency is not None:
            _payload["currency"] = currency
        if name is not None:
            _payload["name"] = name
        if output_path is not None:
            _payload["output_path"] = output_path
        if risk_free_rate is not None:
            _payload["risk_free_rate"] = risk_free_rate
        if start_date is not None:
            _payload["start_date"] = start_date
        if end_date is not None:
            _payload["end_date"] = end_date
        if total_return is not None:
            _payload["total_return"] = total_return
        return await self._call("portfolio.tearsheet", params=_payload, options=options, context=context)

    async def unshare(
        self,
        *,
        id: str,
        target_apikey: str,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Unshare portfolio

        Revoke portfolio sharing.

        Args:
        id: Portfolio ID
        target_apikey: User to remove"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        _payload["target_apikey"] = target_apikey
        return await self._call("portfolio.unshare", params=_payload, options=options, context=context)

    async def update(
        self,
        *,
        id: str,
        name: Optional[str] = None,
        input_data: Optional[Dict[str, Any]] = None,
        benchmark: Optional[str] = None,
        description: Optional[str] = None,
        settings: Optional[Dict[str, Any]] = None,
        options: Optional[Dict[str, Any]] = None,
        context: Optional[Dict[str, Any]] = None,
    ) -> Any:
        """Update portfolio

        Update portfolio details.

        Args:
        id: Portfolio ID
        name: New name
        input_data: New holdings/weights
        benchmark: New benchmark
        description: New description
        settings: New settings"""
        _payload: Dict[str, Any] = {}
        _payload["id"] = id
        if name is not None:
            _payload["name"] = name
        if input_data is not None:
            _payload["input_data"] = input_data
        if benchmark is not None:
            _payload["benchmark"] = benchmark
        if description is not None:
            _payload["description"] = description
        if settings is not None:
            _payload["settings"] = settings
        return await self._call("portfolio.update", params=_payload, options=options, context=context)


