"""Shared tool functions for MCP server and OpenClaw skill.

Thin wrappers around the Horizon Engine API that return plain dicts/lists
suitable for JSON serialization. Both the MCP server and the OpenClaw CLI
delegate to these functions.
"""

from __future__ import annotations

import ipaddress
import math
import os
import socket
import threading
from typing import Any
from urllib.parse import urlparse

from horizon._horizon import (
    Engine,
    EngineStatus,
    FeedSnapshot,
    Fill,
    Market,
    Order,
    OrderRequest,
    OrderSide,
    Position,
    Side,
    ContingentOrder,
)
from horizon.discovery import discover_markets, discover_events, top_markets
from horizon.flow import (
    get_market_trades as _get_market_trades,
    get_wallet_trades as _get_wallet_trades,
    get_wallet_positions as _get_wallet_positions,
    get_wallet_value as _get_wallet_value,
    get_top_holders as _get_top_holders,
    get_wallet_profile as _get_wallet_profile,
    analyze_market_flow as _analyze_market_flow,
)

_engine: Engine | None = None
_engine_lock = threading.Lock()


def get_engine() -> Engine:
    """Lazy-init a singleton Engine from environment variables."""
    global _engine
    if _engine is not None:
        return _engine

    with _engine_lock:
        # Double-check after acquiring lock
        if _engine is not None:
            return _engine

        exchange = os.environ.get("HORIZON_EXCHANGE", "paper")
        db_path = os.environ.get("HORIZON_DB") or None

        kwargs: dict[str, Any] = {
            "exchange_type": exchange,
            "db_path": db_path,
            "api_key": os.environ.get("HORIZON_API_KEY"),
        }

        if exchange == "polymarket":
            kwargs["exchange_key"] = os.environ.get("POLYMARKET_API_KEY")
            kwargs["exchange_secret"] = os.environ.get("POLYMARKET_API_SECRET")
            kwargs["exchange_passphrase"] = os.environ.get("POLYMARKET_API_PASSPHRASE")
            kwargs["private_key"] = os.environ.get("POLYMARKET_PRIVATE_KEY")
            kwargs["clob_url"] = os.environ.get("POLYMARKET_CLOB_URL")
        elif exchange == "kalshi":
            kwargs["email"] = os.environ.get("KALSHI_EMAIL")
            kwargs["password"] = os.environ.get("KALSHI_PASSWORD")
            kwargs["exchange_key"] = os.environ.get("KALSHI_API_KEY")
            kwargs["api_url"] = os.environ.get("KALSHI_API_URL")

        _engine = Engine(**kwargs)
        return _engine


def reset_engine() -> None:
    """Reset the singleton engine (for testing)."""
    global _engine
    with _engine_lock:
        _engine = None


# ---------------------------------------------------------------------------
# Serialization helpers
# ---------------------------------------------------------------------------

def _status_to_dict(s: EngineStatus) -> dict:
    return {
        "running": s.running,
        "kill_switch_active": s.kill_switch_active,
        "kill_switch_reason": s.kill_switch_reason,
        "open_orders": s.open_orders,
        "active_positions": s.active_positions,
        "total_realized_pnl": round(s.total_realized_pnl, 6),
        "total_unrealized_pnl": round(s.total_unrealized_pnl, 6),
        "daily_pnl": round(s.daily_pnl, 6),
        "uptime_secs": s.uptime_secs,
    }


def _position_to_dict(p: Position) -> dict:
    return {
        "market_id": p.market_id,
        "side": "yes" if p.side == Side.Yes else "no",
        "size": round(p.size, 6),
        "avg_entry_price": round(p.avg_entry_price, 6),
        "realized_pnl": round(p.realized_pnl, 6),
        "unrealized_pnl": round(p.unrealized_pnl, 6),
        "exchange": p.exchange,
    }


def _order_to_dict(o: Order) -> dict:
    return {
        "id": o.id,
        "market_id": o.market_id,
        "side": "yes" if o.side == Side.Yes else "no",
        "order_side": "buy" if o.order_side == OrderSide.Buy else "sell",
        "price": round(o.price, 6),
        "size": round(o.size, 6),
        "filled_size": round(o.filled_size, 6),
        "remaining_size": round(o.remaining_size, 6),
        "status": str(o.status),
        "exchange": o.exchange,
        "created_at": o.created_at,
    }


def _fill_to_dict(f: Fill) -> dict:
    return {
        "fill_id": f.fill_id,
        "order_id": f.order_id,
        "market_id": f.market_id,
        "side": "yes" if f.side == Side.Yes else "no",
        "order_side": "buy" if f.order_side == OrderSide.Buy else "sell",
        "price": round(f.price, 6),
        "size": round(f.size, 6),
        "fee": round(f.fee, 6),
        "timestamp": f.timestamp,
        "exchange": f.exchange,
    }


def _feed_to_dict(name: str, s: FeedSnapshot) -> dict:
    d = {
        "name": name,
        "price": round(s.price, 6),
        "bid": round(s.bid, 6),
        "ask": round(s.ask, 6),
        "volume_24h": round(s.volume_24h, 2),
        "source": s.source,
        "timestamp": s.timestamp,
    }
    if hasattr(s, "last_trade_size"):
        d["last_trade_size"] = round(s.last_trade_size, 6)
        d["last_trade_is_buy"] = s.last_trade_is_buy
    return d


def _market_to_dict(m: Market) -> dict:
    return {
        "id": m.id,
        "name": m.name,
        "slug": m.slug,
        "exchange": m.exchange,
        "expiry": m.expiry,
        "active": m.active,
    }


def _contingent_to_dict(c: ContingentOrder) -> dict:
    return {
        "id": c.id,
        "trigger_type": str(c.trigger_type),
        "market_id": c.market_id,
        "side": "yes" if c.side == Side.Yes else "no",
        "order_side": "buy" if c.order_side == OrderSide.Buy else "sell",
        "size": round(c.size, 6),
        "trigger_price": round(c.trigger_price, 6),
        "trigger_pnl": c.trigger_pnl,
        "exchange": c.exchange,
        "triggered": c.triggered,
        "child_order_id": c.child_order_id,
    }


# ---------------------------------------------------------------------------
# Tool functions - each returns dict | list[dict] | str
# ---------------------------------------------------------------------------

def engine_status() -> dict:
    """Get trading engine status."""
    try:
        return _status_to_dict(get_engine().status())
    except Exception as e:
        return {"error": str(e)}


def list_positions() -> list[dict] | dict:
    """List all open positions."""
    try:
        return [_position_to_dict(p) for p in get_engine().positions()]
    except Exception as e:
        return {"error": str(e)}


def list_open_orders(market_id: str | None = None) -> list[dict] | dict:
    """List open orders, optionally filtered by market."""
    try:
        eng = get_engine()
        if market_id:
            orders = eng.open_orders_for_market(market_id)
        else:
            orders = eng.open_orders()
        return [_order_to_dict(o) for o in orders]
    except Exception as e:
        return {"error": str(e)}


def list_recent_fills(limit: int = 20) -> list[dict] | dict:
    """List recent fills."""
    try:
        if limit <= 0:
            limit = 20
        fills = get_engine().recent_fills()
        return [_fill_to_dict(f) for f in fills[-limit:]]
    except Exception as e:
        return {"error": str(e)}


def submit_order(
    market_id: str, side: str, price: float, size: float, market_side: str = "yes",
) -> dict:
    """Submit a limit order. side: 'buy' or 'sell'. market_side: 'yes' or 'no'."""
    try:
        if math.isnan(price) or math.isinf(price) or not (0.0 < price < 1.0):
            return {"error": f"price must be a finite number between 0 and 1 (exclusive), got {price}"}
        if math.isnan(size) or math.isinf(size) or size <= 0:
            return {"error": f"size must be a positive finite number, got {size}"}
        side_lower = side.lower()
        if side_lower not in ("buy", "sell"):
            return {"error": f"side must be 'buy' or 'sell', got '{side}'"}
        ms_lower = market_side.lower()
        if ms_lower not in ("yes", "no"):
            return {"error": f"market_side must be 'yes' or 'no', got '{market_side}'"}
        order_side = OrderSide.Buy if side_lower == "buy" else OrderSide.Sell
        ms = Side.Yes if ms_lower == "yes" else Side.No
        req = OrderRequest(
            market_id=market_id,
            side=ms,
            order_side=order_side,
            size=size,
            price=price,
        )
        order_id = get_engine().submit_order(req)
        return {
            "order_id": order_id, "market_id": market_id, "side": side,
            "market_side": market_side, "price": price, "size": size,
        }
    except Exception as e:
        return {"error": str(e)}


def cancel_order(order_id: str) -> dict:
    """Cancel a single order by ID."""
    try:
        get_engine().cancel(order_id)
        return {"canceled": order_id}
    except Exception as e:
        return {"error": str(e)}


def cancel_all_orders() -> dict:
    """Cancel all open orders."""
    try:
        count = get_engine().cancel_all()
        return {"canceled_count": count}
    except Exception as e:
        return {"error": str(e)}


def cancel_market_orders(market_id: str) -> dict:
    """Cancel all orders for a specific market."""
    try:
        count = get_engine().cancel_market(market_id)
        return {"market_id": market_id, "canceled_count": count}
    except Exception as e:
        return {"error": str(e)}


def activate_kill_switch(reason: str) -> dict:
    """Activate the kill switch - emergency stop. Cancels all orders."""
    try:
        get_engine().activate_kill_switch(reason)
        return {"kill_switch": "activated", "reason": reason}
    except Exception as e:
        return {"error": str(e)}


def deactivate_kill_switch() -> dict:
    """Deactivate the kill switch - resume trading."""
    try:
        get_engine().deactivate_kill_switch()
        return {"kill_switch": "deactivated"}
    except Exception as e:
        return {"error": str(e)}


def get_feed_snapshot(name: str) -> dict:
    """Get price/bid/ask snapshot for a named feed."""
    try:
        snap = get_engine().feed_snapshot(name)
        if snap is None:
            return {"error": f"feed not found: {name}"}
        return _feed_to_dict(name, snap)
    except Exception as e:
        return {"error": str(e)}


def list_all_feeds() -> list[dict] | dict:
    """List all feed snapshots."""
    try:
        snapshots = get_engine().all_feed_snapshots()
        return [_feed_to_dict(name, snap) for name, snap in snapshots.items()]
    except Exception as e:
        return {"error": str(e)}


def discover(
    exchange: str = "polymarket",
    query: str = "",
    limit: int = 10,
    market_type: str = "all",
    category: str = "",
) -> list[dict] | dict:
    """Search for markets on an exchange.

    market_type: "all" (default), "binary", or "multi".
    category: Tag/category filter (e.g., "crypto", "politics").
    """
    try:
        results: list[dict] = []

        if market_type in ("all", "binary"):
            markets = discover_markets(exchange=exchange, query=query, limit=limit, category=category)
            results.extend(_market_to_dict(m) for m in markets)

        if market_type in ("all", "multi") and exchange == "polymarket":
            events = discover_events(exchange="polymarket", query=query, limit=limit)
            for ev in events:
                outcomes = []
                for o in ev.outcomes:
                    outcomes.append({
                        "name": o.name,
                        "market_id": o.market_id,
                        "yes_price": round(o.yes_price, 4),
                    })
                results.append({
                    "id": ev.id,
                    "name": ev.name,
                    "type": "multi",
                    "outcome_count": len(outcomes),
                    "outcomes": outcomes,
                    "exchange": ev.exchange,
                    "condition_id": ev.condition_id,
                    "expiry": ev.expiry,
                })

        return results[:limit]
    except Exception as e:
        return {"error": str(e)}


def kelly_sizing(
    prob: float,
    price: float,
    bankroll: float = 1000.0,
    fraction: float = 0.25,
    max_size: float = 100.0,
) -> dict:
    """Compute Kelly-optimal position size."""
    try:
        from horizon._horizon import kelly_size, edge as kelly_edge

        size = kelly_size(prob, price, bankroll, fraction, max_size)
        e = kelly_edge(prob, price)
        return {
            "optimal_size": round(size, 4),
            "edge": round(e, 4),
            "prob": prob,
            "price": price,
            "bankroll": bankroll,
            "fraction": fraction,
        }
    except Exception as e:
        return {"error": str(e)}


def check_parity(market_id: str, feed_name: str | None = None) -> dict:
    """Check YES/NO price parity for a market. Optionally specify a feed_name."""
    try:
        if feed_name is not None:
            result = get_engine().parity_check(market_id, feed_name=feed_name)
        else:
            result = get_engine().parity_check(market_id)
        if result is None:
            return {"error": f"no parity data for market: {market_id}"}
        return {
            "market_id": result.market_id,
            "yes_price": round(result.yes_price, 6),
            "no_price": round(result.no_price, 6),
            "deviation": round(result.deviation, 6),
            "is_violation": result.is_violation,
            "exchange": result.exchange,
        }
    except Exception as e:
        return {"error": str(e)}


def feed_metrics(name: str) -> dict:
    """Get feed connection metrics (update count, errors, reconnects)."""
    try:
        m = get_engine().feed_metrics(name)
        if m is None:
            return {"error": f"no metrics for feed: {name}"}
        return {
            "name": name,
            "update_count": m.update_count,
            "error_count": m.error_count,
            "last_update_time": m.last_update_time,
            "last_error": m.last_error,
            "is_connected": m.is_connected,
            "reconnect_count": m.reconnect_count,
        }
    except Exception as e:
        return {"error": str(e)}


def all_feed_metrics() -> list[dict] | dict:
    """Get metrics for all active feeds."""
    try:
        metrics = get_engine().all_feed_metrics()
        return [
            {
                "name": name,
                "update_count": m.update_count,
                "error_count": m.error_count,
                "last_update_time": m.last_update_time,
                "last_error": m.last_error,
                "is_connected": m.is_connected,
                "reconnect_count": m.reconnect_count,
            }
            for name, m in metrics.items()
        ]
    except Exception as e:
        return {"error": str(e)}


def add_stop_loss(
    market_id: str,
    side: str,
    order_side: str,
    size: float,
    trigger: float,
) -> dict:
    """Add a stop-loss contingent order."""
    try:
        if not math.isfinite(size) or size <= 0:
            return {"error": f"size must be a positive finite number, got {size}"}
        if not math.isfinite(trigger) or trigger <= 0:
            return {"error": f"trigger must be a positive finite number, got {trigger}"}
        side_lower = side.lower()
        if side_lower not in ("yes", "no"):
            return {"error": f"side must be 'yes' or 'no', got '{side}'"}
        os_lower = order_side.lower()
        if os_lower not in ("buy", "sell"):
            return {"error": f"order_side must be 'buy' or 'sell', got '{order_side}'"}
        s = Side.Yes if side_lower == "yes" else Side.No
        os_ = OrderSide.Buy if os_lower == "buy" else OrderSide.Sell
        cid = get_engine().add_stop_loss(market_id, s, os_, size, trigger)
        return {"contingent_id": cid, "type": "stop_loss", "market_id": market_id}
    except Exception as e:
        return {"error": str(e)}


