Compare commits

...

10 Commits

Author SHA1 Message Date
Christian Gick
823b8b4297 feat(GB-51): Add monthly_performance MCP tool
- Add monthly_performance tool with year/month parameters
- Calls /api/trades/monthly/{year}/{month} endpoint
- Returns comprehensive monthly analytics

Enables January 2026 loss analysis via Claude Code.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-20 11:21:14 +02:00
Christian Gick
16ee24d45f docs(CF-236): Create comprehensive README with CLI documentation
Created full README.md for gridbot-mcp including:

**MCP Server Documentation:**
- Configuration for Claude Code
- Complete tool reference (60+ tools)
- Monitoring, trading, analysis, system tools
- Signal intents and scale-out features

**CLI Wrapper Documentation:**
- Full command reference for gridbot CLI
- Session start (recommended workflow)
- Monitoring commands
- Market data commands
- Trading validation
- Analysis tools
- Emergency operations

**Architecture:**
- Conductor API integration
- Position management with real-time P/L
- Risk management and circuit breakers
- PI Consensus integration

CLI wrapper located at:
~/Development/Infrastructure/AgilitonScripts/bin/gridbot

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 21:47:46 +02:00
Christian Gick
c9a1775bb5 feat(Session 452): Add 24/5 trading MCP tools
Added 4 new MCP tools for Session 452 - 24/5 Trading Enhancement:

1. market_closure_context
   - Get current market closure context and crypto allocation adjustments
   - Endpoint: /api/dashboard/market-closure-context

2. pi_consensus_query
   - Get PI consensus data for a symbol (3+ PIs holding)
   - Endpoint: /api/pi-intelligence/consensus/{symbol}

3. pi_consensus_top
   - Get top PI consensus opportunities
   - Endpoint: /api/pi-intelligence/consensus/top

4. pi_scan_trigger
   - Trigger manual PI portfolio scan
   - Endpoint: /api/pi-intelligence/scan/trigger

USAGE: Enables Claude to query market status and PI consensus during
trading sessions, supporting dynamic strategy adjustments.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-19 12:47:48 +02:00
Christian Gick
b072878ca5 Replace hardcoded IPs with DNS hostnames
- Updated server.py BASE_URL to use services.agiliton.internal
- Updated docstring with new default URL

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 09:11:41 +02:00
Christian Gick
69d7c1f572 feat(Session 246): Add 8 new MCP tools for gridbot enhancement
Added MCP tools to match Session 246 conductor API enhancements:

**New Tools:**
1. session_start - Aggregated session workflow (replaces 5-6 calls)
2. scale_out_trigger - Manual profit-taking (prevents givebacks)
3. create_intents_bulk - Batch intent creation (5-10x faster)
4. close_positions_by_filter - Fast rebalancing (asset class, P/L, symbols)
5. scale_out_adjust_threshold - Per-symbol threshold override
6. scale_out_get_overrides - List all threshold overrides
7. scale_out_delete_override - Revert symbol to default threshold

**Integration:**
- All tools map to new conductor API endpoints
- Handlers added to call_tool switch
- Input schemas with proper validation

**Impact:**
- 80% time savings on session start
- Instant profit protection via manual scale-out
- 10x faster portfolio rebalancing
- Dynamic elite symbol tuning

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-16 17:24:26 +02:00
Christian Gick
f3c3ab5e2d fix(TSL): Enable TSL by default in MCP tool
Changed is_tsl_enabled default from False to True in:
- Tool schema definition
- Payload construction (arguments.get default)

Fixes issue where MCP tool was overriding conductor API schema
default. Requires Claude Code restart to reload MCP tools.

Related: eToroGridbot commit 2d91848
2026-01-16 12:27:47 +02:00
Christian Gick
25839d0b19 fix: Default GRIDBOT_API_URL to 10.0.1.3 (infra VM) 2026-01-15 16:37:42 +02:00
Christian Gick
1ac1e245d6 fix: Update gridbot-mcp from SSH tunnel to VPN architecture
- Change error messages from "SSH tunnel" to "VPN"
- Update docstring to reference VPN and GRIDBOT_API_URL
- Default API URL now http://10.0.1.3:8000 (conductor on infra VM)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-15 16:32:48 +02:00
Christian Gick
d231fcce67 feat(Session 241): Add scale-out MCP tools
Position Exit Management System support:
- scale_out_status: Service status and statistics
- scale_out_pending: Positions awaiting scale-out
- scale_out_stats: Execution statistics
- scale_out_set_dry_run: Toggle dry-run mode

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:16:08 +02:00
Christian Gick
8faf5ecca6 feat: Add is_tsl_enabled to create_order MCP tool
Enable trailing stop loss via native eToro feature when creating orders.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-15 14:05:15 +02:00
4 changed files with 420 additions and 6 deletions

