pub struct MassiveRestClient { /* private fields */ }Expand description
REST client for Massive historical and intraday market data.
§Example
use rustrade_data::exchange::massive::MassiveRestClient;
use chrono::{Utc, Duration};
let client = MassiveRestClient::from_env()?;
let to = Utc::now();
let from = to - Duration::days(1);
let mut stream = client.fetch_aggregates("X:BTCUSD", 1, "minute", from, to);
while let Some(candle) = stream.next().await {
println!("{:?}", candle?);
}Implementations§
Source§impl MassiveRestClient
impl MassiveRestClient
Sourcepub async fn fetch_option_contracts(
&self,
query: &OptionContractQuery,
) -> Result<Vec<MassiveOptionContract>, MassiveError>
pub async fn fetch_option_contracts( &self, query: &OptionContractQuery, ) -> Result<Vec<MassiveOptionContract>, MassiveError>
Fetch option contracts matching the query.
Automatically paginates through all results.
§Subscription
Available on all Options plans including Basic (free tier).
§Example
use rustrade_data::exchange::massive::{MassiveRestClient, OptionContractQuery};
let client = MassiveRestClient::from_env()?;
let query = OptionContractQuery::new()
.underlying_ticker("AAPL")
.contract_type(OptionKind::Call)
.limit(100);
let contracts = client.fetch_option_contracts(&query).await?;
for c in &contracts {
println!("{}: {} {} @ {}", c.ticker, c.expiration_date, c.contract_type, c.strike_price);
}Sourcepub async fn fetch_option_chain_snapshot(
&self,
underlying: &str,
query: &OptionSnapshotQuery,
) -> Result<Vec<MassiveOptionSnapshot>, MassiveError>
pub async fn fetch_option_chain_snapshot( &self, underlying: &str, query: &OptionSnapshotQuery, ) -> Result<Vec<MassiveOptionSnapshot>, MassiveError>
Fetch option chain snapshot for an underlying asset.
Returns all option contracts for the underlying with current market data including Greeks.
§Subscription
Requires Options Starter or higher subscription. Data recency:
- Starter/Developer: 15-minute delayed
- Advanced/Business: Real-time
§Note
Greeks may be None for deep ITM options. Rho is NOT available.
§Example
use rustrade_data::exchange::massive::{MassiveRestClient, OptionSnapshotQuery};
let client = MassiveRestClient::from_env()?;
let query = OptionSnapshotQuery::new()
.strike_price_gte(dec!(150))
.strike_price_lte(dec!(200))
.limit(50);
let snapshots = client.fetch_option_chain_snapshot("AAPL", &query).await?;
for snap in snapshots {
if let Some(greeks) = &snap.greeks {
println!("{}: delta={:?}", snap.contract.ticker, greeks.delta);
}
}Sourcepub async fn fetch_option_snapshot(
&self,
underlying: &str,
contract: &str,
) -> Result<MassiveOptionSnapshot, MassiveError>
pub async fn fetch_option_snapshot( &self, underlying: &str, contract: &str, ) -> Result<MassiveOptionSnapshot, MassiveError>
Fetch a single option contract snapshot.
§Subscription
Requires Options Starter or higher subscription.
§Arguments
underlying- Underlying ticker (e.g., “AAPL”)contract- Option contract ticker (e.g., “O:AAPL251219C00150000”)
§Example
let snapshot = client.fetch_option_snapshot("AAPL", "O:AAPL251219C00150000").await?;
println!("IV: {:?}, Delta: {:?}",
snapshot.implied_volatility,
snapshot.greeks.as_ref().and_then(|g| g.delta)
);Source§impl MassiveRestClient
impl MassiveRestClient
Sourcepub fn fetch_tickers<'a>(
&'a self,
query: &'a TickerQuery,
) -> impl Stream<Item = Result<Ticker, MassiveError>> + 'a
pub fn fetch_tickers<'a>( &'a self, query: &'a TickerQuery, ) -> impl Stream<Item = Result<Ticker, MassiveError>> + 'a
Sourcepub async fn fetch_ticker_details(
&self,
ticker: &str,
) -> Result<TickerDetails, MassiveError>
pub async fn fetch_ticker_details( &self, ticker: &str, ) -> Result<TickerDetails, MassiveError>
Sourcepub async fn fetch_exchanges(
&self,
asset_class: Option<&str>,
locale: Option<&str>,
) -> Result<Vec<Exchange>, MassiveError>
pub async fn fetch_exchanges( &self, asset_class: Option<&str>, locale: Option<&str>, ) -> Result<Vec<Exchange>, MassiveError>
Fetch all exchanges.
§Arguments
asset_class- Optional filter by asset class (stocks, crypto, fx, etc.)locale- Optional filter by locale (us, global)
§Example
let exchanges = client.fetch_exchanges(Some("stocks"), Some("us")).await?;
for exchange in exchanges {
println!("{}: {}", exchange.mic.unwrap_or_default(), exchange.name);
}Sourcepub async fn fetch_market_status(&self) -> Result<MarketStatus, MassiveError>
pub async fn fetch_market_status(&self) -> Result<MarketStatus, MassiveError>
Sourcepub async fn fetch_market_holidays(
&self,
) -> Result<Vec<MarketHoliday>, MassiveError>
pub async fn fetch_market_holidays( &self, ) -> Result<Vec<MarketHoliday>, MassiveError>
Sourcepub fn fetch_dividends<'a>(
&'a self,
query: &'a DividendQuery,
) -> impl Stream<Item = Result<Dividend, MassiveError>> + 'a
pub fn fetch_dividends<'a>( &'a self, query: &'a DividendQuery, ) -> impl Stream<Item = Result<Dividend, MassiveError>> + 'a
Sourcepub fn fetch_splits_raw<'a>(
&'a self,
query: &'a SplitQuery,
) -> impl Stream<Item = Result<StockSplit, MassiveError>> + 'a
pub fn fetch_splits_raw<'a>( &'a self, query: &'a SplitQuery, ) -> impl Stream<Item = Result<StockSplit, MassiveError>> + 'a
Source§impl MassiveRestClient
impl MassiveRestClient
Sourcepub fn new(api_key: impl Into<String>) -> Result<Self, MassiveError>
pub fn new(api_key: impl Into<String>) -> Result<Self, MassiveError>
Create a new client with explicit API key.
§Arguments
api_key- Massive API key from https://massive.com/dashboard/api-keys
§Redirects
The client does not follow HTTP redirects. The API key is attached as
an Authorization: Bearer header to each request, from a single
origin-validated chokepoint, so auto-following a
server-issued 3xx could carry it off the trusted origin. Massive uses
explicit next_url cursor pagination and is not expected to redirect, so
an unexpected 3xx surfaces as MassiveError::Api rather than being
followed. A base URL set via Self::with_base_url must therefore serve
responses directly, without redirect indirection.
§Known limitation
Redirect-following is disabled wholesale (reqwest::redirect::Policy::none()),
so this applies to same-origin redirects too: even a same-origin 301/308
— e.g. trailing-slash normalization by a load balancer or CDN — is surfaced
as a terminal MassiveError::Api with the 3xx status rather than being
transparently followed. This is a deliberate trade-off: a wholesale block
keeps the “token never leaves the trusted origin” guarantee structural
rather than dependent on reqwest’s cross-origin header-stripping. It relies
on Massive serving next_url pages directly; a deployment fronted by a
redirecting proxy is not supported.
Sourcepub fn from_env() -> Result<Self, MassiveError>
pub fn from_env() -> Result<Self, MassiveError>
Create a new client from MASSIVE_API_KEY environment variable.
Sourcepub fn with_base_url(
self,
base_url: impl Into<String>,
) -> Result<Self, MassiveError>
pub fn with_base_url( self, base_url: impl Into<String>, ) -> Result<Self, MassiveError>
Override the base URL (useful for testing or legacy polygon.io endpoint).
The base URL defines the trusted origin: a paginated next_url is followed
only when it shares this scheme, host, and port, and redirects are never
followed (see the “Redirects” note on Self::new). The origin is parsed
and cached here, so a base_url that is not a valid URL is rejected up
front with MassiveError::InvalidInput rather than deferred to the first
request.
§Errors
Returns MassiveError::InvalidInput if base_url does not parse as a
URL, or if it parses but uses a scheme other than http/https — a
non-special scheme (e.g. file:) yields an opaque origin that would
reject every subsequent request, so it is refused up front.
Sourcepub fn fetch_aggregates<'a>(
&'a self,
ticker: &'a str,
multiplier: u32,
timespan: &'a str,
from: DateTime<Utc>,
to: DateTime<Utc>,
) -> impl Stream<Item = Result<Candle, MassiveError>> + 'a
pub fn fetch_aggregates<'a>( &'a self, ticker: &'a str, multiplier: u32, timespan: &'a str, from: DateTime<Utc>, to: DateTime<Utc>, ) -> impl Stream<Item = Result<Candle, MassiveError>> + 'a
Fetch aggregated OHLCV bars for a symbol.
Returns a stream that handles pagination automatically. Does not collect results into memory — processes each page as it arrives.
Each Candle’s close_time is the exclusive end-of-period boundary
bar_open + interval (see Candle::close_time).
Fixed units (second…week) are exact in UTC; calendar units
(month/quarter/year) use leap-year-correct calendar arithmetic —
e.g. a January monthly bar closes at Feb 1 00:00 UTC, aligning with
Binance 1M / IBKR monthly boundaries (previously an approximate
+30/91/365 days).
§Range contract
Yields exactly the candles whose close_time ∈ [from, to] (both inclusive),
matched on close_time — the field consumers receive. Massive’s endpoint
natively filters by the bar’s open-time, so this method widens the request
by one interval and trims by close_time, consistent with the library’s
other historical fetches.
§Arguments
ticker- Symbol with asset class prefix (e.g.,X:BTCUSD,C:EURUSD,AAPL)multiplier- Size of the timespan multiplier (e.g., 1, 5, 15)timespan- Size unit:second,minute,hour,day,week,month,quarter,yearfrom- Start timestampto- End timestamp
§Example
let stream = client.fetch_aggregates("X:BTCUSD", 1, "minute", from, to);Sourcepub fn fetch_trades<'a>(
&'a self,
ticker: &'a str,
from: DateTime<Utc>,
to: DateTime<Utc>,
) -> impl Stream<Item = Result<PublicTrade, MassiveError>> + 'a
pub fn fetch_trades<'a>( &'a self, ticker: &'a str, from: DateTime<Utc>, to: DateTime<Utc>, ) -> impl Stream<Item = Result<PublicTrade, MassiveError>> + 'a
Fetch tick-level trades for a symbol.
Returns a stream that handles pagination automatically.
§Arguments
ticker- Symbol with asset class prefix (e.g.,X:BTCUSD,AAPL)from- Start timestampto- End timestamp
Sourcepub fn fetch_quotes<'a>(
&'a self,
ticker: &'a str,
from: DateTime<Utc>,
to: DateTime<Utc>,
) -> impl Stream<Item = Result<OrderBookL1, MassiveError>> + 'a
pub fn fetch_quotes<'a>( &'a self, ticker: &'a str, from: DateTime<Utc>, to: DateTime<Utc>, ) -> impl Stream<Item = Result<OrderBookL1, MassiveError>> + 'a
Fetch quotes (BBO/NBBO) for a symbol.
Returns a stream that handles pagination automatically.
§Arguments
ticker- Symbol with asset class prefix (e.g.,C:EURUSD,AAPL)from- Start timestampto- End timestamp
Trait Implementations§
Source§impl Clone for MassiveRestClient
impl Clone for MassiveRestClient
Source§impl Debug for MassiveRestClient
impl Debug for MassiveRestClient
Source§impl StockSplitSource for MassiveRestClient
impl StockSplitSource for MassiveRestClient
Source§fn fetch_splits(
&self,
filter: &CorporateActionFilter,
) -> impl Stream<Item = Result<CorporateAction<SmolStr>, Self::Error>> + Send
fn fetch_splits( &self, filter: &CorporateActionFilter, ) -> impl Stream<Item = Result<CorporateAction<SmolStr>, Self::Error>> + Send
Fetch stock splits for filter’s symbols and effective-date range, mapped to
CorporateAction<SmolStr> descriptors.
effective_date provenance: this impl maps it onto Massive’s execution_date — the split’s
market execution date, satisfying the StockSplitSource::fetch_splits effective_date
contract. (StockSplit exposes no other date field, so there is no ambiguity to resolve.)
Massive’s /v3/reference/splits endpoint filters by a single ticker, so a multi-symbol filter
fans out into one query per symbol, concatenated into a single stream in symbols order; an
empty symbols list issues one unfiltered query (all splits in the date range, subject
to provider page limits). Splits whose raw split_to / split_from yield a degenerate ratio
(zero, negative, or division by zero) are logged and skipped — see
CorporateActionKind::stock_split.
Source§type Error = MassiveError
type Error = MassiveError
Auto Trait Implementations§
impl !RefUnwindSafe for MassiveRestClient
impl !UnwindSafe for MassiveRestClient
impl Freeze for MassiveRestClient
impl Send for MassiveRestClient
impl Sync for MassiveRestClient
impl Unpin for MassiveRestClient
impl UnsafeUnpin for MassiveRestClient
Blanket Implementations§
Source§impl<T> AttachedTransformer<()> for T
impl<T> AttachedTransformer<()> for T
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> JsonSchemaMaybe for T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.