def add_take_profit(
    market_id: str,
    side: str,
    order_side: str,
    size: float,
    trigger: float,
) -> dict:
    """Add a take-profit contingent order."""
    try:
        if not math.isfinite(size) or size <= 0:
            return {"error": f"size must be a positive finite number, got {size}"}
        if not math.isfinite(trigger) or trigger <= 0:
            return {"error": f"trigger must be a positive finite number, got {trigger}"}
        side_lower = side.lower()
        if side_lower not in ("yes", "no"):
            return {"error": f"side must be 'yes' or 'no', got '{side}'"}
        os_lower = order_side.lower()
        if os_lower not in ("buy", "sell"):
            return {"error": f"order_side must be 'buy' or 'sell', got '{order_side}'"}
        s = Side.Yes if side_lower == "yes" else Side.No
        os_ = OrderSide.Buy if os_lower == "buy" else OrderSide.Sell
        cid = get_engine().add_take_profit(market_id, s, os_, size, trigger)
        return {"contingent_id": cid, "type": "take_profit", "market_id": market_id}
    except Exception as e:
        return {"error": str(e)}


def list_contingent_orders() -> list[dict] | dict:
    """List pending stop-loss and take-profit orders."""
    try:
        return [_contingent_to_dict(c) for c in get_engine().pending_contingent_orders()]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Discovery tools
# ---------------------------------------------------------------------------

def discover_event(
    query: str = "",
    limit: int = 10,
    min_volume: float = 0.0,
) -> list[dict] | dict:
    """Discover multi-outcome events on Polymarket."""
    try:
        events = discover_events(
            exchange="polymarket", query=query,
            active=True, limit=limit, min_volume=min_volume,
        )
        results = []
        for ev in events:
            outcomes = []
            for o in ev.outcomes:
                outcomes.append({
                    "name": o.name,
                    "market_id": o.market_id,
                    "yes_price": round(o.yes_price, 4),
                })
            results.append({
                "id": ev.id,
                "name": ev.name,
                "outcome_count": len(outcomes),
                "outcomes": outcomes,
                "exchange": ev.exchange,
                "condition_id": ev.condition_id,
                "expiry": ev.expiry,
            })
        return results
    except Exception as e:
        return {"error": str(e)}


def market_detail(slug_or_id: str, exchange: str = "polymarket") -> dict:
    """Fetch full detail for a single market."""
    try:
        from horizon.discovery import get_market_detail
        return get_market_detail(slug_or_id, exchange=exchange)
    except Exception as e:
        return {"error": str(e)}


def get_top_markets(
    exchange: str = "polymarket",
    limit: int = 10,
    category: str = "",
) -> list[dict] | dict:
    """Get top markets by volume."""
    try:
        markets = top_markets(exchange=exchange, limit=limit, category=category)
        return [_market_to_dict(m) for m in markets]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Wallet analytics tools
# ---------------------------------------------------------------------------

def wallet_trades(
    address: str,
    limit: int = 50,
    condition_id: str | None = None,
) -> list[dict] | dict:
    """Fetch trade history for a Polymarket wallet."""
    try:
        trades = _get_wallet_trades(address, limit=limit, condition_id=condition_id)
        return [
            {
                "wallet": t.wallet,
                "side": t.side,
                "outcome": t.outcome,
                "size": round(t.size, 4),
                "price": round(t.price, 4),
                "usdc_size": round(t.usdc_size, 2),
                "timestamp": t.timestamp,
                "market_slug": t.market_slug,
                "market_title": t.market_title,
                "pseudonym": t.pseudonym,
            }
            for t in trades
        ]
    except Exception as e:
        return {"error": str(e)}


def market_trades(
    condition_id: str,
    limit: int = 50,
    side: str | None = None,
    min_size: float = 0.0,
) -> list[dict] | dict:
    """Fetch recent trades for a Polymarket market."""
    try:
        trades = _get_market_trades(
            condition_id, limit=limit, side=side, min_size=min_size,
        )
        return [
            {
                "wallet": t.wallet,
                "side": t.side,
                "outcome": t.outcome,
                "size": round(t.size, 4),
                "price": round(t.price, 4),
                "usdc_size": round(t.usdc_size, 2),
                "timestamp": t.timestamp,
                "market_title": t.market_title,
                "pseudonym": t.pseudonym,
            }
            for t in trades
        ]
    except Exception as e:
        return {"error": str(e)}


def wallet_positions(
    address: str,
    limit: int = 50,
    sort_by: str = "CURRENT",
) -> list[dict] | dict:
    """Fetch open positions for a Polymarket wallet."""
    try:
        positions = _get_wallet_positions(address, limit=limit, sort_by=sort_by)
        return [
            {
                "market_title": p.market_title,
                "market_slug": p.market_slug,
                "outcome": p.outcome,
                "size": round(p.size, 4),
                "avg_price": round(p.avg_price, 4),
                "current_price": round(p.current_price, 4),
                "current_value": round(p.current_value, 2),
                "pnl": round(p.pnl, 2),
                "pnl_percent": round(p.pnl_percent, 2),
            }
            for p in positions
        ]
    except Exception as e:
        return {"error": str(e)}


def wallet_value(address: str) -> dict:
    """Get total USD value of a Polymarket wallet's positions."""
    try:
        value = _get_wallet_value(address)
        return {"wallet": address, "total_value_usd": round(value, 2)}
    except Exception as e:
        return {"error": str(e)}


def wallet_profile(address: str) -> dict:
    """Get public profile for a Polymarket wallet."""
    try:
        profile = _get_wallet_profile(address)
        if profile is None:
            return {"error": f"no profile found for {address}"}
        return {
            "wallet": profile.wallet,
            "pseudonym": profile.pseudonym,
            "name": profile.name,
            "bio": profile.bio,
            "profile_image": profile.profile_image,
            "x_username": profile.x_username,
            "created_at": profile.created_at,
        }
    except Exception as e:
        return {"error": str(e)}


def market_top_holders(condition_id: str, limit: int = 20) -> list[dict] | dict:
    """Get top holders for a Polymarket market."""
    try:
        holders = _get_top_holders(condition_id, limit=limit)
        return [
            {
                "wallet": h.wallet,
                "amount": round(h.amount, 4),
                "token_id": h.token_id,
                "outcome_index": h.outcome_index,
                "pseudonym": h.pseudonym,
                "name": h.name,
            }
            for h in holders
        ]
    except Exception as e:
        return {"error": str(e)}


