initial commit with charts and assistant chat
This commit is contained in:
170
backend/src/datasource/websocket_protocol.py
Normal file
170
backend/src/datasource/websocket_protocol.py
Normal file
@@ -0,0 +1,170 @@
|
||||
"""
|
||||
WebSocket protocol messages for TradingView-compatible datafeed API.
|
||||
|
||||
These messages define the wire format for client-server communication
|
||||
over WebSocket for symbol search, historical data, and real-time subscriptions.
|
||||
"""
|
||||
|
||||
from typing import Any, Dict, List, Literal, Optional, Union
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Client -> Server Messages
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class SearchSymbolsRequest(BaseModel):
|
||||
"""Request to search for symbols matching a query"""
|
||||
|
||||
type: Literal["search_symbols"] = "search_symbols"
|
||||
request_id: str = Field(description="Client-generated request ID for matching responses")
|
||||
query: str = Field(description="Search query string")
|
||||
symbol_type: Optional[str] = Field(default=None, description="Filter by instrument type")
|
||||
exchange: Optional[str] = Field(default=None, description="Filter by exchange")
|
||||
limit: int = Field(default=30, description="Maximum number of results")
|
||||
|
||||
|
||||
class ResolveSymbolRequest(BaseModel):
|
||||
"""Request full metadata for a specific symbol"""
|
||||
|
||||
type: Literal["resolve_symbol"] = "resolve_symbol"
|
||||
request_id: str
|
||||
symbol: str = Field(description="Symbol identifier to resolve")
|
||||
|
||||
|
||||
class GetBarsRequest(BaseModel):
|
||||
"""Request historical bar data"""
|
||||
|
||||
type: Literal["get_bars"] = "get_bars"
|
||||
request_id: str
|
||||
symbol: str
|
||||
resolution: str = Field(description="Time resolution (e.g., '1', '5', '60', '1D')")
|
||||
from_time: int = Field(description="Start time (Unix timestamp in seconds)")
|
||||
to_time: int = Field(description="End time (Unix timestamp in seconds)")
|
||||
countback: Optional[int] = Field(default=None, description="Maximum number of bars to return")
|
||||
|
||||
|
||||
class SubscribeBarsRequest(BaseModel):
|
||||
"""Subscribe to real-time bar updates"""
|
||||
|
||||
type: Literal["subscribe_bars"] = "subscribe_bars"
|
||||
request_id: str
|
||||
symbol: str
|
||||
resolution: str
|
||||
subscription_id: str = Field(description="Client-generated subscription ID")
|
||||
|
||||
|
||||
class UnsubscribeBarsRequest(BaseModel):
|
||||
"""Unsubscribe from real-time updates"""
|
||||
|
||||
type: Literal["unsubscribe_bars"] = "unsubscribe_bars"
|
||||
request_id: str
|
||||
subscription_id: str
|
||||
|
||||
|
||||
class GetConfigRequest(BaseModel):
|
||||
"""Request datafeed configuration"""
|
||||
|
||||
type: Literal["get_config"] = "get_config"
|
||||
request_id: str
|
||||
|
||||
|
||||
# Union of all client request types
|
||||
ClientRequest = Union[
|
||||
SearchSymbolsRequest,
|
||||
ResolveSymbolRequest,
|
||||
GetBarsRequest,
|
||||
SubscribeBarsRequest,
|
||||
UnsubscribeBarsRequest,
|
||||
GetConfigRequest,
|
||||
]
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# Server -> Client Messages
|
||||
# ============================================================================
|
||||
|
||||
|
||||
class SearchSymbolsResponse(BaseModel):
|
||||
"""Response with search results"""
|
||||
|
||||
type: Literal["search_symbols_response"] = "search_symbols_response"
|
||||
request_id: str
|
||||
results: List[Dict[str, Any]] = Field(description="List of SearchResult objects")
|
||||
|
||||
|
||||
class ResolveSymbolResponse(BaseModel):
|
||||
"""Response with symbol metadata"""
|
||||
|
||||
type: Literal["resolve_symbol_response"] = "resolve_symbol_response"
|
||||
request_id: str
|
||||
symbol_info: Dict[str, Any] = Field(description="SymbolInfo object")
|
||||
|
||||
|
||||
class GetBarsResponse(BaseModel):
|
||||
"""Response with historical bars"""
|
||||
|
||||
type: Literal["get_bars_response"] = "get_bars_response"
|
||||
request_id: str
|
||||
history: Dict[str, Any] = Field(description="HistoryResult object with bars and metadata")
|
||||
|
||||
|
||||
class SubscribeBarsResponse(BaseModel):
|
||||
"""Acknowledgment of subscription"""
|
||||
|
||||
type: Literal["subscribe_bars_response"] = "subscribe_bars_response"
|
||||
request_id: str
|
||||
subscription_id: str
|
||||
success: bool
|
||||
message: Optional[str] = None
|
||||
|
||||
|
||||
class UnsubscribeBarsResponse(BaseModel):
|
||||
"""Acknowledgment of unsubscribe"""
|
||||
|
||||
type: Literal["unsubscribe_bars_response"] = "unsubscribe_bars_response"
|
||||
request_id: str
|
||||
subscription_id: str
|
||||
success: bool
|
||||
|
||||
|
||||
class GetConfigResponse(BaseModel):
|
||||
"""Response with datafeed configuration"""
|
||||
|
||||
type: Literal["get_config_response"] = "get_config_response"
|
||||
request_id: str
|
||||
config: Dict[str, Any] = Field(description="DatafeedConfig object")
|
||||
|
||||
|
||||
class BarUpdateMessage(BaseModel):
|
||||
"""Real-time bar update (server-initiated, no request_id)"""
|
||||
|
||||
type: Literal["bar_update"] = "bar_update"
|
||||
subscription_id: str
|
||||
symbol: str
|
||||
resolution: str
|
||||
bar: Dict[str, Any] = Field(description="Bar data including time and all columns")
|
||||
|
||||
|
||||
class ErrorResponse(BaseModel):
|
||||
"""Error response for any failed request"""
|
||||
|
||||
type: Literal["error"] = "error"
|
||||
request_id: str
|
||||
error_code: str = Field(description="Machine-readable error code")
|
||||
error_message: str = Field(description="Human-readable error description")
|
||||
|
||||
|
||||
# Union of all server response types
|
||||
ServerResponse = Union[
|
||||
SearchSymbolsResponse,
|
||||
ResolveSymbolResponse,
|
||||
GetBarsResponse,
|
||||
SubscribeBarsResponse,
|
||||
UnsubscribeBarsResponse,
|
||||
GetConfigResponse,
|
||||
BarUpdateMessage,
|
||||
ErrorResponse,
|
||||
]
|
||||
Reference in New Issue
Block a user