# TLI API Documentation **Foxhunt Trading System - gRPC API Reference** Version: 1.0 Last Updated: 2025-01-23 Document Classification: Technical Reference --- ## Table of Contents 1. [API Overview](#api-overview) 2. [Authentication](#authentication) 3. [Trading Service API](#trading-service-api) 4. [Backtesting Service API](#backtesting-service-api) 5. [Error Codes Reference](#error-codes-reference) 6. [Rate Limiting](#rate-limiting) 7. [Real-time Streaming](#real-time-streaming) 8. [Code Examples](#code-examples) --- ## API Overview The TLI system provides two main gRPC services: - **TradingService**: Unified service for trading, risk management, monitoring, and configuration - **BacktestingService**: Strategy testing and performance analysis ### Base Endpoints | Service | Default Endpoint | Protocol | |---------|------------------|----------| | TradingService | `localhost:50051` | gRPC over TLS | | BacktestingService | `localhost:50052` | gRPC over TLS | ### Protocol Buffer Definition All services are defined in `/tli/proto/trading.proto` with the package name `foxhunt.tli`. --- ## Authentication ### Authentication Methods 1. **Session Tokens**: Username/password authentication with JWT-like tokens 2. **API Keys**: Long-lived keys for programmatic access 3. **mTLS**: Mutual TLS for service-to-service communication ### Headers All authenticated requests must include one of: ``` Authorization: Bearer X-API-Key: ``` ### Authentication Flow ```mermaid sequenceDiagram participant C as Client participant T as TradingService participant A as AuthService C->>A: authenticate(username, password) A->>C: session_token + expires_at C->>T: request with Bearer token T->>A: validate_session(token) A->>T: user_id + permissions T->>C: response or error ``` --- ## Trading Service API ### Order Management #### Submit Order **Method:** `SubmitOrder` **Request:** ```protobuf message SubmitOrderRequest { string symbol = 1; // Trading symbol (e.g., "AAPL") OrderSide side = 2; // BUY or SELL OrderType order_type = 3; // MARKET, LIMIT, STOP, STOP_LIMIT double quantity = 4; // Order quantity optional double price = 5; // Price (required for LIMIT orders) optional double stop_price = 6; // Stop price (for STOP orders) string time_in_force = 7; // "DAY", "GTC", "IOC", "FOK" string client_order_id = 8; // Client-provided order ID } ``` **Response:** ```protobuf message SubmitOrderResponse { bool success = 1; // True if order accepted string order_id = 2; // System-assigned order ID string message = 3; // Success/error message int64 timestamp_unix_nanos = 4; // Execution timestamp } ``` **Example:** ```bash grpcurl -plaintext \ -H "Authorization: Bearer " \ -d '{ "symbol": "AAPL", "side": "ORDER_SIDE_BUY", "order_type": "ORDER_TYPE_MARKET", "quantity": 100, "time_in_force": "DAY", "client_order_id": "client_001" }' \ localhost:50051 foxhunt.tli.TradingService/SubmitOrder ``` #### Cancel Order **Method:** `CancelOrder` **Request:** ```protobuf message CancelOrderRequest { string order_id = 1; // System order ID string symbol = 2; // Trading symbol } ``` **Response:** ```protobuf message CancelOrderResponse { bool success = 1; // True if cancel successful string message = 2; // Success/error message int64 timestamp_unix_nanos = 3; // Cancellation timestamp } ``` #### Get Order Status **Method:** `GetOrderStatus` **Request:** ```protobuf message GetOrderStatusRequest { string order_id = 1; // System order ID } ``` **Response:** ```protobuf message GetOrderStatusResponse { string order_id = 1; string symbol = 2; OrderSide side = 3; OrderType order_type = 4; double quantity = 5; double filled_quantity = 6; // Amount filled double remaining_quantity = 7; // Amount remaining double average_price = 8; // Average fill price OrderStatus status = 9; // NEW, PARTIALLY_FILLED, FILLED, etc. int64 created_at_unix_nanos = 10; int64 updated_at_unix_nanos = 11; } ``` ### Account and Portfolio Management #### Get Account Information **Method:** `GetAccountInfo` **Request:** ```protobuf message GetAccountInfoRequest { string account_id = 1; // Account identifier } ``` **Response:** ```protobuf message GetAccountInfoResponse { string account_id = 1; double total_value = 2; // Total account value double cash_balance = 3; // Available cash double buying_power = 4; // Available buying power double maintenance_margin = 5; // Required maintenance margin double day_trading_buying_power = 6; // Day trading buying power } ``` #### Get Positions **Method:** `GetPositions` **Request:** ```protobuf message GetPositionsRequest { optional string symbol = 1; // Filter by symbol (optional) } ``` **Response:** ```protobuf message GetPositionsResponse { repeated Position positions = 1; } message Position { string symbol = 1; double quantity = 2; // Position size (+ long, - short) double market_price = 3; // Current market price double market_value = 4; // Current market value double average_cost = 5; // Average cost basis double unrealized_pnl = 6; // Unrealized P&L double realized_pnl = 7; // Realized P&L } ``` ### Risk Management #### Get VaR (Value at Risk) **Method:** `GetVaR` **Request:** ```protobuf message GetVaRRequest { repeated string symbols = 1; // Symbols for calculation double confidence_level = 2; // e.g., 0.95, 0.99 uint32 lookback_days = 3; // Historical data period VaRMethodology methodology = 4; // HISTORICAL, MONTE_CARLO, etc. } ``` **Response:** ```protobuf message GetVaRResponse { double portfolio_var = 1; // Portfolio VaR amount repeated SymbolVaR symbol_vars = 2; // Per-symbol VaR breakdown int64 timestamp_unix_nanos = 3; string methodology_used = 4; } ``` #### Validate Order **Method:** `ValidateOrder` **Request:** ```protobuf message ValidateOrderRequest { string symbol = 1; OrderSide side = 2; double quantity = 3; double price = 4; string account_id = 5; } ``` **Response:** ```protobuf message ValidateOrderResponse { bool approved = 1; // True if order passes validation string reason = 2; // Approval/rejection reason repeated RiskViolation violations = 3; // Risk violations found double projected_exposure = 4; // Projected portfolio exposure double margin_impact = 5; // Margin requirement impact } ``` #### Emergency Stop **Method:** `EmergencyStop` **Request:** ```protobuf message EmergencyStopRequest { EmergencyStopType stop_type = 1; // CANCEL_ORDERS, CLOSE_POSITIONS, FULL_SHUTDOWN string reason = 2; // Reason for emergency stop repeated string symbols = 3; // Symbols to affect (empty = all) bool confirm = 4; // Must be true for execution } ``` **Response:** ```protobuf message EmergencyStopResponse { bool success = 1; string message = 2; uint32 orders_cancelled = 3; // Number of orders cancelled uint32 positions_closed = 4; // Number of positions closed int64 timestamp_unix_nanos = 5; } ``` ### Market Data #### Subscribe to Market Data **Method:** `SubscribeMarketData` (Streaming) **Request:** ```protobuf message SubscribeMarketDataRequest { repeated string symbols = 1; // Symbols to subscribe to repeated MarketDataType data_types = 2; // TICKS, QUOTES, TRADES, BARS } ``` **Response Stream:** ```protobuf message MarketDataEvent { oneof event { TickData tick = 1; QuoteData quote = 2; TradeData trade = 3; BarData bar = 4; } } ``` ### Monitoring #### Get Metrics **Method:** `GetMetrics` **Request:** ```protobuf message GetMetricsRequest { repeated string metric_names = 1; // Specific metrics to retrieve optional int64 start_time_unix_nanos = 2; optional int64 end_time_unix_nanos = 3; } ``` **Response:** ```protobuf message GetMetricsResponse { repeated Metric metrics = 1; int64 timestamp_unix_nanos = 2; } message Metric { string name = 1; // Metric name double value = 2; // Metric value string unit = 3; // Unit (ms, req/s, etc.) map labels = 4; // Additional labels int64 timestamp_unix_nanos = 5; } ``` #### Get Latency Statistics **Method:** `GetLatency` **Request:** ```protobuf message GetLatencyRequest { optional string service_name = 1; // Service to query optional string operation = 2; // Specific operation optional int64 start_time_unix_nanos = 3; optional int64 end_time_unix_nanos = 4; } ``` **Response:** ```protobuf message GetLatencyResponse { double p50_micros = 1; // 50th percentile latency double p95_micros = 2; // 95th percentile latency double p99_micros = 3; // 99th percentile latency double p999_micros = 4; // 99.9th percentile latency double avg_micros = 5; // Average latency double max_micros = 6; // Maximum latency double min_micros = 7; // Minimum latency uint64 sample_count = 8; // Number of samples } ``` ### Configuration #### Update Parameters **Method:** `UpdateParameters` **Request:** ```protobuf message UpdateParametersRequest { map parameters = 1; // Key-value parameter updates bool persist = 2; // Whether to persist changes } ``` **Response:** ```protobuf message UpdateParametersResponse { bool success = 1; string message = 2; repeated string updated_keys = 3; // Successfully updated keys } ``` #### Get Configuration **Method:** `GetConfig` **Request:** ```protobuf message GetConfigRequest { repeated string keys = 1; // Specific keys (empty = all) } ``` **Response:** ```protobuf message GetConfigResponse { map config = 1; // Configuration key-value pairs int64 version = 2; // Configuration version int64 last_updated_unix_nanos = 3; } ``` --- ## Backtesting Service API ### Backtest Management #### Start Backtest **Method:** `StartBacktest` **Request:** ```protobuf message StartBacktestRequest { string strategy_name = 1; // Strategy identifier repeated string symbols = 2; // Symbols to test int64 start_date_unix_nanos = 3; // Backtest start date int64 end_date_unix_nanos = 4; // Backtest end date double initial_capital = 5; // Starting capital map parameters = 6; // Strategy parameters bool save_results = 7; // Whether to persist results string description = 8; // Backtest description } ``` **Response:** ```protobuf message StartBacktestResponse { bool success = 1; string backtest_id = 2; // Unique backtest identifier string message = 3; int64 estimated_duration_seconds = 4; // Estimated completion time } ``` #### Get Backtest Status **Method:** `GetBacktestStatus` **Request:** ```protobuf message GetBacktestStatusRequest { string backtest_id = 1; } ``` **Response:** ```protobuf message GetBacktestStatusResponse { string backtest_id = 1; BacktestStatus status = 2; // QUEUED, RUNNING, COMPLETED, etc. double progress_percent = 3; // Completion percentage string current_date = 4; // Current simulation date uint64 trades_executed = 5; // Number of trades executed double current_pnl = 6; // Current P&L int64 started_at_unix_nanos = 7; optional int64 completed_at_unix_nanos = 8; optional string error_message = 9; } ``` #### Get Backtest Results **Method:** `GetBacktestResults` **Request:** ```protobuf message GetBacktestResultsRequest { string backtest_id = 1; bool include_trades = 2; // Include individual trades bool include_metrics = 3; // Include performance metrics } ``` **Response:** ```protobuf message GetBacktestResultsResponse { string backtest_id = 1; BacktestMetrics metrics = 2; // Performance metrics repeated Trade trades = 3; // Individual trades repeated EquityCurvePoint equity_curve = 4; // Equity curve data repeated DrawdownPeriod drawdown_periods = 5; // Drawdown analysis } ``` ### Backtest Results Analysis #### Performance Metrics ```protobuf message BacktestMetrics { double total_return = 1; // Total return percentage double annualized_return = 2; // Annualized return percentage double sharpe_ratio = 3; // Risk-adjusted return double sortino_ratio = 4; // Downside risk-adjusted return double max_drawdown = 5; // Maximum drawdown percentage double volatility = 6; // Return volatility double win_rate = 7; // Percentage of winning trades double profit_factor = 8; // Gross profit / gross loss uint64 total_trades = 9; // Total number of trades uint64 winning_trades = 10; // Number of winning trades uint64 losing_trades = 11; // Number of losing trades double avg_win = 12; // Average winning trade double avg_loss = 13; // Average losing trade double largest_win = 14; // Largest winning trade double largest_loss = 15; // Largest losing trade double calmar_ratio = 16; // Annual return / max drawdown int64 backtest_duration_nanos = 17; // Execution time } ``` --- ## Error Codes Reference ### gRPC Status Codes | Code | Status | Description | Retry | |------|--------|-------------|-------| | 0 | OK | Success | No | | 1 | CANCELLED | Request cancelled | Yes | | 2 | UNKNOWN | Unknown error | Yes | | 3 | INVALID_ARGUMENT | Invalid request parameters | No | | 4 | DEADLINE_EXCEEDED | Request timeout | Yes | | 5 | NOT_FOUND | Resource not found | No | | 6 | ALREADY_EXISTS | Resource already exists | No | | 7 | PERMISSION_DENIED | Insufficient permissions | No | | 8 | RESOURCE_EXHAUSTED | Rate limit exceeded | Yes | | 9 | FAILED_PRECONDITION | System state error | Depends | | 10 | ABORTED | Transaction conflict | Yes | | 11 | OUT_OF_RANGE | Value out of range | No | | 12 | UNIMPLEMENTED | Method not implemented | No | | 13 | INTERNAL | Internal server error | Yes | | 14 | UNAVAILABLE | Service unavailable | Yes | | 15 | DATA_LOSS | Data corruption | No | | 16 | UNAUTHENTICATED | Authentication required | No | ### Custom Error Details #### Trading Errors ```json { "error_code": "INSUFFICIENT_BUYING_POWER", "message": "Insufficient buying power for order", "details": { "required": 50000.00, "available": 45000.00, "symbol": "AAPL" } } ``` #### Risk Management Errors ```json { "error_code": "POSITION_LIMIT_EXCEEDED", "message": "Order would exceed position limit", "details": { "current_position": 10000, "order_quantity": 5000, "position_limit": 12000, "symbol": "GOOGL" } } ``` #### Authentication Errors ```json { "error_code": "SESSION_EXPIRED", "message": "Session token has expired", "details": { "expired_at": "2025-01-23T15:30:00Z", "current_time": "2025-01-23T16:00:00Z" } } ``` --- ## Rate Limiting ### Rate Limit Tiers | Authentication Type | Requests/Minute | Burst Allowance | Window | |-------------------|-----------------|-----------------|---------| | Unauthenticated | 100 | 10 | 60s | | Session Token | 1,000 | 50 | 60s | | API Key | 5,000 | 100 | 60s | | Trading Operations | Special | 100 | 10s | ### Rate Limit Headers Responses include rate limiting information: ``` X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 856 X-RateLimit-Reset: 1643875200 X-RateLimit-Window: 60 ``` ### Rate Limit Exceeded Response ```json { "error": { "code": "RESOURCE_EXHAUSTED", "message": "Rate limit exceeded", "details": { "limit": 1000, "window_seconds": 60, "retry_after_seconds": 23 } } } ``` --- ## Real-time Streaming ### Market Data Streaming ```rust use tli::prelude::*; #[tokio::main] async fn main() -> Result<(), Box> { let client = TradingClient::connect("http://localhost:50051").await?; let request = SubscribeMarketDataRequest { symbols: vec!["AAPL".to_string(), "GOOGL".to_string()], data_types: vec![MarketDataType::Ticks as i32, MarketDataType::Quotes as i32], }; let mut stream = client.subscribe_market_data(request).await?; while let Some(event) = stream.message().await? { match event.event { Some(market_data_event::Event::Tick(tick)) => { println!("Tick: {} @ {} size {}", tick.symbol, tick.price, tick.size); }, Some(market_data_event::Event::Quote(quote)) => { println!("Quote: {} bid {} @ {} ask {} @ {}", quote.symbol, quote.bid_price, quote.bid_size, quote.ask_price, quote.ask_size); }, _ => {} } } Ok(()) } ``` ### Order Updates Streaming ```rust let request = SubscribeOrderUpdatesRequest { account_id: Some("account_123".to_string()), }; let mut stream = client.subscribe_order_updates(request).await?; while let Some(update) = stream.message().await? { println!("Order {} status: {:?} filled: {}", update.order_id, update.status, update.filled_quantity); } ``` ### Risk Alerts Streaming ```rust let request = SubscribeRiskAlertsRequest { min_severity: vec![RiskSeverity::Warning as i32], symbols: vec![], // All symbols }; let mut stream = client.subscribe_risk_alerts(request).await?; while let Some(alert) = stream.message().await? { println!("Risk Alert: {} - {} (severity: {:?})", alert.symbol, alert.message, alert.severity); } ``` --- ## Code Examples ### Basic Trading Client ```rust use tli::prelude::*; #[tokio::main] async fn main() -> Result<(), Box> { // Create client with authentication let client_suite = TliClientBuilder::new() .with_service_endpoint("trading_service".to_string(), "https://localhost:50051".to_string()) .with_trading_config(TradingClientConfig::default()) .build() .await?; let trading_client = client_suite.trading_client .ok_or("Trading client not configured")?; // Submit a market order let order_request = SubmitOrderRequest { symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Market as i32, quantity: 100.0, time_in_force: "DAY".to_string(), client_order_id: "order_001".to_string(), ..Default::default() }; let response = trading_client.submit_order(order_request).await?; if response.success { println!("Order submitted successfully: {}", response.order_id); } else { println!("Order failed: {}", response.message); } Ok(()) } ``` ### Risk Management Integration ```rust // Validate order before submission let validation_request = ValidateOrderRequest { symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, quantity: 1000.0, price: 150.0, account_id: "account_123".to_string(), }; let validation = trading_client.validate_order(validation_request).await?; if validation.approved { // Submit the order let order_request = SubmitOrderRequest { symbol: "AAPL".to_string(), side: OrderSide::Buy as i32, order_type: OrderType::Limit as i32, quantity: 1000.0, price: Some(150.0), time_in_force: "DAY".to_string(), client_order_id: uuid::Uuid::new_v4().to_string(), ..Default::default() }; let response = trading_client.submit_order(order_request).await?; println!("Order submitted: {}", response.order_id); } else { println!("Order rejected: {}", validation.reason); for violation in validation.violations { println!("Violation: {:?} - {}", violation.r#type, violation.description); } } ``` ### Backtesting Example ```rust let backtest_client = client_suite.backtesting_client .ok_or("Backtesting client not configured")?; // Start a backtest let backtest_request = StartBacktestRequest { strategy_name: "momentum_strategy".to_string(), symbols: vec!["AAPL".to_string(), "GOOGL".to_string()], start_date_unix_nanos: chrono::Utc::now() .checked_sub_days(chrono::Days::new(365)) .unwrap() .timestamp_nanos_opt() .unwrap(), end_date_unix_nanos: chrono::Utc::now().timestamp_nanos_opt().unwrap(), initial_capital: 100000.0, parameters: [ ("lookback_period".to_string(), "20".to_string()), ("momentum_threshold".to_string(), "0.02".to_string()), ].into_iter().collect(), save_results: true, description: "Momentum strategy backtest".to_string(), }; let response = backtest_client.start_backtest(backtest_request).await?; if response.success { println!("Backtest started: {}", response.backtest_id); // Monitor progress loop { let status_request = GetBacktestStatusRequest { backtest_id: response.backtest_id.clone(), }; let status = backtest_client.get_backtest_status(status_request).await?; println!("Progress: {:.1}% - PnL: ${:.2}", status.progress_percent, status.current_pnl); if matches!(status.status(), BacktestStatus::Completed | BacktestStatus::Failed) { break; } tokio::time::sleep(tokio::time::Duration::from_secs(5)).await; } // Get results let results_request = GetBacktestResultsRequest { backtest_id: response.backtest_id.clone(), include_trades: true, include_metrics: true, }; let results = backtest_client.get_backtest_results(results_request).await?; println!("Backtest Results:"); println!("Total Return: {:.2}%", results.metrics.as_ref().unwrap().total_return * 100.0); println!("Sharpe Ratio: {:.2}", results.metrics.as_ref().unwrap().sharpe_ratio); println!("Max Drawdown: {:.2}%", results.metrics.as_ref().unwrap().max_drawdown * 100.0); println!("Total Trades: {}", results.trades.len()); } else { println!("Backtest failed: {}", response.message); } ``` ### Authentication and Security ```rust use tli::auth::*; // Create authentication service let security_config = SecurityConfig::default(); let auth_service = AuthenticationService::new(security_config).await?; // Authenticate user let auth_result = auth_service.authenticate_user( "trader_001", "secure_password", "192.168.1.100" ).await?; println!("Authenticated: {}", auth_result.user_id); println!("Session expires: {}", auth_result.expires_at); // Create API key for programmatic access let api_key = auth_service.create_api_key( &auth_result.user_id, "Trading Bot API Key", vec![ "trade:execute".to_string(), "order:place".to_string(), "market_data:view".to_string(), ], Some(90) // 90 days expiration ).await?; println!("API Key created: {}", api_key.id); ``` ### Error Handling ```rust use tonic::{Code, Status}; match trading_client.submit_order(order_request).await { Ok(response) => { if response.success { println!("Order submitted: {}", response.order_id); } else { println!("Order rejected: {}", response.message); } }, Err(status) => { match status.code() { Code::Unauthenticated => { println!("Authentication required"); // Refresh session or re-authenticate }, Code::PermissionDenied => { println!("Insufficient permissions"); // Check required permissions }, Code::ResourceExhausted => { println!("Rate limit exceeded"); // Implement backoff and retry }, Code::FailedPrecondition => { println!("Risk limits exceeded or market closed"); // Check risk status and market hours }, Code::Unavailable => { println!("Service temporarily unavailable"); // Implement retry with exponential backoff }, _ => { println!("Unexpected error: {}", status.message()); } } } } ``` --- ## Performance Considerations ### Connection Pooling ```rust // Configure connection pooling for high throughput let trading_config = TradingClientConfig { max_connections: 20, connection_timeout: Duration::from_secs(5), request_timeout: Duration::from_secs(30), keepalive_interval: Duration::from_secs(30), enable_compression: true, ..Default::default() }; ``` ### Streaming Best Practices 1. **Use streaming for real-time data** instead of polling 2. **Implement proper backpressure handling** for high-volume streams 3. **Use connection multiplexing** for multiple subscriptions 4. **Handle reconnection gracefully** with exponential backoff ### Latency Optimization 1. **Use dedicated connections** for latency-critical operations 2. **Minimize serialization overhead** with binary protocols 3. **Implement client-side caching** for configuration data 4. **Use connection affinity** for related requests --- *This API documentation is maintained by the Trading Platform Team. For questions or clarifications, please contact: api-support@company.com*