pub trait Alerts: MaybeSend + 'static {
// Required methods
fn watch(&self, events: Events<AlertEvent>);
fn save(&self, alert: Alert, reply: Reply<()>);
fn remove(&self, id: AlertId, reply: Reply<()>);
// Provided method
fn engine(&self) -> Option<&AlertEngine> { ... }
}Expand description
The host’s alerts. The host stores and evaluates them, on its own prices or on a server; the
library shows what the host pushes and sends every change the user makes through
save and remove. With the alert-engine feature,
services::AlertEngine is a ready-made implementation that evaluates
the alerts on the bars the host feeds it; without it the library evaluates nothing.
The host is the source of truth. The terminal shows only the alerts and triggers that
watch pushed: an alert the user creates appears once the host pushes it, and
the terminal never marks an alert triggered on its own. When the host pushes
AlertEvent::Triggered, the terminal shows a popup and an entry in the alert log; the status
it shows is the one the host last pushed in an AlertEvent::Upsert. Sound and delivery
outside the application (email, push notifications) are the host’s: it can play a sound or send
a message when it pushes the trigger.
Evaluation is the host’s, so these rules are the contract between the library that edits an
alert and the service that runs it. A channel is inclusive at both boundaries. The state
conditions InsideChannel and
OutsideChannel hold on every evaluation
while the value is in that state, so pair them with a frequency that limits repeats, whereas
entering and exiting hold only on the evaluation that crosses a boundary.
AlertFrequency::OncePerMinute allows one
trigger per UTC clock minute, from hh:mm:00 up to but excluding the next minute, whatever the
chart’s interval. An alert’s schedule allows triggers only when
NotificationSchedule::allows accepts the
trigger time. Outside it, keep observing values for crossings without consuming an occurrence
or disarming an alert that fires once.
A StrategyFills alert receives each execution
of a host-named run through AlertEngine::strategy_fills, with strategies and alert-engine.
Its event carries the fill time, execution price and a message such as
“Buy 2 at 187.50, position 4”. The host supplies bars and retains the run; delivery outside the
application remains the host’s responsibility.
These methods are called on the UI thread, while the terminal shows a frame or runs a command,
and must return at once. Do the work elsewhere and answer through the Reply or push through
the Events you were given, from any thread, runtime or browser task. A Reply dropped
unanswered reports FeedError::Unanswered.
use std::sync::Mutex;
use egui_charts::data::Reply;
use egui_charts::model::{Alert, AlertId};
use egui_charts::services::{AlertEvent, Alerts, Events};
/// Alerts held in memory, lost when the application exits. Answers inline. A real host also
/// evaluates the alerts on its prices and pushes `AlertEvent::Triggered` when one fires.
#[derive(Default)]
struct InMemory(Mutex<State>);
#[derive(Default)]
struct State {
alerts: Vec<Alert>,
events: Option<Events<AlertEvent>>,
next_id: u64,
}
impl Alerts for InMemory {
fn watch(&self, events: Events<AlertEvent>) {
let mut state = self.0.lock().unwrap();
for alert in &state.alerts {
events.push(AlertEvent::Upsert(alert.clone()));
}
state.events = Some(events);
}
fn save(&self, mut alert: Alert, reply: Reply<()>) {
let mut state = self.0.lock().unwrap();
if alert.id.is_none() {
state.next_id += 1;
alert.id = Some(AlertId(state.next_id.to_string()));
}
state.alerts.retain(|kept| kept.id != alert.id);
state.alerts.push(alert.clone());
if let Some(events) = &state.events {
events.push(AlertEvent::Upsert(alert));
}
reply.send(Ok(()));
}
fn remove(&self, id: AlertId, reply: Reply<()>) {
let mut state = self.0.lock().unwrap();
state.alerts.retain(|kept| kept.id.as_ref() != Some(&id));
if let Some(events) = &state.events {
events.push(AlertEvent::Remove(id));
}
reply.send(Ok(()));
}
}
let alerts: std::sync::Arc<dyn Alerts> = std::sync::Arc::new(InMemory::default());Required Methods§
Sourcefn watch(&self, events: Events<AlertEvent>)
fn watch(&self, events: Events<AlertEvent>)
Pushes the host’s alerts, then every change and trigger. Called when the terminal starts and
again after a lagged stream, each time with a new stream that starts from no alerts: push
the current list first, then keep pushing until events is inactive. On the first call,
also push the triggers that fired while the application was closed; do not push them again
on a later call.
The stream takes at most 10,000 pushes between two frames, the current list and the missed triggers included: send at most that many at once (for example only the most recent triggers), or the stream lags on every call and no alert shows.
Sourcefn save(&self, alert: Alert, reply: Reply<()>)
fn save(&self, alert: Alert, reply: Reply<()>)
Creates (alert.id is None) or replaces an alert. Keep alert.inputs with the alert:
its independent study parameters and source view must survive copies and restoration.
Answer Ok once the change is kept;
the alert appears when watch pushes it, so push the saved alert, with its id, as
AlertEvent::Upsert.
Provided Methods§
Sourcefn engine(&self) -> Option<&AlertEngine>
fn engine(&self) -> Option<&AlertEngine>
The local evaluator, when this service uses one. The assembled terminal feeds it from its datafeed, including subjects that no live chart shows. Server-backed services keep the default so evaluation remains on the server.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".