syntax = "proto3"; option java_multiple_files = true; option java_package = "com.dexorder.proto"; // User container event system for delivering notifications to users // via active sessions or external channels (Telegram, email, push). // // Two ZMQ patterns: // - XPUB/SUB (port 5570): Fast path for informational events to active sessions // - DEALER/ROUTER (port 5571): Guaranteed delivery for critical events with ack // // See doc/protocol.md and doc/user_container_events.md for details. // ============================================================================= // User Event (Container → Gateway) // Message Type ID: 0x20 // ============================================================================= message UserEvent { // User ID this event belongs to string user_id = 1; // Unique event ID for deduplication and ack tracking (UUID) string event_id = 2; // Timestamp when event was generated (Unix milliseconds) int64 timestamp = 3; // Type of event EventType event_type = 4; // Event payload (JSON or nested protobuf, depending on event_type) bytes payload = 5; // Delivery specification (priority and channel preferences) DeliverySpec delivery = 6; } enum EventType { // Trading events ORDER_PLACED = 0; ORDER_FILLED = 1; ORDER_CANCELLED = 2; ORDER_REJECTED = 3; ORDER_EXPIRED = 4; // Alert events ALERT_TRIGGERED = 10; ALERT_CREATED = 11; ALERT_DELETED = 12; // Position events POSITION_OPENED = 20; POSITION_CLOSED = 21; POSITION_UPDATED = 22; POSITION_LIQUIDATED = 23; // Workspace/chart events WORKSPACE_CHANGED = 30; CHART_ANNOTATION_ADDED = 31; CHART_ANNOTATION_REMOVED = 32; INDICATOR_UPDATED = 33; // Strategy events STRATEGY_STARTED = 40; STRATEGY_STOPPED = 41; STRATEGY_LOG = 42; STRATEGY_ERROR = 43; BACKTEST_COMPLETED = 44; // System events CONTAINER_STARTING = 50; CONTAINER_READY = 51; CONTAINER_SHUTTING_DOWN = 52; EVENT_ERROR = 53; } // ============================================================================= // Delivery Specification // ============================================================================= message DeliverySpec { // Priority determines routing behavior Priority priority = 1; // Ordered list of channel preferences (try first, then second, etc.) repeated ChannelPreference channels = 2; } enum Priority { // Drop if no active session (fire-and-forget via XPUB) // Use for: indicator updates, chart syncs, strategy logs when watching INFORMATIONAL = 0; // Best effort delivery - queue briefly, deliver when possible // Uses XPUB if subscribed, otherwise DEALER // Use for: alerts, position updates NORMAL = 1; // Must deliver - retry until acked, escalate channels // Always uses DEALER for guaranteed delivery // Use for: order fills, liquidations, critical errors CRITICAL = 2; } message ChannelPreference { // Channel to deliver to ChannelType channel = 1; // If true, skip this channel if user is not connected to it // If false, deliver even if user is not actively connected // (e.g., send Telegram message even if user isn't in Telegram chat) bool only_if_active = 2; } enum ChannelType { // Whatever channel the user currently has open (WebSocket, Telegram session) ACTIVE_SESSION = 0; // Specific channels WEB = 1; // WebSocket to web UI TELEGRAM = 2; // Telegram bot message EMAIL = 3; // Email notification PUSH = 4; // Mobile push notification (iOS/Android) DISCORD = 5; // Discord webhook (future) SLACK = 6; // Slack webhook (future) } // ============================================================================= // Event Acknowledgment (Gateway → Container) // Message Type ID: 0x21 // ============================================================================= message EventAck { // Event ID being acknowledged string event_id = 1; // Delivery status AckStatus status = 2; // Error message if status is ERROR string error_message = 3; // Channel that successfully delivered (for logging/debugging) ChannelType delivered_via = 4; } enum AckStatus { // Successfully delivered to at least one channel DELIVERED = 0; // Accepted and queued for delivery (e.g., rate limited, will retry) QUEUED = 1; // Permanent failure - all channels failed ACK_ERROR = 2; } // ============================================================================= // Event Payloads // These are JSON-encoded in the UserEvent.payload field. // Defined here for documentation; actual encoding is JSON for flexibility. // ============================================================================= // Payload for ORDER_PLACED, ORDER_FILLED, ORDER_CANCELLED, etc. message OrderEventPayload { string order_id = 1; string symbol = 2; string side = 3; // "buy" or "sell" string order_type = 4; // "market", "limit", "stop_limit", etc. string quantity = 5; // Decimal string string price = 6; // Decimal string (for limit orders) string fill_price = 7; // Decimal string (for fills) string fill_quantity = 8; // Decimal string (for partial fills) string status = 9; // "open", "filled", "cancelled", etc. string exchange = 10; int64 timestamp = 11; // Unix milliseconds string strategy_id = 12; // If order was placed by a strategy string error_message = 13; // If rejected/failed } // Payload for ALERT_TRIGGERED message AlertEventPayload { string alert_id = 1; string symbol = 2; string condition = 3; // Human-readable condition (e.g., "BTC > 50000") string triggered_price = 4; // Decimal string int64 timestamp = 5; } // Payload for POSITION_OPENED, POSITION_CLOSED, POSITION_UPDATED message PositionEventPayload { string position_id = 1; string symbol = 2; string side = 3; // "long" or "short" string size = 4; // Decimal string string entry_price = 5; // Decimal string string current_price = 6; // Decimal string string unrealized_pnl = 7; // Decimal string string realized_pnl = 8; // Decimal string (for closed positions) string leverage = 9; // Decimal string (for margin) string liquidation_price = 10; string exchange = 11; int64 timestamp = 12; } // Payload for WORKSPACE_CHANGED, CHART_ANNOTATION_*, INDICATOR_UPDATED message WorkspaceEventPayload { string workspace_id = 1; string change_type = 2; // "symbol_changed", "timeframe_changed", "annotation_added", etc. string symbol = 3; string timeframe = 4; // For annotations string annotation_id = 5; string annotation_type = 6; // "trendline", "horizontal", "rectangle", "text", etc. string annotation_data = 7; // JSON string with coordinates, style, etc. // For indicators string indicator_name = 8; string indicator_params = 9; // JSON string with indicator parameters int64 timestamp = 10; } // Payload for STRATEGY_LOG, STRATEGY_ERROR message StrategyEventPayload { string strategy_id = 1; string strategy_name = 2; string log_level = 3; // "debug", "info", "warn", "error" string message = 4; string details = 5; // JSON string with additional context int64 timestamp = 6; } // Payload for BACKTEST_COMPLETED message BacktestEventPayload { string backtest_id = 1; string strategy_id = 2; string strategy_name = 3; string symbol = 4; string timeframe = 5; int64 start_time = 6; int64 end_time = 7; // Results summary int32 total_trades = 8; int32 winning_trades = 9; int32 losing_trades = 10; string total_pnl = 11; // Decimal string string win_rate = 12; // Decimal string (0-1) string sharpe_ratio = 13; // Decimal string string max_drawdown = 14; // Decimal string (0-1) string results_path = 15; // Path to full results file int64 completed_at = 16; }