def market_flow(
    condition_id: str,
    trade_limit: int = 500,
    top_n: int = 10,
) -> dict:
    """Analyze trade flow for a Polymarket market."""
    try:
        flow = _analyze_market_flow(
            condition_id, trade_limit=trade_limit, top_n=top_n,
        )
        return {
            "condition_id": flow.condition_id,
            "total_trades": flow.total_trades,
            "buy_volume": round(flow.buy_volume, 2),
            "sell_volume": round(flow.sell_volume, 2),
            "net_flow": round(flow.net_flow, 2),
            "unique_wallets": flow.unique_wallets,
            "top_buyers": [
                {"wallet": w, "volume": round(v, 2)} for w, v in flow.top_buyers
            ],
            "top_sellers": [
                {"wallet": w, "volume": round(v, 2)} for w, v in flow.top_sellers
            ],
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# URL validation (SSRF prevention)
# ---------------------------------------------------------------------------

# Private/reserved IP networks that must not be reached by feeds.
_BLOCKED_NETWORKS = [
    ipaddress.ip_network("127.0.0.0/8"),       # loopback
    ipaddress.ip_network("10.0.0.0/8"),         # RFC 1918
    ipaddress.ip_network("172.16.0.0/12"),      # RFC 1918
    ipaddress.ip_network("192.168.0.0/16"),     # RFC 1918
    ipaddress.ip_network("169.254.0.0/16"),     # link-local
    ipaddress.ip_network("::1/128"),            # IPv6 loopback
    ipaddress.ip_network("fc00::/7"),           # IPv6 unique-local
    ipaddress.ip_network("fe80::/10"),          # IPv6 link-local
]


def _validate_url(url: str) -> str:
    """Validate a URL for use in feeds, preventing SSRF attacks.

    Checks:
    1. Scheme must be http or https.
    2. Hostname must be present.
    3. Resolved IP addresses must not fall in private/reserved ranges.

    Returns the original URL if valid; raises ``ValueError`` otherwise.
    """
    parsed = urlparse(url)

    # 1. Scheme check
    if parsed.scheme not in ("http", "https"):
        raise ValueError(
            f"Invalid URL scheme '{parsed.scheme}': only http and https are allowed"
        )

    # 2. Hostname check
    hostname = parsed.hostname
    if not hostname:
        raise ValueError("URL must include a hostname")

    # 3. Resolve and check against blocked networks
    try:
        addr_infos = socket.getaddrinfo(hostname, parsed.port or 443)
    except socket.gaierror as e:
        raise ValueError(f"Cannot resolve hostname '{hostname}': {e}") from e

    for _family, _type, _proto, _canonname, sockaddr in addr_infos:
        ip = ipaddress.ip_address(sockaddr[0])
        for network in _BLOCKED_NETWORKS:
            if ip in network:
                raise ValueError(
                    f"URL resolves to private/reserved address {ip} "
                    f"(network {network}): request blocked for security"
                )

    return url


# ---------------------------------------------------------------------------
# Feed health tools
# ---------------------------------------------------------------------------

def start_feed(
    name: str,
    feed_type: str,
    config_json: str | None = None,
    symbol: str | None = None,
    url: str | None = None,
    interval: float = 5.0,
) -> dict:
    """Start a live data feed on the engine.

    For newer feed types (predictit, manifold, espn, nws, rest_json_path,
    chainlink), pass structured config via ``config_json``.
    For legacy types (binance_ws, polymarket_book, kalshi_book, rest),
    use the keyword arguments.
    """
    try:
        # SSRF prevention: validate any URL before passing to the engine.
        if url is not None:
            _validate_url(url)

        # Also validate URLs embedded in config_json for feed types that
        # accept a url/rpc_url field.
        if config_json is not None:
            import json as _json
            try:
                cfg = _json.loads(config_json)
                for url_key in ("url", "rpc_url", "api_url"):
                    if url_key in cfg and isinstance(cfg[url_key], str):
                        _validate_url(cfg[url_key])
            except (ValueError, TypeError):
                # Re-raise ValueError from _validate_url; ignore JSON parse
                # errors (the engine will handle malformed JSON).
                import sys
                exc = sys.exc_info()[1]
                if isinstance(exc, ValueError) and "URL" in str(exc):
                    raise
                # Otherwise it's a JSON parse issue — let the engine handle it.

        kwargs: dict[str, Any] = {}
        if symbol is not None:
            kwargs["symbol"] = symbol
        if url is not None:
            kwargs["url"] = url
        kwargs["interval"] = interval
        if config_json is not None:
            kwargs["config_json"] = config_json
        get_engine().start_feed(name, feed_type, **kwargs)
        return {"started": name, "feed_type": feed_type}
    except ValueError as e:
        return {"error": str(e)}
    except Exception as e:
        return {"error": str(e)}


def check_feed_health(stale_threshold: float = 30.0) -> dict:
    """Check staleness and health of all active feeds."""
    try:
        import time
        snapshots = get_engine().all_feed_snapshots()
        now = time.time()
        feeds = {}
        stale_count = 0
        for name, snap in snapshots.items():
            age = now - snap.timestamp if snap.timestamp > 0 else float("inf")
            is_stale = age > stale_threshold or snap.timestamp <= 0
            if is_stale:
                stale_count += 1
            feeds[name] = {
                "name": name,
                "is_stale": is_stale,
                "age_secs": round(age, 1),
                "price": round(snap.price, 6),
                "bid": round(snap.bid, 6),
                "ask": round(snap.ask, 6),
            }
        return {
            "feeds": feeds,
            "total_feeds": len(feeds),
            "stale_count": stale_count,
            "all_stale": stale_count == len(feeds) and len(feeds) > 0,
            "stale_threshold_secs": stale_threshold,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Simulation tools
# ---------------------------------------------------------------------------

def simulate_portfolio(
    scenarios: int = 10000,
    seed: int | None = None,
) -> dict:
    """Run Monte Carlo simulation on the engine's current positions."""
    try:
        from horizon.simulate import simulate
        result = simulate(engine=get_engine(), scenarios=scenarios, seed=seed)
        return {
            "mean_pnl": round(result.mean_pnl, 2),
            "median_pnl": round(result.median_pnl, 2),
            "std_dev": round(result.std_dev, 2),
            "var_95": round(result.var_95, 2),
            "var_99": round(result.var_99, 2),
            "cvar_95": round(result.cvar_95, 2),
            "max_loss": round(result.max_loss, 2),
            "max_gain": round(result.max_gain, 2),
            "win_probability": round(result.win_probability, 4),
            "scenarios": scenarios,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Arbitrage tools
# ---------------------------------------------------------------------------

def execute_arb(
    market_id: str,
    buy_exchange: str,
    sell_exchange: str,
    buy_price: float,
    sell_price: float,
    size: float,
) -> dict:
    """Execute a cross-exchange arbitrage trade with atomic rollback."""
    try:
        buy_id, sell_id = get_engine().execute_arbitrage(
            market_id, buy_exchange, sell_exchange,
            buy_price=buy_price, sell_price=sell_price, size=size,
        )
        return {
            "buy_order_id": buy_id,
            "sell_order_id": sell_id,
            "market_id": market_id,
            "buy_exchange": buy_exchange,
            "sell_exchange": sell_exchange,
            "buy_price": buy_price,
            "sell_price": sell_price,
            "size": size,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Quantitative analytics tools
# ---------------------------------------------------------------------------

def compute_shannon_entropy(p: float) -> dict:
    """Compute binary Shannon entropy for a probability."""
    try:
        from horizon._horizon import shannon_entropy
        return {"entropy": round(shannon_entropy(p), 6), "probability": p}
    except Exception as e:
        return {"error": str(e)}


def compute_kl_divergence(p: list[float], q: list[float]) -> dict:
    """Compute KL divergence between two probability distributions."""
    try:
        from horizon._horizon import kl_divergence
        return {"kl_divergence": round(kl_divergence(p, q), 6)}
    except Exception as e:
        return {"error": str(e)}


def compute_hurst_exponent(prices: list[float]) -> dict:
    """Compute Hurst exponent for a price series. >0.5 trending, <0.5 mean-reverting."""
    try:
        from horizon._horizon import hurst_exponent
        h = hurst_exponent(prices)
        regime = "trending" if h > 0.55 else "mean-reverting" if h < 0.45 else "random walk"
        return {"hurst": round(h, 4), "regime": regime}
    except Exception as e:
        return {"error": str(e)}


def compute_variance_ratio(returns: list[float], period: int = 2) -> dict:
    """Variance ratio test. 1.0 = random walk."""
    try:
        from horizon._horizon import variance_ratio
        vr = variance_ratio(returns, period)
        is_efficient = 0.8 <= vr <= 1.2
        return {"variance_ratio": round(vr, 4), "period": period, "is_efficient": is_efficient}
    except Exception as e:
        return {"error": str(e)}


def compute_cornish_fisher_var(returns: list[float], confidence: float = 0.95) -> dict:
    """Cornish-Fisher VaR/CVaR (skew/kurtosis-adjusted)."""
    try:
        from horizon._horizon import cornish_fisher_var, cornish_fisher_cvar
        var = cornish_fisher_var(returns, confidence)
        cvar = cornish_fisher_cvar(returns, confidence)
        return {
            "var": round(var, 6),
            "cvar": round(cvar, 6),
            "confidence": confidence,
            "n_observations": len(returns),
        }
    except Exception as e:
        return {"error": str(e)}


def compute_prediction_greeks(
    price: float,
    size: float,
    is_yes: bool = True,
    t_hours: float = 24.0,
    vol: float = 0.2,
) -> dict:
    """Compute prediction Greeks (delta, gamma, theta, vega) for a binary market position."""
    try:
        from horizon._horizon import prediction_greeks
        g = prediction_greeks(price, size, is_yes, t_hours, vol)
        return {
            "delta": round(g.delta, 6),
            "gamma": round(g.gamma, 6),
            "theta": round(g.theta, 6),
            "vega": round(g.vega, 6),
            "price": price,
            "size": size,
        }
    except Exception as e:
        return {"error": str(e)}


def compute_deflated_sharpe(
    sharpe: float,
    n_obs: int,
    n_trials: int,
    skew: float = 0.0,
    kurt: float = 3.0,
) -> dict:
    """Deflated Sharpe Ratio: tests if observed Sharpe is statistically significant given multiple trials."""
    try:
        from horizon._horizon import deflated_sharpe, bonferroni_threshold
        p_value = deflated_sharpe(sharpe, n_obs, n_trials, skew, kurt)
        bonf = bonferroni_threshold(0.05, n_trials)
        return {
            "p_value": round(p_value, 6),
            "is_significant": p_value < 0.05,
            "bonferroni_alpha": round(bonf, 6),
            "sharpe": sharpe,
            "n_obs": n_obs,
            "n_trials": n_trials,
        }
    except Exception as e:
        return {"error": str(e)}


def run_signal_diagnostics(predictions: list[float], outcomes: list[float]) -> dict:
    """Run signal diagnostics: information coefficient, half-life, Hurst exponent."""
    try:
        from horizon.quant import signal_diagnostics
        return signal_diagnostics(predictions, outcomes)
    except Exception as e:
        return {"error": str(e)}


def run_market_efficiency(prices: list[float]) -> dict:
    """Analyze market efficiency: variance ratio, Hurst exponent, efficiency flag."""
    try:
        from horizon.quant import market_efficiency
        return market_efficiency(prices)
    except Exception as e:
        return {"error": str(e)}


def run_stress_test(
    n_simulations: int = 10000,
    seed: int | None = None,
) -> dict:
    """Run stress test on current engine positions under adverse scenarios."""
    try:
        n_simulations = min(n_simulations, 100_000)
        from horizon._horizon import SimPosition
        from horizon.stress import stress_test, CORRELATION_SPIKE, ALL_RESOLVE_NO, LIQUIDITY_SHOCK, TAIL_RISK

        eng = get_engine()
        positions = eng.positions()
        if not positions:
            return {"error": "no open positions to stress test"}

        sim_positions = []
        feeds = eng.all_feed_snapshots()
        for p in positions:
            price = 0.5
            snap = feeds.get(p.market_id)
            if snap is not None:
                price = snap.price
            sim_positions.append(SimPosition(
                p.market_id,
                "yes" if p.side == Side.Yes else "no",
                p.size,
                p.avg_entry_price,
                price,
            ))

        result = stress_test(sim_positions, n_simulations=n_simulations, seed=seed)
        return {
            "worst_scenario": result.worst_scenario,
            "worst_pnl": round(result.worst_pnl, 2),
            "scenarios": [
                {
                    "name": s.scenario.name,
                    "mean_pnl": round(s.sim.mean_pnl, 2),
                    "var_95": round(s.sim.var_95, 2),
                    "worst_pnl": round(s.sim.max_loss, 2),
                }
                for s in result.scenarios
            ],
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Tearsheet tools
# ---------------------------------------------------------------------------

def generate_tearsheet_report(
    equity_curve: list[float] | None = None,
    timestamps: list[float] | None = None,
    trades: list | None = None,
    initial_capital: float = 1000.0,
) -> dict:
    """Generate a tearsheet with monthly returns, rolling Sharpe/Sortino, drawdown analysis, and trade stats."""
    try:
        from horizon.analytics import generate_tearsheet
        # Build (timestamp, equity) tuples from separate lists
        ec = equity_curve or []
        ts_list = timestamps or []
        if ts_list and ec:
            curve = list(zip(ts_list, ec))
        else:
            curve = [(float(i), v) for i, v in enumerate(ec)]
        ts = generate_tearsheet(
            equity_curve=curve,
            trades=trades or [],
            initial_capital=initial_capital,
        )
        return {
            "monthly_returns": ts.monthly_returns,
            "avg_win": round(ts.avg_win, 4),
            "avg_loss": round(ts.avg_loss, 4),
            "largest_win": round(ts.largest_win, 4),
            "largest_loss": round(ts.largest_loss, 4),
            "avg_hold_time": round(ts.avg_hold_time, 2),
            "win_streak": ts.win_streak,
            "loss_streak": ts.loss_streak,
            "max_consecutive_wins": ts.max_consecutive_wins,
            "max_consecutive_losses": ts.max_consecutive_losses,
            "tail_ratio": round(ts.tail_ratio, 4),
            "time_of_day": {str(k): round(v, 6) for k, v in ts.time_of_day.items()},
            "drawdowns": [
                {
                    "start_ts": round(d.start_ts, 2),
                    "end_ts": round(d.end_ts, 2),
                    "recovery_ts": round(d.recovery_ts, 2) if d.recovery_ts else None,
                    "depth_pct": round(d.depth_pct, 6),
                    "duration_secs": round(d.duration_secs, 2),
                }
                for d in (ts.drawdowns or [])
            ],
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Bayesian optimization tools
# ---------------------------------------------------------------------------

def run_bayesian_optimize(
    param_space: dict[str, list[float]],
    n_iterations: int = 20,
    n_initial: int = 5,
    seed: int | None = None,
) -> dict:
    """Run Bayesian optimization (GP + Expected Improvement) to find optimal strategy parameters."""
    try:
        from horizon.bayesian_opt import bayesian_optimize
        # Create a simple quadratic objective for parameter exploration
        # In practice, users would provide their own objective via Python
        def objective(**params):
            # Default: negative sum of squared deviations from midpoint
            total = 0.0
            for name, val in params.items():
                bounds = param_space.get(name, [0, 1])
                mid = (bounds[0] + bounds[1]) / 2
                total -= (val - mid) ** 2
            return total

        result = bayesian_optimize(
            objective=objective,
            param_space=param_space,
            n_iterations=n_iterations,
            n_initial=n_initial,
            seed=seed,
        )
        return {
            "best_params": {k: round(v, 6) for k, v in result.best_params.items()},
            "best_value": round(result.best_value, 6),
            "n_iterations": result.n_iterations,
            "all_values": [round(v, 6) for v in result.all_values],
            "note": (
                "Using default quadratic objective (finds midpoint of each "
                "parameter range). For real strategy optimization, pass a "
                "custom objective via the Python API: "
                "bayesian_optimize(objective=my_fn, ...)"
            ),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Portfolio management tools
# ---------------------------------------------------------------------------

def get_portfolio_metrics() -> dict:
    """Get portfolio metrics: total value, PnL, diversification, concentration, Sharpe."""
    try:
        from horizon.portfolio import Portfolio
        eng = get_engine()
        portfolio = Portfolio.from_engine(eng)
        metrics = portfolio.metrics()
        return {
            "total_value": round(metrics.total_value, 2),
            "total_pnl": round(metrics.total_pnl, 2),
            "total_pnl_pct": round(metrics.total_pnl_pct, 4),
            "num_positions": metrics.num_positions,
            "long_exposure": round(metrics.long_exposure, 2),
            "short_exposure": round(metrics.short_exposure, 2),
            "net_exposure": round(metrics.net_exposure, 2),
            "gross_exposure": round(metrics.gross_exposure, 2),
            "herfindahl_index": round(metrics.herfindahl_index, 4),
            "max_concentration": round(metrics.max_concentration, 4),
        }
    except Exception as e:
        return {"error": str(e)}


def get_portfolio_weights(method: str = "equal") -> dict:
    """Compute optimal portfolio weights. method: 'equal', 'kelly', 'risk_parity', 'min_variance'."""
    try:
        from horizon.portfolio import Portfolio
        eng = get_engine()
        portfolio = Portfolio.from_engine(eng)
        if method == "kelly":
            weights = portfolio.optimize_kelly()
        elif method == "risk_parity":
            weights = portfolio.optimize_risk_parity()
        elif method == "min_variance":
            weights = portfolio.optimize_min_variance()
        else:
            weights = portfolio.optimize_equal_weight()
        return {
            "method": method,
            "weights": {k: round(v, 6) for k, v in weights.items()},
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Hot-reload parameter tools
# ---------------------------------------------------------------------------

def update_runtime_params(params: dict[str, float]) -> dict:
    """Update runtime parameters on the engine (hot-reload). Values available to pipeline via ctx.params."""
    try:
        if any(k.startswith("_") for k in params):
            return {"error": "parameter keys starting with '_' are reserved for internal use"}
        if any(not math.isfinite(v) for v in params.values()):
            return {"error": "params contain NaN or Inf values"}
        eng = get_engine()
        eng.update_params_batch(params)
        return {"updated": list(params.keys()), "count": len(params)}
    except Exception as e:
        return {"error": str(e)}


def get_runtime_params() -> dict:
    """Get all current runtime parameters from the engine."""
    try:
        eng = get_engine()
        params = eng.get_all_params()
        return {"params": {k: round(v, 6) for k, v in params.items()}, "count": len(params)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Hawkes process tools
# ---------------------------------------------------------------------------

def compute_hawkes_intensity(
    event_times: list[float],
    mu: float = 0.1,
    alpha: float = 0.5,
    beta: float = 1.0,
) -> dict:
    """Compute Hawkes process intensity given event timestamps. Models self-exciting trade arrival."""
    try:
        from horizon._horizon import HawkesProcess
        hp = HawkesProcess(mu=mu, alpha=alpha, beta=beta)
        for t in event_times:
            hp.add_event(t)
        now = event_times[-1] + 1e-6 if event_times else 0.0
        return {
            "intensity": round(hp.intensity(now), 6),
            "branching_ratio": round(hp.branching_ratio(), 6),
            "expected_events_1m": round(hp.expected_events(now, 60.0), 4),
            "event_count": hp.event_count(),
            "mu": mu,
            "alpha": alpha,
            "beta": beta,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Ledoit-Wolf correlation tools
# ---------------------------------------------------------------------------

def compute_correlation_matrix(
    returns: list[list[float]],
) -> dict:
    """Compute Ledoit-Wolf shrinkage covariance matrix. Input: list of observations, each a list of asset returns."""
    try:
        from horizon._horizon import ledoit_wolf_shrinkage
        matrix, shrinkage = ledoit_wolf_shrinkage(returns)
        return {
            "matrix": [[round(v, 8) for v in row] for row in matrix],
            "shrinkage_intensity": round(shrinkage, 6),
            "n_assets": len(matrix),
            "n_observations": len(returns),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# AFML: Information-driven bars
# ---------------------------------------------------------------------------

def compute_tick_bars(
    timestamps: list[float], prices: list[float], volumes: list[float], bar_size: int,
) -> list[dict] | dict:
    """Generate tick bars (fixed number of ticks per bar)."""
    try:
        from horizon._horizon import tick_bars
        bars = tick_bars(timestamps, prices, volumes, bar_size)
        return [_bar_to_dict(b) for b in bars]
    except Exception as e:
        return {"error": str(e)}


def compute_volume_bars(
    timestamps: list[float], prices: list[float], volumes: list[float], bar_size: float,
) -> list[dict] | dict:
    """Generate volume bars (fixed total volume per bar)."""
    try:
        from horizon._horizon import volume_bars
        bars = volume_bars(timestamps, prices, volumes, bar_size)
        return [_bar_to_dict(b) for b in bars]
    except Exception as e:
        return {"error": str(e)}


def compute_dollar_bars(
    timestamps: list[float], prices: list[float], volumes: list[float], bar_size: float,
) -> list[dict] | dict:
    """Generate dollar bars (fixed total dollar value per bar)."""
    try:
        from horizon._horizon import dollar_bars
        bars = dollar_bars(timestamps, prices, volumes, bar_size)
        return [_bar_to_dict(b) for b in bars]
    except Exception as e:
        return {"error": str(e)}


def _bar_to_dict(b) -> dict:
    return {
        "timestamp": b.timestamp,
        "open": round(b.open, 6),
        "high": round(b.high, 6),
        "low": round(b.low, 6),
        "close": round(b.close, 6),
        "volume": round(b.volume, 4),
        "vwap": round(b.vwap, 6),
        "n_ticks": b.n_ticks,
    }


# ---------------------------------------------------------------------------
# AFML: Triple barrier labeling
# ---------------------------------------------------------------------------

def compute_cusum_filter(prices: list[float], threshold: float) -> list[int] | dict:
    """Run CUSUM filter for structural break detection. Returns event indices."""
    try:
        from horizon._horizon import cusum_filter
        return cusum_filter(prices, threshold)
    except Exception as e:
        return {"error": str(e)}


def compute_triple_barrier(
    prices: list[float],
    timestamps: list[float],
    events: list[int],
    pt_sl: list[float] | None = None,
    min_ret: float = 0.0,
    max_holding: int = 100,
    vol_span: int = 20,
) -> list[dict] | dict:
    """Apply triple barrier labeling to event indices."""
    try:
        from horizon._horizon import triple_barrier_labels
        labels = triple_barrier_labels(
            prices, timestamps, events,
            pt_sl=pt_sl or [1.0, 1.0],
            min_ret=min_ret, max_holding=max_holding, vol_span=vol_span,
        )
        return [
            {
                "event_idx": lb.event_idx,
                "label": lb.label,
                "ret": round(lb.ret, 6),
                "barrier": lb.barrier,
                "touch_idx": lb.touch_idx,
            }
            for lb in labels
        ]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# AFML: Fractional differentiation
# ---------------------------------------------------------------------------

def compute_frac_diff(
    series: list[float], d: float, threshold: float = 1e-5,
) -> list[float] | dict:
    """Apply Fixed-Width Window fractional differentiation."""
    try:
        from horizon._horizon import frac_diff_ffd
        return [round(v, 8) for v in frac_diff_ffd(series, d, threshold)]
    except Exception as e:
        return {"error": str(e)}


def compute_min_frac_diff(
    series: list[float],
    p_threshold: float = 0.05,
    max_d: float = 1.0,
    n_steps: int = 10,
) -> dict:
    """Find minimum fractional differentiation d for stationarity."""
    try:
        from horizon._horizon import min_frac_diff
        d = min_frac_diff(series, p_threshold, max_d, n_steps)
        return {"d_star": round(d, 4), "p_threshold": p_threshold}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# AFML: HRP & denoising
# ---------------------------------------------------------------------------

def compute_hrp_weights(covariance: list[list[float]]) -> dict:
    """Compute Hierarchical Risk Parity weights from a covariance matrix."""
    try:
        from horizon._horizon import hrp_weights
        result = hrp_weights(covariance)
        return {
            "weights": [round(w, 6) for w in result.weights],
            "sorted_indices": list(result.sorted_indices),
            "n_assets": len(result.weights),
        }
    except Exception as e:
        return {"error": str(e)}


def compute_denoise_covariance(
    covariance: list[list[float]], n_observations: int,
) -> dict:
    """Denoise a covariance matrix using Marcenko-Pastur random matrix theory."""
    try:
        from horizon._horizon import denoise_covariance
        result = denoise_covariance(covariance, n_observations)
        return {
            "covariance": [[round(v, 8) for v in row] for row in result.covariance],
            "eigenvalues": [round(e, 8) for e in result.eigenvalues],
            "n_signals": result.n_signals,
            "n_noise": result.n_noise,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Copy-trading tools
# ---------------------------------------------------------------------------

def start_copy_trades(
    wallet: str,
    size_scale: float = 1.0,
    max_position: float = 1000.0,
    poll_interval: float = 30.0,
    exchange: str = "paper",
    inverse: bool = False,
    dry_run: bool = False,
) -> dict:
    """Start copy-trading a Polymarket wallet.

    Launches the copy-trade loop in a background thread.
    """
    try:
        from horizon.copy_trader import copy_trades
        import threading

        kwargs = {
            "wallet": wallet,
            "size_scale": size_scale,
            "max_position": max_position,
            "poll_interval": poll_interval,
            "exchange": exchange,
            "inverse": inverse,
            "dry_run": dry_run,
        }

        thread = threading.Thread(
            target=copy_trades, kwargs=kwargs, daemon=True,
        )
        thread.start()

        return {
            "started": True,
            "wallet": wallet,
            "size_scale": size_scale,
            "max_position": max_position,
            "poll_interval": poll_interval,
            "exchange": exchange,
            "inverse": inverse,
            "dry_run": dry_run,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Wallet intelligence tools
# ---------------------------------------------------------------------------

def wallet_score(address: str, limit: int = 500) -> dict:
    """Score a wallet's trading performance (win rate, Sharpe, composite score)."""
    try:
        from horizon.wallet_intel import score_wallet
        s = score_wallet(address, limit=limit)
        return {
            "wallet": s.wallet,
            "win_rate": s.win_rate,
            "avg_pnl_pct": s.avg_pnl_pct,
            "sharpe": s.sharpe,
            "total_pnl": s.total_pnl,
            "trade_count": s.trade_count,
            "position_count": s.position_count,
            "composite_score": s.composite_score,
        }
    except Exception as e:
        return {"error": str(e)}


def wallet_analysis(address: str, trade_limit: int = 500) -> dict:
    """Analyze a wallet for exploitable trading patterns."""
    try:
        from horizon.wallet_intel import analyze_wallet
        a = analyze_wallet(address, trade_limit=trade_limit)
        return {
            "wallet": a.wallet,
            "patterns": [
                {
                    "name": p.name,
                    "description": p.description,
                    "value": p.value,
                    "exploitable": p.exploitable,
                    "counter_strategy": p.counter_strategy,
                }
                for p in a.patterns
            ],
            "vulnerability_score": a.vulnerability_score,
            "counter_strategies": a.counter_strategies,
            "trade_count": a.trade_count,
            "analysis_period_hours": a.analysis_period_hours,
        }
    except Exception as e:
        return {"error": str(e)}


def wallet_profiler(address: str, trade_limit: int = 500) -> dict:
    """Generate a deep behavioral profile for a wallet with profit strategies."""
    try:
        from horizon.wallet_profiler import profile_wallet
        p = profile_wallet(address, trade_limit=trade_limit)
        return {
            "wallet": p.wallet,
            "composite_score": p.score.composite_score,
            "win_rate": p.score.win_rate,
            "total_pnl": p.score.total_pnl,
            "data_quality": p.data_quality,
            # Temporal
            "peak_hour": p.temporal.hour_distribution.peak_hour,
            "hour_entropy": round(p.temporal.hour_distribution.entropy, 4),
            "session": p.temporal.session.session,
            "is_bursty": p.temporal.burst.is_bursty,
            "burstiness": p.temporal.burst.burstiness,
            "active_days_pct": p.temporal.active_days_pct,
            "weekend_ratio": p.temporal.day_distribution.weekend_ratio,
            # Market selection
            "best_category": p.market_selection.best_category,
            "worst_category": p.market_selection.worst_category,
            "herfindahl": p.market_selection.herfindahl,
            "diversity_score": p.market_selection.diversity_score,
            "market_count": p.market_selection.market_count,
            "early_entrant_score": p.market_selection.early_entrant_score,
            "categories": [
                {"name": c.name, "trade_count": c.trade_count, "win_rate": c.win_rate}
                for c in p.market_selection.categories
            ],
            # Order flow
            "building_style": p.order_flow.building_style.style,
            "exit_style": p.order_flow.exit_style.style,
            "avg_hold_hours": p.order_flow.avg_hold_hours,
            "size_trend": p.order_flow.size_trend,
            "dip_buyer_score": p.order_flow.dip_buyer_score,
            "rip_seller_score": p.order_flow.rip_seller_score,
            # Edge
            "information_score": p.edge.information_score,
            "timing_quality": p.edge.timing_quality,
            "streak_type": p.edge.streak_type,
            "edge_bps": p.edge.edge_bps,
            "edge_confidence": p.edge.confidence,
            "win_rate_by_size": p.edge.win_rate_by_size,
            # Strategies
            "strategies": [
                {
                    "name": s.name,
                    "description": s.description,
                    "expected_edge": s.expected_edge,
                    "risk_level": s.risk_level,
                    "confidence": s.confidence,
                    "impl_type": s.impl_type,
                }
                for s in p.strategies
            ],
            "best_strategy": p.best_strategy.name if p.best_strategy else None,
            "best_strategy_confidence": p.best_strategy.confidence if p.best_strategy else None,
        }
    except Exception as e:
        return {"error": str(e)}


def market_bot_scan(
    condition_id: str,
    trade_limit: int = 1000,
    min_trades: int = 5,
) -> list[dict] | dict:
    """Scan a market to detect bot wallets with strategy classification."""
    try:
        from horizon.wallet_intel import scan_bots
        results = scan_bots(
            condition_id, trade_limit=trade_limit, min_trades=min_trades,
        )
        return [
            {
                "wallet": r.wallet,
                "is_bot": r.is_bot,
                "confidence": r.confidence,
                "strategy_type": r.strategy_type,
                "evidence": r.evidence,
                "trade_count": r.trade_count,
                "avg_interval_seconds": r.avg_interval_seconds,
                "size_regularity": r.size_regularity,
            }
            for r in results
        ]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Stealth execution tools (Ultra)
# ---------------------------------------------------------------------------

def stealth_estimate_impact(
    market_id: str, size: float, feed_name: str | None = None,
) -> dict:
    """Estimate market impact before execution."""
    try:
        from horizon.stealth import estimate_impact
        eng = get_engine()
        est = estimate_impact(eng, market_id, size, feed_name=feed_name)
        return {
            "market_id": est.market_id,
            "size": est.size,
            "estimated_slippage_bps": est.estimated_slippage_bps,
            "kyle_lambda": est.kyle_lambda,
            "effective_spread_bps": est.effective_spread_bps,
            "volatility": est.volatility,
            "recommended_strategy": est.recommended_strategy,
            "estimated_duration_secs": est.estimated_duration_secs,
        }
    except Exception as e:
        return {"error": str(e)}


def stealth_execute_order(
    market_id: str,
    side: str,
    order_side: str,
    size: float,
    price: float,
    strategy: str = "auto",
) -> dict:
    """Execute an order using stealth algorithms (TWAP, Iceberg, Sniper)."""
    try:
        if not math.isfinite(size) or size <= 0:
            return {"error": f"size must be a positive finite number, got {size}"}
        if not math.isfinite(price) or price <= 0:
            return {"error": f"price must be a positive finite number, got {price}"}
        side_lower = side.lower()
        if side_lower not in ("yes", "no"):
            return {"error": f"side must be 'yes' or 'no', got '{side}'"}
        os_lower = order_side.lower()
        if os_lower not in ("buy", "sell"):
            return {"error": f"order_side must be 'buy' or 'sell', got '{order_side}'"}
        from horizon.stealth import stealth_execute
        eng = get_engine()
        s = Side.Yes if side_lower == "yes" else Side.No
        os_ = OrderSide.Buy if os_lower == "buy" else OrderSide.Sell
        plan = stealth_execute(eng, market_id, s, os_, size, price, strategy=strategy)
        return {
            "strategy": plan.strategy,
            "total_size": plan.total_size,
            "estimated_cost_bps": plan.estimated_cost_bps,
            "estimated_duration_secs": plan.estimated_duration_secs,
            "child_orders": len(plan.child_orders),
            "routes": [
                {
                    "exchange": r.exchange,
                    "size_fraction": r.size_fraction,
                    "estimated_cost_bps": r.estimated_cost_bps,
                }
                for r in plan.routes
            ],
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Sentinel risk monitoring tools (Ultra)
# ---------------------------------------------------------------------------

def get_sentinel_report() -> dict:
    """Get a portfolio risk report."""
    try:
        from horizon.sentinel import sentinel_report
        eng = get_engine()
        r = sentinel_report(eng)
        return {
            "regime": r.regime,
            "portfolio_value": round(r.portfolio_value, 2),
            "var_95": round(r.var_95, 4),
            "cvar_95": round(r.cvar_95, 4),
            "max_position_pct": round(r.max_position_pct, 4),
            "correlation_alerts": len(r.correlation_alerts),
            "drawdown_levels": [
                {
                    "scope": d.scope,
                    "scope_id": d.scope_id,
                    "current_dd": round(d.current_dd, 4),
                    "threshold": d.threshold,
                    "action": d.action,
                    "triggered": d.triggered,
                }
                for d in r.drawdown_levels
            ],
            "hedges": [
                {
                    "market_id": h.market_id,
                    "side": h.side,
                    "size": round(h.size, 4),
                    "risk_reduction_pct": round(h.risk_reduction_pct, 2),
                    "rationale": h.rationale,
                }
                for h in r.hedges
            ],
            "risk_budget": {
                "total": round(r.risk_budget.total_budget, 2),
                "used": round(r.risk_budget.used_budget, 2),
                "usage_pct": round(r.risk_budget.usage_pct, 4),
                "regime_multiplier": r.risk_budget.regime_multiplier,
            },
            "timestamp": r.timestamp,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Oracle forecasting tools (Ultra)
# ---------------------------------------------------------------------------

def oracle_forecast_market(
    market_id: str,
    market_title: str = "",
    market_price: float = 0.0,
    exchange: str = "polymarket",
) -> dict:
    """Forecast a market's probability using ensemble signals."""
    try:
        from horizon.oracle import forecast_market
        fc = forecast_market(
            market_id, market_title=market_title, market_price=market_price,
            exchange=exchange,
        )
        return {
            "market_id": fc.market_id,
            "ensemble_prob": round(fc.ensemble_prob, 4),
            "confidence_low": round(fc.confidence_low, 4),
            "confidence_high": round(fc.confidence_high, 4),
            "edge_bps": round(fc.edge_bps, 2),
            "market_price": fc.market_price,
            "signals": [
                {
                    "name": s.name,
                    "value": round(s.normalized_value, 4),
                    "weight": round(s.weight, 4),
                    "contribution": round(s.contribution, 4),
                }
                for s in fc.signals
            ],
            "timestamp": fc.timestamp,
        }
    except Exception as e:
        return {"error": str(e)}


def oracle_scan_edges(
    min_edge_bps: float = 200.0,
    max_markets: int = 30,
    exchange: str = "polymarket",
) -> list[dict] | dict:
    """Scan top markets for forecast edge opportunities."""
    try:
        from horizon.oracle import scan_edges
        edges = scan_edges(
            min_edge_bps=min_edge_bps, max_markets=max_markets,
            exchange=exchange,
        )
        return [
            {
                "market_id": e.market_id,
                "market_title": e.market_title,
                "forecast_prob": round(e.forecast_prob, 4),
                "market_price": round(e.market_price, 4),
                "edge_bps": round(e.edge_bps, 2),
                "confidence": round(e.confidence, 4),
                "direction": e.direction,
                "recommended_size": round(e.recommended_size, 2),
            }
            for e in edges
        ]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Whale galaxy tools (Ultra)
# ---------------------------------------------------------------------------

def whale_galaxy_scan(
    top_n: int = 20,
    max_markets: int = 50,
) -> dict:
    """Scan Polymarket for top/bottom wallets, clusters, and whale alerts."""
    try:
        from horizon.whale_galaxy import scan_galaxy
        snap = scan_galaxy(top_n=top_n, max_markets=max_markets)
        return {
            "scan_time": round(snap.scan_time, 2),
            "market_count": snap.market_count,
            "wallet_count": snap.wallet_count,
            "top_wallets": [
                {
                    "address": w.address,
                    "score": round(w.score, 4),
                    "win_rate": round(w.win_rate, 4),
                    "pnl": round(w.pnl, 2),
                    "edge_category": w.edge_category,
                    "trade_count": w.trade_count,
                }
                for w in snap.top_wallets
            ],
            "bottom_wallets": [
                {
                    "address": w.address,
                    "score": round(w.score, 4),
                    "edge_category": w.edge_category,
                }
                for w in snap.bottom_wallets
            ],
            "clusters": [
                {
                    "wallets": c.wallets,
                    "co_trade_count": c.co_trade_count,
                    "cluster_type": c.cluster_type,
                }
                for c in snap.clusters
            ],
            "alerts": [
                {
                    "wallet": a.wallet,
                    "pseudonym": a.pseudonym,
                    "market_id": a.market_id,
                    "action": a.action,
                    "size_usdc": round(a.size_usdc, 2),
                    "significance": round(a.significance, 4),
                }
                for a in snap.alerts
            ],
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# LLM Signal Engine tools
# ---------------------------------------------------------------------------

def llm_forecast_market(
    market_id: str,
    market_title: str = "",
    market_price: float = 0.5,
    provider: str = "anthropic",
    model: str = "",
) -> dict:
    """Forecast market probability via LLM + news analysis."""
    try:
        from horizon.llm import llm_forecast as _llm_forecast, LLMConfig
        config = LLMConfig(provider=provider, model=model)
        fc = _llm_forecast(market_id, market_title, market_price, config=config)
        return {
            "market_id": fc.market_id,
            "market_title": fc.market_title,
            "llm_prob": round(fc.llm_prob, 4),
            "reasoning": fc.reasoning,
            "confidence": round(fc.confidence, 4),
            "edge_bps": round(fc.edge_bps, 4),
            "market_price": round(fc.market_price, 4),
            "model": fc.model,
            "news_sources": fc.news_sources,
        }
    except Exception as e:
        return {"error": str(e)}


def llm_scan_markets(
    min_edge_bps: float = 200.0,
    max_markets: int = 20,
    provider: str = "anthropic",
    model: str = "",
    exchange: str = "polymarket",
) -> list[dict]:
    """Scan top markets for LLM-detected edges."""
    try:
        from horizon.llm import llm_scan as _llm_scan, LLMConfig
        from horizon.discovery import top_markets

        config = LLMConfig(provider=provider, model=model)
        discovered = top_markets(limit=max_markets, exchange=exchange)
        markets = [
            {"id": m.id, "title": m.name, "price": 0.5}
            for m in discovered
        ]
        results = _llm_scan(markets, min_edge_bps=min_edge_bps, config=config)
        return [
            {
                "market_id": fc.market_id,
                "market_title": fc.market_title,
                "llm_prob": round(fc.llm_prob, 4),
                "edge_bps": round(fc.edge_bps, 4),
                "confidence": round(fc.confidence, 4),
                "reasoning": fc.reasoning,
            }
            for fc in results
        ]
    except Exception as e:
        return [{"error": str(e)}]


# ---------------------------------------------------------------------------
# Resolution Analysis tools
# ---------------------------------------------------------------------------

def analyze_resolution_tool(
    market_id: str,
    market_title: str = "",
    provider: str = "anthropic",
    model: str = "",
    exchange: str = "polymarket",
) -> dict:
    """Analyze resolution conditions and risks for a market."""
    try:
        from horizon.resolution import analyze_resolution as _analyze, ResolutionConfig
        config = ResolutionConfig(provider=provider, model=model)
        analysis = _analyze(
            market_id, market_title=market_title, config=config,
            exchange=exchange,
        )
        return {
            "market_id": analysis.market_id,
            "market_title": analysis.market_title,
            "resolution_source": analysis.resolution_source,
            "conditions": [
                {
                    "description": c.description,
                    "source": c.source,
                    "verifiable": c.verifiable,
                    "ambiguity_notes": c.ambiguity_notes,
                }
                for c in analysis.conditions
            ],
            "ambiguity_score": round(analysis.ambiguity_score, 4),
            "edge_cases": analysis.edge_cases,
            "timing_risks": analysis.timing_risks,
            "resolution_type": analysis.resolution_type,
            "estimated_resolution_date": analysis.estimated_resolution_date,
            "risk_level": analysis.risk_level,
            "reasoning": analysis.reasoning,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Sniper tools
# ---------------------------------------------------------------------------

def sniper_scan_tool(
    provider: str = "anthropic",
    max_markets: int = 10,
    model: str = "",
    exchange: str = "polymarket",
) -> list[dict]:
    """Scan for markets about to resolve."""
    try:
        from horizon.sniper import scan_resolutions as _scan, SniperConfig
        from horizon.discovery import top_markets

        config = SniperConfig(provider=provider, model=model)
        discovered = top_markets(limit=max_markets, exchange=exchange)
        markets = [
            {"id": m.id, "title": m.name}
            for m in discovered
        ]
        signals = _scan(markets, config=config)
        return [
            {
                "market_id": s.market_id,
                "market_title": s.market_title,
                "resolved": s.resolved,
                "confidence": round(s.confidence, 4),
                "resolution_side": s.resolution_side,
                "evidence": s.evidence,
                "reasoning": s.reasoning,
            }
            for s in signals
        ]
    except Exception as e:
        return [{"error": str(e)}]


# ---------------------------------------------------------------------------
# Wallet tracker tools (Ultra)
# ---------------------------------------------------------------------------

def _wallet_signal_to_dict(s) -> dict:
    return {
        "wallet": s.wallet,
        "market_id": s.market_id,
        "signal": round(s.signal, 4),
        "direction": round(s.direction, 4),
        "conviction": round(s.conviction, 4),
        "recency": round(s.recency, 4),
        "momentum": round(s.momentum, 4),
        "wallet_quality": round(s.wallet_quality, 4),
        "confidence": round(s.confidence, 4),
        "confidence_low": round(s.confidence_low, 4),
        "confidence_high": round(s.confidence_high, 4),
        "trade_count": s.trade_count,
        "position_size_usdc": round(s.position_size_usdc, 2),
        "regime": s.regime,
        "edge_bps": round(s.edge_bps, 4),
        "is_actionable": s.is_actionable,
    }


def track_wallet_tool(
    wallet: str, market_id: str = "", limit: int = 500,
) -> dict | list[dict]:
    """Compute directional signals for a wallet across all its markets, or a specific market."""
    try:
        from horizon.wallet_tracker import compute_wallet_signal, track_wallet

        if market_id:
            sig = compute_wallet_signal(wallet, market_id)
            return _wallet_signal_to_dict(sig)
        else:
            signals = track_wallet(wallet)
            return [_wallet_signal_to_dict(s) for s in signals]
    except Exception as e:
        return {"error": str(e)}


def wallet_consensus_tool(
    market_id: str, min_quality: float = 0.1,
) -> dict:
    """Compute multi-wallet consensus signal for a market."""
    try:
        from horizon.wallet_tracker import compute_consensus, TrackerConfig

        config = TrackerConfig(min_wallet_quality=min_quality)
        c = compute_consensus(market_id, config=config)
        return {
            "market_id": c.market_id,
            "signal": round(c.signal, 4),
            "confidence": round(c.confidence, 4),
            "confidence_low": round(c.confidence_low, 4),
            "confidence_high": round(c.confidence_high, 4),
            "agreement": round(c.agreement, 4),
            "n_wallets": c.n_wallets,
            "edge_bps": round(c.edge_bps, 4),
            "best_wallet": c.best_wallet,
            "is_actionable": c.is_actionable,
            "wallet_signals": [_wallet_signal_to_dict(s) for s in c.wallet_signals],
        }
    except Exception as e:
        return {"error": str(e)}


def scan_wallet_signals_tool(
    wallet: str, limit: int = 500,
) -> list[dict] | dict:
    """Scan a wallet's positions and return directional signals sorted by strength."""
    try:
        from horizon.wallet_tracker import track_wallet

        signals = track_wallet(wallet)
        return [_wallet_signal_to_dict(s) for s in signals[:limit]]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Microstructure invariance tools
# ---------------------------------------------------------------------------

def invariance_analysis_tool(
    dollar_volume: float,
    volatility: float,
    n_trades: int,
    avg_trade_size: float,
) -> dict:
    """Compute microstructure invariance analysis: trading activity, bet size, impact, efficiency."""
    try:
        from horizon._horizon import invariance_analysis
        result = invariance_analysis(dollar_volume, volatility, n_trades, avg_trade_size)
        return {
            "trading_activity": round(result.trading_activity, 6),
            "bet_size": round(result.bet_size, 6),
            "normal_trade_size": round(result.normal_trade_size, 6),
            "impact_per_bet": round(result.impact_per_bet, 6),
            "market_efficiency_score": round(result.market_efficiency_score, 6),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Signal selection (elastic net) tools
# ---------------------------------------------------------------------------

def signal_selection_tool(
    x: list[list[float]],
    y: list[float],
    alpha: float = 1.0,
    l1_ratio: float = 0.5,
) -> dict:
    """Fit elastic net regression for signal selection. Returns coefficients, R-squared, nonzero count."""
    try:
        from horizon._horizon import elastic_net_fit
        result = elastic_net_fit(x, y, alpha, l1_ratio)
        return {
            "coefficients": [round(c, 8) for c in result.coefficients],
            "intercept": round(result.intercept, 8),
            "alpha": round(result.alpha, 6),
            "l1_ratio": round(result.l1_ratio, 4),
            "nonzero_count": result.nonzero_count,
            "r_squared": round(result.r_squared, 6),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# ACD duration model tools
# ---------------------------------------------------------------------------

def duration_analysis_tool(
    durations: list[float],
    omega: float = 0.1,
    alpha: float = 0.1,
    beta: float = 0.8,
) -> dict:
    """Fit ACD duration model and return state info: expected duration, surprise, hazard rate."""
    try:
        from horizon._horizon import AcdModel
        model = AcdModel(omega=omega, alpha=alpha, beta=beta)
        last_state = None
        for i, d in enumerate(durations):
            last_state = model.update(d)
        if last_state is None:
            return {"error": "no durations provided"}
        return {
            "expected_duration": round(last_state.expected_duration, 6),
            "actual_duration": round(last_state.actual_duration, 6),
            "surprise": round(last_state.surprise, 6),
            "is_unusual": last_state.is_unusual,
            "hazard_rate": round(model.hazard_rate(0.0), 6),
            "n_events": len(durations),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Volatility signature plot tools
# ---------------------------------------------------------------------------

def volatility_signature_tool(
    prices: list[float],
    max_freq: int | None = None,
    n_points: int = 20,
) -> dict:
    """Compute volatility signature plot: realized vol at different sampling frequencies."""
    try:
        from horizon._horizon import volatility_signature
        result = volatility_signature(prices, max_freq, n_points)
        return {
            "frequencies": list(result.frequencies),
            "realized_vols": [round(v, 8) for v in result.realized_vols],
            "optimal_frequency": result.optimal_frequency,
            "two_scale_rv": round(result.two_scale_rv, 8),
            "noise_variance": round(result.noise_variance, 10),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Kalman filter tools
# ---------------------------------------------------------------------------

def kalman_filter_state_tool(
    observations: list[float],
    state_dim: int = 1,
    obs_dim: int = 1,
) -> dict:
    """Run Kalman filter on scalar observations. Returns filtered state and covariance."""
    try:
        from horizon._horizon import KalmanFilter
        kf = KalmanFilter(state_dim, obs_dim)
        state = [0.0] * state_dim
        for obs in observations:
            kf.predict()
            state = kf.update([obs])
        return {
            "state": [round(s, 8) for s in state],
            "n_observations": len(observations),
            "state_dim": state_dim,
            "obs_dim": obs_dim,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Particle filter tools
# ---------------------------------------------------------------------------

def particle_filter_state_tool(
    observations: list[float],
    n_particles: int = 1000,
    process_noise: float = 0.1,
    measurement_noise: float = 0.5,
) -> dict:
    """Run particle filter on observations. Returns final state estimate and variance."""
    try:
        n_particles = min(n_particles, 10_000)
        from horizon._horizon import ParticleFilter
        initial = observations[0] if observations else 0.0
        pf = ParticleFilter(n_particles, initial, process_noise, measurement_noise)
        last_state = None
        for obs in observations:
            last_state = pf.update(obs)
        if last_state is None:
            return {"error": "no observations provided"}
        return {
            "estimate": round(last_state.estimate, 8),
            "variance": round(last_state.variance, 8),
            "ess": round(last_state.ess, 2),
            "resampled": last_state.resampled,
            "n_observations": len(observations),
            "n_particles": n_particles,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# BOCPD change point detection tools
# ---------------------------------------------------------------------------

def bocpd_detect_tool(
    observations: list[float],
    hazard_rate: float = 250.0,
    threshold: float = 0.5,
) -> dict:
    """Run Bayesian Online Change Point Detection. Returns changepoints detected."""
    try:
        from horizon._horizon import BocpdDetector
        detector = BocpdDetector(hazard_rate=hazard_rate)
        changepoints = []
        last_result = None
        for i, obs in enumerate(observations):
            result = detector.update(obs)
            if result.is_changepoint:
                changepoints.append({
                    "index": i,
                    "change_prob": round(result.change_prob, 6),
                    "run_length": result.most_likely_run_length,
                })
            last_result = result
        return {
            "changepoints": changepoints,
            "n_changepoints": len(changepoints),
            "n_observations": len(observations),
            "final_change_prob": round(last_result.change_prob, 6) if last_result else 0.0,
            "final_run_length": last_result.most_likely_run_length if last_result else 0,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Lead-lag analysis tools
# ---------------------------------------------------------------------------

def lead_lag_analysis_tool(
    series_a: list[float],
    series_b: list[float],
    max_lag: int = 10,
) -> dict:
    """Compute cross-correlation lags between two series. Returns lag-correlation pairs and peak."""
    try:
        from horizon._horizon import cross_correlation_lags
        lags = cross_correlation_lags(series_a, series_b, max_lag)
        # Find peak
        peak_lag, peak_corr = max(lags, key=lambda x: abs(x[1]))
        return {
            "lags": [{"lag": lag, "correlation": round(corr, 6)} for lag, corr in lags],
            "peak_lag": peak_lag,
            "peak_correlation": round(peak_corr, 6),
            "n_lags": len(lags),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Granger causality tools
# ---------------------------------------------------------------------------

def granger_test_tool(
    x: list[float],
    y: list[float],
    max_lag: int = 5,
) -> dict:
    """Run Granger causality test: does x Granger-cause y?"""
    try:
        from horizon._horizon import granger_causality
        result = granger_causality(x, y, max_lag)
        return {
            "f_statistic": round(result.f_statistic, 6),
            "p_value": round(result.p_value, 6),
            "lag": result.lag,
            "is_significant": result.is_significant,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Market graph analysis tools
# ---------------------------------------------------------------------------

def market_graph_analysis_tool(
    corr_matrix: list[list[float]],
    names: list[str],
    threshold: float = 0.5,
) -> dict:
    """Build correlation graph from a matrix. Returns nodes, edges, communities, density."""
    try:
        from horizon._horizon import build_correlation_graph
        graph = build_correlation_graph(corr_matrix, names, threshold)
        return {
            "nodes": [
                {
                    "name": n.name,
                    "degree": n.degree,
                    "betweenness": round(n.betweenness, 6),
                    "closeness": round(n.closeness, 6),
                }
                for n in graph.nodes
            ],
            "edges": [
                {
                    "source": e.source,
                    "target": e.target,
                    "weight": round(e.weight, 6),
                }
                for e in graph.edges
            ],
            "communities": [
                {
                    "id": c.id,
                    "members": c.members,
                    "modularity": round(c.modularity, 6),
                }
                for c in graph.communities
            ],
            "mst_edges": [
                {
                    "source": e.source,
                    "target": e.target,
                    "weight": round(e.weight, 6),
                }
                for e in graph.mst_edges
            ],
            "density": round(graph.density, 6),
            "n_nodes": len(graph.nodes),
            "n_edges": len(graph.edges),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Garleanu-Pedersen optimal execution tools
# ---------------------------------------------------------------------------

def gp_optimal_execution_tool(
    current_pos: float,
    target_pos: float,
    alpha_decay: float,
    temp_impact: float,
    perm_impact: float,
    risk_aversion: float,
    n_steps: int,
    dt: float,
) -> dict:
    """Compute Garleanu-Pedersen optimal execution trajectory."""
    try:
        from horizon._horizon import gp_optimal_trajectory
        traj = gp_optimal_trajectory(
            current_pos, target_pos, alpha_decay, temp_impact, perm_impact,
            risk_aversion, n_steps, dt,
        )
        return {
            "times": [round(t, 6) for t in traj.times],
            "positions": [round(p, 6) for p in traj.positions],
            "target": round(traj.target, 6),
            "rate": round(traj.rate, 6),
            "total_cost": round(traj.total_cost, 8),
            "n_steps": len(traj.times),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Almgren-Chriss optimal liquidation tools
# ---------------------------------------------------------------------------

def ac_optimal_liquidation_tool(
    total_shares: float,
    n_steps: int,
    volatility: float,
    perm_impact: float,
    temp_impact: float,
    risk_aversion: float,
) -> dict:
    """Compute Almgren-Chriss optimal liquidation schedule."""
    try:
        from horizon._horizon import ac_optimal_schedule
        traj = ac_optimal_schedule(
            total_shares, n_steps, volatility, perm_impact, temp_impact, risk_aversion,
        )
        return {
            "schedule": [round(s, 6) for s in traj.schedule],
            "expected_cost": round(traj.expected_cost, 8),
            "variance": round(traj.variance, 8),
            "efficient_frontier": [
                {"expected_cost": round(ec, 8), "variance": round(v, 8)}
                for ec, v in traj.efficient_frontier
            ],
            "n_steps": n_steps,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Queue fill probability tools
# ---------------------------------------------------------------------------

def queue_fill_probability_tool(
    queue_size: float,
    position: float,
    arrival_rate: float,
    cancel_rate: float,
    time_horizon: float,
) -> dict:
    """Estimate probability of being filled at a queue position."""
    try:
        from horizon._horizon import queue_fill_prob
        result = queue_fill_prob(queue_size, position, arrival_rate, cancel_rate, time_horizon)
        return {
            "probability": round(result.probability, 6),
            "expected_time": round(result.expected_time, 4),
            "queue_position": round(result.queue_position, 2),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Copula tools
# ---------------------------------------------------------------------------

def fit_copula_tool(
    u: list[float],
    v: list[float],
    family: str = "gaussian",
) -> dict:
    """Fit a copula to bivariate data. family: 'gaussian', 'student_t', 'clayton', 'gumbel', 'frank'."""
    try:
        from horizon._horizon import fit_copula, CopulaFamily
        family_map = {
            "gaussian": CopulaFamily.Gaussian,
            "student_t": CopulaFamily.StudentT,
            "clayton": CopulaFamily.Clayton,
            "gumbel": CopulaFamily.Gumbel,
            "frank": CopulaFamily.Frank,
        }
        fam = family_map.get(family.lower())
        if fam is None:
            return {"error": f"unknown copula family: {family}. Use: gaussian, student_t, clayton, gumbel, frank"}
        result = fit_copula(u, v, fam)
        return {
            "family": str(result.family),
            "parameter": round(result.parameter, 6),
            "log_likelihood": round(result.log_likelihood, 6),
            "aic": round(result.aic, 6),
            "kendall_tau": round(result.kendall_tau, 6),
        }
    except Exception as e:
        return {"error": str(e)}


def best_copula_tool(
    u: list[float],
    v: list[float],
) -> dict:
    """Find the best-fitting copula family for bivariate data (by AIC)."""
    try:
        from horizon._horizon import best_copula
        result = best_copula(u, v)
        return {
            "family": str(result.family),
            "parameter": round(result.parameter, 6),
            "log_likelihood": round(result.log_likelihood, 6),
            "aic": round(result.aic, 6),
            "kendall_tau": round(result.kendall_tau, 6),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Vine copula tools
# ---------------------------------------------------------------------------

def vine_copula_fit_tool(
    data: list[list[float]],
    vine_type: str = "cvine",
) -> dict:
    """Fit a vine copula to multivariate data. vine_type: 'cvine' or 'dvine'."""
    try:
        from horizon._horizon import fit_vine, VineType, auth_require_ultra
        auth_require_ultra()
        vt = VineType.CVine if vine_type.lower() == "cvine" else VineType.DVine
        result = fit_vine(data, vt)
        return {
            "vine_type": str(result.vine_type),
            "n_variables": result.n_variables,
            "log_likelihood": round(result.log_likelihood, 6),
            "pair_copulas": [
                {
                    "family": str(pc.family),
                    "parameter": round(pc.parameter, 6),
                    "var1": pc.var1,
                    "var2": pc.var2,
                    "conditioning": list(pc.conditioning),
                }
                for pc in result.pair_copulas
            ],
        }
    except Exception as e:
        return {"error": str(e)}


def vine_tail_risk_tool(
    data: list[list[float]],
    vine_type: str = "cvine",
    threshold: float = 0.05,
    n_sim: int = 10000,
) -> dict:
    """Fit vine copula and estimate tail risk (joint exceedance probability)."""
    try:
        from horizon._horizon import fit_vine, vine_tail_risk, VineType, auth_require_ultra
        auth_require_ultra()
        vt = VineType.CVine if vine_type.lower() == "cvine" else VineType.DVine
        vine = fit_vine(data, vt)
        tail_prob = vine_tail_risk(vine, threshold, n_sim, 42)
        return {
            "tail_risk": round(tail_prob, 8),
            "threshold": threshold,
            "n_sim": n_sim,
            "vine_type": str(vine.vine_type),
            "n_variables": vine.n_variables,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Cross-impact matrix tools
# ---------------------------------------------------------------------------

def cross_impact_matrix_tool(
    returns_matrix: list[list[float]],
    volume_matrix: list[list[float]],
    names: list[str],
) -> dict:
    """Estimate cross-impact matrix from returns and volume data."""
    try:
        from horizon._horizon import estimate_cross_impact, auth_require_ultra
        auth_require_ultra()
        result = estimate_cross_impact(returns_matrix, volume_matrix, names)
        return {
            "matrix": [[round(v, 8) for v in row] for row in result.matrix],
            "market_names": result.market_names,
            "eigenvalues": [round(e, 8) for e in result.eigenvalues],
            "is_psd": result.is_psd,
            "n_markets": len(result.market_names),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Entropy pooling tools
# ---------------------------------------------------------------------------

def entropy_pooling_tool(
    prior_probs: list[float],
    scenarios: list[list[float]],
    views: list[dict],
) -> dict:
    """Run Meucci entropy pooling. views: list of dicts with 'coefficients', 'bound', 'is_equality' keys."""
    try:
        from horizon._horizon import entropy_pool, ViewConstraint, auth_require_ultra
        auth_require_ultra()
        constraints = []
        for v in views:
            constraints.append(ViewConstraint(
                coefficients=v["coefficients"],
                bound=v["bound"],
                is_equality=v.get("is_equality", True),
            ))
        result = entropy_pool(prior_probs, scenarios, constraints)
        return {
            "posterior_probs": [round(p, 8) for p in result.posterior_probs],
            "relative_entropy": round(result.relative_entropy, 8),
            "effective_scenarios": round(result.effective_scenarios, 4),
            "n_scenarios": len(result.posterior_probs),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Robust portfolio tools
# ---------------------------------------------------------------------------

def robust_portfolio_tool(
    expected_returns: list[float],
    covariance: list[list[float]],
    return_uncertainty: list[float],
    uncertainty_budget: float = 1.0,
) -> dict:
    """Compute robust portfolio weights under return uncertainty."""
    try:
        from horizon._horizon import robust_optimize, auth_require_ultra
        auth_require_ultra()
        result = robust_optimize(expected_returns, covariance, return_uncertainty, uncertainty_budget)
        return {
            "weights": [round(w, 6) for w in result.weights],
            "worst_case_return": round(result.worst_case_return, 8),
            "nominal_return": round(result.nominal_return, 8),
            "uncertainty_budget": round(result.uncertainty_budget, 6),
            "n_assets": len(result.weights),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Optimal exit (Longstaff-Schwartz) tools
# ---------------------------------------------------------------------------

def optimal_exit_tool(
    s0: float,
    mu: float,
    sigma: float,
    dt: float,
    n_steps: int,
    n_paths: int,
    strike: float,
) -> dict:
    """Generate GBM paths and compute optimal exit policy via Longstaff-Schwartz."""
    try:
        from horizon._horizon import generate_gbm_paths, longstaff_schwartz
        paths = generate_gbm_paths(s0, mu, sigma, dt, n_steps, n_paths, 42)
        policy = longstaff_schwartz(paths, strike)
        return {
            "exercise_boundary": [round(b, 6) for b in policy.exercise_boundary],
            "expected_payoff": round(policy.expected_payoff, 8),
            "optimal_stop_time": round(policy.optimal_stop_time, 6),
            "n_steps": n_steps,
            "n_paths": n_paths,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Binary option pricing tools
# ---------------------------------------------------------------------------

def binary_option_price_tool(
    model: str,
    strike: float,
    time_to_expiry: float,
    s0: float = 1.0,
    r: float = 0.0,
) -> dict:
    """Price a binary option using characteristic function models. model: 'heston', 'merton', 'vg'."""
    try:
        model_lower = model.lower()
        if model_lower == "heston":
            from horizon._horizon import binary_price_heston, HestonParams
            params = HestonParams()
            result = binary_price_heston(strike, time_to_expiry, params, r, s0)
        elif model_lower == "merton":
            from horizon._horizon import binary_price_merton, MertonParams
            params = MertonParams()
            result = binary_price_merton(strike, time_to_expiry, 0.2, params, r, s0)
        elif model_lower == "vg":
            from horizon._horizon import binary_price_vg, VGParams
            params = VGParams()
            result = binary_price_vg(strike, time_to_expiry, params, r, s0)
        else:
            return {"error": f"unknown model: {model}. Use: heston, merton, vg"}
        return {
            "price": round(result.price, 8),
            "delta": round(result.delta, 8),
            "vega": round(result.vega, 8),
            "model": str(result.model),
            "strike": strike,
            "time_to_expiry": time_to_expiry,
            "s0": s0,
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# HJB optimal market making tools
# ---------------------------------------------------------------------------

def hjb_optimal_quotes_tool(
    max_inventory: int = 10,
    n_time_steps: int = 100,
    gamma: float = 0.1,
    sigma: float = 0.3,
    kappa: float = 1.5,
    alpha: float = 0.01,
    terminal_time: float = 1.0,
    current_inventory: int = 0,
    time_fraction: float = 0.0,
) -> dict:
    """Solve HJB for optimal market making quotes (Avellaneda-Stoikov). Returns bid/ask deltas."""
    try:
        from horizon._horizon import auth_require_ultra
        auth_require_ultra()
        from horizon._horizon import HJBConfig, solve_hjb, hjb_quote
        config = HJBConfig(
            max_inventory=max_inventory,
            n_time_steps=n_time_steps,
            gamma=gamma,
            sigma=sigma,
            kappa=kappa,
            alpha=alpha,
            terminal_time=terminal_time,
        )
        solution = solve_hjb(config)
        quote = hjb_quote(solution, current_inventory, time_fraction)
        return {
            "bid_delta": round(quote.bid_delta, 6),
            "ask_delta": round(quote.ask_delta, 6),
            "spread": round(quote.spread, 6),
            "value": round(quote.value, 8),
            "max_inventory": max_inventory,
            "current_inventory": current_inventory,
            "time_fraction": time_fraction,
        }
    except Exception as e:
        return {"error": str(e)}


# --- Stock Hedging Tools ---


def hedge_analysis(
    spot_prices: list[float],
    hedge_prices: list[float],
    window: int = 60,
    position_size: float = 1.0,
) -> dict:
    """Compute hedge ratio, effectiveness, basis risk, and sensitivities."""
    try:
        from horizon._horizon import (
            hedge_ratio_ols,
            hedge_effectiveness as he_fn,
            basis_risk as br_fn,
            compute_hedge_sensitivities,
            rolling_correlation,
            optimal_hedge_size,
        )
        import math

        # Returns
        spot_ret = []
        for i in range(1, len(spot_prices)):
            if spot_prices[i] > 0 and spot_prices[i - 1] > 0:
                spot_ret.append(math.log(spot_prices[i] / spot_prices[i - 1]))
            else:
                spot_ret.append(0.0)
        hedge_ret = []
        for i in range(1, len(hedge_prices)):
            if hedge_prices[i] > 0 and hedge_prices[i - 1] > 0:
                hedge_ret.append(math.log(hedge_prices[i] / hedge_prices[i - 1]))
            else:
                hedge_ret.append(0.0)

        h = hedge_ratio_ols(spot_prices, hedge_prices, window)
        he = he_fn(spot_ret, hedge_ret, h) if len(spot_ret) >= 3 else 0.0
        br = br_fn(spot_ret, hedge_ret, h) if len(spot_ret) >= 3 else 0.0
        sens = compute_hedge_sensitivities(spot_prices, hedge_prices, position_size, window)
        corr = rolling_correlation(spot_prices, hedge_prices, window)

        return {
            "hedge_ratio": round(h, 6),
            "hedge_effectiveness": round(he, 6),
            "basis_risk": round(br, 8),
            "recommended_hedge_size": round(optimal_hedge_size(1.0, h), 6),
            "current_correlation": round(corr[-1], 6) if corr else 0.0,
            "sensitivities": {
                "delta": round(sens.delta, 6),
                "cross_gamma": round(sens.cross_gamma, 8),
                "beta": round(sens.beta, 6),
                "tracking_error": round(sens.tracking_error, 6),
                "hedge_decay": round(sens.hedge_decay, 6),
            },
        }
    except Exception as e:
        return {"error": str(e)}


def hedge_scenario_analysis(
    spot_position: float,
    spot_price: float,
    hedge_position: float,
    hedge_price: float,
    spot_moves: list[float] | None = None,
    correlation: float = 0.8,
    hedge_vol: float = 0.2,
    spot_vol: float = 0.2,
) -> list[dict] | dict:
    """Run scenario analysis on a hedged position."""
    try:
        from horizon._horizon import hedge_scenario

        if spot_moves is None:
            spot_moves = [-0.20, -0.10, -0.05, 0.0, 0.05, 0.10, 0.20]

        results = []
        for move in spot_moves:
            outcome = hedge_scenario(
                spot_position, spot_price, hedge_position, hedge_price,
                move, correlation, hedge_vol, spot_vol,
            )
            results.append({
                "spot_move_pct": round(outcome.spot_move_pct * 100, 2),
                "hedge_move_pct": round(outcome.hedge_move_pct * 100, 2),
                "portfolio_pnl": round(outcome.portfolio_pnl, 2),
                "unhedged_pnl": round(outcome.unhedged_pnl, 2),
                "hedge_benefit": round(outcome.hedge_benefit, 2),
            })
        return results
    except Exception as e:
        return {"error": str(e)}


def multi_ticker_hedge_analysis(
    spot_returns: list[float],
    hedge_returns_matrix: list[list[float]],
    tickers: list[str],
) -> dict:
    """Compute optimal multi-ticker hedge weights."""
    try:
        from horizon._horizon import multi_ticker_hedge

        result = multi_ticker_hedge(spot_returns, hedge_returns_matrix, tickers)
        return {
            "weights": {t: round(w, 6) for t, w in zip(result.tickers, result.weights)},
            "hedge_effectiveness": round(result.hedge_effectiveness, 6),
            "portfolio_variance": round(result.portfolio_variance, 8),
            "tracking_error": round(result.tracking_error, 6),
        }
    except Exception as e:
        return {"error": str(e)}


def hedge_cost_summary() -> dict:
    """Get hedge cost tracking summary from the running engine."""
    try:
        engine = get_engine()
        status = engine.status()
        return {
            "engine_running": status.running,
            "total_pnl": round(status.total_pnl, 4),
            "note": "Use HedgeCostTracker in pipeline for per-hedge cost tracking",
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Account & Credentials
# ---------------------------------------------------------------------------

def horizon_setup(email: str, password: str = "", name: str = "") -> dict:
    """Create a Horizon account and generate an SDK API key.

    Tries login first (existing user), then signup if needed.
    Saves the key (encrypted) to ~/.horizon/credentials.json.

    Password resolution: prefers HORIZON_PASSWORD env var over the
    ``password`` argument to avoid exposure in CLI args and logs.
    """
    try:
        from horizon.auth import setup, resolve_password
        pw = resolve_password(password)
        if not pw:
            return {"error": "no password provided. Set HORIZON_PASSWORD env var or pass password argument."}
        return setup(email, pw, name)
    except Exception as e:
        return {"error": str(e)}


def horizon_login(email: str, password: str = "") -> dict:
    """Login to an existing Horizon account and generate a new SDK key.

    Saves the key (encrypted) to ~/.horizon/credentials.json.

    Password resolution: prefers HORIZON_PASSWORD env var over the
    ``password`` argument to avoid exposure in CLI args and logs.
    The full API key is never returned -- only the prefix.
    """
    try:
        from horizon.auth import login, create_sdk_key, save_credentials, resolve_password
        pw = resolve_password(password)
        if not pw:
            return {"error": "no password provided. Set HORIZON_PASSWORD env var or pass password argument."}
        result = login(email, pw)
        if "error" in result:
            return result
        key_result = create_sdk_key(result["access_token"])
        if "error" in key_result:
            return key_result
        path = save_credentials(key_result["key"])
        return {
            "status": "ok",
            "prefix": key_result["prefix"],
            "credentials_path": path,
            "message": (
                f"SDK key saved (encrypted) to {path}. "
                f"Key prefix: {key_result['prefix']}... "
                "The engine will auto-load from this file."
            ),
        }
    except Exception as e:
        return {"error": str(e)}


def horizon_key_status() -> dict:
    """Check if Horizon credentials are configured and valid."""
    try:
        import os
        from pathlib import Path
        from horizon.auth import load_credentials

        env_key = os.environ.get("HORIZON_API_KEY", "")
        saved_key = load_credentials()

        has_env = bool(env_key)
        has_saved = bool(saved_key)
        active_key = env_key or saved_key or ""
        prefix = active_key[:15] if active_key else None

        return {
            "has_env_key": has_env,
            "has_saved_key": has_saved,
            "active_source": "env" if has_env else ("file" if has_saved else "none"),
            "prefix": prefix,
            "credentials_path": str(Path.home() / ".horizon" / "credentials.json"),
        }
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Logit-space pricing
# ---------------------------------------------------------------------------

def logit_greeks_tool(price: float, size: float, is_yes: bool = True) -> dict:
    """Compute logit-space Greeks for a binary option position."""
    try:
        from horizon._horizon import logit_greeks
        g = logit_greeks(price, size, is_yes)
        return {"delta": round(g.delta, 6), "gamma": round(g.gamma, 6),
                "theta": round(g.theta, 6), "vega": round(g.vega, 6)}
    except Exception as e:
        return {"error": str(e)}


def logit_reservation_price_tool(
    mid: float, inventory: float, gamma: float, belief_vol: float, t: float = 1.0,
) -> dict:
    """Compute logit-space reservation price (correct near 0 and 1 boundaries)."""
    try:
        from horizon._horizon import logit_reservation_price
        p = logit_reservation_price(mid, inventory, gamma, belief_vol, t)
        return {"reservation_price": round(p, 6), "mid": mid, "inventory": inventory}
    except Exception as e:
        return {"error": str(e)}


def logit_optimal_spread_tool(
    belief_vol: float, inventory: float, gamma: float, kappa: float, t: float = 1.0,
) -> dict:
    """Compute logit-space optimal spread."""
    try:
        from horizon._horizon import logit_optimal_spread
        s = logit_optimal_spread(belief_vol, inventory, gamma, kappa, t)
        return {"optimal_spread": round(s, 6), "belief_vol": belief_vol}
    except Exception as e:
        return {"error": str(e)}


def logit_pnl_decompose_tool(
    entry_price: float, exit_price: float, size: float, is_yes: bool = True,
) -> dict:
    """Decompose P&L into logit-space components (delta, gamma, theta, residual)."""
    try:
        from horizon._horizon import logit_pnl_decompose
        a = logit_pnl_decompose(entry_price, exit_price, size, is_yes)
        return {"total_pnl": round(a.total_pnl, 6), "delta_pnl": round(a.delta_pnl, 6),
                "gamma_pnl": round(a.gamma_pnl, 6), "theta_pnl": round(a.theta_pnl, 6),
                "residual_pnl": round(a.residual_pnl, 6)}
    except Exception as e:
        return {"error": str(e)}


def toxicity_adjusted_spread_tool(
    base_spread: float, vpin: float, ofi: float,
    vpin_weight: float = 0.5, ofi_weight: float = 0.5,
) -> dict:
    """Compute toxicity-adjusted spread using VPIN and OFI."""
    try:
        from horizon._horizon import toxicity_adjusted_spread
        s = toxicity_adjusted_spread(base_spread, vpin, ofi, vpin_weight, ofi_weight)
        return {"adjusted_spread": round(s, 6), "base_spread": base_spread}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Bootstrap methods
# ---------------------------------------------------------------------------

def bootstrap_sharpe_tool(returns: list[float], n_bootstrap: int = 1000) -> dict:
    """Bootstrap confidence interval for Sharpe ratio."""
    try:
        n_bootstrap = min(n_bootstrap, 10_000)
        from horizon._horizon import bootstrap_sharpe
        r = bootstrap_sharpe(returns, n_bootstrap)
        return {"point_estimate": round(r.point_estimate, 6),
                "ci_lower": round(r.ci_lower, 6), "ci_upper": round(r.ci_upper, 6)}
    except Exception as e:
        return {"error": str(e)}


def bootstrap_mean_tool(data: list[float], n_bootstrap: int = 1000) -> dict:
    """Bootstrap confidence interval for mean."""
    try:
        n_bootstrap = min(n_bootstrap, 10_000)
        from horizon._horizon import bootstrap_mean
        r = bootstrap_mean(data, n_bootstrap)
        return {"point_estimate": round(r.point_estimate, 6),
                "ci_lower": round(r.ci_lower, 6), "ci_upper": round(r.ci_upper, 6)}
    except Exception as e:
        return {"error": str(e)}


def bootstrap_var_tool(returns: list[float], n_bootstrap: int = 1000, confidence: float = 0.95) -> dict:
    """Bootstrap confidence interval for Value at Risk."""
    try:
        n_bootstrap = min(n_bootstrap, 10_000)
        from horizon._horizon import bootstrap_var
        r = bootstrap_var(returns, n_bootstrap, confidence)
        return {"point_estimate": round(r.point_estimate, 6),
                "ci_lower": round(r.ci_lower, 6), "ci_upper": round(r.ci_upper, 6)}
    except Exception as e:
        return {"error": str(e)}


def bootstrap_edge_tool(probs: list[float], prices: list[float], n_bootstrap: int = 1000) -> dict:
    """Bootstrap confidence interval for trading edge."""
    try:
        n_bootstrap = min(n_bootstrap, 10_000)
        from horizon._horizon import bootstrap_edge
        r = bootstrap_edge(probs, prices, n_bootstrap)
        return {"point_estimate": round(r.point_estimate, 6),
                "ci_lower": round(r.ci_lower, 6), "ci_upper": round(r.ci_upper, 6)}
    except Exception as e:
        return {"error": str(e)}


def bootstrap_hypothesis_tool(sample_a: list[float], sample_b: list[float], n_bootstrap: int = 1000) -> dict:
    """Bootstrap hypothesis test: is sample_a significantly different from sample_b?"""
    try:
        n_bootstrap = min(n_bootstrap, 10_000)
        from horizon._horizon import bootstrap_hypothesis_test
        r = bootstrap_hypothesis_test(sample_a, sample_b, n_bootstrap)
        return {"p_value": round(r.p_value, 6), "observed_diff": round(r.observed_diff, 6),
                "significant_at_05": r.p_value < 0.05}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Breeden-Litzenberger / risk-neutral density
# ---------------------------------------------------------------------------

def risk_neutral_density_tool(prices: list[float], strikes: list[float]) -> dict:
    """Extract risk-neutral probability density from option prices (Breeden-Litzenberger)."""
    try:
        from horizon._horizon import risk_neutral_density
        rnd = risk_neutral_density(prices, strikes)
        return {"densities": [round(d, 6) for d in rnd.densities],
                "strikes": [round(s, 6) for s in rnd.strikes],
                "mean": round(rnd.mean, 6), "variance": round(rnd.variance, 6)}
    except Exception as e:
        return {"error": str(e)}


def implied_probability_tool(prices: list[float], strikes: list[float], lower: float, upper: float) -> dict:
    """Compute implied probability of price being between lower and upper bounds."""
    try:
        from horizon._horizon import implied_probability_between
        prob = implied_probability_between(prices, strikes, lower, upper)
        return {"probability": round(prob, 6), "lower": lower, "upper": upper}
    except Exception as e:
        return {"error": str(e)}


def cross_asset_edge_tool(
    prices_a: list[float], strikes_a: list[float],
    prices_b: list[float], strikes_b: list[float],
) -> dict:
    """Find edge between two correlated assets using risk-neutral densities."""
    try:
        from horizon._horizon import cross_asset_edge
        r = cross_asset_edge(prices_a, strikes_a, prices_b, strikes_b)
        return {"edge": round(r.edge, 6), "confidence": round(r.confidence, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Yield-adjusted Kelly / Treasury
# ---------------------------------------------------------------------------

def yield_adjusted_kelly_tool(
    prob: float, price: float, rfr: float, duration_days: float, fraction: float = 0.5,
) -> dict:
    """Kelly sizing adjusted for risk-free rate opportunity cost."""
    try:
        from horizon._horizon import yield_adjusted_kelly, breakeven_edge, opportunity_cost
        k = yield_adjusted_kelly(prob, price, rfr, duration_days, fraction)
        be = breakeven_edge(rfr, duration_days)
        oc = opportunity_cost(1.0, rfr, duration_days)
        return {"kelly_fraction": round(k, 6), "breakeven_edge": round(be, 6),
                "opportunity_cost_per_dollar": round(oc, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Synthetic index
# ---------------------------------------------------------------------------

def compute_index_level_tool(prices: list[float], weights: list[float], base: float = 100.0) -> dict:
    """Compute synthetic index level from component prices and weights."""
    try:
        from horizon._horizon import compute_index_level
        level = compute_index_level(prices, weights, base)
        return {"index_level": round(level.level, 6), "timestamp": level.timestamp}
    except Exception as e:
        return {"error": str(e)}


def index_tracking_error_tool(index_levels: list[float], benchmark_levels: list[float]) -> dict:
    """Compute tracking error between a synthetic index and benchmark."""
    try:
        from horizon._horizon import index_tracking_error
        te = index_tracking_error(index_levels, benchmark_levels)
        return {"tracking_error": round(te, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Correlation regime detection
# ---------------------------------------------------------------------------

def correlation_regime_tool(returns_a: list[float], returns_b: list[float], window: int = 60) -> dict:
    """Detect correlation regime shifts between two return series."""
    try:
        from horizon._horizon import live_correlation_matrix, detect_regime_shift
        corr = live_correlation_matrix([returns_a, returns_b], window)
        shift = detect_regime_shift([returns_a, returns_b], window)
        return {"current_correlation": round(corr[0][1] if corr else 0.0, 6),
                "regime_shift_detected": shift.is_shift if hasattr(shift, 'is_shift') else False,
                "shift_magnitude": round(shift.magnitude, 6) if hasattr(shift, 'magnitude') else 0.0}
    except Exception as e:
        return {"error": str(e)}


def contagion_score_tool(returns_matrix: list[list[float]], window: int = 60) -> dict:
    """Compute contagion score for a set of assets."""
    try:
        from horizon._horizon import contagion_score
        score = contagion_score(returns_matrix, window)
        return {"contagion_score": round(score, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Portable alpha / market neutral
# ---------------------------------------------------------------------------

def beta_decompose_tool(strategy_returns: list[float], benchmark_returns: list[float]) -> dict:
    """Decompose strategy returns into alpha and beta components."""
    try:
        from horizon._horizon import beta_decompose
        r = beta_decompose(strategy_returns, benchmark_returns)
        return {"alpha": round(r.alpha, 6), "beta": round(r.beta, 6), "r_squared": round(r.r_squared, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Options overlay
# ---------------------------------------------------------------------------

def build_options_chain_tool(mid_price: float, n_strikes: int = 5, vol: float = 0.3, t_days: float = 30.0) -> list[dict] | dict:
    """Build synthetic options chain for a prediction market."""
    try:
        from horizon._horizon import build_options_chain
        chain = build_options_chain(mid_price, n_strikes, vol, t_days)
        return [{"strike": round(o.strike, 6), "call_price": round(o.call_price, 6),
                 "put_price": round(o.put_price, 6), "delta": round(o.delta, 6),
                 "gamma": round(o.gamma, 6)} for o in chain]
    except Exception as e:
        return {"error": str(e)}


def vol_surface_tool(prices: list[float], strikes: list[float], expirations: list[float]) -> list[dict] | dict:
    """Compute implied volatility surface from prices."""
    try:
        from horizon._horizon import vol_surface
        surface = vol_surface(prices, strikes, expirations)
        return [{"strike": round(p.strike, 6), "expiration": round(p.expiration, 6),
                 "implied_vol": round(p.implied_vol, 6)} for p in surface]
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Liquidity aggregation
# ---------------------------------------------------------------------------

def best_venue_tool(bids: list[float], asks: list[float], venues: list[str]) -> dict:
    """Find the best venue (highest bid, lowest ask) across multiple venues."""
    try:
        from horizon._horizon import best_venue
        result = best_venue(bids, asks, venues)
        return {"best_bid_venue": result.best_bid_venue, "best_bid": round(result.best_bid, 6),
                "best_ask_venue": result.best_ask_venue, "best_ask": round(result.best_ask, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Adversarial simulation
# ---------------------------------------------------------------------------

def vulnerability_score_tool(returns: list[float]) -> dict:
    """Compute vulnerability score for a return series."""
    try:
        from horizon._horizon import vulnerability_score
        score = vulnerability_score(returns)
        return {"vulnerability_score": round(score, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Characteristic function pricing
# ---------------------------------------------------------------------------

def binary_price_heston_tool(
    price: float, strike: float, t: float, vol: float,
    kappa: float = 2.0, theta: float = 0.04, xi: float = 0.3, rho: float = -0.7,
) -> dict:
    """Price binary option using Heston stochastic vol model."""
    try:
        from horizon._horizon import binary_price_heston, HestonParams
        params = HestonParams(v0=vol**2, kappa=kappa, theta=theta, xi=xi, rho=rho)
        bp = binary_price_heston(price, strike, t, params)
        return {"binary_price": round(bp.price, 6), "delta": round(bp.delta, 6)}
    except Exception as e:
        return {"error": str(e)}


def implied_vol_tool(binary_price: float, spot: float, strike: float, t: float) -> dict:
    """Extract implied volatility from a binary option price."""
    try:
        from horizon._horizon import implied_vol_from_binary
        iv = implied_vol_from_binary(binary_price, spot, strike, t)
        return {"implied_vol": round(iv, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Evolution optimizer
# ---------------------------------------------------------------------------

def evolution_optimize_tool(
    param_names: list[str], param_mins: list[float], param_maxs: list[float],
    population_size: int = 50, generations: int = 100,
) -> dict:
    """Set up evolutionary optimization for strategy parameters."""
    try:
        population_size = min(population_size, 1_000)
        generations = min(generations, 1_000)
        from horizon._horizon import ParamBound, EvolutionConfig, init_population
        bounds = [ParamBound(name=n, min_val=lo, max_val=hi)
                  for n, lo, hi in zip(param_names, param_mins, param_maxs)]
        config = EvolutionConfig(bounds=bounds, population_size=population_size, generations=generations)
        pop = init_population(config)
        return {"population_size": len(pop), "n_params": len(bounds),
                "param_names": param_names, "status": "initialized"}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Microstructure invariance (duplicate removed — canonical def above at ~line 2054)
# ---------------------------------------------------------------------------


# ---------------------------------------------------------------------------
# Volatility signature (duplicate removed — canonical def above at ~line 2136)
# ---------------------------------------------------------------------------


def two_scale_vol_tool(prices: list[float]) -> dict:
    """Compute two-scale realized volatility (noise-robust)."""
    try:
        from horizon._horizon import two_scale_realized_vol, noise_variance_estimate
        vol = two_scale_realized_vol(prices)
        noise = noise_variance_estimate(prices)
        return {"two_scale_vol": round(vol, 6), "noise_variance": round(noise, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# ACD duration models
# ---------------------------------------------------------------------------

def fit_acd_tool(durations: list[float]) -> dict:
    """Fit ACD (Autoregressive Conditional Duration) model to trade durations."""
    try:
        from horizon._horizon import fit_acd
        m = fit_acd(durations)
        return {"omega": round(m.omega, 6), "alpha": round(m.alpha, 6),
                "beta": round(m.beta, 6), "log_likelihood": round(m.log_likelihood, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Elastic net / LASSO / Ridge
# ---------------------------------------------------------------------------

def elastic_net_fit_tool(x: list[list[float]], y: list[float], alpha: float = 1.0, l1_ratio: float = 0.5) -> dict:
    """Fit elastic net regression for signal selection."""
    try:
        from horizon._horizon import elastic_net_fit
        r = elastic_net_fit(x, y, alpha, l1_ratio)
        return {"coefficients": [round(c, 6) for c in r.coefficients],
                "intercept": round(r.intercept, 6),
                "n_nonzero": sum(1 for c in r.coefficients if abs(c) > 1e-10)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Copula dependence
# ---------------------------------------------------------------------------

# fit_copula_tool duplicate removed — canonical def above at ~line 2446

# best_copula_tool duplicate removed — canonical def above at ~line 2476


# ---------------------------------------------------------------------------
# Entropy pooling (Meucci)
# ---------------------------------------------------------------------------

def entropy_pool_tool(prior_probs: list[float], views: list[list[float]], view_values: list[float]) -> dict:
    """Meucci entropy pooling: blend subjective views with prior distribution."""
    try:
        from horizon._horizon import entropy_pool
        r = entropy_pool(prior_probs, views, view_values)
        return {"posterior_probs": [round(p, 6) for p in r.posterior_probs],
                "relative_entropy": round(r.relative_entropy, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Robust portfolio
# ---------------------------------------------------------------------------

def robust_optimize_tool(expected_returns: list[float], cov_matrix: list[list[float]], uncertainty: float = 0.1) -> dict:
    """Robust portfolio optimization under parameter uncertainty."""
    try:
        from horizon._horizon import robust_optimize
        r = robust_optimize(expected_returns, cov_matrix, uncertainty)
        return {"weights": [round(w, 6) for w in r.weights],
                "expected_return": round(r.expected_return, 6), "risk": round(r.risk, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Optimal stopping
# ---------------------------------------------------------------------------

# optimal_exit_tool duplicate removed — canonical def above at ~line 2638


# ---------------------------------------------------------------------------
# HJB market making
# ---------------------------------------------------------------------------

def hjb_quote_tool(
    mid: float, inventory: float, gamma: float = 0.1,
    sigma: float = 0.3, kappa: float = 1.5, t: float = 1.0,
) -> dict:
    """Compute HJB-optimal market making quotes."""
    try:
        from horizon._horizon import hjb_quote, HJBConfig
        config = HJBConfig(gamma=gamma, sigma=sigma, kappa=kappa)
        q = hjb_quote(mid, inventory, config, t)
        return {"bid": round(q.bid, 6), "ask": round(q.ask, 6),
                "spread": round(q.ask - q.bid, 6), "skew": round((q.bid + q.ask) / 2 - mid, 6)}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Cross-impact
# ---------------------------------------------------------------------------

def cross_impact_tool(returns_matrix: list[list[float]], volumes_matrix: list[list[float]]) -> dict:
    """Estimate cross-impact matrix: how trading one asset affects others."""
    try:
        from horizon._horizon import estimate_cross_impact
        r = estimate_cross_impact(returns_matrix, volumes_matrix)
        return {"impact_matrix": [[round(v, 6) for v in row] for row in r.matrix], "n_assets": r.n_assets}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Trigger system
# ---------------------------------------------------------------------------

def evaluate_trigger_tool(condition: str, threshold: float, current_value: float) -> dict:
    """Evaluate a trigger condition (e.g., price crosses threshold)."""
    try:
        from horizon._horizon import evaluate_trigger, TriggerCondition
        cond = TriggerCondition(condition=condition, threshold=threshold)
        r = evaluate_trigger(cond, current_value)
        return {"triggered": r.triggered, "condition": condition,
                "threshold": threshold, "current_value": current_value}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Multi-leg execution
# ---------------------------------------------------------------------------

def validate_legs_tool(market_ids: list[str], sides: list[str], prices: list[float], sizes: list[float]) -> dict:
    """Validate a multi-leg order for consistency and risk."""
    try:
        from horizon._horizon import validate_legs, Leg, aggregate_leg_risk
        legs = [Leg(market_id=m, side=s, price=p, size=sz)
                for m, s, p, sz in zip(market_ids, sides, prices, sizes)]
        valid = validate_legs(legs)
        risk = aggregate_leg_risk(legs)
        return {"valid": valid, "n_legs": len(legs),
                "total_notional": round(risk, 6) if isinstance(risk, float) else risk}
    except Exception as e:
        return {"error": str(e)}


# ---------------------------------------------------------------------------
# Fund management tools
# ---------------------------------------------------------------------------

_fund_manager = None
_fund_lock = threading.Lock()

_FUND_NOT_ENABLED = {
    "error": "Fund mode not enabled. Set HORIZON_FUND_MODE=1 to activate fund tools.",
}


def _fund_enabled() -> bool:
    """Check if fund mode is explicitly enabled."""
    return os.environ.get("HORIZON_FUND_MODE", "").strip() in ("1", "true", "yes")


def _get_fund():
    """Get or create the singleton FundManager. Raises if fund mode not enabled."""
    if not _fund_enabled():
        raise PermissionError("Fund mode not enabled")
    global _fund_manager
    if _fund_manager is not None:
        return _fund_manager
    with _fund_lock:
        if _fund_manager is not None:
            return _fund_manager
        from horizon.fund import FundManager, FundConfig
        capital = float(os.environ.get("HORIZON_FUND_CAPITAL", "100000"))
        _fund_manager = FundManager(FundConfig(total_capital=capital))
        return _fund_manager


def _reset_fund():
    """Reset the singleton fund (for testing)."""
    global _fund_manager
    with _fund_lock:
        if _fund_manager is not None:
            try:
                _fund_manager.close()
            except Exception:
                pass
        _fund_manager = None


def fund_status() -> dict:
    """Get full fund status."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.status()
    except Exception as e:
        return {"error": str(e)}


def fund_report() -> dict:
    """Generate a full fund report."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        report = fund.report()
        return {
            "timestamp": report.timestamp,
            "nav": {
                "total_nav": report.nav.total_nav,
                "cash": report.nav.cash,
                "drawdown_pct": round(report.nav.drawdown_pct, 2),
                "high_water_mark": report.nav.high_water_mark,
            },
            "total_strategies": report.total_strategies,
            "running_strategies": report.running_strategies,
            "allocation": report.allocation,
        }
    except Exception as e:
        return {"error": str(e)}


def fund_deploy_strategy(
    name: str,
    markets: list[str],
    mode: str = "paper",
) -> dict:
    """Deploy a strategy to the fund."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        from horizon.fund import StrategyConfig
        fund = _get_fund()
        config = StrategyConfig(
            name=name,
            pipeline=[],
            markets=markets,
            mode=mode,
        )
        fund.add_strategy(config)
        return {"deployed": name, "mode": mode, "markets": markets}
    except Exception as e:
        return {"error": str(e)}


def fund_stop_strategy(name: str) -> dict:
    """Stop and remove a strategy from the fund."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        fund.remove_strategy(name)
        return {"stopped": name}
    except Exception as e:
        return {"error": str(e)}


def fund_pause_strategy(name: str) -> dict:
    """Pause a running strategy."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        fund.pause_strategy(name)
        return {"paused": name}
    except Exception as e:
        return {"error": str(e)}


def fund_resume_strategy(name: str) -> dict:
    """Resume a paused strategy."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        fund.resume_strategy(name)
        return {"resumed": name}
    except Exception as e:
        return {"error": str(e)}


def fund_list_strategies() -> dict:
    """List all strategies in the fund with their state and allocation."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        statuses = fund.controller.all_statuses()
        return {
            "strategies": [
                {
                    "name": s.name,
                    "state": s.state.value,
                    "allocated_capital": round(s.allocated_capital, 2),
                    "markets": s.markets,
                    "mode": s.mode,
                }
                for s in statuses
            ]
        }
    except Exception as e:
        return {"error": str(e)}


def fund_scale_strategy(name: str, new_capital: float) -> dict:
    """Scale capital allocation for a strategy."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        fund.scale_strategy(name, new_capital)
        return {"scaled": name, "new_capital": new_capital}
    except Exception as e:
        return {"error": str(e)}


def fund_nav_history(limit: int = 50) -> dict:
    """Get recent NAV history."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        history = fund.nav_history(limit)
        return {
            "snapshots": [
                {
                    "timestamp": h.timestamp,
                    "total_nav": round(h.total_nav, 2),
                    "cash": round(h.cash, 2),
                    "drawdown_pct": round(h.drawdown_pct, 2),
                    "high_water_mark": round(h.high_water_mark, 2),
                }
                for h in history
            ]
        }
    except Exception as e:
        return {"error": str(e)}


def fund_risk_dashboard() -> dict:
    """Get consolidated risk dashboard: VaR, correlations, execution quality."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.risk_dashboard()
    except Exception as e:
        return {"error": str(e)}


def fund_stress_test() -> dict:
    """Run fund-level stress scenarios against current state."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        result = fund.stress_test()
        return result.summary()
    except Exception as e:
        return {"error": str(e)}


def fund_pnl_attribution() -> dict:
    """Get P&L attribution per strategy."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.pnl_attribution()
    except Exception as e:
        return {"error": str(e)}


def fund_memory_query(category: str | None = None, key_contains: str | None = None, limit: int = 20) -> dict:
    """Query fund strategy memory."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        entries = fund.memory.query(category=category, key_contains=key_contains, limit=limit)
        return {
            "entries": [
                {
                    "category": e.category,
                    "key": e.key,
                    "value": e.value,
                    "confidence": round(e.confidence, 3),
                }
                for e in entries
            ]
        }
    except Exception as e:
        return {"error": str(e)}


def fund_memory_record(category: str, key: str, value: str, confidence: float = 0.5) -> dict:
    """Record a learning/observation to fund memory."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        entry_id = fund.memory.record(category, key, value, confidence)
        return {"recorded": True, "entry_id": entry_id}
    except Exception as e:
        return {"error": str(e)}


def fund_correlation_matrix() -> dict:
    """Get cross-strategy correlation matrix."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        matrix = fund.correlation_monitor.correlation_matrix()
        return {"matrix": matrix}
    except Exception as e:
        return {"error": str(e)}


def fund_execution_report() -> dict:
    """Get execution quality report across all strategies."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        report = fund.exec_quality.snapshot()
        return report.summary()
    except Exception as e:
        return {"error": str(e)}


def fund_explain() -> dict:
    """Get full fund state explanation with all subsystems."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.explainer.explain_fund_state(fund)
    except Exception as e:
        return {"error": str(e)}


def fund_explain_strategy(name: str) -> dict:
    """Get detailed explanation of a single strategy's state and performance."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.explainer.explain_strategy(fund, name)
    except Exception as e:
        return {"error": str(e)}


def fund_explain_risk() -> dict:
    """Get full risk analysis: tail risk, Greeks, correlations, stress, VaR."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.explainer.explain_risk(fund)
    except Exception as e:
        return {"error": str(e)}


def fund_hypotheses(limit: int = 20) -> dict:
    """List all trading hypotheses with lifecycle states and confidence."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        active = fund.hypothesis_manager.active_hypotheses()
        return {
            "hypotheses": [
                {
                    "id": h.hypothesis_id,
                    "market_id": h.market_id,
                    "statement": h.statement,
                    "direction": h.direction,
                    "state": h.state.value,
                    "confidence": round(h.confidence, 3),
                    "edge_estimate": round(h.edge_estimate, 4),
                    "evidence_count": h.evidence_count,
                    "source": h.source,
                }
                for h in active[:limit]
            ],
            "total": len(active),
        }
    except Exception as e:
        return {"error": str(e)}


def fund_regime() -> dict:
    """Get current market regime with history."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        current = fund.regime_detector.current_regime()
        history = fund.regime_detector.regime_history(limit=10)
        result = {"current": None, "history": []}
        if current is not None:
            result["current"] = {
                "regime": current.regime,
                "confidence": round(current.confidence, 3),
                "volatility": round(current.volatility, 4),
                "trend_strength": round(current.trend_strength, 4),
                "mean_reversion_score": round(current.mean_reversion_score, 4),
            }
        result["history"] = [
            {"regime": h.regime, "confidence": round(h.confidence, 3)}
            for h in history
        ]
        return result
    except Exception as e:
        return {"error": str(e)}


def fund_alpha_model() -> dict:
    """Get alpha model factor report with information coefficients."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        factors = fund.alpha_model.factor_report()
        return {
            "factors": [
                {
                    "name": f.name,
                    "ic": round(f.ic, 4),
                    "ic_ir": round(f.ic_ir, 4),
                    "n_observations": f.n_observations,
                    "is_significant": f.is_significant,
                }
                for f in factors
            ],
        }
    except Exception as e:
        return {"error": str(e)}


def fund_decisions(limit: int = 20) -> dict:
    """Get recent autonomous decisions with reasoning and outcomes."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        agent = getattr(fund, "_agent", None)
        if agent is not None:
            decisions = agent.decision_log(limit=limit)
        else:
            decisions = []
        return {
            "decisions": [
                {
                    "id": d.decision_id,
                    "timestamp": d.timestamp,
                    "action": d.action.value if hasattr(d.action, "value") else str(d.action),
                    "confidence": round(d.confidence, 3),
                    "outcome": d.outcome,
                    "reasoning": d.reasoning,
                    "error": d.error,
                }
                for d in decisions
            ],
        }
    except Exception as e:
        return {"error": str(e)}


def fund_decay_report() -> dict:
    """Get alpha decay tracking report for all strategies."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        alerts = fund.alpha_decay.check_alerts()
        return {
            "alerts": [
                {
                    "type": a.alert_type,
                    "strategy": a.strategy_name,
                    "message": a.message,
                }
                for a in alerts
            ],
        }
    except Exception as e:
        return {"error": str(e)}


def fund_alerts(limit: int = 50) -> dict:
    """Get recent fund alerts and notifications."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        alerts = fund.alert_manager.recent_alerts(limit=limit)
        return {
            "alerts": [a.to_dict() for a in alerts],
            "counts": fund.alert_manager.alert_counts(),
        }
    except Exception as e:
        return {"error": str(e)}


def fund_ledger_entries(limit: int = 50) -> dict:
    """Get recent ledger journal entries (double-entry accounting)."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        if fund.ledger is None:
            return {"error": "Ledger not enabled. Set ledger_enabled=True in FundConfig."}
        entries = fund.ledger.recent_entries(limit=limit)
        return {
            "entries": [
                {
                    "id": e.entry_id,
                    "timestamp": e.timestamp,
                    "debit": e.debit_account.value,
                    "credit": e.credit_account.value,
                    "amount": round(e.amount, 4),
                    "reference": e.reference,
                    "description": e.description,
                }
                for e in entries
            ],
            "balance_sheet": fund.ledger.balance_sheet(),
            "income_statement": fund.ledger.income_statement(),
        }
    except Exception as e:
        return {"error": str(e)}


def fund_promotion_status() -> dict:
    """Get promotion stage for all tracked strategies."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        if fund.promotion_manager is None:
            return {"error": "Promotion not enabled. Set promotion_enabled=True in FundConfig."}
        stages = fund.promotion_manager.all_stages()
        history = fund.promotion_manager.history(limit=20)
        return {
            "stages": stages,
            "history": [
                {
                    "strategy": r.strategy_name,
                    "from": r.from_stage,
                    "to": r.to_stage,
                    "timestamp": r.timestamp,
                }
                for r in history
            ],
        }
    except Exception as e:
        return {"error": str(e)}


def fund_full_snapshot() -> dict:
    """Get everything about the fund in one call: status, regime, risk, strategies, hypotheses, decisions, alerts, alpha model."""
    if not _fund_enabled():
        return _FUND_NOT_ENABLED
    try:
        fund = _get_fund()
        return fund.explainer.explain_fund_state(fund)
    except Exception as e:
        return {"error": str(e)}
