tradingview/source/mod.rs
1//! Data source abstraction.
2//!
3//! Sources produce normalized [`MarketEvent`](crate::events::MarketEvent) batches and feed them into the
4//! loader pipeline. The [`DataSource`](crate::source::DataSource) trait is the extension point for new
5//! data providers (REST APIs, WebSocket feeds, CSV files, etc.).
6
7use async_trait::async_trait;
8use tokio_util::sync::CancellationToken;
9
10use crate::Result;
11use crate::events::MarketEvent;
12
13/// A provider of normalized market events.
14///
15/// A data source is responsible for:
16/// 1. Connecting to the underlying data feed (WebSocket, REST, file).
17/// 2. Fetching/streaming raw data.
18/// 3. Normalizing raw data into [`MarketEvent`] variants.
19/// 4. Sending events to the supplied `sink` channel.
20///
21/// The `run` method is the main execution loop. It runs until the feed is
22/// exhausted, an unrecoverable error occurs, or the [`CancellationToken`] is
23/// triggered.
24#[async_trait]
25pub trait DataSource: Send + Sync + 'static {
26 /// Start streaming events.
27 ///
28 /// The implementation sends `Vec<MarketEvent>` batches to the provided
29 /// async channel sender. The `cancel` token should be polled periodically
30 /// to support graceful shutdown.
31 async fn run(
32 &self,
33 sink: tokio::sync::mpsc::Sender<Vec<MarketEvent>>,
34 cancel: CancellationToken,
35 ) -> Result<()>;
36
37 /// A human-readable name for logging and debugging.
38 fn name(&self) -> &str;
39}
40
41/// Configuration for a data source subscription.
42#[derive(Debug, Clone)]
43pub struct Subscription {
44 /// The instrument to subscribe to (e.g. `"BINANCE:BTCUSDT"`, `"AAPL"`).
45 pub symbol: String,
46 /// What kind of data to request.
47 pub data_kind: crate::events::DataKind,
48 /// Optional bar interval for candle subscriptions.
49 pub interval: Option<crate::models::Interval>,
50 /// Optional number of bars to fetch (historical only).
51 pub bar_count: Option<u64>,
52}
53
54impl Subscription {
55 /// Create a new candle subscription for a symbol.
56 pub fn candle(symbol: impl Into<String>, interval: crate::models::Interval) -> Self {
57 Self {
58 symbol: symbol.into(),
59 data_kind: crate::events::DataKind::Candle,
60 interval: Some(interval),
61 bar_count: None,
62 }
63 }
64
65 /// Create a new quote subscription for a symbol.
66 pub fn quote(symbol: impl Into<String>) -> Self {
67 Self {
68 symbol: symbol.into(),
69 data_kind: crate::events::DataKind::Quote,
70 interval: None,
71 bar_count: None,
72 }
73 }
74
75 /// Create a new economic data subscription.
76 pub fn economic(indicator_id: impl Into<String>) -> Self {
77 Self {
78 symbol: indicator_id.into(),
79 data_kind: crate::events::DataKind::Economic,
80 interval: None,
81 bar_count: None,
82 }
83 }
84}
85
86/// TradingView WebSocket data source adapter.
87///
88/// Wraps the existing [`WebSocketClient`](crate::websocket::WebSocketClient) and `CommandRunner` infrastructure
89/// to produce normalized [`MarketEvent`] batches.
90///
91/// Note: This is a forward-looking design. The full implementation that bridges
92/// the existing WebSocket handler to the new event pipeline requires the
93/// existing handler code to be adapted. This module provides the trait
94/// interface and a skeleton that can be completed incrementally.
95pub mod tradingview;