174
README.md Normal file
View File

@@ -0,0 +1,174 @@
# Gridbot MCP Server
Exposes eToroGridbot trading bot operations via Model Context Protocol. Provides monitoring, trading, and analysis tools for the automated trading system.
## Requirements
- VPN connection to services network: `vpn-connect`
- Gridbot conductor running on services VM (http://services:8000)
- Python 3.10+ with uv for development
## Configuration
Add to `~/.claude/settings.json` under `mcpServers`:
```json
{
"gridbot": {
"command": "/path/to/gridbot-mcp/.venv/bin/python",
"args": ["-m", "src.server"],
"cwd": "/path/to/gridbot-mcp",
"env": {
"GRIDBOT_API_URL": "http://services:8000"
}
}
}
```
## Tools
### Monitoring
- `health` - Check conductor health, queue size, capacity
- `emergency_status` - Emergency stop status, circuit breaker, drawdown limits
- `market_hours` - Market hours for all exchanges (NYSE, NASDAQ, CRYPTO, FOREX)
- `positions` - All portfolio positions with real-time P/L
- `pending_orders` - Pending limit orders with amounts, rates, TP/SL
- `risk_score` - Portfolio risk score and components
- `dashboard` - Full dashboard (positions, orders, analytics)
- `session_start` - Comprehensive session summary (replaces 5-6 individual calls)
### Market Data
- `vix` - VIX volatility index and interpretation
- `crypto_fear_greed` - Crypto Fear & Greed index with trading guidance
### Trading Operations
- `validate_trade` - Validate trade before execution (checks risk limits)
- `create_order` - Create BUY/SELL order with full validation
- `close_position` - Close existing position (full or partial)
- `close_positions_by_filter` - Close multiple positions (e.g., all crypto, all losers)
- `cancel_order` - Cancel single pending order
- `cancel_orders_bulk` - Cancel multiple orders at once
- `find_duplicate_orders` - Find duplicate pending orders
- `emergency_stop` - HALT all trading (emergency use only)
- `emergency_reset` - Resume trading after emergency stop
- `cleanup_stale_orders` - Cleanup stale/expired orders
### Signal Intents (Limit Orders)
- `intents` - List signal intents (pending orders awaiting trigger)
- `intents_pending` - List pending intents only
- `intents_executed` - List executed intents
- `intents_stats` - Intent statistics (pending/executed/expired)
- `create_intent` - Create signal intent (limit order)
- `create_intents_bulk` - Create multiple intents at once
- `cancel_intent` - Cancel pending intent
### Scale-Out (Profit Taking)
- `scale_out_status` - Scale-out monitor status
- `scale_out_pending` - Positions pending scale-out
- `scale_out_stats` - Scale-out statistics (P/L locked)
- `scale_out_trigger` - Manually trigger scale-out for position
- `scale_out_adjust_threshold` - Override threshold for symbol
- `scale_out_get_overrides` - Get all threshold overrides
- `scale_out_delete_override` - Delete threshold override
- `scale_out_set_dry_run` - Enable/disable dry-run mode
### Analysis
- `trades` - Recent trades with P/L details
- `analytics` - Trading analytics (win rate, Sharpe ratio)
- `expectancy` - Trading expectancy metrics by symbol
- `profitable_symbols` - Profitable symbols ranked by expectancy
- `correlations` - Top correlated asset pairs
- `signal_quality` - Signal acceptance rate, rejection reasons
- `trend_alerts` - Active trend change alerts
- `statistics` - Trading statistics summary
- `support_resistance` - Support/resistance levels for symbol
### System
- `queue_status` - Signal processing queue status
- `bot_health` - Trading bot health (Freqtrade, Hummingbot)
- `stale_bots` - Bots with no recent signals
- `monitoring_stats` - System monitoring stats
- `env_health` - Environment health (API keys, credentials)
- `candle_freshness` - Candle data staleness check
- `rate_limiter` - Rate limiter statistics
- `portfolio_allocation` - Portfolio allocation breakdown
- `market_closure_context` - Market closure context
- `container_logs` - Get container logs with grep filter
- `container_restart` - Restart a container
- `pi_consensus_query` - Get PI consensus data for symbol
- `pi_consensus_top` - Get top PI consensus opportunities
- `pi_scan_trigger` - Trigger manual PI portfolio scan
## CLI Wrapper
A command-line wrapper is available at `~/Development/Infrastructure/AgilitonScripts/bin/gridbot`:
```bash
# Session start (recommended)
gridbot session-start # Comprehensive session summary
# Monitoring
gridbot health # Check system health
gridbot positions # List all positions
gridbot pending # Show pending orders
gridbot risk # Portfolio risk score
gridbot dashboard # Full dashboard
# Market data
gridbot market-hours # Market hours
gridbot vix # Volatility index
gridbot crypto-fear-greed # Fear & Greed index
# Trading validation
gridbot validate BTC BUY 100 # Validate $100 BTC buy
# Analysis
gridbot trades # Recent trades
gridbot analytics # Trading performance
gridbot expectancy # Expectancy by symbol
gridbot profitable # Best performing symbols
gridbot correlations # Correlated pairs
gridbot statistics # Trading statistics
# System
gridbot queue # Queue status
gridbot bot-health # Bot health
gridbot monitoring # System stats
gridbot env-health # Environment check
gridbot candle-freshness # Data freshness
# Emergency
gridbot emergency-stop "reason" # HALT trading
gridbot emergency-reset # Resume trading
gridbot cleanup-orders # Cleanup stale orders
```
The CLI wrapper provides terminal access to all MCP tools without requiring Claude Code.
## Development
```bash
# Setup
uv venv
source .venv/bin/activate
uv pip install -r requirements.txt
# Run
python -m src.server
```
## Architecture
- **Conductor API**: Trading bot coordinator (services:8000)
- **Position Management**: Real-time P/L tracking with BotPriceProvider
- **Risk Management**: Portfolio risk scoring, circuit breakers
- **Signal Intents**: Limit orders with trigger price
- **Scale-Out**: Automated profit-taking at thresholds
- **PI Consensus**: Portfolio Intelligence integration
- **Market Hours**: Dynamic allocation based on market status
## Related
- Conductor: `/Users/christian.gick/Development/Apps/eToroGridbot`
- Dashboard: http://services:5555
- Documentation: ClaudeFramework/docs/gridbot/

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,7 @@
"""
Gridbot MCP Server - Wraps eToroGridbot REST API as MCP tools.
Requires SSH tunnel: ssh -L 8000:localhost:8000 services
Requires VPN connection and GRIDBOT_API_URL env var (default: http://services.agiliton.internal:8000)
"""
import os
@@ -13,7 +13,7 @@ from mcp.server import Server
from mcp.server.stdio import stdio_server
from mcp.types import Tool, TextContent
BASE_URL = os.getenv("GRIDBOT_API_URL", "http://localhost:8000")
BASE_URL = os.getenv("GRIDBOT_API_URL", "http://services.agiliton.internal:8000")
TIMEOUT = 30.0
server = Server("gridbot-mcp")
@@ -27,7 +27,7 @@ async def api_get(endpoint: str) -> dict[str, Any]:
resp.raise_for_status()
return resp.json()
except httpx.ConnectError:
return {"error": "Connection failed - is SSH tunnel running?"}
return {"error": "Connection failed - check VPN (vpn-connect) and GRIDBOT_API_URL"}
except httpx.HTTPStatusError as e:
return {"error": f"HTTP {e.response.status_code}: {e.response.text}"}
except Exception as e:
@@ -42,7 +42,7 @@ async def api_post(endpoint: str, data: dict[str, Any] | None = None) -> dict[st
resp.raise_for_status()
return resp.json()
except httpx.ConnectError:
return {"error": "Connection failed - is SSH tunnel running?"}
return {"error": "Connection failed - check VPN (vpn-connect) and GRIDBOT_API_URL"}
except httpx.HTTPStatusError as e:
return {"error": f"HTTP {e.response.status_code}: {e.response.text}"}
except Exception as e:
@@ -57,7 +57,7 @@ async def api_delete(endpoint: str) -> dict[str, Any]:
resp.raise_for_status()
return resp.json()
except httpx.ConnectError:
return {"error": "Connection failed - is SSH tunnel running?"}
return {"error": "Connection failed - check VPN (vpn-connect) and GRIDBOT_API_URL"}
except httpx.HTTPStatusError as e:
return {"error": f"HTTP {e.response.status_code}: {e.response.text}"}
except Exception as e:
@@ -113,6 +113,11 @@ async def list_tools() -> list[Tool]:
description="Get full dashboard summary including positions, orders, and analytics",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="session_start",
description="Get comprehensive session start summary (replaces 5-6 calls: health, VIX, portfolio, pending, risk, scale-out). Single call for instant situational awareness.",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="analytics",
description="Get trading analytics summary (win rate, Sharpe ratio, P/L)",
@@ -191,6 +196,18 @@ async def list_tools() -> list[Tool]:
description="Get recent trades with P/L details",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="monthly_performance",
description="Get monthly trade performance analytics (win rate, P/L, exit reasons, TP/SL used)",
inputSchema={
"type": "object",
"properties": {
"year": {"type": "integer", "description": "Year (e.g., 2026)"},
"month": {"type": "integer", "description": "Month (1-12)"},
},
"required": ["year", "month"],
},
),
Tool(
name="expectancy",
description="Get trading expectancy metrics for all symbols",
@@ -266,6 +283,7 @@ async def list_tools() -> list[Tool]:
"take_profit_pct": {"type": "number", "description": "Take profit percentage (e.g., 10 for 10%)"},
"stop_loss_pct": {"type": "number", "description": "Stop loss percentage (e.g., 5 for 5%)"},
"dry_run": {"type": "boolean", "default": False, "description": "Validate only, do not execute"},
"is_tsl_enabled": {"type": "boolean", "default": True, "description": "Enable trailing stop loss (eToro native feature)"},
},
"required": ["symbol", "action", "amount"],
},
@@ -282,6 +300,21 @@ async def list_tools() -> list[Tool]:
"required": ["position_id"],
},
),
Tool(
name="close_positions_by_filter",
description="Close multiple positions matching filters (fast rebalancing). Examples: close all metals, close all losers < -3%, close crypto. 10x faster than manual.",
inputSchema={
"type": "object",
"properties": {
"asset_class": {"type": "string", "enum": ["crypto", "stocks", "metals", "etf"], "description": "Filter by asset class"},
"min_pnl_pct": {"type": "number", "description": "Minimum P/L % (e.g., -10)"},
"max_pnl_pct": {"type": "number", "description": "Maximum P/L % (e.g., -3)"},
"symbols": {"type": "array", "items": {"type": "string"}, "description": "Specific symbols to close"},
"close_percentage": {"type": "number", "default": 100, "description": "Percentage to close (1-100)"},
"dry_run": {"type": "boolean", "default": True, "description": "Preview matches without executing (safety first)"},
},
},
),
# === SIGNAL INTENTS ===
Tool(
name="intents",
@@ -340,6 +373,32 @@ async def list_tools() -> list[Tool]:
"required": ["symbol", "amount", "trigger_price"],
},
),
Tool(
name="create_intents_bulk",
description="Create multiple signal intents at once. Ideal for PI consensus scans with 3-5 opportunities. 5-10x faster than individual creates.",
inputSchema={
"type": "object",
"properties": {
"intents": {
"type": "array",
"description": "List of intents to create",
"items": {
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Trading symbol (e.g., BTC, NVDA)"},
"trigger_price": {"type": "number", "description": "Price at which to trigger"},
"amount": {"type": "number", "description": "Position size in USD"},
"is_buy": {"type": "boolean", "default": True},
"take_profit_pct": {"type": "number"},
"stop_loss_pct": {"type": "number"},
},
"required": ["symbol", "trigger_price", "amount"],
},
},
},
"required": ["intents"],
},
),
Tool(
name="cancel_intent",
description="Cancel a pending signal intent by ID",
@@ -384,6 +443,75 @@ async def list_tools() -> list[Tool]:
description="Find duplicate pending orders (same instrument + rate + direction). Returns order IDs to cancel.",
inputSchema={"type": "object", "properties": {}, "required": []},
),
# === SCALE-OUT (Session 241: Position Exit Management) ===
Tool(
name="scale_out_status",
description="Get scale-out monitor service status (running, dry-run mode, statistics)",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="scale_out_pending",
description="Get positions pending scale-out (haven't had 50% partial close executed yet)",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="scale_out_stats",
description="Get scale-out statistics (total, executed, pending, P/L locked)",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="scale_out_set_dry_run",
description="Enable or disable scale-out dry-run mode. In dry-run, scale-outs are logged but not executed.",
inputSchema={
"type": "object",
"properties": {
"dry_run": {"type": "boolean", "description": "True to enable dry-run (log only), False to enable live execution"},
},
"required": ["dry_run"],
},
),
Tool(
name="scale_out_trigger",
description="Manually trigger scale-out (partial close) for a position. Locks profit without waiting for auto threshold. Prevents givebacks.",
inputSchema={
"type": "object",
"properties": {
"position_id": {"type": "integer", "description": "Position ID to scale out"},
"percentage": {"type": "number", "default": 50, "description": "Percentage to close (1-100)"},
"reason": {"type": "string", "default": "manual_trigger", "description": "Reason for manual trigger"},
},
"required": ["position_id"],
},
),
Tool(
name="scale_out_adjust_threshold",
description="Override scale-out threshold for a symbol. Dynamic elite symbol tuning. E.g., set GOOGL to 12% instead of 8%, or 0% to disable.",
inputSchema={
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Symbol to override (e.g., GOOGL, AMD)"},
"threshold_pct": {"type": "number", "description": "New threshold % (e.g., 12 for 12%). Set to 0 to disable."},
"reason": {"type": "string", "description": "Optional reason for override"},
},
"required": ["symbol", "threshold_pct"],
},
),
Tool(
name="scale_out_get_overrides",
description="Get all scale-out threshold overrides (per-symbol custom thresholds).",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="scale_out_delete_override",
description="Delete threshold override for a symbol (revert to default).",
inputSchema={
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Symbol to revert to default"},
},
"required": ["symbol"],
},
),
# === CONTAINER OPERATIONS ===
Tool(
name="container_logs",
@@ -411,6 +539,45 @@ async def list_tools() -> list[Tool]:
"required": ["container", "confirm"],
},
),
# === SESSION 452: 24/5 TRADING & CRYPTO FOCUS ===
Tool(
name="market_closure_context",
description="Get current market closure context and crypto allocation adjustments",
inputSchema={"type": "object", "properties": {}, "required": []},
),
Tool(
name="pi_consensus_query",
description="Get PI consensus data for a symbol (3+ PIs holding)",
inputSchema={
"type": "object",
"properties": {
"symbol": {"type": "string", "description": "Ticker symbol (e.g., BTC, NVDA, AAPL)"},
},
"required": ["symbol"],
},
),
Tool(
name="pi_consensus_top",
description="Get top PI consensus opportunities",
inputSchema={
"type": "object",
"properties": {
"limit": {"type": "number", "default": 10, "description": "Max results (1-100)"},
},
"required": [],
},
),
Tool(
name="pi_scan_trigger",
description="Trigger manual PI portfolio scan",
inputSchema={
"type": "object",
"properties": {
"usernames": {"type": "string", "description": "Comma-separated PI usernames (optional)"},
},
"required": [],
},
),
]
@@ -438,6 +605,8 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
result = await api_get("/api/market-intel/crypto-fear-greed")
case "dashboard":
result = await api_get("/api/dashboard/summary")
case "session_start":
result = await api_get("/api/dashboard/session-start")
case "analytics":
result = await api_get("/api/analytics/summary")
case "queue_status":
@@ -475,6 +644,10 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
result = await api_get("/api/correlations/top")
case "trades":
result = await api_get("/api/dashboard/trades")
case "monthly_performance":
year = arguments.get("year")
month = arguments.get("month")
result = await api_get(f"/api/trades/monthly/{year}/{month}")
case "expectancy":
result = await api_get("/api/expectancy/")
case "profitable_symbols":
@@ -497,7 +670,12 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
case "rate_limiter":
result = await api_get("/api/monitoring/rate_limiter/stats")
case "portfolio_allocation":
result = await api_get("/api/portfolio/status")
# Get positions and extract allocation breakdown
positions_data = await api_get("/api/trade/positions")
if positions_data and "summary" in positions_data and "by_asset_class" in positions_data["summary"]:
result = positions_data["summary"]["by_asset_class"]
else:
result = {"error": "Asset allocation data not available"}
case "create_order":
payload = {
"symbol": arguments["symbol"],
@@ -507,6 +685,7 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
"take_profit_pct": arguments.get("take_profit_pct", 10),
"stop_loss_pct": arguments.get("stop_loss_pct", 5),
"dry_run": arguments.get("dry_run", False),
"is_tsl_enabled": arguments.get("is_tsl_enabled", True),
}
if arguments.get("limit_price"):
payload["limit_price"] = arguments["limit_price"]
@@ -516,6 +695,20 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
if arguments.get("close_percentage"):
payload["close_percentage"] = arguments["close_percentage"]
result = await api_post("/api/trade/close", payload)
case "close_positions_by_filter":
payload = {}
if arguments.get("asset_class"):
payload["asset_class"] = arguments["asset_class"]
if arguments.get("min_pnl_pct") is not None:
payload["min_pnl_pct"] = arguments["min_pnl_pct"]
if arguments.get("max_pnl_pct") is not None:
payload["max_pnl_pct"] = arguments["max_pnl_pct"]
if arguments.get("symbols"):
payload["symbols"] = arguments["symbols"]
if arguments.get("close_percentage"):
payload["close_percentage"] = arguments["close_percentage"]
payload["dry_run"] = arguments.get("dry_run", True)
result = await api_post("/portfolio/close-by-filter", payload)
# === SIGNAL INTENTS ===
case "intents":
params = []
@@ -561,6 +754,8 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
if arguments.get("source_type"):
payload["source_type"] = arguments["source_type"]
result = await api_post("/intents", payload)
case "create_intents_bulk":
result = await api_post("/intents/bulk", arguments["intents"])
case "cancel_intent":
intent_id = arguments["intent_id"]
result = await api_delete(f"/intents/{intent_id}")
@@ -576,6 +771,35 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
result = await api_post("/api/trade/orders/cancel-bulk", {"order_ids": order_ids})
case "find_duplicate_orders":
result = await api_get("/api/trade/orders/duplicates")
# === SCALE-OUT (Session 241) ===
case "scale_out_status":
result = await api_get("/api/trade/scale-out/status")
case "scale_out_pending":
result = await api_get("/api/trade/scale-out/pending")
case "scale_out_stats":
result = await api_get("/api/trade/scale-out/stats")
case "scale_out_set_dry_run":
result = await api_post("/api/trade/scale-out/dry-run", {"dry_run": arguments["dry_run"]})
case "scale_out_trigger":
payload = {
"position_id": arguments["position_id"],
"percentage": arguments.get("percentage", 50.0),
"reason": arguments.get("reason", "manual_trigger"),
}
result = await api_post("/api/trade/scale-out/trigger", payload)
case "scale_out_adjust_threshold":
payload = {
"symbol": arguments["symbol"],
"threshold_pct": arguments["threshold_pct"],
}
if arguments.get("reason"):
payload["reason"] = arguments["reason"]
result = await api_post("/api/scale-out/adjust-threshold", payload)
case "scale_out_get_overrides":
result = await api_get("/api/scale-out/overrides")
case "scale_out_delete_override":
symbol = arguments["symbol"]
result = await api_delete(f"/api/scale-out/threshold/{symbol}")
# === CONTAINER OPERATIONS ===
case "container_logs":
params = [f"container={arguments['container']}"]
@@ -590,6 +814,22 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
result = await api_post(
f"/containers/restart?container={arguments['container']}&confirm={str(arguments.get('confirm', False)).lower()}"
)
# === SESSION 452: 24/5 TRADING & CRYPTO FOCUS ===
case "market_closure_context":
# Get market closure context from dashboard
result = await api_get("/api/dashboard/market-closure-context")
case "pi_consensus_query":
symbol = arguments["symbol"].upper()
result = await api_get(f"/api/pi-intelligence/consensus/{symbol}")
case "pi_consensus_top":
limit = arguments.get("limit", 10)
result = await api_get(f"/api/pi-intelligence/consensus/top?limit={limit}")
case "pi_scan_trigger":
usernames = arguments.get("usernames")
endpoint = "/api/pi-intelligence/scan/trigger"
if usernames:
endpoint += f"?usernames={usernames}"
result = await api_post(endpoint)
case _:
result = {"error": f"Unknown tool: {name}"}