Expand description
§tvdata-rs
tvdata-rs is a modern async Rust library for working with TradingView’s unofficial data surfaces.
It combines:
- high-level facades for equities, crypto, and FX
- low-level screener access for custom TradingView queries
- typed models for quotes, fundamentals, analyst data, calendars, and history
- capability-aware validation against live scanner metainfo
- simple builder setup plus grouped backend-oriented configuration
§Installation
[dependencies]
tvdata-rs = "0.1.2"
tokio = { version = "1", features = ["macros", "rt-multi-thread"] }§Feature Flags
Optional product-surface features:
searchequitycryptoforexcalendareconomicstracing
Core scanner and history APIs remain available in the base crate.
§Stability Policy
- current MSRV: Rust
1.85 - patch releases aim to stay non-breaking
- while the crate is
0.x, minor releases may still contain intentional breaking API changes - documented public types and methods are the public contract; internal transport and generated registry internals are not
§Start Here
Use these entry points as a rule of thumb:
client.equity()for quotes, fundamentals, analyst data, and stock overviewsclient.crypto()andclient.forex()for market snapshots and moversclient.history(...)orclient.download_history(...)for OHLCV seriesclient.search_response(...)for rich symbol lookup metadataclient.economic_calendar(...),earnings_calendar(...),dividend_calendar(...), andipo_calendar(...)for calendar productsclient.scan(...)when you need exact TradingView screener fields and filtersclient.metainfo(...),validate_scan_query(...), andscan_supported(...)when you want safer scanner workflows
Initialization paths:
TradingViewClient::builder()for the shortest default setupTradingViewClient::from_config(...)withTradingViewClientConfigfor grouped backend configuration- preset constructors like
for_backend_history(),for_research(), andfor_interactive()when you want tuned defaults
for_backend_history() starts with a tuned chart-history envelope: 6 concurrent
websocket sessions and a matching default batch concurrency for large daily-bar ingestion.
Screener-backed snapshot batch APIs use SnapshotBatchStrategy::Auto by default and can be
forced into SingleRequest or explicit chunked modes through SnapshotBatchConfig.
§Quick Start
use tvdata_rs::{Result, TradingViewClient};
#[tokio::main]
async fn main() -> Result<()> {
let client = TradingViewClient::builder().build()?;
let quote = client.equity().quote("NASDAQ:AAPL").await?;
println!(
"{} close: {:?}",
quote.instrument.ticker.as_str(),
quote.close
);
Ok(())
}§Low-Level Scanner
use tvdata_rs::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let client = TradingViewClient::builder().build()?;
let query = ScanQuery::new()
.market("america")
.tickers(["NASDAQ:AAPL"])
.select([
fields::core::NAME,
fields::price::CLOSE,
fields::technical::RSI,
]);
let response = client.scan(&query).await?;
let record = response.rows[0].as_record(&query.columns);
println!("{record:#?}");
Ok(())
}§Capability-Aware Scans
use tvdata_rs::prelude::*;
#[tokio::main]
async fn main() -> Result<()> {
let client = TradingViewClient::builder().build()?;
let query = ScanQuery::new()
.market("america")
.select([fields::core::NAME, fields::price::CLOSE]);
let report = client.validate_scan_query(&query).await?;
assert!(report.is_strictly_supported());
let response = client.scan_validated(&query).await?;
println!("rows: {}", response.rows.len());
Ok(())
}§Search, Calendars, And History
use tvdata_rs::{
CalendarWindowRequest, EconomicCalendarRequest, HistoryRequest, Interval, Result,
TradingViewClient,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = TradingViewClient::builder().build()?;
let search = client.search_equities_response("AAPL").await?;
println!("remaining: {}", search.symbols_remaining);
let events = client
.economic_calendar(&EconomicCalendarRequest::upcoming(7))
.await?;
println!("macro events: {}", events.events.len());
let earnings = client
.earnings_calendar(&CalendarWindowRequest::upcoming("america", 7))
.await?;
println!("earnings events: {}", earnings.len());
let history = client
.history(&HistoryRequest::new("NASDAQ:AAPL", Interval::Day1, 30))
.await?;
println!("bars: {}", history.bars.len());
Ok(())
}§Configuration
TradingViewClient::builder() supports:
- retry configuration
- endpoint overrides
- explicit
AuthConfigmodes for anonymous, session, token, or combined auth - auth-aware
sessionidcookies for HTTP and websocket requests - grouped
TransportConfigandTradingViewClientConfigfor backend-oriented setup SnapshotBatchConfigwithAuto,SingleRequest, and chunked batch modes for large snapshot workloads- optional custom websocket connector injection for transport-controlled environments
- optional typed
ClientObserverhooks for HTTP, websocket, and batch events - optional
RequestBudgetlimits for HTTP pacing and websocket session caps - injecting a shared HTTP client when your application already owns transport middleware
- optional
tracinginstrumentation for HTTP, scanner, history, and websocket flows - operational error helpers such as
is_rate_limited()andis_auth_error()
§Caveat
TradingView does not provide a public end-user data API for this use case. This crate works against unofficial, reverse-engineered surfaces, so field support and payload shapes can change over time.
Re-exports§
pub use batch::BatchResult;pub use batch::SymbolFailure;pub use calendar::CalendarWindowRequest;pub use calendar::DividendCalendarEntry;pub use calendar::DividendCalendarRequest;pub use calendar::DividendDateKind;pub use calendar::EarningsCalendarEntry;pub use calendar::IpoCalendarEntry;pub use client::AuthConfig;pub use client::AuthMode;pub use client::ClientEvent;pub use client::ClientObserver;pub use client::DefaultWebSocketConnector;pub use client::Endpoints;pub use client::HistoryBatchCompletedEvent;pub use client::HistoryBatchMode;pub use client::HistoryClientConfig;pub use client::HttpRequestCompletedEvent;pub use client::HttpRequestFailedEvent;pub use client::RequestBudget;pub use client::RetryConfig;pub use client::RetryJitter;pub use client::SnapshotBatchConfig;pub use client::SnapshotBatchStrategy;pub use client::TradingViewClient;pub use client::TradingViewClientConfig;pub use client::TransportConfig;pub use client::WebSocketConnectFuture;pub use client::WebSocketConnectedEvent;pub use client::WebSocketConnectionFailedEvent;pub use client::WebSocketConnector;pub use crypto::CryptoClient;pub use crypto::CryptoOverview;pub use economics::EconomicCalendarRequest;pub use economics::EconomicCalendarResponse;pub use economics::EconomicEvent;pub use economics::EconomicValue;pub use equity::AnalystForecasts;pub use equity::AnalystFxRates;pub use equity::AnalystPriceTargets;pub use equity::AnalystRecommendations;pub use equity::AnalystSummary;pub use equity::EarningsCalendar;pub use equity::EarningsMetrics;pub use equity::EquityClient;pub use equity::EquityOverview;pub use equity::EstimateHistory;pub use equity::EstimateMetrics;pub use equity::EstimateObservation;pub use equity::FundamentalMetrics;pub use equity::FundamentalObservation;pub use equity::FundamentalsSnapshot;pub use equity::PointInTimeFundamentals;pub use error::Error;pub use error::ErrorKind;pub use error::Result;pub use forex::ForexClient;pub use forex::ForexOverview;pub use history::Adjustment;pub use history::Bar;pub use history::BarSelectionPolicy;pub use history::DailyBarRangeRequest;pub use history::DailyBarRequest;pub use history::HistoryBatchRequest;pub use history::HistoryProvenance;pub use history::HistoryRequest;pub use history::HistorySeries;pub use history::Interval;pub use history::TradingSession;pub use metadata::DataLineage;pub use metadata::DataSourceKind;pub use metadata::HistoryKind;pub use scanner::HeuristicSymbolNormalizer;pub use scanner::InstrumentRef;pub use scanner::PartiallySupportedColumn;pub use scanner::ScanValidationReport;pub use scanner::ScannerFieldMetainfo;pub use scanner::ScannerFieldType;pub use scanner::ScannerMetainfo;pub use scanner::SymbolNormalizer;pub use search::SearchAssetClass;pub use search::SearchHit;pub use search::SearchRequest;pub use search::SearchResponse;pub use time_series::FiscalPeriod;pub use time_series::HistoricalObservation;