{"swagger": "2.0", "basePath": "/api/v1", "paths": {"/ai-copilot/admin/refresh-vector-db": {"post": {"responses": {"500": {"description": "Internal server error - refresh failed", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Vector database refreshed successfully", "schema": {"$ref": "#/definitions/RefreshVectorDBResponse"}}, "401": {"description": "Unauthorized - valid JWT token required"}, "403": {"description": "Forbidden - management key required"}}, "summary": "Refresh vector database (management key required)", "description": "Refresh vector database by clearing and re-seeding with current documents", "operationId": "post_refresh_vector_db", "tags": ["ai-copilot"]}}, "/ai-copilot/chat/{session_id}": {"parameters": [{"name": "session_id", "in": "path", "required": true, "type": "string"}], "post": {"responses": {"503": {"description": "Service unavailable", "schema": {"$ref": "#/definitions/Error"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "202": {"description": "Message accepted for processing"}}, "summary": "Send a message to an existing conversation (async processing)", "operationId": "post_chat", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ChatRequest"}}], "tags": ["ai-copilot"]}}, "/ai-copilot/configuration": {"get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Configuration retrieved successfully", "schema": {"$ref": "#/definitions/Configuration"}}}, "summary": "List the key reference files used by the AI Copilot workflows", "operationId": "get_configuration_endpoint", "tags": ["ai-copilot"]}}, "/ai-copilot/conversations/{session_id}": {"parameters": [{"name": "session_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Conversation retrieved"}}, "summary": "Get full conversation state with working context", "operationId": "get_get_conversation", "tags": ["ai-copilot"]}, "delete": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Conversation deleted", "schema": {"$ref": "#/definitions/DeleteResponse"}}}, "summary": "Delete a conversation", "operationId": "delete_get_conversation", "tags": ["ai-copilot"]}}, "/ai-copilot/conversations/{session_id}/rename": {"parameters": [{"name": "session_id", "in": "path", "required": true, "type": "string"}], "put": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not found", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Conversation renamed", "schema": {"$ref": "#/definitions/RenameResponse"}}}, "summary": "Rename a conversation", "operationId": "put_rename_conversation", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/RenameRequest"}}], "tags": ["ai-copilot"]}}, "/ai-copilot/get_latest_conversation": {"get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Conversation retrieved", "schema": {"$ref": "#/definitions/ConversationResponse"}}}, "summary": "Get the most recently created conversation", "operationId": "get_get_latest_conversation", "tags": ["ai-copilot"]}}, "/ai-copilot/list_conversations": {"get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Conversations listed", "schema": {"$ref": "#/definitions/ConversationList"}}}, "summary": "List all stored conversations", "operationId": "get_list_conversations", "tags": ["ai-copilot"]}}, "/ai-copilot/save_strategy": {"post": {"responses": {"200": {"description": "Strategy saved"}, "400": {"description": "Validation error"}, "500": {"description": "Internal server error"}}, "summary": "Save strategy configuration to the database", "description": "Expects 'strategy_config' dict with the strategy definition.\nStrategy config should include: asset, entry rules, exit rules, reward_factor, etc.", "operationId": "post_save_strategy", "tags": ["ai-copilot"]}}, "/ai-copilot/start_new_conversation": {"post": {"responses": {"503": {"description": "Service unavailable", "schema": {"$ref": "#/definitions/Error"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "201": {"description": "Conversation created", "schema": {"$ref": "#/definitions/ConversationResponse"}}}, "summary": "Start a new conversation session", "operationId": "post_start_conversation", "tags": ["ai-copilot"]}}, "/auth/allowlist/emails": {"get": {"responses": {"200": {"description": "List of allowed emails"}, "401": {"description": "Unauthorized"}}, "summary": "List all allowed emails (requires authentication)", "operationId": "get_allowlist_emails", "tags": ["auth"]}, "post": {"responses": {"200": {"description": "Email(s) added"}, "400": {"description": "Validation error"}, "401": {"description": "Unauthorized"}, "403": {"description": "Management key required"}}, "summary": "Add one or more emails to allowlist (mgmt key required)", "description": "Accepts single email string or array.", "operationId": "post_allowlist_emails", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/AllowlistAddRequest"}}], "tags": ["auth"]}}, "/auth/allowlist/emails/{email}": {"parameters": [{"name": "email", "in": "path", "required": true, "type": "string"}], "delete": {"responses": {"200": {"description": "Email revoked"}, "404": {"description": "Not found"}, "401": {"description": "Unauthorized"}, "403": {"description": "Management key required"}}, "summary": "Revoke email from allowlist (mgmt key required)", "operationId": "delete_allowlist_email", "tags": ["auth"]}}, "/auth/api-keys": {"get": {"responses": {"200": {"description": "API keys retrieved successfully", "schema": {"$ref": "#/definitions/ApiKeyList"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/ApiKeyListErrorResponse"}}}, "summary": "List all API keys for the authenticated user", "description": "Retrieves a list of all API keys associated with the currently authenticated user.\nFor security reasons, the actual key values are masked and only the key prefixes\nare shown. Use the key_prefix to identify specific keys.\n\nAuthentication is required via JWT token, API key, or Firebase token.\nThe user ID is extracted from the authentication context.\n\nReturns:\n    200 Success: List of API keys (with masked values)\n    500 Error: If server error occurs during processing", "operationId": "get_api_keys", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}, "post": {"responses": {"201": {"description": "API key created successfully", "schema": {"$ref": "#/definitions/ApiKeyResponse"}}, "500": {"description": "Internal server error"}, "400": {"description": "Missing required fields", "schema": {"$ref": "#/definitions/ApiKeyCreateErrorResponse"}}}, "summary": "Generate a new API key for the authenticated user", "description": "Creates a new API key associated with the currently authenticated user.\nThe key is only shown once at creation time and cannot be retrieved later,\nso it must be saved securely by the client.\n\nAuthentication is required via JWT token, API key, or Firebase token.\nThe user ID is extracted from the authentication context.\n\nParameters:\n    name (str): Descriptive name for the API key (required)\n    scopes (list): Optional list of permission scopes for this key\n    expires_days (int): Optional number of days until expiration\n    \nReturns:\n    201 Created: New API key details including the actual key value\n    400 Error: If required fields are missing\n    500 Error: If server error occurs during processing\n    \nNote:\n    The API key value is only returned once and cannot be retrieved later.\n    Make sure to save it securely immediately after creation.", "operationId": "post_api_keys", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ApiKeyRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}}, "/auth/api-keys/{key_id}": {"parameters": [{"name": "key_id", "in": "path", "required": true, "type": "string"}], "delete": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/ApiKeyRevokeErrorResponse"}}, "404": {"description": "API key not found", "schema": {"$ref": "#/definitions/ApiKeyNotFoundResponse"}}, "200": {"description": "API key revoked successfully", "schema": {"$ref": "#/definitions/ApiKeyRevokeResponse"}}}, "summary": "Revoke an API key", "description": "Permanently revokes the specified API key, preventing it from being used for\nauthentication in the future. This operation cannot be undone. The key is not\ndeleted from the database but is marked as revoked with a timestamp.\n\nAuthentication is required via JWT token, API key, or Firebase token.\nOnly the owner of the API key can revoke it.\n\nParameters:\n    key_id (str): The UUID of the API key to revoke (from the URL path)\n    \nReturns:\n    200 Success: Confirmation that the key was revoked\n    404 Error: If the key does not exist or does not belong to the user\n    500 Error: If server error occurs during processing", "operationId": "delete_api_key_detail", "tags": ["auth"]}}, "/auth/callback": {"get": {"responses": {"500": {"description": "Internal server error"}, "401": {"description": "Invalid Google token"}, "400": {"description": "Invalid request or OAuth error", "schema": {"$ref": "#/definitions/OAuthErrorResponse"}}, "200": {"description": "Authentication successful", "schema": {"$ref": "#/definitions/LoginResponse"}}}, "summary": "Handle OAuth callback from Google authentication", "description": "This endpoint processes the callback from Google OAuth flow. It extracts the ID token\nfrom either the query parameters or URL fragment, verifies it with Google, creates or\nupdates the user record, and generates JWT tokens for API authentication.\n\nIf the ID token is not in the query parameters, it returns HTML with JavaScript that\nextracts the token from the URL fragment and reloads the page with the token as a query parameter.\n\nReturns:\n    200 Success: JWT tokens and user profile if authentication succeeds\n    400 Error: If OAuth error parameter is present or request is invalid\n    401 Error: If Google token is invalid or missing required claims\n    500 Error: If server error occurs during processing", "operationId": "get_auth_callback", "tags": ["auth"]}}, "/auth/is-admin": {"get": {"responses": {"200": {"description": "Admin status check"}, "401": {"description": "Unauthorized"}}, "summary": "Check if current user has admin privileges", "operationId": "get_is_admin", "tags": ["auth"]}}, "/auth/login": {"post": {"responses": {"200": {"description": "Authentication successful", "schema": {"$ref": "#/definitions/LoginResponse"}}, "500": {"description": "Internal server error"}, "401": {"description": "Invalid Firebase token"}, "400": {"description": "Missing firebase_token", "schema": {"$ref": "#/definitions/LoginErrorResponse"}}}, "summary": "Exchange Firebase ID token for internal JWT tokens", "description": "This endpoint allows clients to authenticate with Firebase (via Google, GitHub, etc.)\nand then exchange the Firebase ID token for MangroveAI's internal JWT access and refresh tokens.\nThe access token is used for API authentication and expires after 1 hour, while the refresh\ntoken can be used to obtain new access tokens and expires after 30 days.\n\nParameters:\n    firebase_token (str): Firebase ID token from client-side authentication\n    \nReturns:\n    200 Success: JWT tokens and user profile if authentication succeeds\n    400 Error: If firebase_token is missing from request\n    401 Error: If Firebase token is invalid or expired\n    500 Error: If server error occurs during processing", "operationId": "post_login", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/LoginRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}}, "/auth/login/google": {"get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/ErrorResponse"}}, "302": {"description": "Redirect to Google OAuth"}}, "summary": "Initiate Google OAuth login flow", "description": "Redirects the browser to Google's sign-in page. After successful authentication,\nGoogle redirects back to /auth/callback with an ID token in the URL fragment.\n\nReturns:\n    302 Redirect: Redirects to Google OAuth authorization URL\n    500 Error: If OAuth configuration is missing or an error occurs", "operationId": "get_google_login", "tags": ["auth"]}}, "/auth/profile": {"put": {"responses": {"200": {"description": "Profile updated successfully", "schema": {"$ref": "#/definitions/UserProfile"}}, "500": {"description": "Internal server error"}, "404": {"description": "User not found", "schema": {"$ref": "#/definitions/ProfileUpdateErrorResponse"}}}, "summary": "Update current user profile information", "description": "Updates profile information for the currently authenticated user.\nAuthentication is required via JWT token, API key, or Firebase token.\nThe user ID is extracted from the authentication context.\n\nParameters:\n    name (str): New display name for the user\n    \nReturns:\n    200 Success: Updated user profile information\n    404 Error: If user record is not found\n    500 Error: If server error occurs during processing", "operationId": "put_profile", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateProfile"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}, "get": {"responses": {"200": {"description": "Profile retrieved successfully", "schema": {"$ref": "#/definitions/UserProfile"}}, "500": {"description": "Internal server error"}, "404": {"description": "User not found", "schema": {"$ref": "#/definitions/ProfileErrorResponse"}}}, "summary": "Get current user profile information", "description": "Retrieves the profile information for the currently authenticated user.\nAuthentication is required via JWT token, API key, or Firebase token.\nThe user ID is extracted from the authentication context.\n\nReturns:\n    200 Success: User profile information\n    404 Error: If user record is not found\n    500 Error: If server error occurs during processing", "operationId": "get_profile", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}}, "/auth/refresh": {"post": {"responses": {"200": {"description": "Token refresh successful", "schema": {"$ref": "#/definitions/RefreshResponse"}}, "500": {"description": "Internal server error"}, "401": {"description": "Invalid or expired refresh token"}, "400": {"description": "Missing refresh_token", "schema": {"$ref": "#/definitions/RefreshErrorResponse"}}}, "summary": "Refresh access token using a valid refresh token", "description": "When an access token expires (after 1 hour), this endpoint allows clients to obtain\na new access token by providing a valid refresh token. Refresh tokens have a longer\nlifetime (30 days) and can be used multiple times until they expire.\n\nParameters:\n    refresh_token (str): A valid refresh token previously obtained from /login or /callback\n    \nReturns:\n    200 Success: New access token if refresh token is valid\n    400 Error: If refresh_token is missing from request\n    401 Error: If refresh token is invalid or expired\n    500 Error: If server error occurs during processing", "operationId": "post_refresh", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/RefreshRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["auth"]}}, "/auth/switch-org": {"post": {"responses": {"200": {"description": "Organization switched successfully"}, "400": {"description": "Invalid request"}, "401": {"description": "Unauthorized"}, "403": {"description": "Not a member of the target organization"}, "500": {"description": "Internal server error"}}, "summary": "Switch active organization and issue new JWT tokens", "description": "Switch the active organization and get new JWT tokens", "operationId": "post_switch_org", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/SwitchOrgRequest"}}], "tags": ["auth"]}}, "/backtesting/backtest": {"post": {"responses": {"503": {"description": "Backtest engine busy; retry (Retry-After) or use the async endpoint", "schema": {"$ref": "#/definitions/Error"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest completed successfully", "schema": {"$ref": "#/definitions/BacktestResult"}}}, "summary": "Run a backtest", "description": "This endpoint runs a single-strategy backtest using `strategy_json`.\n\nThe backtest engine runs one backtest at a time. If another synchronous\nbacktest is already running, this returns `503` with a `Retry-After`\nheader rather than blocking until the gateway times out -- retry after\nthe indicated delay, run backtests sequentially, or use the bulk /\nasync endpoints for concurrent or many-strategy workloads.\n\nATR parameters (atr_period, atr_volatility_factor) are read from `execution_config`.\nIf not provided, defaults from trading_defaults.json are used. These values are\ninjected into the Strategy object at runtime and should NOT be included in strategy_json.\n\nMarket data can be sourced from:\n- Market Data API: set `data_source=\"api\"` (default) and provide `asset`, `interval`, `lookback_months`\n- Local CSV file: set `data_source=\"file\"` and provide `data_file`\n\nLegacy support:\n- `hourly_data_file` is accepted and treated as `data_file` (file mode)\n\nReturns:\n- success: Boolean indicating if backtest completed successfully\n- metrics: Dict with performance metrics\n- trade_history: List of serialized TradeRecord objects (entry/exit prices, timestamps, profit/loss, exit reasons)\n- error: Error message if backtest failed\n- execution_time_seconds: Time taken to run backtest\n- trade_count: Number of trades executed\n- strategy_names: List of strategy names that were run", "operationId": "post_backtest", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BacktestRequest"}}], "tags": ["backtesting"]}}, "/backtesting/backtest/bulk": {"post": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Bulk backtest completed", "schema": {"$ref": "#/definitions/BulkBacktestResult"}}}, "summary": "Run backtests for multiple strategies over a shared date range", "description": "Market data is fetched once per unique (asset, timeframe) pair and\nshared across all strategies that need the same data.  For example,\nfour BTC/1h strategies result in a single API call for BTC 1h data.\n\nStrategy sources\n----------------\nProvide exactly one of:\n- **strategy_ids** -- list of UUIDs from the strategies table. Strategies\n  are loaded from the database and must belong to the caller's org.\n- **strategy_configs** -- list of strategy config objects in the canonical\n  entry/exit format (same structure as the ``strategy_json`` field in\n  ``POST /backtest``, but already parsed as JSON objects, not strings).\n\nDate range\n----------\nBoth ``start_date`` and ``end_date`` are required.\n\nExecution config\n----------------\n``execution_config`` is optional and is applied to every strategy in the\nbatch.  Per-strategy execution_config embedded inside each strategy record\nis merged on top of this value.  If omitted entirely, defaults from\n``trading_defaults.json`` are used (atr_period=14, atr_volatility_factor=2.0).\n\nFailures\n--------\nIndividual strategy failures are captured per-result and do not abort\nthe batch.  Check ``results[i].success`` and ``results[i].error`` for\neach strategy.\n\nSubscription counting\n---------------------\nEach strategy result with ``trade_count >= 2`` increments the backtest\nusage counter once (see ``docs/architecture/billable-endpoints.md`` for\nrationale).  The total required quota is checked upfront.  The\nresponse includes ``X-Quota-Counted-Total`` and ``X-Quota-Counted-Of``\nheaders so callers can tell how many results actually counted.", "operationId": "post_bulk_backtest", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BulkBacktestRequest"}}], "tags": ["backtesting"]}}, "/backtesting/backtest/{backtest_id}": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest retrieved successfully"}}, "summary": "Retrieve a backtest result by ID", "description": "Returns the complete backtest result including:\n- status (pending, completed, failed)\n- metrics (performance statistics)\n- trade_history (all trades executed)\n- config (strategy configuration used)\n- timestamps (created_at, completed_at)\n\nAuthorization: Only returns backtest if it belongs to the authenticated user's organization", "operationId": "get_backtest_by_id", "tags": ["backtesting"]}}, "/backtesting/backtest/{backtest_id}/trades": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Trades retrieved successfully"}}, "summary": "Retrieve trade history for a backtest run", "description": "Returns the list of trades executed during the backtest, including\nentry/exit prices, timestamps, profit/loss, and exit reasons.", "operationId": "get_backtest_trades", "tags": ["backtesting"]}}, "/backtests": {"post": {"responses": {"503": {"description": "Backtest engine busy; retry (Retry-After) or use the async endpoint", "schema": {"$ref": "#/definitions/Error"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest completed successfully", "schema": {"$ref": "#/definitions/BacktestResult"}}}, "summary": "Run a backtest", "description": "This endpoint runs a single-strategy backtest using `strategy_json`.\n\nThe backtest engine runs one backtest at a time. If another synchronous\nbacktest is already running, this returns `503` with a `Retry-After`\nheader rather than blocking until the gateway times out -- retry after\nthe indicated delay, run backtests sequentially, or use the bulk /\nasync endpoints for concurrent or many-strategy workloads.\n\nATR parameters (atr_period, atr_volatility_factor) are read from `execution_config`.\nIf not provided, defaults from trading_defaults.json are used. These values are\ninjected into the Strategy object at runtime and should NOT be included in strategy_json.\n\nMarket data can be sourced from:\n- Market Data API: set `data_source=\"api\"` (default) and provide `asset`, `interval`, `lookback_months`\n- Local CSV file: set `data_source=\"file\"` and provide `data_file`\n\nLegacy support:\n- `hourly_data_file` is accepted and treated as `data_file` (file mode)\n\nReturns:\n- success: Boolean indicating if backtest completed successfully\n- metrics: Dict with performance metrics\n- trade_history: List of serialized TradeRecord objects (entry/exit prices, timestamps, profit/loss, exit reasons)\n- error: Error message if backtest failed\n- execution_time_seconds: Time taken to run backtest\n- trade_count: Number of trades executed\n- strategy_names: List of strategy names that were run", "operationId": "post_backtests_collection", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BacktestRequest"}}], "tags": ["backtests"]}}, "/backtests/": {"post": {"responses": {"503": {"description": "Backtest engine busy; retry (Retry-After) or use the async endpoint", "schema": {"$ref": "#/definitions/Error"}}, "500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest completed successfully", "schema": {"$ref": "#/definitions/BacktestResult"}}}, "summary": "Run a backtest", "description": "This endpoint runs a single-strategy backtest using `strategy_json`.\n\nThe backtest engine runs one backtest at a time. If another synchronous\nbacktest is already running, this returns `503` with a `Retry-After`\nheader rather than blocking until the gateway times out -- retry after\nthe indicated delay, run backtests sequentially, or use the bulk /\nasync endpoints for concurrent or many-strategy workloads.\n\nATR parameters (atr_period, atr_volatility_factor) are read from `execution_config`.\nIf not provided, defaults from trading_defaults.json are used. These values are\ninjected into the Strategy object at runtime and should NOT be included in strategy_json.\n\nMarket data can be sourced from:\n- Market Data API: set `data_source=\"api\"` (default) and provide `asset`, `interval`, `lookback_months`\n- Local CSV file: set `data_source=\"file\"` and provide `data_file`\n\nLegacy support:\n- `hourly_data_file` is accepted and treated as `data_file` (file mode)\n\nReturns:\n- success: Boolean indicating if backtest completed successfully\n- metrics: Dict with performance metrics\n- trade_history: List of serialized TradeRecord objects (entry/exit prices, timestamps, profit/loss, exit reasons)\n- error: Error message if backtest failed\n- execution_time_seconds: Time taken to run backtest\n- trade_count: Number of trades executed\n- strategy_names: List of strategy names that were run", "operationId": "post_backtests_collection", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BacktestRequest"}}], "tags": ["backtests"]}}, "/backtests/bulk": {"post": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Bulk backtest completed", "schema": {"$ref": "#/definitions/BulkBacktestResult"}}}, "summary": "Run backtests for multiple strategies over a shared date range", "description": "Market data is fetched once per unique (asset, timeframe) pair and\nshared across all strategies that need the same data.  For example,\nfour BTC/1h strategies result in a single API call for BTC 1h data.\n\nStrategy sources\n----------------\nProvide exactly one of:\n- **strategy_ids** -- list of UUIDs from the strategies table. Strategies\n  are loaded from the database and must belong to the caller's org.\n- **strategy_configs** -- list of strategy config objects in the canonical\n  entry/exit format (same structure as the ``strategy_json`` field in\n  ``POST /backtest``, but already parsed as JSON objects, not strings).\n\nDate range\n----------\nBoth ``start_date`` and ``end_date`` are required.\n\nExecution config\n----------------\n``execution_config`` is optional and is applied to every strategy in the\nbatch.  Per-strategy execution_config embedded inside each strategy record\nis merged on top of this value.  If omitted entirely, defaults from\n``trading_defaults.json`` are used (atr_period=14, atr_volatility_factor=2.0).\n\nFailures\n--------\nIndividual strategy failures are captured per-result and do not abort\nthe batch.  Check ``results[i].success`` and ``results[i].error`` for\neach strategy.\n\nSubscription counting\n---------------------\nEach strategy result with ``trade_count >= 2`` increments the backtest\nusage counter once (see ``docs/architecture/billable-endpoints.md`` for\nrationale).  The total required quota is checked upfront.  The\nresponse includes ``X-Quota-Counted-Total`` and ``X-Quota-Counted-Of``\nheaders so callers can tell how many results actually counted.", "operationId": "post_backtests_bulk_alias", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BulkBacktestRequest"}}], "tags": ["backtests"]}}, "/backtests/{backtest_id}": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest retrieved successfully"}}, "summary": "Retrieve a backtest result by ID", "description": "Returns the complete backtest result including:\n- status (pending, completed, failed)\n- metrics (performance statistics)\n- trade_history (all trades executed)\n- config (strategy configuration used)\n- timestamps (created_at, completed_at)\n\nAuthorization: Only returns backtest if it belongs to the authenticated user's organization", "operationId": "get_backtests_by_id_alias", "tags": ["backtests"]}}, "/backtests/{backtest_id}/archive": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest archived", "schema": {"$ref": "#/definitions/BacktestArchiveResponse"}}}, "summary": "Archive a backtest run (hide it from the default history view)", "description": "Backtests are never deleted -- archiving is a reversible view-state that\nremoves the run from GET /api/v1/users/me/backtests by default. Pass\n?include_archived=true to that endpoint to list archived runs, and POST\n/api/v1/backtests/<id>/unarchive to restore one.\n\nAuthorization: only affects a backtest owned by the caller's org.", "operationId": "post_backtest_archive", "tags": ["backtests"]}}, "/backtests/{backtest_id}/trades": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Trades retrieved successfully"}}, "summary": "Retrieve trade history for a backtest run", "description": "Returns the list of trades executed during the backtest, including\nentry/exit prices, timestamps, profit/loss, and exit reasons.", "operationId": "get_backtests_trades_alias", "tags": ["backtests"]}}, "/backtests/{backtest_id}/unarchive": {"parameters": [{"name": "backtest_id", "in": "path", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Backtest not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Backtest unarchived", "schema": {"$ref": "#/definitions/BacktestArchiveResponse"}}}, "summary": "Unarchive a backtest run (restore it to the default history view)", "description": "The inverse of POST /api/v1/backtests/<id>/archive.\n\nAuthorization: only affects a backtest owned by the caller's org.", "operationId": "post_backtest_unarchive", "tags": ["backtests"]}}, "/batch/job/status": {"get": {"responses": {"500": {"description": "Internal Server Error (one or more jobs failed)"}, "200": {"description": "OK", "schema": {"type": "array", "items": {"$ref": "#/definitions/BatchJob"}}}}, "summary": "Get all completed/failed jobs that haven't been notified yet", "operationId": "get_unnotified_jobs", "tags": ["batch"]}}, "/batch/job/status/{job_id}": {"parameters": [{"name": "job_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error"}, "404": {"description": "Not Found"}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/BatchJob"}}}, "summary": "Get status of a specific batch job", "operationId": "get_job_status", "tags": ["batch"]}}, "/config/execution-defaults": {"get": {"responses": {"200": {"description": "Flattened execution config as applied by the server"}}, "summary": "Return the flattened `execution_config` the server builds from defaults", "description": "Matches exactly what `domains/strategies/services.py` uses when a\nrequest omits `execution_config`. Sections `risk_management`,\n`position_limits`, `volatility_settings`, `trading_rules`,\n`time_based_exits` are merged into one dict; `signal_defaults` and\n`backtest_defaults` are intentionally excluded (same as the legacy\nflattening).", "operationId": "get_execution_defaults", "tags": ["config"]}}, "/config/trading-defaults": {"get": {"responses": {"200": {"description": "Full trading_defaults.json contents (nested sections intact)"}}, "summary": "Return the full trading defaults, nested sections intact", "description": "Shape mirrors `trading_defaults.json` one-to-one: `signal_defaults`,\n`backtest_defaults`, `risk_management`, `position_limits`,\n`volatility_settings`, `trading_rules`, `time_based_exits`, plus the\ntop-level `description` field.", "operationId": "get_trading_defaults", "tags": ["config"]}}, "/crypto-assets/admin/symbols/{symbol}/approve": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/ApproveAssetResponse"}}}, "summary": "Approve a crypto asset (restore approval)", "operationId": "approve_asset", "tags": ["crypto-assets"]}}, "/crypto-assets/admin/symbols/{symbol}/regulatory-status": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "patch": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/UpdateRegulatoryStatusResponse"}}}, "summary": "Update regulatory status for a crypto asset (admin only)", "operationId": "update_regulatory_status", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateRegulatoryStatus"}}], "tags": ["crypto-assets"]}}, "/crypto-assets/admin/symbols/{symbol}/security-status": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "patch": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/UpdateSecurityStatusResponse"}}}, "summary": "Update security status for a crypto asset (admin only)", "description": "Auto-suspends if compromised.", "operationId": "update_security_status", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateSecurityStatus"}}], "tags": ["crypto-assets"]}}, "/crypto-assets/admin/symbols/{symbol}/suspend": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SuspendAssetResponse"}}}, "summary": "Suspend a crypto asset (remove approval)", "operationId": "suspend_asset", "tags": ["crypto-assets"]}}, "/crypto-assets/admin/update-all": {"post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "403": {"description": "Forbidden", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/UpdateAllAssetsResponse"}}}, "summary": "Trigger update of all crypto assets from external APIs (team@mangrovetechnologies", "description": "ai only).", "operationId": "update_all_assets", "tags": ["crypto-assets"]}}, "/crypto-assets/all": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK"}}, "summary": "List all crypto assets with filtering options - for frontend dropdowns and AI copilot", "operationId": "list_all_crypto_assets", "parameters": [{"type": "int", "required": false, "default": 100, "in": "query", "description": "Maximum number of results", "name": "limit"}, {"type": "float", "required": false, "in": "query", "description": "Minimum risk score (0-100)", "name": "min_score"}, {"type": "boolean", "required": false, "in": "query", "description": "Filter by approval status (true/false)", "name": "approved_only"}], "tags": ["crypto-assets"]}}, "/crypto-assets/exchanges": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/ExchangeListResponse"}}}, "summary": "List all exchanges with tier and volume information", "operationId": "list_exchanges", "tags": ["crypto-assets"]}}, "/crypto-assets/flow-intelligence/{symbol}": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/FlowIntelligenceResponse"}}}, "summary": "Get real-time flow intelligence for a specific crypto asset (Nansen)", "operationId": "get_flow_intelligence", "parameters": [{"type": "string", "required": false, "in": "query", "description": "Time range: 5m, 1h, 6h, 12h, 1d, 7d (default: 1d)", "name": "timeframe"}, {"type": "string", "required": false, "in": "query", "description": "Blockchain (default: ethereum)", "name": "chain"}], "deprecated": true, "tags": ["crypto-assets"]}}, "/crypto-assets/global-market": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/GlobalMarketResponse"}}}, "summary": "Get global cryptocurrency market statistics", "operationId": "get_global_market", "tags": ["crypto-assets"]}}, "/crypto-assets/market-data/{symbol}": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/MarketDataResponse"}}}, "summary": "Get real-time market data for a specific crypto asset", "operationId": "get_market_data", "tags": ["crypto-assets"]}}, "/crypto-assets/ohlcv/{symbol}": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/OHLCVResponse"}}}, "summary": "Get OHLCV (candlestick) data for a specific crypto asset", "operationId": "get_ohlcv", "parameters": [{"type": "string", "required": false, "in": "query", "description": "Data provider. Omit to use the cost-ordered fallback chain (mangrove -> kraken_rest -> binance_public -> coinapi -> coingecko).", "name": "provider"}, {"type": "int", "required": false, "in": "query", "description": "Number of days (default: 30)", "name": "days"}], "tags": ["crypto-assets"]}}, "/crypto-assets/query": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK"}}, "summary": "Query approved crypto assets with simplified risk scores for frontend display", "operationId": "query_crypto_assets", "parameters": [{"type": "integer", "default": 100, "in": "query", "description": "Maximum number of results", "name": "limit"}, {"type": "integer", "default": 0, "in": "query", "description": "Minimum risk score", "name": "min_score"}, {"type": "boolean", "default": true, "in": "query", "description": "Filter by approval status", "name": "approved_only"}], "tags": ["crypto-assets"]}}, "/crypto-assets/smart-money/holdings": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyHoldingsResponse"}}}, "summary": "Get aggregated smart money holdings across all tokens", "operationId": "get_smart_money_holdings", "parameters": [{"type": "int", "required": false, "in": "query", "description": "Max results (default: 20)", "name": "limit"}, {"type": "float", "required": false, "in": "query", "description": "Min position size in USD (default: 1000000)", "name": "min_value"}, {"type": "string", "required": false, "in": "query", "description": "Comma-separated labels (default: Fund,Smart Trader)", "name": "labels"}, {"type": "string", "required": false, "in": "query", "description": "Comma-separated chains (default: ethereum)", "name": "chains"}], "deprecated": true, "tags": ["crypto-assets"]}}, "/crypto-assets/smart-money/netflows": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyNetflowsResponse"}}}, "summary": "Get aggregated smart money netflows across all tokens", "operationId": "get_smart_money_netflows", "parameters": [{"type": "int", "required": false, "in": "query", "description": "Max results (default: 20)", "name": "limit"}, {"type": "string", "required": false, "in": "query", "description": "1h, 24h, 7d, or 30d (default: 24h)", "name": "timeframe"}, {"type": "string", "required": false, "in": "query", "description": "Comma-separated labels (default: Fund,Smart Trader)", "name": "labels"}, {"type": "string", "required": false, "in": "query", "description": "Comma-separated chains (default: ethereum)", "name": "chains"}], "deprecated": true, "tags": ["crypto-assets"]}}, "/crypto-assets/symbols": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/CryptoAssetListResponse"}}}, "summary": "List all approved crypto assets with risk scores", "operationId": "list_crypto_assets", "tags": ["crypto-assets"]}}, "/crypto-assets/symbols/{symbol}": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/CryptoAssetDetailResponse"}}}, "summary": "Get detailed information about a specific crypto asset", "operationId": "get_crypto_asset", "tags": ["crypto-assets"]}}, "/crypto-assets/symbols/{symbol}/exchanges": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/AssetExchangesResponse"}}}, "summary": "Get all exchanges where a specific asset is listed", "operationId": "get_asset_exchanges", "tags": ["crypto-assets"]}}, "/crypto-assets/token-holders/{symbol}": {"parameters": [{"name": "symbol", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/TokenHoldersResponse"}}}, "summary": "Get token holder distribution for a specific crypto asset (Nansen)", "operationId": "get_token_holders", "deprecated": true, "tags": ["crypto-assets"]}}, "/crypto-assets/trending": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/TrendingAssetsResponse"}}}, "summary": "Get top trending crypto assets (24h search volume)", "operationId": "get_trending_assets", "tags": ["crypto-assets"]}}, "/defi/chain/{chain}/tvl": {"parameters": [{"in": "path", "description": "Blockchain name (e.g. Ethereum, Solana, Arbitrum)", "name": "chain", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "404": {"description": "Chain not found", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/ChainTVLResponse"}}}, "summary": "Get TVL and top protocols for a blockchain", "operationId": "get_chain_tvl", "tags": ["defi"]}}, "/defi/etf-flows": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "403": {"description": "Upgrade required", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/DefiProResponse"}}}, "summary": "Crypto ETF net flows (institutional flow signal)", "description": "Pro.", "operationId": "get_etf_flows", "tags": ["defi"]}}, "/defi/lending-rates": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "403": {"description": "Upgrade required", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/DefiProResponse"}}}, "summary": "Lending-pool borrow rates (rate-spread features)", "description": "Pro.", "operationId": "get_lending_borrow_rates", "tags": ["defi"]}}, "/defi/perp-funding": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "403": {"description": "Upgrade required", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/DefiProResponse"}}}, "summary": "Aggregated DeFi perpetual funding rates across venues", "description": "Pro.", "operationId": "get_perp_funding", "tags": ["defi"]}}, "/defi/protocol/{protocol}/tvl": {"parameters": [{"in": "path", "description": "Protocol name or slug (e.g. aave, uniswap, lido)", "name": "protocol", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "404": {"description": "Protocol not found", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/ProtocolTVLResponse"}}}, "summary": "Get TVL and chain breakdown for a DeFi protocol", "operationId": "get_protocol_tvl", "tags": ["defi"]}}, "/defi/stablecoins/metrics": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/StablecoinMetricsResponse"}}}, "summary": "Get stablecoin supply metrics with per-chain breakdown", "operationId": "get_stablecoin_metrics", "tags": ["defi"]}}, "/defi/token-unlocks": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "403": {"description": "Upgrade required", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/DefiProResponse"}}}, "summary": "Token unlock schedules + supply metrics (supply-shock signal)", "description": "Pro.", "operationId": "get_token_unlocks", "tags": ["defi"]}}, "/defi/treasuries": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/DefiError"}}, "403": {"description": "Upgrade required", "schema": {"$ref": "#/definitions/DefiError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/DefiProResponse"}}}, "summary": "Protocol treasury holdings (crowd-positioning signal)", "description": "Pro.", "operationId": "get_treasuries", "tags": ["defi"]}}, "/docs/content": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/DocContent"}}}, "summary": "Get the content of a specific documentation file", "description": "Returns raw markdown content for the requested document.", "operationId": "get_doc_content", "parameters": [{"in": "query", "description": "Relative path to the document (e.g., \"api/authentication.md\")", "name": "path", "type": "string"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["docs"]}}, "/docs/list": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/DocsList"}}}, "summary": "List all available documentation files", "description": "Returns a list of markdown files in the docs/ directory.", "operationId": "get_docs_list", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["docs"]}}, "/execution/accounts": {"get": {"responses": {"200": {"description": "Success", "schema": {"type": "array", "items": {"$ref": "#/definitions/Account"}}}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "List user's trading accounts", "description": "List trading accounts for the authenticated user", "operationId": "get_account_list", "parameters": [{"description": "Filter by account type (paper or live)", "name": "account_type", "type": "string", "in": "query"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}, "post": {"responses": {"200": {"description": "Account created", "schema": {"$ref": "#/definitions/Account"}}, "400": {"description": "Validation error"}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "Create a new trading account", "description": "Create a new trading account", "operationId": "post_account_list", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/CreateAccountRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/execution/accounts/{account_id}": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/Account"}}, "401": {"description": "Unauthorized"}, "404": {"description": "Account not found"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "Get account by ID", "description": "Get account details", "operationId": "get_account_detail", "parameters": [{"name": "account_id", "in": "path", "required": true, "type": "string", "description": "Account UUID"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/execution/evaluate": {"post": {"responses": {"200": {"description": "Evaluation complete", "schema": {"$ref": "#/definitions/EvaluateResponse"}}, "400": {"description": "Validation error"}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "Evaluate strategy with current market data using strategy object", "description": "Evaluate strategy using strategy object (JSON) instead of ID\nThis endpoint allows evaluation without persisting the strategy first.\nUseful for:\n- Testing draft strategies before saving\n- One-off evaluations\n- Dry-run with modified parameters\n\nRequest body:\n{\n    \"strategy\": {\n        \"name\": \"my_strategy\",\n        \"asset\": \"BTC-USD\",\n        \"rules\": {...},\n        \"execution_config\": {...},\n        \"execution_state\": {\n            \"cash_balance\": 100000,\n            \"account_value\": 100000,\n            \"total_trades\": 0,\n            \"num_open_positions\": 0\n        }\n    },\n    \"persist\": false\n}", "operationId": "post_evaluate_strategy_by_object", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/EvaluateObjectRequest"}}], "tags": ["execution"]}}, "/execution/evaluate/bulk": {"post": {"responses": {"200": {"description": "Bulk evaluation complete", "schema": {"$ref": "#/definitions/BulkEvaluateResult"}}, "400": {"description": "Validation error"}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "Evaluate multiple strategies at the current bar with shared market data", "description": "Evaluate multiple strategies at the current market bar. Market data is fetched once per unique (asset, timeframe) pair and shared across all strategies that need it, minimizing API calls. Individual strategy failures are captured per-result without aborting the batch. Both strategy_ids and strategy_configs may be provided in the same request.\nSupply strategy_ids (DB UUIDs), strategy_configs (inline objects), or both.\nEach strategy is evaluated independently at the current price bar; results\ninclude any orders generated (entry, SL, TP) without running a full\nhistorical simulation.", "operationId": "post_bulk_evaluate_strategies", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/BulkEvaluateRequest"}}], "tags": ["execution"]}}, "/execution/evaluate/{strategy_id}": {"post": {"responses": {"200": {"description": "Evaluation complete", "schema": {"$ref": "#/definitions/EvaluateResponse"}}, "400": {"description": "Validation error"}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "Evaluate strategy with current market data", "description": "Evaluate strategy with current market data and optionally persist results\nThis endpoint evaluates a strategy against current market conditions:\n1. Loads strategy with execution_config and execution_state\n2. Loads any open positions and their orders from database\n3. Evaluates exit conditions (SL, TP, signals, time-based) for open positions\n4. Evaluates entry signals for new positions\n5. Returns order objects (existing SL/TP or new market orders)\n\nBy default (persist=True), positions, orders, and trades are saved to the database.\nSet persist=False for dry-run evaluation without affecting database state.", "operationId": "post_evaluate_strategy", "parameters": [{"name": "strategy_id", "in": "path", "required": true, "type": "string", "description": "Strategy UUID to evaluate"}, {"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/EvaluateRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/execution/portfolio": {"get": {"responses": {"200": {"description": "Portfolio data", "schema": {"$ref": "#/definitions/PortfolioResponse"}}, "400": {"description": "Validation error (missing IDs or exceeds 100)"}, "401": {"description": "Unauthorized"}, "500": {"description": "Internal server error"}}, "summary": "Batch-read portfolio data for N strategies", "description": "Batch-read portfolio data for multiple strategies in one call. Accepts a CSV of strategy IDs or repeated query params. Returns execution state, open position counts, and recent trades for each strategy. Max 100 IDs per request.\nDesigned for dashboard UIs that render multiple strategy cards.\nFetches all data in batched DB queries (strategies, open position\ncounts, recent trades) instead of N+1 individual calls.", "operationId": "get_portfolio_read", "parameters": [{"description": "Comma-separated strategy UUIDs, or repeated query param (?strategy_ids=a&strategy_ids=b). Max 100.", "name": "strategy_ids", "type": "string", "in": "query"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/execution/positions": {"get": {"responses": {"200": {"description": "Success", "schema": {"type": "array", "items": {"$ref": "#/definitions/Position"}}}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "List positions", "description": "List positions with optional filters", "operationId": "get_position_list", "parameters": [{"description": "Filter by account UUID", "name": "account_id", "type": "string", "in": "query"}, {"description": "Filter by strategy UUID", "name": "strategy_id", "type": "string", "in": "query"}, {"description": "Filter by asset symbol", "name": "asset", "type": "string", "in": "query"}, {"description": "Only return open positions (default: true)", "name": "open_only", "type": "string", "in": "query"}, {"description": "Number of records to skip (pagination)", "name": "skip", "type": "string", "in": "query"}, {"description": "Maximum number of records to return", "name": "limit", "type": "string", "in": "query"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/execution/trades": {"get": {"responses": {"200": {"description": "Success", "schema": {"type": "array", "items": {"$ref": "#/definitions/Trade"}}}, "401": {"description": "Unauthorized"}, "429": {"description": "Rate limit exceeded"}, "500": {"description": "Internal server error"}}, "summary": "List trade history", "description": "List trade history with optional filters", "operationId": "get_trade_list", "parameters": [{"description": "Filter by account UUID", "name": "account_id", "type": "string", "in": "query"}, {"description": "Filter by asset symbol", "name": "asset", "type": "string", "in": "query"}, {"description": "Filter by outcome (win or loss)", "name": "outcome", "type": "string", "in": "query"}, {"description": "Number of records to skip (pagination)", "name": "skip", "type": "string", "in": "query"}, {"description": "Maximum number of records to return", "name": "limit", "type": "string", "in": "query"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["execution"]}}, "/health": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/HealthResponse"}}}, "summary": "Unified health check endpoint for the entire application", "operationId": "get_health", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["health"]}}, "/on-chain/exchange-flows": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/ExchangeFlowsResponse"}}}, "summary": "Get aggregated exchange inflows/outflows, optionally filtered by token", "operationId": "get_exchange_flows", "parameters": [{"type": "int", "in": "query", "description": "Lookback hours (default: 24)", "name": "hours_back"}, {"type": "string", "in": "query", "description": "Token symbol (e.g. btc, eth). Omit for all currencies.", "name": "symbol"}], "tags": ["on-chain"]}}, "/on-chain/series": {"post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/OnChainError"}}, "400": {"description": "Bad Request", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/OnChainSeriesResponse"}}}, "summary": "Per-bar on-chain metric series (one key per metric), indexed by timestamp", "description": "The same call serves a live trailing window (e.g. last 10 days, ending now)\nor a long historical range -- it is just a different date_range.", "operationId": "onchain_series", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/OnChainSeriesBody"}}], "tags": ["on-chain"]}}, "/on-chain/smart-money/dex-trades": {"post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyDexTradesResponse"}}}, "summary": "Get recent DEX trades from Smart Money wallets", "description": "Body mirrors upstream Nansen `/v1/smart-money/dex-trades`.", "operationId": "smart_money_dex_trades", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/SmartMoneyQueryBody"}}], "tags": ["on-chain"]}}, "/on-chain/smart-money/historical-holdings": {"post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyHistoricalHoldingsResponse"}}}, "summary": "Get date-stamped Smart Money holdings snapshots across chains", "description": "Body mirrors upstream Nansen `/v1/smart-money/historical-holdings`:\nchains, date_range, filters, order_by, page, per_page.", "operationId": "smart_money_historical_holdings", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/SmartMoneyDatedQueryBody"}}], "tags": ["on-chain"]}}, "/on-chain/smart-money/perp-trades": {"post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyPerpTradesResponse"}}}, "summary": "Get perpetual-futures trades from Smart Money wallets on Hyperliquid", "description": "Body mirrors upstream Nansen `/v1/smart-money/perp-trades` (no chains -- Hyperliquid only).", "operationId": "smart_money_perp_trades", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/SmartMoneyPerpQueryBody"}}], "tags": ["on-chain"]}}, "/on-chain/smart-money/screen": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneyScreenResponse"}}}, "summary": "Screen for tokens with high smart money activity", "operationId": "screen_smart_money_tokens", "parameters": [{"type": "int", "in": "query", "description": "Max results (default: 50)", "name": "limit"}, {"type": "string", "in": "query", "description": "5m, 1h, 6h, 24h, 7d, 30d (default: 24h)", "name": "timeframe"}, {"type": "string", "in": "query", "description": "Comma-separated chains (default: ethereum)", "name": "chains"}], "tags": ["on-chain"]}}, "/on-chain/smart-money/sentiment": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SmartMoneySentimentResponse"}}}, "summary": "Get smart money sentiment (accumulation vs distribution) for a token", "operationId": "get_smart_money_sentiment", "parameters": [{"type": "string", "in": "query", "description": "Blockchain (default: ethereum)", "name": "chain"}, {"type": "string", "required": true, "in": "query", "description": "Token symbol (e.g. ETH, UNI)", "name": "symbol"}], "tags": ["on-chain"]}}, "/on-chain/token-holders/{symbol}": {"parameters": [{"in": "path", "description": "Token symbol (e.g. ETH, UNI)", "name": "symbol", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/OnChainTokenHoldersResponse"}}}, "summary": "Get token holder distribution from Nansen", "operationId": "get_token_holders", "tags": ["on-chain"]}}, "/on-chain/token/{symbol}/dex-trades": {"parameters": [{"in": "path", "description": "Token symbol (e.g. uniswap, ETH). Resolved to contract via CoinGecko.", "name": "symbol", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/TokenDexTradesResponse"}}}, "summary": "Get DEX trades for a single token across all participants in a date window", "description": "Body mirrors upstream Nansen `/v1/tgm/dex-trades`.", "operationId": "token_dex_trades", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/TokenDatedQueryBody"}}], "tags": ["on-chain"]}}, "/on-chain/token/{symbol}/flows": {"parameters": [{"in": "path", "description": "Token symbol (e.g. uniswap, ETH). Stablecoins not supported by this endpoint.", "name": "symbol", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "404": {"description": "Not Found", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/TokenFlowsResponse"}}}, "summary": "Get aggregated per-wallet-category flow data for a single token in a date window", "description": "Body mirrors upstream Nansen `/v1/tgm/flows`. Stablecoins return 404.", "operationId": "token_flows", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/TokenDatedQueryBody"}}], "tags": ["on-chain"]}}, "/on-chain/whale-activity/{symbol}": {"parameters": [{"in": "path", "description": "Token symbol (e.g. btc, eth)", "name": "symbol", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/WhaleActivityResponse"}}}, "summary": "Get high-level whale activity summary for a token", "operationId": "get_whale_activity", "parameters": [{"type": "int", "in": "query", "description": "Lookback hours (default: 24)", "name": "hours_back"}], "tags": ["on-chain"]}}, "/on-chain/whale-transactions": {"get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/OnChainError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/WhaleTransactionsResponse"}}}, "summary": "Get recent large-value on-chain transactions", "operationId": "get_whale_transactions", "parameters": [{"type": "int", "in": "query", "description": "Lookback hours (default: 24)", "name": "hours_back"}, {"type": "int", "in": "query", "description": "Min USD value (default: 500000)", "name": "min_value"}, {"type": "string", "in": "query", "description": "Filter by symbol (e.g. btc, eth)", "name": "symbol"}], "tags": ["on-chain"]}}, "/organizations/": {"get": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "404": {"description": "Organization not found"}, "500": {"description": "Server error"}}, "summary": "Get the organization for the current user", "description": "Get current user organization", "operationId": "get_organization_list", "tags": ["organizations"]}, "post": {"responses": {"201": {"description": "Created", "schema": {"$ref": "#/definitions/Organization"}}, "400": {"description": "Bad request"}, "401": {"description": "Unauthorized"}, "500": {"description": "Server error"}}, "summary": "Create a new organization", "description": "Create a new organization", "operationId": "post_organization_list", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/CreateOrganization"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}}, "/organizations/invitations/accept": {"post": {"responses": {"200": {"description": "Success"}, "400": {"description": "Bad request"}, "401": {"description": "Unauthorized"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Accept an invitation to join an organization", "description": "Accept an invitation", "operationId": "post_accept_invitation", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/AcceptInvitation"}}], "tags": ["organizations"]}}, "/organizations/invitations/mine": {"get": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "500": {"description": "Server error"}}, "summary": "Get pending invitations for the current user's email", "description": "List pending invitations for the current user", "operationId": "get_my_invitations", "tags": ["organizations"]}}, "/organizations/mine": {"get": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "500": {"description": "Server error"}}, "summary": "List all organizations for the current user with their role in each", "description": "List all organizations the current user belongs to", "operationId": "get_user_organizations", "tags": ["organizations"]}}, "/organizations/{org_id}": {"parameters": [{"name": "org_id", "in": "path", "required": true, "type": "string"}], "put": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/Organization"}}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Update organization details", "description": "Update organization", "operationId": "put_organization_detail", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateOrganization"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}, "get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/Organization"}}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Get organization details", "description": "Get organization by ID", "operationId": "get_organization_detail", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}}, "/organizations/{org_id}/invitations": {"parameters": [{"name": "org_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"200": {"description": "Success", "schema": {"type": "array", "items": {"$ref": "#/definitions/Invitation"}}}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "500": {"description": "Server error"}}, "summary": "List all invitations for an organization", "description": "List organization invitations", "operationId": "get_organization_invitations", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}, "post": {"responses": {"201": {"description": "Created", "schema": {"$ref": "#/definitions/Invitation"}}, "400": {"description": "Bad request"}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "500": {"description": "Server error"}}, "summary": "Invite a user to join the organization", "description": "Invite a user to organization", "operationId": "post_organization_invitations", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/InviteMember"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}}, "/organizations/{org_id}/invitations/{invitation_id}": {"parameters": [{"name": "org_id", "in": "path", "required": true, "type": "string"}, {"name": "invitation_id", "in": "path", "required": true, "type": "string"}], "delete": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Cancel a pending invitation", "description": "Cancel an invitation", "operationId": "delete_organization_invitation_detail", "tags": ["organizations"]}}, "/organizations/{org_id}/members": {"parameters": [{"name": "org_id", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"200": {"description": "Success", "schema": {"type": "array", "items": {"$ref": "#/definitions/OrganizationMember"}}}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "500": {"description": "Server error"}}, "summary": "List all members of an organization", "description": "List organization members", "operationId": "get_organization_members", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["organizations"]}}, "/organizations/{org_id}/members/{user_id}": {"parameters": [{"name": "org_id", "in": "path", "required": true, "type": "string"}, {"name": "user_id", "in": "path", "required": true, "type": "string"}], "put": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Update a member's role", "description": "Update member role", "operationId": "put_organization_member_detail", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateMemberRole"}}], "tags": ["organizations"]}, "delete": {"responses": {"200": {"description": "Success"}, "401": {"description": "Unauthorized"}, "403": {"description": "Forbidden"}, "404": {"description": "Not found"}, "500": {"description": "Server error"}}, "summary": "Remove a member from the organization", "description": "Remove member from organization", "operationId": "delete_organization_member_detail", "tags": ["organizations"]}}, "/signals/": {"get": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/SignalListResponse"}}}, "summary": "Get all available signals with metadata", "operationId": "get_signals_list", "parameters": [{"type": "string", "in": "query", "description": "Filter by category (momentum, trend, volume, volatility, patterns, onchain)", "name": "category"}, {"type": "integer", "default": 0, "in": "query", "description": "Pagination offset", "name": "offset"}, {"type": "integer", "default": 50, "in": "query", "description": "Maximum number of signals to return", "name": "limit"}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}, "post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "409": {"description": "Duplicate signal", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "201": {"description": "Signal created", "schema": {"$ref": "#/definitions/CreateSignalResponse"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/CreateSignalResponse"}}}, "summary": "Create a new signal in the signal bank", "operationId": "post_signals_list", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/CreateSignalRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/evaluate-multiple-series": {"post": {"responses": {"500": {"description": "Internal Error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation Error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/EvaluateMultipleSeriesResponse"}}}, "summary": "Evaluate chart data and optional signal triggers over a specific range", "description": "Accepts either:\n- dataset_key (playground mode): loads local CSV data, no CoinAPI call\n- symbol + start_date + end_date (live mode): fetches from CoinAPI", "operationId": "evaluate_multiple_signals_series", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/EvaluateMultipleSeriesRequest"}}], "tags": ["signals"]}}, "/signals/match": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/MatchSignalsResponse"}}}, "summary": "Match a natural language description to known signals using semantic + intent scoring", "operationId": "post_signals_match", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/MatchSignalsRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/playground-data/{dataset_key}": {"parameters": [{"name": "dataset_key", "in": "path", "required": true, "type": "string"}], "get": {"responses": {"200": {"description": "Success"}}, "summary": "Return OHLCV chart data for a specific playground dataset", "operationId": "get_playground_data", "tags": ["signals"]}}, "/signals/playground-datasets": {"get": {"responses": {"200": {"description": "Success"}}, "summary": "Return metadata for all available playground CSV datasets", "operationId": "list_playground_datasets", "tags": ["signals"]}}, "/signals/search": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/SearchSignalsResponse"}}}, "summary": "Search signals by name, params, or keywords", "operationId": "post_signals_search", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/SearchSignalsRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/validate": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Bad request", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/ValidationResult"}}}, "summary": "Run full signal validation (syntax, metadata, execution, trades)", "operationId": "post_validate_signal_endpoint", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalCodeRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/validate-execution": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Bad request", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/ExecutionValidationResult"}}}, "summary": "Validate signal execution with test data", "operationId": "post_validate_execution_endpoint", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalCodeRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/validate-metadata": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Bad request", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/MetadataValidationResult"}}}, "summary": "Validate signal metadata matches function signature", "operationId": "post_validate_metadata_endpoint", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalCodeRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/validate-syntax": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Bad request", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/SyntaxValidationResult"}}}, "summary": "Validate signal syntax (AST parsing, function definition, signature)", "operationId": "post_validate_syntax_endpoint", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalCodeRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/validate-trades": {"post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Bad request", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/TradesValidationResult"}}}, "summary": "Validate signal produces both True and False results", "operationId": "post_validate_trades_endpoint", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalCodeRequest"}}, {"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["signals"]}}, "/signals/{signal_name}": {"parameters": [{"in": "path", "description": "Signal name", "name": "signal_name", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not found", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/Signal"}}}, "summary": "Get detailed information about a signal", "operationId": "get_signal_detail", "tags": ["signals"]}}, "/signals/{signal_name}/evaluate": {"parameters": [{"in": "path", "description": "Signal name", "name": "signal_name", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not found", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/SignalEvaluationResponse"}}}, "summary": "Evaluate a signal against provided market data and parameters", "operationId": "post_signal_evaluate", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/EvaluateSignalRequest"}}], "tags": ["signals"]}}, "/signals/{signal_name}/validate-params": {"parameters": [{"in": "path", "description": "Signal name", "name": "signal_name", "required": true, "type": "string"}], "post": {"responses": {"500": {"description": "Server error", "schema": {"$ref": "#/definitions/Error"}}, "404": {"description": "Not found", "schema": {"$ref": "#/definitions/Error"}}, "400": {"description": "Validation error", "schema": {"$ref": "#/definitions/Error"}}, "200": {"description": "Success", "schema": {"$ref": "#/definitions/SignalValidationResponse"}}}, "summary": "Validate parameters for a signal", "operationId": "post_signal_validate", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/ValidateSignalParamsRequest"}}], "tags": ["signals"]}}, "/social/influence/{username}": {"parameters": [{"in": "path", "description": "X/Twitter username (without @)", "name": "username", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/SocialError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/InfluenceScoreResponse"}}}, "summary": "Get influence score and follower metrics for a user", "operationId": "get_influence", "tags": ["social"]}}, "/social/mentions/{topic}": {"parameters": [{"in": "path", "description": "Topic or keyword to search", "name": "topic", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/SocialError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/MentionsResponse"}}}, "summary": "Get recent mentions for a topic", "operationId": "get_mentions", "parameters": [{"type": "int", "in": "query", "description": "Max posts to return (default 20)", "name": "limit"}, {"type": "int", "in": "query", "description": "Time window in hours (default 24)", "name": "hours_back"}], "tags": ["social"]}}, "/social/sentiment/{topic}": {"parameters": [{"in": "path", "description": "Topic or symbol to analyze (e.g. BTC, ETH, Solana)", "name": "topic", "required": true, "type": "string"}], "get": {"responses": {"500": {"description": "Internal Server Error", "schema": {"$ref": "#/definitions/SocialError"}}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/SentimentResponse"}}}, "summary": "Get social sentiment score for a topic", "operationId": "get_sentiment", "parameters": [{"type": "int", "in": "query", "description": "Time window in hours (default 24)", "name": "hours_back"}], "tags": ["social"]}}, "/strategies/": {"get": {"responses": {"200": {"description": "OK", "schema": {"$ref": "#/definitions/StrategyListResponse"}}}, "summary": "List all strategies for authenticated user", "operationId": "list_strategies", "tags": ["strategies"]}, "post": {"responses": {"201": {"description": "Created", "schema": {"$ref": "#/definitions/CreateStrategyResponse"}}}, "summary": "Create new strategy", "operationId": "post_strategy_list_create", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/CreateStrategyRequest"}}], "tags": ["strategies"]}}, "/strategies/{strategy_id}": {"parameters": [{"name": "strategy_id", "in": "path", "required": true, "type": "string"}], "put": {"responses": {"404": {"description": "Strategy not found"}, "400": {"description": "Validation error (not draft or invalid fields)"}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/UpdateStrategyResponse"}}}, "summary": "Update a draft strategy (name, asset, rules, execution_config)", "operationId": "update_strategy", "tags": ["strategies"]}, "get": {"responses": {"200": {"description": "OK", "schema": {"$ref": "#/definitions/GetStrategyResponse"}}}, "summary": "Get strategy by ID", "operationId": "get_strategy", "tags": ["strategies"]}, "delete": {"responses": {"200": {"description": "OK", "schema": {"$ref": "#/definitions/DeleteStrategyResponse"}}}, "summary": "Delete strategy", "operationId": "delete_strategy", "tags": ["strategies"]}}, "/strategies/{strategy_id}/execution-state": {"parameters": [{"name": "strategy_id", "in": "path", "required": true, "type": "string"}], "patch": {"responses": {"404": {"description": "Strategy not found"}, "200": {"description": "OK"}}, "summary": "Update execution_state (cash_balance, account_value, etc", "description": ").", "operationId": "update_execution_state", "tags": ["strategies"]}}, "/strategies/{strategy_id}/status": {"parameters": [{"name": "strategy_id", "in": "path", "required": true, "type": "string"}], "patch": {"responses": {"404": {"description": "Strategy not found"}, "400": {"description": "Validation error"}, "200": {"description": "OK", "schema": {"$ref": "#/definitions/UpdateStrategyStatusResponse"}}}, "summary": "Update strategy status (draft, inactive, paper, live, archived)", "operationId": "update_strategy_status", "parameters": [{"name": "payload", "required": true, "in": "body", "schema": {"$ref": "#/definitions/UpdateStrategyStatusRequest"}}], "tags": ["strategies"]}}, "/subscriptions/all-status": {"get": {"responses": {"200": {"description": "Success"}}, "summary": "Get user-level subscription and all org-level subscriptions", "description": "Returns the user's personal subscription plus any org subscriptions\nfor organizations the user belongs to (excluding the default org).", "operationId": "get_all_subscription_status", "tags": ["subscriptions"]}}, "/subscriptions/checkout": {"post": {"responses": {"200": {"description": "Success"}}, "summary": "Create a Stripe Checkout session for upgrading subscription", "description": "Default org users: upgrades their personal (user-level) subscription.\nAny authenticated user can upgrade their own subscription.\n\nPersonal org users: upgrades the org subscription.\nRequires SUBSCRIPTION_MANAGE (owner only).", "operationId": "create_checkout_session", "tags": ["subscriptions"]}}, "/subscriptions/org-status": {"get": {"responses": {"200": {"description": "Success"}}, "summary": "Get detailed subscription status including billing info", "description": "For default org users: returns user-level subscription with billing info.\nFor personal org users: returns org-level subscription with billing info.", "operationId": "get_org_subscription_status", "tags": ["subscriptions"]}}, "/subscriptions/portal": {"post": {"responses": {"200": {"description": "Success"}}, "summary": "Create a Stripe Customer Portal session for billing management", "description": "Default org users: opens portal for their personal subscription.\nPersonal org users: opens portal for org subscription (owner only).\n\nAccepts optional 'scope' in request body ('user' or 'org') to\nexplicitly target a subscription. If scope='user', always opens\nthe user-level portal regardless of current org context.", "operationId": "create_portal_session", "tags": ["subscriptions"]}}, "/subscriptions/status": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/SubscriptionStatus"}}}, "summary": "Get subscription status and usage for the current context", "description": "Returns org-level subscription if the user is in a non-default org\nwith an active org subscription. Otherwise returns user-level.", "operationId": "get_subscription_status", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["subscriptions"]}}, "/subscriptions/tiers": {"get": {"responses": {"200": {"description": "Success"}}, "summary": "Get all active subscription tier definitions", "operationId": "get_subscription_tiers", "tags": ["subscriptions"]}}, "/subscriptions/utilization": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/ResourceUtilization"}}}, "summary": "Get resource utilization for the current context", "description": "Returns org-level utilization if the user is in a non-default org\nwith an active org subscription. Otherwise returns user-level.", "operationId": "get_resource_utilization", "parameters": [{"name": "X-Fields", "in": "header", "type": "string", "format": "mask", "description": "An optional fields mask"}], "tags": ["subscriptions"]}}, "/users/me/backtests": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/BacktestsResponse"}}, "401": {"description": "Unauthorized"}, "500": {"description": "Internal server error"}}, "summary": "Get my backtests with filters", "description": "Get my backtests with filters", "operationId": "get_my_backtests", "parameters": [{"description": "Filter by status (pending/running/completed/failed)", "type": "string", "name": "status", "in": "query"}, {"description": "Filter by asset symbol", "type": "string", "name": "asset", "in": "query"}, {"description": "Filter from date (ISO format)", "type": "string", "name": "date_from", "in": "query"}, {"description": "Filter to date (ISO format)", "type": "string", "name": "date_to", "in": "query"}, {"description": "Page size (default 50)", "type": "integer", "name": "limit", "in": "query"}, {"description": "Page offset (default 0)", "type": "integer", "name": "offset", "in": "query"}, {"description": "Include archived runs (default false). Backtests are never deleted; archived runs are hidden by default.", "type": "boolean", "name": "include_archived", "in": "query"}, {"description": "Scope results to a specific chat session (used by the RecentBacktests card to paginate without leaving the session). Omit for full history.", "type": "string", "name": "session_id", "in": "query"}], "tags": ["users"]}}, "/users/me/metrics": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/MetricsResponse"}}, "401": {"description": "Unauthorized"}, "500": {"description": "Internal server error"}}, "summary": "Get my usage metrics (conversations, messages, tokens, etc)", "description": "Get my usage metrics", "operationId": "get_my_metrics", "tags": ["users"]}}, "/users/me/strategies": {"get": {"responses": {"200": {"description": "Success", "schema": {"$ref": "#/definitions/StrategiesResponse"}}, "401": {"description": "Unauthorized"}, "500": {"description": "Internal server error"}}, "summary": "Get my strategies with search and filters", "description": "Get my strategies with search and filters", "operationId": "get_my_strategies", "parameters": [{"description": "Search by name or asset", "type": "string", "name": "search", "in": "query"}, {"description": "Filter by status (active/inactive)", "type": "string", "name": "status", "in": "query"}, {"description": "Page size (default 50)", "type": "integer", "name": "limit", "in": "query"}, {"description": "Page offset (default 0)", "type": "integer", "name": "offset", "in": "query"}], "tags": ["users"]}}}, "info": {"title": "Mangrove Trading Platform API", "version": "1.0", "description": "Complete API for Mangrove trading strategies, AI copilot, and backtesting"}, "produces": ["application/json"], "consumes": ["application/json"], "tags": [{"name": "health", "description": "Health check endpoints"}, {"name": "auth", "description": "Authentication and user management"}, {"name": "organizations", "description": "Organization management operations"}, {"name": "users", "description": "User operations"}, {"name": "subscriptions", "description": "Subscription and usage limit operations"}, {"name": "ai-copilot", "description": "AI Copilot operations"}, {"name": "backtesting", "description": "Synchronous backtesting (DEPRECATED path prefix). The /api/v1/backtesting/backtest* routes are retained for back-compat and behave identically to the canonical /api/v1/backtests* surface -- prefer /api/v1/backtests for new integrations."}, {"name": "backtests", "description": "Synchronous backtest runs (canonical /api/v1/backtests surface). Backtests are immutable and cannot be deleted; use archive/unarchive to hide/restore a run from the default history view."}, {"name": "strategies", "description": "Strategy management"}, {"name": "signals", "description": "Signal management and discovery"}, {"name": "execution", "description": "Trading execution operations"}, {"name": "crypto-assets", "description": "Approved crypto asset management and risk scoring"}, {"name": "docs", "description": "Documentation management"}, {"name": "batch", "description": "Batch job tracking and notifications"}, {"name": "defi", "description": "DeFi analytics -- protocol TVL, chain TVL, stablecoin metrics (DeFiLlama)"}, {"name": "social", "description": "Social signals -- sentiment, mentions, influence (X/Twitter)"}, {"name": "on-chain", "description": "On-chain intelligence -- smart money, whale transactions, exchange flows (Nansen + WhaleAlert)"}, {"name": "config", "description": "Read-only server configuration \u2014 trading defaults + flattened execution config. Source of truth for SDK consumers; closes issue #437."}], "definitions": {"HealthResponse": {"required": ["service", "status", "version"], "properties": {"status": {"type": "string", "description": "Overall health status (healthy/unhealthy)"}, "service": {"type": "string", "description": "Service name"}, "version": {"type": "string", "description": "Service version"}, "checks": {"$ref": "#/definitions/HealthChecks"}}, "type": "object"}, "HealthChecks": {"properties": {"database": {"$ref": "#/definitions/ServiceCheck"}, "llm": {"$ref": "#/definitions/ServiceCheck"}}, "type": "object"}, "ServiceCheck": {"properties": {"status": {"type": "string", "description": "Health status (healthy/unhealthy)"}, "error": {"type": "string", "description": "Error message if unhealthy"}}, "type": "object"}, "AllowlistAddRequest": {"properties": {"emails": {"type": "object", "description": "Single email string \"user@example.com\" or array of email strings [\"user1@example.com\", \"user2@example.com\"]"}}, "type": "object"}, "ErrorResponse": {"properties": {"error": {"type": "string", "description": "Error message"}}, "type": "object"}, "OAuthErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "LoginResponse": {"properties": {"success": {"type": "boolean", "description": "Whether login was successful"}, "access_token": {"type": "string", "description": "JWT access token for API requests"}, "refresh_token": {"type": "string", "description": "JWT refresh token for obtaining new access tokens"}, "user": {"type": "object", "description": "User profile information"}, "error": {"type": "string", "description": "Error message if login failed"}}, "type": "object"}, "LoginRequest": {"required": ["firebase_token"], "properties": {"firebase_token": {"type": "string", "description": "Firebase ID token from client authentication"}}, "type": "object"}, "LoginErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "RefreshRequest": {"required": ["refresh_token"], "properties": {"refresh_token": {"type": "string", "description": "Valid refresh token"}}, "type": "object"}, "RefreshResponse": {"properties": {"success": {"type": "boolean", "description": "Whether refresh was successful"}, "access_token": {"type": "string", "description": "New JWT access token"}, "error": {"type": "string", "description": "Error message if refresh failed"}}, "type": "object"}, "RefreshErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "SwitchOrgRequest": {"required": ["org_id"], "properties": {"org_id": {"type": "string", "description": "Organization UUID to switch to"}}, "type": "object"}, "UpdateProfile": {"properties": {"name": {"type": "string", "description": "New display name"}}, "type": "object"}, "UserProfile": {"properties": {"id": {"type": "string", "description": "User ID"}, "name": {"type": "string", "description": "User display name"}, "email": {"type": "string", "description": "User email address"}, "org_id": {"type": "string", "description": "Organization ID"}, "created_at": {"type": "string", "format": "date-time", "description": "Account creation timestamp"}}, "type": "object"}, "ProfileUpdateErrorResponse": {"properties": {"error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ProfileErrorResponse": {"properties": {"error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ApiKeyRequest": {"required": ["name"], "properties": {"name": {"type": "string", "description": "Descriptive name for the API key"}, "scopes": {"type": "array", "description": "Permission scopes for this key", "items": {"type": "string"}}, "expires_days": {"type": "integer", "description": "Number of days until expiration (optional)"}}, "type": "object"}, "ApiKeyList": {"properties": {"success": {"type": "boolean", "description": "Whether request was successful"}, "keys": {"type": "array", "description": "List of API keys (keys are masked)", "items": {"type": "object"}}, "error": {"type": "string", "description": "Error message if request failed"}}, "type": "object"}, "ApiKeyListErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ApiKeyResponse": {"properties": {"success": {"type": "boolean", "description": "Whether key generation was successful"}, "key": {"type": "string", "description": "The API key (ONLY shown once, save it!)"}, "key_id": {"type": "string", "description": "Key ID for management"}, "key_prefix": {"type": "string", "description": "Key prefix for identification"}, "name": {"type": "string", "description": "Key name"}, "created_at": {"type": "string", "format": "date-time", "description": "Creation timestamp"}, "expires_at": {"type": "string", "format": "date-time", "description": "Expiration timestamp (if set)"}, "error": {"type": "string", "description": "Error message if generation failed"}}, "type": "object"}, "ApiKeyCreateErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ApiKeyRevokeErrorResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ApiKeyNotFoundResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (false)"}, "error": {"type": "string", "description": "Error message"}}, "type": "object"}, "ApiKeyRevokeResponse": {"properties": {"success": {"type": "boolean", "description": "Operation status (true)"}, "message": {"type": "string", "description": "Success message"}}, "type": "object"}, "CreateOrganization": {"required": ["name"], "properties": {"name": {"type": "string", "description": "Organization name"}, "ria_flag": {"type": "boolean", "description": "RIA compliance flag", "default": false}, "info": {"type": "object", "description": "Additional organization information"}}, "type": "object"}, "Organization": {"required": ["name"], "properties": {"id": {"type": "string", "description": "Organization UUID"}, "name": {"type": "string", "description": "Organization name"}, "ria_flag": {"type": "boolean", "description": "RIA compliance flag"}, "is_active": {"type": "boolean", "description": "Whether organization is active"}, "suspended_at": {"type": "string", "format": "date-time", "description": "Suspension timestamp"}, "info": {"type": "object", "description": "Additional organization information"}, "settings": {"type": "object", "description": "Organization settings"}, "created_at": {"type": "string", "format": "date-time", "description": "Creation timestamp"}, "updated_at": {"type": "string", "format": "date-time", "description": "Last update timestamp"}}, "type": "object"}, "UpdateOrganization": {"properties": {"name": {"type": "string", "description": "Organization name"}, "ria_flag": {"type": "boolean", "description": "RIA compliance flag"}, "info": {"type": "object", "description": "Additional organization information"}, "settings": {"type": "object", "description": "Organization settings"}}, "type": "object"}, "OrganizationMember": {"properties": {"id": {"type": "string", "description": "Member UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "user_id": {"type": "string", "description": "User UUID"}, "role": {"type": "string", "description": "Member role (owner, admin, member, viewer)"}, "joined_at": {"type": "string", "format": "date-time", "description": "Join timestamp"}, "invited_by": {"type": "string", "description": "UUID of inviter"}, "user_name": {"type": "string", "description": "User display name"}, "user_email": {"type": "string", "description": "User email address"}}, "type": "object"}, "UpdateMemberRole": {"required": ["role"], "properties": {"role": {"type": "string", "description": "New role (owner, admin, member, viewer)"}}, "type": "object"}, "InviteMember": {"required": ["email"], "properties": {"email": {"type": "string", "description": "Email address to invite"}, "role": {"type": "string", "description": "Role to assign (owner, admin, member, viewer)", "default": "member"}}, "type": "object"}, "Invitation": {"properties": {"id": {"type": "string", "description": "Invitation UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "email": {"type": "string", "description": "Invited email address"}, "role": {"type": "string", "description": "Role to be assigned"}, "invited_by": {"type": "string", "description": "UUID of inviter"}, "status": {"type": "string", "description": "Invitation status (pending, accepted, expired, cancelled)"}, "expires_at": {"type": "string", "format": "date-time", "description": "Expiration timestamp"}, "created_at": {"type": "string", "format": "date-time", "description": "Creation timestamp"}, "inviter_name": {"type": "string", "description": "Inviter display name"}, "inviter_email": {"type": "string", "description": "Inviter email address"}}, "type": "object"}, "AcceptInvitation": {"required": ["token"], "properties": {"token": {"type": "string", "description": "Invitation token"}}, "type": "object"}, "MetricsResponse": {"properties": {"success": {"type": "boolean", "description": "Operation success"}, "metrics": {"$ref": "#/definitions/UserMetrics"}}, "type": "object"}, "UserMetrics": {"properties": {"conversations_count": {"type": "integer"}, "messages_count": {"type": "integer"}, "estimated_tokens": {"type": "integer"}, "token_breakdown": {"description": "Token usage by category", "allOf": [{"$ref": "#/definitions/TokenBreakdown"}]}, "strategies_count": {"type": "integer"}, "backtests_count": {"type": "integer"}, "tool_calls": {"type": "object"}}, "type": "object"}, "TokenBreakdown": {"properties": {"system_tokens": {"type": "integer", "description": "System/agent profile tokens"}, "context_tokens": {"type": "integer", "description": "Context/RAG/tool tokens"}, "user_tokens": {"type": "integer", "description": "User input tokens"}, "assistant_tokens": {"type": "integer", "description": "Assistant response tokens"}, "total_tokens": {"type": "integer", "description": "Total tokens"}}, "type": "object"}, "StrategiesResponse": {"properties": {"success": {"type": "boolean"}, "strategies": {"type": "array", "items": {"$ref": "#/definitions/Strategy"}}, "total": {"type": "integer"}}, "type": "object"}, "Strategy": {"properties": {"id": {"type": "string"}, "name": {"type": "string"}, "asset": {"type": "string"}, "status": {"type": "string"}, "entry_signals": {"type": "array", "items": {"type": "string"}}, "exit_signals": {"type": "array", "items": {"type": "string"}}, "created_at": {"type": "string"}, "config": {"type": "object"}}, "type": "object"}, "BacktestsResponse": {"properties": {"success": {"type": "boolean"}, "backtests": {"type": "array", "items": {"$ref": "#/definitions/Backtest"}}, "total": {"type": "integer"}}, "type": "object"}, "Backtest": {"properties": {"id": {"type": "string"}, "asset": {"type": "string"}, "status": {"type": "string"}, "start_date": {"type": "string"}, "end_date": {"type": "string"}, "initial_balance": {"type": "number"}, "total_return": {"type": "number"}, "irr_annualized": {"type": "number"}, "sharpe_ratio": {"type": "number"}, "win_rate": {"type": "number"}, "max_drawdown": {"type": "number"}, "total_trades": {"type": "integer"}, "execution_time": {"type": "number"}, "created_at": {"type": "string"}, "metrics": {"type": "object"}, "trade_history": {"type": "object"}}, "type": "object"}, "ResourceUtilization": {"properties": {"strategies": {"type": "object", "description": "Strategy utilization details"}, "backtests": {"type": "object", "description": "Backtest utilization details"}, "tokens": {"type": "object", "description": "Token utilization details"}, "api_calls": {"type": "object", "description": "API call utilization details"}}, "type": "object"}, "SubscriptionStatus": {"properties": {"tier_id": {"type": "string", "description": "Subscription tier ID"}, "tier_name": {"type": "string", "description": "Subscription tier name"}, "price_monthly": {"type": "number", "description": "Monthly price"}, "limits": {"type": "object", "description": "Resource limits"}, "usage": {"type": "object", "description": "Current usage"}, "limits_exceeded": {"type": "boolean", "description": "Whether any limits are exceeded"}, "current_period_start": {"type": "string", "format": "date-time", "description": "Current billing period start"}, "current_period_end": {"type": "string", "format": "date-time", "description": "Current billing period end"}}, "type": "object"}, "Error": {"properties": {"error": {"type": "string"}, "message": {"type": "string"}}, "type": "object"}, "Configuration": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether the configuration was retrieved successfully"}, "agentic_files": {"type": "array", "description": "Files present in the agentic/ directory", "items": {"type": "string"}}, "context_files": {"type": "array", "description": "Files present in the context/ directory", "items": {"type": "string"}}, "prompt_files": {"type": "array", "description": "Files present in the prompts/ directory", "items": {"type": "string"}}, "error": {"type": "string", "description": "Error message if retrieval failed"}}, "type": "object"}, "ConversationResponse": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether the operation completed successfully"}, "conversation": {"description": "Conversation data if successful", "allOf": [{"$ref": "#/definitions/Conversation"}]}, "error": {"type": "string", "description": "Error message if operation failed"}}, "type": "object"}, "Conversation": {"required": ["created_at", "session_id", "thread_id", "title"], "properties": {"session_id": {"type": "string", "description": "Unique identifier for the conversation session"}, "thread_id": {"type": "string", "description": "OpenAI thread ID for the conversation"}, "title": {"type": "string", "description": "Human-readable title for the conversation"}, "created_at": {"type": "string", "format": "date-time", "description": "Timestamp when the conversation was created"}, "working_context": {"type": "object", "description": "Optional JSONB context for state machine data"}}, "type": "object"}, "ConversationList": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether the operation completed successfully"}, "conversations": {"type": "array", "description": "List of conversations", "items": {"$ref": "#/definitions/Conversation"}}}, "type": "object"}, "ChatRequest": {"required": ["message"], "properties": {"message": {"type": "string", "description": "The user message content"}}, "type": "object"}, "DeleteResponse": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether the operation completed successfully"}, "message": {"type": "string", "description": "Success message"}, "error": {"type": "string", "description": "Error message if operation failed"}}, "type": "object"}, "RenameRequest": {"required": ["title"], "properties": {"title": {"type": "string", "description": "New conversation title"}}, "type": "object"}, "RenameResponse": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether the operation completed successfully"}, "message": {"type": "string", "description": "Success message"}, "error": {"type": "string", "description": "Error message if operation failed"}}, "type": "object"}, "RefreshVectorDBResponse": {"properties": {"success": {"type": "boolean", "description": "Operation success flag"}, "message": {"type": "string", "description": "Success message with document count"}, "documents_count": {"type": "integer", "description": "Number of documents inserted"}}, "type": "object"}, "BacktestRequest": {"required": ["asset", "enable_volatility_adjustment", "initial_balance", "max_open_positions", "max_risk_per_trade", "max_trade_amount", "max_trades_per_day", "max_units_per_trade", "min_balance_threshold", "min_trade_amount", "target_volatility", "volatility_mode", "volatility_window"], "properties": {"data_source": {"type": "string", "description": "Data source: \"api\" or \"file\" (default: api)"}, "data_file": {"type": "string", "description": "CSV filename if data_source=\"file\""}, "asset": {"type": "string", "description": "Asset symbol (e.g., \"BTC-USD\", \"ETH-USDT\")"}, "interval": {"type": "string", "description": "Time interval (e.g., \"1m\",\"5m\",\"15m\",\"30m\",\"1h\",\"4h\",\"1d\")"}, "lookback_months": {"type": "integer", "description": "Lookback window in months for API data (default: 12)"}, "initial_balance": {"type": "number", "description": "Initial account balance"}, "min_balance_threshold": {"type": "number", "description": "Minimum cash reserve as percentage (0.1 = 10%)"}, "min_trade_amount": {"type": "number", "description": "Minimum trade amount"}, "max_open_positions": {"type": "integer", "description": "Maximum open positions"}, "max_trades_per_day": {"type": "integer", "description": "Maximum trades per day"}, "max_risk_per_trade": {"type": "number", "description": "Maximum risk per trade"}, "max_units_per_trade": {"type": "number", "description": "Maximum units per trade"}, "max_trade_amount": {"type": "number", "description": "Maximum trade amount"}, "volatility_window": {"type": "integer", "description": "Volatility calculation window"}, "target_volatility": {"type": "number", "description": "Target volatility"}, "volatility_mode": {"type": "string", "description": "Volatility mode"}, "enable_volatility_adjustment": {"type": "boolean", "description": "Enable volatility adjustment"}, "cooldown_bars": {"type": "integer", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (24) when omitted."}, "daily_momentum_limit": {"type": "number", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (3) when omitted."}, "weekly_momentum_limit": {"type": "number", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (3) when omitted."}, "strategy_id": {"type": "string", "description": "UUID of a saved strategy to backtest. When provided, strategy_json (and, if omitted, asset and execution_config) are loaded from the saved strategy. Mutually exclusive with strategy_json."}, "strategy_json": {"type": "string", "description": "JSON config for the strategy (entry/exit rules, reward_factor). ATR params come from execution_config. Mutually exclusive with strategy_id; one of the two is required."}, "execution_config": {"type": "object", "description": "Execution config dict with atr_period, atr_volatility_factor, etc. If omitted, defaults from trading_defaults.json are used."}, "start_date": {"type": "string", "description": "Start date ISO format (e.g., \"2024-01-01\"). If omitted, calculated from lookback_months"}, "end_date": {"type": "string", "description": "End date ISO format (e.g., \"2024-12-31\"). If omitted with start_date, defaults to now"}, "slippage_pct": {"type": "number", "description": "Max slippage per leg as decimal (e.g., 0.004 = 0.4%). Random slippage drawn from uniform(0, slippage_pct) independently for entry and exit. Default from trading_defaults.json: 0.004."}, "fee_pct": {"type": "number", "description": "Max fee rate as decimal (default 0.0085 = 0.85%). Size-dependent linear schedule: $10K trades pay full rate, $1M+ trades pay 0.0589%. Applied only to profitable trades. Default from trading_defaults.json."}, "hourly_data_file": {"type": "string", "description": "Legacy: CSV file path (treated as data_file)"}, "exchange": {"type": "string", "description": "Legacy: exchange name (not used for api data source)"}}, "type": "object"}, "BacktestResult": {"required": ["success"], "properties": {"success": {"type": "boolean", "description": "Whether backtest completed successfully"}, "metrics": {"type": "object", "description": "Performance metrics"}, "trade_history": {"type": "array", "description": "List of serialized TradeRecord objects with entry/exit prices, timestamps, profit/loss, exit reasons", "items": {"type": "object"}}, "error": {"type": "string", "description": "Error message if backtest failed"}, "execution_time_seconds": {"type": "number", "description": "Time taken to run backtest"}, "trade_count": {"type": "integer", "description": "Number of trades executed"}, "strategy_names": {"type": "array", "description": "List of strategy names that were run", "items": {"type": "string"}}}, "type": "object"}, "BulkBacktestRequest": {"required": ["enable_volatility_adjustment", "end_date", "initial_balance", "max_open_positions", "max_risk_per_trade", "max_trade_amount", "max_trades_per_day", "max_units_per_trade", "min_balance_threshold", "min_trade_amount", "start_date", "target_volatility", "volatility_mode", "volatility_window"], "properties": {"strategy_ids": {"type": "array", "description": "List of strategy UUIDs to load from the database. Mutually exclusive with strategy_configs.", "items": {"type": "string"}}, "strategy_configs": {"type": "array", "description": "List of strategy config objects in the canonical entry/exit format (already parsed -- not stringified JSON). Mutually exclusive with strategy_ids.", "items": {"type": "object"}}, "start_date": {"type": "string", "description": "Start date ISO format (e.g., \"2024-01-01\")"}, "end_date": {"type": "string", "description": "End date ISO format (e.g., \"2024-12-31\")"}, "initial_balance": {"type": "number", "description": "Initial account balance"}, "min_balance_threshold": {"type": "number", "description": "Minimum cash reserve as percentage (0.1 = 10%)"}, "min_trade_amount": {"type": "number", "description": "Minimum trade amount"}, "max_open_positions": {"type": "integer", "description": "Maximum open positions"}, "max_trades_per_day": {"type": "integer", "description": "Maximum trades per day"}, "max_risk_per_trade": {"type": "number", "description": "Maximum risk per trade"}, "max_units_per_trade": {"type": "number", "description": "Maximum units per trade"}, "max_trade_amount": {"type": "number", "description": "Maximum trade amount"}, "volatility_window": {"type": "integer", "description": "Volatility calculation window"}, "target_volatility": {"type": "number", "description": "Target volatility"}, "volatility_mode": {"type": "string", "description": "Volatility mode"}, "enable_volatility_adjustment": {"type": "boolean", "description": "Enable volatility adjustment"}, "cooldown_bars": {"type": "integer", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (24) when omitted."}, "daily_momentum_limit": {"type": "number", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (3) when omitted."}, "weekly_momentum_limit": {"type": "number", "description": "DEPRECATED (use cooldown_config). Optional; defaults from trading_defaults.json (3) when omitted."}, "execution_config": {"type": "object", "description": "Execution config applied to every strategy (atr_period, atr_volatility_factor, etc.). Defaults from trading_defaults.json are used when omitted."}, "max_hold_time_hours": {"type": "integer", "description": "Maximum position hold time in hours"}, "slippage_pct": {"type": "number", "description": "Max slippage per leg as decimal (default from trading_defaults.json: 0.004)"}, "fee_pct": {"type": "number", "description": "Max fee rate as decimal (default 0.0085). Size-dependent linear schedule, profitable trades only."}}, "type": "object"}, "BulkBacktestResult": {"properties": {"success": {"type": "boolean", "description": "True unless the request itself was invalid"}, "results": {"type": "array", "description": "One result per input strategy, in order", "items": {"$ref": "#/definitions/StrategyBacktestResult"}}, "data_fetches": {"type": "integer", "description": "Number of unique (asset, timeframe) API calls made"}, "total_execution_time_seconds": {"type": "number", "description": "Wall-clock time for the full batch"}, "error": {"type": "string", "description": "Top-level error message (only set on total failure)"}}, "type": "object"}, "StrategyBacktestResult": {"properties": {"success": {"type": "boolean", "description": "Whether this strategy completed without error"}, "strategy_id": {"type": "string", "description": "DB UUID of the strategy (null for inline configs)"}, "strategy_name": {"type": "string", "description": "Name from the strategy config"}, "metrics": {"type": "object", "description": "Performance metrics (empty dict on failure)"}, "trade_count": {"type": "integer", "description": "Number of trades executed"}, "execution_time_seconds": {"type": "number", "description": "Time taken for this strategy"}, "error": {"type": "string", "description": "Error message if success is false"}}, "type": "object"}, "BacktestArchiveResponse": {"properties": {"success": {"type": "boolean", "description": "Whether the operation succeeded"}, "backtest_id": {"type": "string", "description": "UUID of the affected backtest run"}, "archived": {"type": "boolean", "description": "True after archive, False after unarchive"}}, "type": "object"}, "CreateStrategyRequest": {"required": ["asset", "entry", "name"], "properties": {"name": {"type": "string", "description": "Strategy name"}, "org_id": {"type": "string", "description": "Deprecated: ignored, org_id is taken from JWT token. Accepted for backward compatibility."}, "asset": {"type": "string", "description": "Asset symbol (e.g., BTC)"}, "entry": {"type": "array", "description": "Entry rules array (exactly 1 TRIGGER, 0+ FILTERs)", "items": {"type": "object"}}, "exit": {"type": "array", "description": "Exit rules array (optional, 0-1 TRIGGER + 0+ FILTERs)", "items": {"type": "object"}}, "rules": {"type": "array", "description": "Legacy: flat rules array (use entry/exit instead)", "items": {"type": "object"}}, "reward_factor": {"type": "number", "description": "Reward factor for risk/reward calculation (default: 2.0)"}, "status": {"type": "string", "description": "Initial status (draft, inactive, paper, live, archived). Default: inactive"}, "execution_config": {"type": "object", "description": "Execution configuration (risk mgmt, position limits, etc.). Auto-populated from defaults if omitted"}, "execution_state": {"type": "object", "description": "Initial execution state (cash_balance, account_value, etc.). Auto-populated if omitted"}, "session_id": {"type": "string", "description": "Linked conversation session ID (optional)"}, "parent_strategy_id": {"type": "string", "description": "Parent strategy ID for derived strategies (optional)"}, "strategy_type": {"type": "string", "description": "Strategy type (trend_following, momentum, volatility, breakout, mean_reversion)"}, "description": {"type": "string", "description": "Human-readable strategy description"}, "position_size_calc": {"type": "string", "description": "Sizing-math version: \"v1\" or \"v2\". Defaults from canon (currently \"v2\"). Pinned at creation; cannot be changed after."}}, "type": "object"}, "StrategyListResponse": {"properties": {"success": {"type": "boolean"}, "strategies": {"type": "array", "items": {"$ref": "#/definitions/StrategyListItem"}}, "total": {"type": "integer"}, "skip": {"type": "integer"}, "limit": {"type": "integer"}}, "type": "object"}, "StrategyListItem": {"properties": {"id": {"type": "string", "description": "Strategy ID (UUID)"}, "name": {"type": "string", "description": "Strategy name"}, "asset": {"type": "string", "description": "Asset symbol"}, "status": {"type": "string", "description": "Strategy status"}, "created_at": {"type": "string", "description": "Creation timestamp"}, "strategy_type": {"type": "string", "description": "Strategy type"}, "description": {"type": "string", "description": "Human-readable strategy description"}, "position_size_calc": {"type": "string", "description": "Sizing-math version: \"v1\" or \"v2\""}}, "type": "object"}, "CreateStrategyResponse": {"properties": {"success": {"type": "boolean"}, "strategy": {"$ref": "#/definitions/StrategyDetail"}}, "type": "object"}, "StrategyDetail": {"properties": {"id": {"type": "string", "description": "Strategy ID (UUID)"}, "name": {"type": "string", "description": "Strategy name"}, "user_id": {"type": "string", "description": "User ID (owner)"}, "org_id": {"type": "string", "description": "Organization ID"}, "asset": {"type": "string", "description": "Asset symbol"}, "rules": {"type": "object", "description": "Entry/exit rules (JSON)"}, "status": {"type": "string", "description": "Strategy status (draft, inactive, paper, live, archived)"}, "created_at": {"type": "string", "description": "Creation timestamp"}, "execution_config": {"type": "object", "description": "Execution configuration (risk management, position limits, etc.)"}, "execution_state": {"type": "object", "description": "Runtime execution state (cash_balance, account_value, trades)"}, "session_id": {"type": "string", "description": "Linked conversation session ID"}, "parent_strategy_id": {"type": "string", "description": "Parent strategy ID (for derived strategies)"}, "content_hash": {"type": "string", "description": "Content hash for deduplication"}, "strategy_type": {"type": "string", "description": "Strategy type (trend_following, momentum, volatility, breakout, mean_reversion)"}, "description": {"type": "string", "description": "Human-readable strategy description"}, "last_evaluated_at": {"type": "string", "description": "Timestamp of last evaluation (ISO format, null if never evaluated)"}, "evaluation_count": {"type": "integer", "description": "Total number of evaluations performed"}, "position_size_calc": {"type": "string", "description": "Sizing-math version: \"v1\" or \"v2\". Pinned at creation; cannot be changed after."}}, "type": "object"}, "UpdateStrategyResponse": {"properties": {"success": {"type": "boolean"}, "strategy": {"$ref": "#/definitions/StrategyDetail"}}, "type": "object"}, "GetStrategyResponse": {"properties": {"success": {"type": "boolean"}, "strategy": {"$ref": "#/definitions/StrategyDetail"}}, "type": "object"}, "DeleteStrategyResponse": {"properties": {"success": {"type": "boolean"}, "message": {"type": "string"}}, "type": "object"}, "UpdateStrategyStatusRequest": {"required": ["status"], "properties": {"status": {"type": "string", "description": "New status (draft, inactive, paper, live, archived)"}}, "type": "object"}, "UpdateStrategyStatusResponse": {"properties": {"success": {"type": "boolean"}, "message": {"type": "string"}}, "type": "object"}, "CreateSignalRequest": {"required": ["code", "description", "name", "params"], "properties": {"name": {"type": "string", "description": "Signal name (lowercase, no spaces)"}, "code": {"type": "string", "description": "Python function code"}, "params": {"type": "object", "description": "Parameter definitions (JSON object)"}, "description": {"type": "string", "description": "Human-readable description"}}, "type": "object"}, "SignalListResponse": {"properties": {"signals": {"type": "array", "items": {"$ref": "#/definitions/Signal"}}, "total": {"type": "integer"}, "limit": {"type": "integer"}, "offset": {"type": "integer"}}, "type": "object"}, "Signal": {"required": ["category", "name"], "properties": {"name": {"type": "string"}, "category": {"type": "string"}, "signal_type": {"type": "string", "description": "TRIGGER or FILTER"}, "metadata": {"$ref": "#/definitions/SignalMetadata"}, "code": {"type": "string", "description": "Python code"}, "usage_count": {"type": "integer", "description": "Number of strategies using this signal"}}, "type": "object"}, "SignalMetadata": {"required": ["rule_name"], "properties": {"rule_name": {"type": "string"}, "description": {"type": "string"}, "requires": {"type": "array", "items": {"type": "string"}}, "params": {"type": "object"}}, "type": "object"}, "CreateSignalResponse": {"properties": {"id": {"type": "string", "description": "Signal ID (UUID)"}, "name": {"type": "string"}, "category": {"type": "string"}, "metadata": {"$ref": "#/definitions/SignalMetadata"}, "code": {"type": "string"}, "usage_count": {"type": "integer"}}, "type": "object"}, "MatchSignalsRequest": {"required": ["description"], "properties": {"description": {"type": "string", "description": "Natural language description of the desired signal/rule"}, "user_intent": {"type": "object", "description": "Optional intent dict (e.g., from intent extractor)"}, "top_k": {"type": "integer", "description": "Number of matches to return", "default": 5}, "similarity_threshold": {"type": "number", "description": "Minimum similarity score to include", "default": 0.5}}, "type": "object"}, "MatchSignalsResponse": {"properties": {"query": {"type": "string"}, "top_k": {"type": "integer"}, "similarity_threshold": {"type": "number"}, "matches": {"type": "array", "items": {"$ref": "#/definitions/MatchedSignal"}}}, "type": "object"}, "MatchedSignal": {"properties": {"signal_name": {"type": "string", "description": "Matched signal name from registry"}, "description": {"type": "string", "description": "Signal description"}, "similarity_score": {"type": "number"}, "semantic_score": {"type": "number"}, "intent_score": {"type": "number"}, "usecase_score": {"type": "number"}, "params": {"type": "object"}, "match_reasoning": {"type": "string"}}, "type": "object"}, "EvaluateSignalRequest": {"required": ["market_data", "parameters"], "properties": {"market_data": {"type": "array", "items": {"$ref": "#/definitions/MarketDataBar"}}, "parameters": {"type": "object"}}, "type": "object"}, "MarketDataBar": {"required": ["Close"], "properties": {"Close": {"type": "number"}, "Open": {"type": "number"}, "High": {"type": "number"}, "Low": {"type": "number"}, "Volume": {"type": "number"}}, "type": "object"}, "SignalEvaluationResponse": {"required": ["success"], "properties": {"success": {"type": "boolean"}, "result": {"type": "boolean"}, "error": {"type": "string"}}, "type": "object"}, "ValidateSignalParamsRequest": {"required": ["parameters"], "properties": {"parameters": {"type": "object"}}, "type": "object"}, "SignalValidationResponse": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "ValidateSignalCodeRequest": {"required": ["code", "description", "params"], "properties": {"code": {"type": "string", "description": "Python function code"}, "params": {"type": "object", "description": "Parameter definitions (JSON object)"}, "description": {"type": "string", "description": "Signal description"}, "rule_name": {"type": "string", "description": "Expected function/rule name"}}, "type": "object"}, "SyntaxValidationResult": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "MetadataValidationResult": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "ExecutionValidationResult": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "TradesValidationResult": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "ValidationResult": {"required": ["valid"], "properties": {"valid": {"type": "boolean"}, "syntax_valid": {"type": "boolean"}, "metadata_valid": {"type": "boolean"}, "execution_valid": {"type": "boolean"}, "trades_valid": {"type": "boolean"}, "errors": {"type": "array", "items": {"type": "string"}}, "warnings": {"type": "array", "items": {"type": "string"}}}, "type": "object"}, "SearchSignalsRequest": {"required": ["query"], "properties": {"query": {"type": "string", "description": "Search query string"}, "search_type": {"type": "string", "description": "Type of search", "default": "name", "example": "name", "enum": ["name", "params", "keywords"]}, "limit": {"type": "integer", "description": "Maximum results", "default": 50}, "offset": {"type": "integer", "description": "Pagination offset", "default": 0}}, "type": "object"}, "SearchSignalsResponse": {"properties": {"signals": {"type": "array", "items": {"$ref": "#/definitions/Signal"}}, "total": {"type": "integer"}, "limit": {"type": "integer"}, "offset": {"type": "integer"}, "search_type": {"type": "string"}}, "type": "object"}, "EvaluateMultipleSeriesRequest": {"required": ["end_date", "start_date", "symbol"], "properties": {"symbol": {"type": "string", "description": "Asset symbol (e.g., BTC, BTC-USDT)"}, "chart_timeframe": {"type": "string", "description": "Chart timeframe (5m, 15m, 30m, 1h, 4h, 1D)"}, "start_date": {"type": "string", "description": "Chart start date/time (ISO format)"}, "end_date": {"type": "string", "description": "Chart end date/time (ISO format)"}, "signals": {"type": "array", "description": "List of signals to evaluate", "items": {"$ref": "#/definitions/EvaluateMultipleSeriesSignal"}}}, "type": "object"}, "EvaluateMultipleSeriesSignal": {"required": ["name", "params"], "properties": {"name": {"type": "string", "description": "Signal type/name"}, "timeframe": {"type": "string", "description": "Timeframe for this signal (5m, 15m, 30m, 1h, 4h, 1D)"}, "params": {"type": "object", "description": "Signal parameters"}}, "type": "object"}, "EvaluateMultipleSeriesResponse": {"properties": {"chart_timeframe": {"type": "string", "description": "Chart timeframe"}, "start_date": {"type": "string", "description": "Chart range start"}, "end_date": {"type": "string", "description": "Chart range end"}, "chart_data": {"type": "array", "description": "OHLCV data for chart rendering", "items": {"type": "object"}}, "signal_results": {"type": "array", "description": "Individual signal evaluation results", "items": {"$ref": "#/definitions/SignalTriggerResult"}}}, "type": "object"}, "SignalTriggerResult": {"properties": {"signal_name": {"type": "string", "description": "Name of the signal"}, "timeframe": {"type": "string", "description": "Timeframe used for this signal"}, "bars_fetched": {"type": "integer", "description": "Number of bars fetched"}, "trigger_indices": {"type": "array", "description": "Bar indices where signal triggers", "items": {"type": "integer"}}, "trigger_timestamps": {"type": "array", "description": "ISO timestamps where signal triggers", "items": {"type": "string"}}, "market_data": {"type": "array", "description": "OHLCV data for this signal", "items": {"type": "object"}}}, "type": "object"}, "CreateAccountRequest": {"required": ["account_type"], "properties": {"account_type": {"type": "string", "description": "Account type (paper or live)"}, "name": {"type": "string", "description": "Account name"}, "initial_balance": {"type": "number", "description": "Starting cash balance", "default": 10000}, "min_balance_threshold": {"type": "number", "description": "Minimum cash reserve as percentage (0.1 = 10%)", "default": 0.1}, "min_trade_amount": {"type": "number", "description": "Minimum trade amount", "default": 25}, "max_open_positions": {"type": "integer", "description": "Maximum open positions", "default": 3}, "max_trades_per_day": {"type": "integer", "description": "Maximum trades per day", "default": 10}, "max_risk_per_trade": {"type": "number", "description": "Maximum risk per trade", "default": 0.02}, "risk_params": {"type": "object", "description": "Additional risk parameters"}}, "type": "object"}, "Account": {"properties": {"id": {"type": "string", "description": "Account UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "user_id": {"type": "string", "description": "User UUID"}, "account_type": {"type": "string", "description": "Account type (paper or live)"}, "name": {"type": "string", "description": "Account name"}, "cash_balance": {"type": "number", "description": "Current cash balance"}, "account_value": {"type": "number", "description": "Total account value (cash + positions)"}, "min_balance_threshold": {"type": "number", "description": "Minimum cash reserve as percentage of balance (0.1 = 10%)"}, "min_trade_amount": {"type": "number", "description": "Minimum position size"}, "max_open_positions": {"type": "integer", "description": "Maximum concurrent positions"}, "max_trades_per_day": {"type": "integer", "description": "Daily trade limit"}, "max_risk_per_trade": {"type": "number", "description": "Maximum risk per trade (0.02 = 2%)"}, "risk_params": {"type": "object", "description": "Additional risk configuration"}, "active": {"type": "boolean", "description": "Whether account is active"}, "created_at": {"type": "string", "description": "Creation timestamp"}, "updated_at": {"type": "string", "description": "Last update timestamp"}}, "type": "object"}, "Position": {"properties": {"id": {"type": "string", "description": "Position UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "user_id": {"type": "string", "description": "User UUID"}, "account_id": {"type": "string", "description": "Account UUID"}, "strategy_id": {"type": "string", "description": "Strategy UUID"}, "asset": {"type": "string", "description": "Asset symbol"}, "exchange": {"type": "string", "description": "Exchange name"}, "entry_price": {"type": "number", "description": "Entry price"}, "exit_price": {"type": "number", "description": "Exit price"}, "position_size": {"type": "number", "description": "Position size (units)"}, "cost": {"type": "number", "description": "Total cost (entry_price * position_size)"}, "value_at_close": {"type": "number", "description": "Value at close"}, "open": {"type": "boolean", "description": "Whether position is currently open"}, "exit_reason": {"type": "string", "description": "Exit reason (SL, TP, MN, MANUAL)"}, "stop_loss_price": {"type": "number", "description": "Stop loss price"}, "take_profit_price": {"type": "number", "description": "Take profit price"}, "created_at": {"type": "string", "description": "Creation timestamp"}, "entry_timestamp": {"type": "string", "description": "Entry timestamp"}, "exit_timestamp": {"type": "string", "description": "Exit timestamp"}}, "type": "object"}, "Trade": {"properties": {"id": {"type": "string", "description": "Trade UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "user_id": {"type": "string", "description": "User UUID"}, "account_id": {"type": "string", "description": "Account UUID"}, "position_id": {"type": "string", "description": "Position UUID"}, "outcome": {"type": "string", "description": "Trade outcome (win or loss)"}, "profit_loss": {"type": "number", "description": "Profit/loss in dollars"}, "profit_loss_pct": {"type": "number", "description": "Profit/loss percentage"}, "asset": {"type": "string", "description": "Asset symbol"}, "exchange": {"type": "string", "description": "Exchange name"}, "strategy_name": {"type": "string", "description": "Strategy name"}, "entry_price": {"type": "number", "description": "Entry price"}, "exit_price": {"type": "number", "description": "Exit price"}, "position_size": {"type": "number", "description": "Position size"}, "beginning_balance": {"type": "number", "description": "Account balance before trade"}, "ending_balance": {"type": "number", "description": "Account balance after trade"}, "closed_at": {"type": "string", "description": "Trade close timestamp"}}, "type": "object"}, "EvaluateRequest": {"properties": {"persist": {"type": "boolean", "description": "Whether to persist orders, positions, and trades to database", "default": true}}, "type": "object"}, "EvaluateResponse": {"properties": {"success": {"type": "boolean", "description": "Whether evaluation succeeded"}, "error": {"type": "string", "description": "Error message if success=False"}, "strategy_id": {"type": "string", "description": "Strategy UUID"}, "strategy_name": {"type": "string", "description": "Strategy name"}, "user_id": {"type": "string", "description": "User UUID"}, "org_id": {"type": "string", "description": "Organization UUID"}, "asset": {"type": "string", "description": "Asset being traded"}, "current_price": {"type": "number", "description": "Current market price"}, "timestamp": {"type": "string", "description": "Evaluation timestamp (ISO format)"}, "execution_state": {"description": "Strategy execution state", "allOf": [{"$ref": "#/definitions/ExecutionState"}]}, "new_orders": {"type": "array", "description": "Orders generated or triggered during evaluation", "items": {"$ref": "#/definitions/OrderResponse"}}, "execution_time_seconds": {"type": "number", "description": "Time taken to complete evaluation"}}, "type": "object"}, "ExecutionState": {"properties": {"cash_balance": {"type": "number", "description": "Current cash balance"}, "account_value": {"type": "number", "description": "Total account value"}, "total_trades": {"type": "integer", "description": "Total completed trades"}, "num_open_positions": {"type": "integer", "description": "Number of currently open positions"}, "risk_state": {"type": "object", "description": "Serialized RiskManager state (cooldown deques, counters)"}, "bar_index": {"type": "integer", "description": "Monotonic bar counter for max_hold_bars continuity"}}, "type": "object"}, "OrderResponse": {"properties": {"order_id": {"type": "string", "description": "Order UUID"}, "asset": {"type": "string", "description": "Asset symbol (e.g., BTC-USD)"}, "side": {"type": "string", "description": "Order side (enter_long, exit_long)", "example": "enter_long", "enum": ["enter_long", "exit_long"]}, "order_type": {"type": "string", "description": "Order type", "example": "market", "enum": ["market", "limit", "stop_loss", "take_profit"]}, "status": {"type": "string", "description": "Order status", "example": "inactive", "enum": ["inactive", "pending", "filled", "cancelled"]}, "price": {"type": "number", "description": "Order price (null for unfilled market orders)"}, "position_size": {"type": "number", "description": "Position size in units"}, "position_id": {"type": "string", "description": "Associated position UUID"}, "history": {"description": "Order lifecycle timestamps", "allOf": [{"$ref": "#/definitions/OrderHistory"}]}}, "type": "object"}, "OrderHistory": {"properties": {"created": {"type": "string", "description": "Order creation timestamp (ISO format)"}, "activated": {"type": "string", "description": "Order activation timestamp (ISO format)"}, "filled": {"type": "string", "description": "Order fill timestamp (ISO format)"}, "cancelled": {"type": "string", "description": "Order cancellation timestamp (ISO format)"}}, "type": "object"}, "EvaluateObjectRequest": {"required": ["strategy"], "properties": {"strategy": {"description": "Strategy object to evaluate", "allOf": [{"$ref": "#/definitions/StrategyObject"}]}, "persist": {"type": "boolean", "description": "Whether to persist results (default False for object-based)", "default": false}}, "type": "object"}, "StrategyObject": {"required": ["asset", "rules"], "properties": {"name": {"type": "string", "description": "Strategy name"}, "asset": {"type": "string", "description": "Asset symbol (e.g., BTC-USD)"}, "rules": {"type": "object", "description": "Entry/exit rules (JSON)"}, "execution_config": {"type": "object", "description": "Execution configuration (risk management, position limits)"}, "execution_state": {"type": "object", "description": "Initial execution state (balances, trade counts)"}}, "type": "object"}, "BulkEvaluateRequest": {"properties": {"strategy_ids": {"type": "array", "description": "List of strategy UUIDs to load from DB and evaluate", "items": {"type": "string"}}, "strategy_configs": {"type": "array", "description": "List of inline strategy objects to evaluate. Each must include asset, entry/rules, execution_config, and execution_state.", "items": {"type": "object"}}, "persist": {"type": "boolean", "description": "Persist orders and positions to DB for each strategy (default: false)", "default": false}}, "type": "object"}, "BulkEvaluateResult": {"properties": {"success": {"type": "boolean", "description": "True if the batch ran to completion; false only on a top-level batch error"}, "results": {"type": "array", "description": "Per-strategy results in the same order as the request", "items": {"$ref": "#/definitions/StrategyEvaluateResult"}}, "data_fetches": {"type": "integer", "description": "Number of unique (asset, timeframe) market-data API calls made"}, "total_execution_time_seconds": {"type": "number", "description": "Wall-clock time for the full batch"}, "error": {"type": "string", "description": "Top-level error if the batch could not start"}}, "type": "object"}, "StrategyEvaluateResult": {"properties": {"success": {"type": "boolean", "description": "Whether this strategy evaluated without error"}, "strategy_id": {"type": "string", "description": "Strategy UUID (null for inline configs)"}, "strategy_name": {"type": "string", "description": "Strategy name"}, "asset": {"type": "string", "description": "Asset symbol"}, "current_price": {"type": "number", "description": "Market price at evaluation time"}, "new_orders": {"type": "array", "description": "Orders generated or triggered during evaluation", "items": {"$ref": "#/definitions/OrderResponse"}}, "execution_time_seconds": {"type": "number", "description": "Wall-clock time for this strategy"}, "error": {"type": "string", "description": "Error message if success=False"}}, "type": "object"}, "PortfolioResponse": {"properties": {"results": {"type": "array", "description": "Portfolio entries in the order requested (missing ones omitted)", "items": {"$ref": "#/definitions/PortfolioEntry"}}, "missing": {"type": "array", "description": "Strategy IDs that were not found", "items": {"type": "string"}}}, "type": "object"}, "PortfolioEntry": {"properties": {"strategy_id": {"type": "string", "description": "Strategy UUID"}, "strategy_name": {"type": "string", "description": "Strategy name"}, "asset": {"type": "string", "description": "Asset symbol"}, "execution_state": {"description": "Execution state snapshot", "allOf": [{"$ref": "#/definitions/PortfolioExecutionState"}]}, "last_evaluated_at": {"type": "string", "description": "Last evaluation timestamp (ISO 8601, nullable)"}, "open_positions_count": {"type": "integer", "description": "Number of currently open positions (from DB)"}, "recent_trades": {"type": "array", "description": "Last 5 trades, newest first", "items": {"$ref": "#/definitions/RecentTradeEntry"}}}, "type": "object"}, "PortfolioExecutionState": {"properties": {"cash_balance": {"type": "number", "description": "Current cash balance"}, "account_value": {"type": "number", "description": "Total account value"}, "total_trades": {"type": "integer", "description": "Total completed trades"}, "num_open_positions": {"type": "integer", "description": "Number of currently open positions"}}, "type": "object"}, "RecentTradeEntry": {"properties": {"closed_at": {"type": "string", "description": "Trade close timestamp (ISO 8601, nullable)"}, "outcome": {"type": "string", "description": "Trade outcome (win or loss)"}, "profit_loss": {"type": "number", "description": "Profit/loss in dollars"}, "profit_loss_pct": {"type": "number", "description": "Profit/loss as percentage"}, "asset": {"type": "string", "description": "Asset symbol"}}, "type": "object"}, "ExchangeListResponse": {"properties": {"success": {"type": "boolean"}, "exchanges": {"type": "array", "items": {"type": "object"}}, "count": {"type": "integer"}}, "type": "object"}, "CryptoAssetListResponse": {"properties": {"success": {"type": "boolean"}, "assets": {"type": "array", "items": {"$ref": "#/definitions/CryptoAsset"}}, "count": {"type": "integer"}}, "type": "object"}, "CryptoAsset": {"properties": {"id": {"type": "string", "description": "Asset ID (UUID)"}, "symbol": {"type": "string", "description": "Asset symbol (e.g., BTC)"}, "name": {"type": "string", "description": "Asset name (e.g., Bitcoin)"}, "risk_scores": {"$ref": "#/definitions/RiskScores"}, "is_approved": {"type": "boolean", "description": "Approval status"}, "regulatory_status": {"type": "string", "description": "Regulatory status (pending, approved, restricted, banned)"}, "security_status": {"type": "string", "description": "Security status (pending, secure, vulnerable, compromised)"}, "metadata": {"$ref": "#/definitions/AssetMetadata"}, "timestamps": {"$ref": "#/definitions/Timestamps"}}, "type": "object"}, "RiskScores": {"properties": {"market_cap": {"type": "integer", "description": "Market cap score (0-100)"}, "liquidity": {"type": "integer", "description": "Liquidity score (0-100)"}, "exchange": {"type": "integer", "description": "Exchange availability score (0-100)"}, "age": {"type": "integer", "description": "Age score (0-100)"}, "volatility": {"type": "integer", "description": "Volatility score (0-100)"}, "supply_distribution": {"type": "integer", "description": "Supply distribution score (0-100)"}, "price_stability": {"type": "integer", "description": "Price stability score (0-100)"}, "overall": {"type": "number", "description": "Overall risk score (weighted average, 0-100)"}}, "type": "object"}, "AssetMetadata": {"properties": {"market_cap": {"type": "number", "description": "Market capitalization (USD)"}, "volume_24h": {"type": "number", "description": "24-hour trading volume (USD)"}, "age_days": {"type": "integer", "description": "Asset age in days"}, "exchanges": {"type": "array", "description": "Exchange listings", "items": {"type": "string"}}}, "type": "object"}, "Timestamps": {"properties": {"created_at": {"type": "string", "description": "Creation timestamp"}, "updated_at": {"type": "string", "description": "Last update timestamp"}, "last_evaluated_at": {"type": "string", "description": "Last risk evaluation timestamp"}}, "type": "object"}, "CryptoAssetDetailResponse": {"properties": {"success": {"type": "boolean"}, "asset": {"$ref": "#/definitions/CryptoAsset"}}, "type": "object"}, "AssetExchangesResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "count": {"type": "integer"}, "exchanges": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "TrendingAssetsResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer"}, "trending": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "GlobalMarketResponse": {"properties": {"success": {"type": "boolean"}, "data": {"type": "object"}}, "type": "object"}, "MarketDataResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "data": {"type": "object"}}, "type": "object"}, "OHLCVResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "data_points": {"type": "integer"}, "data": {"type": "object"}}, "type": "object"}, "TokenHoldersResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "data": {"type": "object"}}, "type": "object"}, "FlowIntelligenceResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "chain": {"type": "string"}, "timeframe": {"type": "string"}, "data": {"type": "object"}}, "type": "object"}, "SmartMoneyNetflowsResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer"}, "chains": {"type": "array", "items": {"type": "string"}}, "timeframe": {"type": "string"}, "labels": {"type": "array", "items": {"type": "string"}}, "data": {"type": "object"}}, "type": "object"}, "SmartMoneyHoldingsResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer"}, "chains": {"type": "array", "items": {"type": "string"}}, "labels": {"type": "array", "items": {"type": "string"}}, "min_value_usd": {"type": "number"}, "data": {"type": "object"}}, "type": "object"}, "UpdateRegulatoryStatus": {"required": ["status"], "properties": {"status": {"type": "string", "description": "Regulatory status", "example": "pending", "enum": ["pending", "approved", "restricted", "banned"]}}, "type": "object"}, "UpdateRegulatoryStatusResponse": {"properties": {"success": {"type": "boolean"}, "asset": {"$ref": "#/definitions/CryptoAsset"}}, "type": "object"}, "UpdateSecurityStatus": {"required": ["status"], "properties": {"status": {"type": "string", "description": "Security status", "example": "pending", "enum": ["pending", "secure", "vulnerable", "compromised"]}}, "type": "object"}, "UpdateSecurityStatusResponse": {"properties": {"success": {"type": "boolean"}, "asset": {"$ref": "#/definitions/CryptoAsset"}, "auto_suspended": {"type": "boolean", "description": "True if asset was auto-suspended"}}, "type": "object"}, "SuspendAssetResponse": {"properties": {"success": {"type": "boolean"}, "asset": {"$ref": "#/definitions/CryptoAsset"}}, "type": "object"}, "ApproveAssetResponse": {"properties": {"success": {"type": "boolean"}, "asset": {"$ref": "#/definitions/CryptoAsset"}}, "type": "object"}, "UpdateAllAssetsResponse": {"properties": {"success": {"type": "boolean"}, "message": {"type": "string"}, "results": {"type": "object"}}, "type": "object"}, "DocsList": {"properties": {"success": {"type": "boolean", "description": "Whether request was successful"}, "docs": {"type": "array", "description": "List of available documents", "items": {"$ref": "#/definitions/DocItem"}}, "error": {"type": "string", "description": "Error message if request failed"}}, "type": "object"}, "DocItem": {"properties": {"path": {"type": "string", "description": "Relative path to the document"}, "name": {"type": "string", "description": "File name"}, "title": {"type": "string", "description": "Document title (extracted from first heading if possible)"}}, "type": "object"}, "DocContent": {"properties": {"success": {"type": "boolean", "description": "Whether request was successful"}, "content": {"type": "string", "description": "Raw markdown content"}, "path": {"type": "string", "description": "Document path"}, "error": {"type": "string", "description": "Error message if request failed"}}, "type": "object"}, "BatchJob": {"properties": {"id": {"type": "string", "description": "Job UUID"}, "name": {"type": "string", "description": "Job name"}, "status": {"type": "string", "description": "Job status (running, complete, failed)"}, "failure_reason": {"type": "string", "description": "Error message if failed"}, "invoked": {"type": "string", "description": "Start timestamp"}, "completed": {"type": "string", "description": "Completion timestamp"}, "result_data": {"type": "object", "description": "Structured output from completed batch job"}}, "type": "object"}, "DefiError": {"properties": {"error": {"type": "string"}, "message": {"type": "string"}, "code": {"type": "string"}}, "type": "object"}, "ProtocolTVLResponse": {"properties": {"success": {"type": "boolean"}, "protocol": {"type": "string"}, "tvl_usd": {"type": "number"}, "chains": {"type": "object", "description": "Chain name -> TVL breakdown"}, "data": {"type": "object", "description": "Full provider response"}}, "type": "object"}, "ChainTVLResponse": {"properties": {"success": {"type": "boolean"}, "chain": {"type": "string"}, "tvl_usd": {"type": "number"}, "top_protocols": {"type": "array", "description": "Top 10 protocols on this chain", "items": {"type": "object"}}, "data": {"type": "object", "description": "Full provider response"}}, "type": "object"}, "StablecoinMetricsResponse": {"properties": {"success": {"type": "boolean"}, "total_supply_usd": {"type": "number"}, "supply_by_chain": {"type": "object", "description": "Chain name -> stablecoin supply"}, "data": {"type": "object", "description": "Top stablecoins and metadata"}}, "type": "object"}, "DefiProResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer", "description": "Number of records (when list-shaped)"}, "data": {"type": "object", "description": "Full provider response"}}, "type": "object"}, "SocialError": {"properties": {"error": {"type": "string"}, "message": {"type": "string"}, "code": {"type": "string"}}, "type": "object"}, "SentimentResponse": {"properties": {"success": {"type": "boolean"}, "topic": {"type": "string"}, "sentiment": {"type": "string", "description": "bullish, bearish, or neutral"}, "score": {"type": "number", "description": "Sentiment score 0-100"}, "mentions": {"type": "integer"}, "data": {"type": "object", "description": "Full provider response"}}, "type": "object"}, "MentionsResponse": {"properties": {"success": {"type": "boolean"}, "topic": {"type": "string"}, "count": {"type": "integer"}, "posts": {"type": "array", "description": "Recent posts matching topic", "items": {"type": "object"}}}, "type": "object"}, "InfluenceScoreResponse": {"properties": {"success": {"type": "boolean"}, "username": {"type": "string"}, "score": {"type": "number", "description": "Influence score 0-100"}, "followers": {"type": "integer"}, "data": {"type": "object", "description": "Full user metrics"}}, "type": "object"}, "OnChainError": {"properties": {"error": {"type": "string"}, "message": {"type": "string"}, "code": {"type": "string"}}, "type": "object"}, "SmartMoneySentimentResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "chain": {"type": "string"}, "sentiment": {"type": "string", "description": "accumulating, distributing, or neutral"}, "smart_money_inflow_usd": {"type": "number"}, "smart_money_outflow_usd": {"type": "number"}, "net_flow_usd": {"type": "number"}, "trend_7d": {"type": "string"}, "data": {"type": "object"}}, "type": "object"}, "SmartMoneyScreenResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer"}, "chains": {"type": "array", "items": {"type": "string"}}, "timeframe": {"type": "string"}, "tokens": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "OnChainTokenHoldersResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "holder_count": {"type": "integer"}, "top_10_holders_pct": {"type": "number"}, "concentration_score": {"type": "number"}, "data": {"type": "object"}}, "type": "object"}, "WhaleTransactionsResponse": {"properties": {"success": {"type": "boolean"}, "count": {"type": "integer"}, "min_value_usd": {"type": "number"}, "transactions": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "ExchangeFlowsResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "timeframe": {"type": "string"}, "net_flow_usd": {"type": "number"}, "flows": {"type": "array", "description": "Per-exchange flow data", "items": {"type": "object"}}}, "type": "object"}, "WhaleActivityResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "hours_back": {"type": "integer"}, "summary": {"type": "object", "description": "Aggregated whale activity metrics"}}, "type": "object"}, "SmartMoneyDatedQueryBody": {"properties": {"chains": {"type": "array", "description": "Chain filter", "items": {"type": "string"}}, "date_range": {"type": "object", "description": "{from: YYYY-MM-DD, to: YYYY-MM-DD}; default trailing 7 days"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "page": {"type": "integer", "default": 1}, "per_page": {"type": "integer", "default": 100}}, "type": "object"}, "SmartMoneyHistoricalHoldingsResponse": {"properties": {"success": {"type": "boolean"}, "chains": {"type": "array", "items": {"type": "string"}}, "date_range": {"type": "object"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "count": {"type": "integer"}, "holdings": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "SmartMoneyQueryBody": {"properties": {"chains": {"type": "array", "description": "Chain filter (default: ['ethereum'])", "items": {"type": "string"}}, "filters": {"type": "object", "description": "Nansen-shape filter dict (e.g. include_smart_money_labels, value_usd: {min,max})"}, "order_by": {"type": "object", "description": "Nansen-shape order_by list (e.g. [{field, direction}])"}, "page": {"type": "integer", "default": 1}, "per_page": {"type": "integer", "default": 100}}, "type": "object"}, "SmartMoneyDexTradesResponse": {"properties": {"success": {"type": "boolean"}, "chains": {"type": "array", "items": {"type": "string"}}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "count": {"type": "integer"}, "trades": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "SmartMoneyPerpQueryBody": {"properties": {"filters": {"type": "object", "description": "action, side, token_symbol, value_usd:{min,max}, only_new_positions"}, "order_by": {"type": "object"}, "page": {"type": "integer", "default": 1}, "per_page": {"type": "integer", "default": 100}}, "type": "object"}, "SmartMoneyPerpTradesResponse": {"properties": {"success": {"type": "boolean"}, "venue": {"type": "string", "description": "Always 'hyperliquid' currently"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "count": {"type": "integer"}, "trades": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "TokenDatedQueryBody": {"properties": {"chain": {"type": "string", "description": "Blockchain (default: ethereum)"}, "date_range": {"type": "object", "description": "{from: YYYY-MM-DD, to: YYYY-MM-DD}; default trailing 7 days"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "page": {"type": "integer", "default": 1}, "per_page": {"type": "integer", "default": 100}}, "type": "object"}, "TokenDexTradesResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "chain": {"type": "string"}, "contract_address": {"type": "string"}, "date_range": {"type": "object"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "count": {"type": "integer"}, "trades": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "TokenFlowsResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "chain": {"type": "string"}, "contract_address": {"type": "string"}, "date_range": {"type": "object"}, "filters": {"type": "object"}, "order_by": {"type": "object"}, "count": {"type": "integer"}, "flows": {"type": "array", "items": {"type": "object"}}}, "type": "object"}, "OnChainSeriesBody": {"required": ["metrics", "symbol"], "properties": {"symbol": {"type": "string", "description": "Token symbol, e.g. WETH"}, "metrics": {"type": "array", "description": "SmartMoneyNetflow, SmartMoneyHoldings, ExchangeNetflow, WhaleNetInflow, HolderConcentration", "items": {"type": "string"}}, "date_range": {"type": "object", "description": "{from: YYYY-MM-DD, to: YYYY-MM-DD}; default trailing 10 days"}, "interval": {"type": "string", "description": "1h | 4h | 1d | 1w", "default": "1h"}, "chain": {"type": "string", "default": "ethereum"}, "provider": {"type": "string", "description": "'nansen' (default) or 'whalealert' (30-day fallback)"}, "top_n": {"type": "integer", "description": "Top-N holders for HolderConcentration", "default": 10}}, "type": "object"}, "OnChainSeriesResponse": {"properties": {"success": {"type": "boolean"}, "symbol": {"type": "string"}, "chain": {"type": "string"}, "interval": {"type": "string"}, "date_range": {"type": "object"}, "metrics": {"type": "array", "items": {"type": "string"}}, "count": {"type": "integer"}, "series": {"type": "array", "items": {"type": "object"}}}, "type": "object"}}, "responses": {"ParseError": {"description": "When a mask can't be parsed"}, "MaskError": {"description": "When any error occurs on mask"}}}
