pub trait Datafeed: MaybeSend + 'static {
Show 23 methods
// Required method
fn history(&self, request: HistoryRequest, reply: Reply<HistoryPage>);
// Provided methods
fn capabilities(&self, reply: Reply<FeedCapabilities>) { ... }
fn resolve(&self, symbol: &str, reply: Reply<Instrument>) { ... }
fn resolve_converted(
&self,
symbol: &str,
conversion: &str,
reply: Reply<Instrument>,
) { ... }
fn subscribe(&self, subscription: Subscription) { ... }
fn unsubscribe(&self, id: SubscriptionId) { ... }
fn trades(&self, request: TradeRequest, reply: Reply<TradePage>) { ... }
fn options_volume(&self, query: OptionsVolumeQuery, sink: OptionsVolumeSink) { ... }
fn option_expiries(&self, underlying: &str, reply: Reply<Vec<NaiveDate>>) { ... }
fn option_chain(&self, query: OptionChainQuery, sink: OptionChainSink) { ... }
fn option_exposure(
&self,
query: OptionExposureQuery,
sink: OptionExposureSink,
) { ... }
fn depth_history(&self, request: DepthRequest, reply: Reply<DepthPage>) { ... }
fn metrics(&self, symbol: &str, reply: Reply<Vec<MetricSeries>>) { ... }
fn metric_history(&self, request: MetricRequest, reply: Reply<MetricPage>) { ... }
fn subscribe_metric(&self, subscription: MetricSubscription) { ... }
fn price_targets(&self, symbol: &str, reply: Reply<PriceTargets>) { ... }
fn symbol_details(&self, symbol: &str, reply: Reply<SymbolDetails>) { ... }
fn news(&self, query: NewsQuery, reply: Reply<Vec<NewsStory>>) { ... }
fn calendar(&self, query: CalendarQuery, reply: Reply<Vec<CalendarEvent>>) { ... }
fn screen(&self, query: ScreenerQuery, reply: Reply<Vec<ScreenerRow>>) { ... }
fn hotlist(&self, query: HotlistQuery, reply: Reply<Vec<HotlistEntry>>) { ... }
fn screen_text(
&self,
query: ScreenerQuery,
reply: Reply<ScreenerTextAnswer>,
) { ... }
fn request_depth_snapshot(&self, id: SubscriptionId) { ... }
}Expand description
Source of instrument metadata, history and live updates for a chart, given to it with
ChartBuilder::with_feed.
Methods are called on the UI thread and must return promptly. Do the work elsewhere and answer
through the Reply or Sink you were given, from any thread, runtime or browser task.
use egui_charts::data::{Datafeed, HistoryPage, HistoryRequest, Reply};
use egui_charts::model::Bar;
/// Bars held in memory, oldest first. Answers inline, without live updates.
struct InMemory(Vec<Bar>);
impl Datafeed for InMemory {
fn history(&self, request: HistoryRequest, reply: Reply<HistoryPage>) {
let before = |bar: &Bar| request.before.is_none_or(|before| bar.time < before);
let end = self.0.partition_point(before);
let since = |bar: &Bar| request.since.is_some_and(|since| bar.time < since);
let first = self.0.partition_point(since).min(end);
let start = end.saturating_sub(request.count).max(first);
reply.send(Ok(HistoryPage::new(self.0[start..end].to_vec(), start == 0)));
}
}Required Methods§
Sourcefn history(&self, request: HistoryRequest, reply: Reply<HistoryPage>)
fn history(&self, request: HistoryRequest, reply: Reply<HistoryPage>)
Up to request.count bars of the range [request.since, request.before), the newest ones
when there are more. Either end left None is unbounded: without before the range
reaches the latest bar.
Provided Methods§
Sourcefn capabilities(&self, reply: Reply<FeedCapabilities>)
fn capabilities(&self, reply: Reply<FeedCapabilities>)
What the feed offers as a whole, before any symbol is resolved: the intervals, exchanges
and symbol classes its selectors may offer, and the optional services it supplies. The
chart asks once when it attaches the feed and keeps the answer in
Chart::feed_capabilities (requires widget). The default
answers FeedCapabilities::default, which reports nothing and so restricts nothing.
Sourcefn resolve(&self, symbol: &str, reply: Reply<Instrument>)
fn resolve(&self, symbol: &str, reply: Reply<Instrument>)
Describes symbol. The default reports Instrument::new of the symbol.
Fill Instrument::profile_resolutions to suggest the bars volume profile studies and
drawings read.
Sourcefn resolve_converted(
&self,
symbol: &str,
conversion: &str,
reply: Reply<Instrument>,
)
fn resolve_converted( &self, symbol: &str, conversion: &str, reply: Reply<Instrument>, )
Describes symbol with its prices converted to conversion, the currency or unit the
host chose with Chart::set_conversion (requires widget). Label the
instrument with the converted currency and
unit. The library converts nothing: the default answers
FeedError::NotSupported, which shows no data rather than unconverted data under a
converted choice.
Sourcefn subscribe(&self, subscription: Subscription)
fn subscribe(&self, subscription: Subscription)
Starts pushing live updates into subscription.sink until unsubscribe. The default does
nothing, which gives a history-only chart.
Sourcefn unsubscribe(&self, id: SubscriptionId)
fn unsubscribe(&self, id: SubscriptionId)
Stops what subscribe started. Pushes that arrive afterwards are ignored. The default does
nothing; a producer can then poll Sink::is_active to know when to stop.
Also called when the chart is dropped, which an application may do while egui holds the
lock of its Context, for example inside Context::input or Ui::input. A push into a
Sink or an answer through a Reply may wake a chart, and waking waits for that lock
until the application’s closure returns. So:
- Return without waiting for a thread that pushes or answers: do not join it, and do not take a lock it holds while it pushes or answers.
- Answer or drop here only the replies of the chart that held
id, and push into no other subscription’sSink: another chart would be woken on this thread, which holds the lock. A feed that cannot tell which chart aReplyis for keeps its replies and answers them as usual; an answer for a dropped chart is never read.
When the chart held the last reference to the feed, the feed’s own Drop runs right
after this call and must not wait for such a thread either.
Sourcefn trades(&self, request: TradeRequest, reply: Reply<TradePage>)
fn trades(&self, request: TradeRequest, reply: Reply<TradePage>)
Up to request.count trades of the range [request.since, request.before), the newest
ones when there are more, so order flow survives a reload and follows the view back in
time. The default answers FeedError::NotSupported.
Sourcefn options_volume(&self, query: OptionsVolumeQuery, sink: OptionsVolumeSink)
fn options_volume(&self, query: OptionsVolumeQuery, sink: OptionsVolumeSink)
Push complete options-volume snapshots for the underlying and inclusive expiry range.
Each push replaces the previous figures, including an empty snapshot. Sum contracts
across the requested expiries at each strike. Stop when sink.is_active() is false.
The default supplies none; the library never fetches options data itself.
Sourcefn option_expiries(&self, underlying: &str, reply: Reply<Vec<NaiveDate>>)
fn option_expiries(&self, underlying: &str, reply: Reply<Vec<NaiveDate>>)
Listed expiry dates for underlying, in ascending order with no duplicates.
The default answers FeedError::NotSupported. Both options methods are declared by
FeedService::OptionChain; the host supplies the data.
Sourcefn option_chain(&self, query: OptionChainQuery, sink: OptionChainSink)
fn option_chain(&self, query: OptionChainQuery, sink: OptionChainSink)
Push complete snapshots of the listed contracts in query’s inclusive expiry range.
Without as_of, keep pushing until the sink is inactive.
With it, push one snapshot for that instant or report FeedError::NotSupported.
Unknown figures stay absent. See OptionQuote for units and OptionChainSink::push
for validation. The default reports FeedError::NotSupported to the sink.
use chrono::{NaiveDate, TimeZone, Utc};
use egui_charts::data::{
Datafeed, HistoryPage, HistoryRequest, OptionChain, OptionChainQuery,
OptionChainSink, OptionKind, OptionQuote, Reply,
};
struct Feed;
impl Datafeed for Feed {
fn history(&self, _: HistoryRequest, reply: Reply<HistoryPage>) {
reply.send(Ok(HistoryPage::default()));
}
fn option_expiries(&self, _: &str, reply: Reply<Vec<NaiveDate>>) {
reply.send(Ok(vec![
NaiveDate::from_ymd_opt(2026, 12, 18).unwrap(),
NaiveDate::from_ymd_opt(2027, 1, 15).unwrap(),
]));
}
fn option_chain(&self, query: OptionChainQuery, sink: OptionChainSink) {
let time = Utc.with_ymd_and_hms(2026, 11, 2, 12, 0, 0).unwrap();
let mut row = OptionQuote::new(
"SAMPLE-261218-C100", *query.expiries.start(), 100.0, OptionKind::Call, time,
);
row.bid = Some(3.5);
row.open_interest = Some(1200.0);
row.gamma = Some(0.04);
sink.push(vec![row]).unwrap();
}
}
let expiry = NaiveDate::from_ymd_opt(2026, 12, 18).unwrap();
let chain = OptionChain::new(
&Feed, OptionChainQuery::new("SAMPLE", expiry..=expiry), || {},
).unwrap();
let rows = chain.rows();
assert_eq!(rows.len(), 1);
assert_eq!(rows[0].bid, Some(3.5));
assert_eq!(rows[0].open_interest, Some(1200.0));
assert_eq!(rows[0].gamma, Some(0.04));
assert_eq!(rows[0].ask, None);
assert_eq!(rows[0].volume, None);
assert_eq!(chain.error(), None);Sourcefn option_exposure(&self, query: OptionExposureQuery, sink: OptionExposureSink)
fn option_exposure(&self, query: OptionExposureQuery, sink: OptionExposureSink)
Push complete exposure snapshots for the underlying, inclusive expiry range and kind.
Without as_of, keep pushing until the sink is inactive;
with it, answer once for that instant or report FeedError::NotSupported (the default).
Declared by FeedService::OptionExposure. The host supplies the data and model.
OptionExposureHandle::snapshot_or_gamma prefers the supplied snapshot unchanged over
computed gamma. See OptionExposureSink::push for atomic validation and replacement.
Sourcefn depth_history(&self, request: DepthRequest, reply: Reply<DepthPage>)
fn depth_history(&self, request: DepthRequest, reply: Reply<DepthPage>)
One page of recorded depth on the requested grid. The default answers
FeedError::NotSupported; live-only feeds need not implement this method.
Sourcefn metrics(&self, symbol: &str, reply: Reply<Vec<MetricSeries>>)
fn metrics(&self, symbol: &str, reply: Reply<Vec<MetricSeries>>)
Metrics offered for symbol, in display order. The default offers none.
The host publishes the values; the library computes no instrument metrics.
Sourcefn metric_history(&self, request: MetricRequest, reply: Reply<MetricPage>)
fn metric_history(&self, request: MetricRequest, reply: Reply<MetricPage>)
Metric history. The default answers FeedError::NotSupported.
Sourcefn subscribe_metric(&self, subscription: MetricSubscription)
fn subscribe_metric(&self, subscription: MetricSubscription)
Start publishing metric points until Self::unsubscribe. The default does nothing.
Sourcefn price_targets(&self, symbol: &str, reply: Reply<PriceTargets>)
fn price_targets(&self, symbol: &str, reply: Reply<PriceTargets>)
Analyst price targets for symbol. The default answers FeedError::NotSupported,
which leaves the chart without targets and shows no error.
Sourcefn symbol_details(&self, symbol: &str, reply: Reply<SymbolDetails>)
fn symbol_details(&self, symbol: &str, reply: Reply<SymbolDetails>)
Key statistics and the company or contract profile of symbol, for the symbol details
panel. The default answers FeedError::NotSupported, and the panel then shows neither.
Sourcefn news(&self, query: NewsQuery, reply: Reply<Vec<NewsStory>>)
fn news(&self, query: NewsQuery, reply: Reply<Vec<NewsStory>>)
Up to query.limit stories, newest first, for the news and highlights panels. Answer
FeedError::NotSupported (the default) to have the panels say the feed has none.
Sourcefn calendar(&self, query: CalendarQuery, reply: Reply<Vec<CalendarEvent>>)
fn calendar(&self, query: CalendarQuery, reply: Reply<Vec<CalendarEvent>>)
The events of one calendar that pass query’s filters, in time order, for the calendar
panel. Answer FeedError::NotSupported (the default) to have the panel say the feed has
none.
Sourcefn screen(&self, query: ScreenerQuery, reply: Reply<Vec<ScreenerRow>>)
fn screen(&self, query: ScreenerQuery, reply: Reply<Vec<ScreenerRow>>)
Up to query.limit symbols that meet every filter of query, sorted as it asks, each
with the values of its columns, for the screener. The feed does the screening. Answer
FeedError::InvalidData for a filter it cannot apply, and FeedError::NotSupported
(the default) to have the panel say the feed has none.
Sourcefn hotlist(&self, query: HotlistQuery, reply: Reply<Vec<HotlistEntry>>)
fn hotlist(&self, query: HotlistQuery, reply: Reply<Vec<HotlistEntry>>)
Up to query.limit symbols of the hotlist query.list, in the list’s order, for the
hotlists panel. Answer FeedError::NotSupported (the default) to have the panel say the
feed has none.
Sourcefn screen_text(&self, query: ScreenerQuery, reply: Reply<ScreenerTextAnswer>)
fn screen_text(&self, query: ScreenerQuery, reply: Reply<ScreenerTextAnswer>)
As screen, for a query whose text describes the screen in words. The
feed interprets the text with the other criteria and answers the rows with an explanation
of how it understood them. Answer FeedError::NotSupported (the default) to have the
panel say the feed takes no descriptions, and FeedError::InvalidData for one it cannot
interpret.
Sourcefn request_depth_snapshot(&self, id: SubscriptionId)
fn request_depth_snapshot(&self, id: SubscriptionId)
The order book of subscription id was lost to a gap, an unusable update or a book deeper
than the limit: push a new snapshot with Sink::push_depth_snapshot, and keep pushing
deltas while it is fetched. The snapshot may be older than the latest delta: the chart
holds the deltas pushed while the book waits and applies those numbered above the
snapshot. Called once per loss: after an unusable snapshot the chart does not ask
again, and the book stays empty until the feed pushes a usable one or the subscription
restarts. The default does nothing, for feeds without depth.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".