Skip to main content

AlertEngine

Struct AlertEngine 

Source
pub struct AlertEngine { /* private fields */ }
Expand description

An Alerts service that keeps alerts in memory and evaluates them on the bars the host feeds it with update, as PaperAccount fills orders on the prices it is fed. It needs no egui, so a server can run the same code. A host that evaluates alerts on its own server implements Alerts itself instead. With studies, AlertEvaluator reads the saved source definitions from a datafeed and supplies these evaluations without constructing a chart.

The host keeps the alerts: alerts returns them with their status for storage, and with_alerts restores them. Evaluation state lives in memory only, so after a restart an alert that fires on every occurrence may fire again while its condition still holds; an alert with frequency Once that fired stays Triggered.

§Rules

Subject. An alert is evaluated on its symbol, or on each member of its watchlist as set_watchlist gave it, with its own state per symbol. An update for another symbol, or for a timeframe other than the alert’s, does not touch the alert. An alert without a timeframe takes the timeframe of the first update that reaches it, which the engine saves and pushes as an AlertEvent::Upsert, so it is fixed from then on.

Evaluated bar. The newest bar, still forming, or for OncePerBarClose the newest completed one. Every rule of an alert, the first and the additional conditions, is judged on that bar, and the alert holds when every rule holds. A missing or non-finite value makes its rule false. Price is the close and volume the volume of a bar; the value function of update resolves the other sources.

Change. An update whose evaluated bar, its close and volume and the value of every source equal those of the previous update does nothing, unless a per-minute alert enters a new minute or its schedule opens. An update whose evaluated bar is older than the newest one already evaluated for the alert is ignored: reloading history, rewinding a replay or switching to a coarser timeframe never fires an alert again.

Crossings. The previous value is the value at the alert’s previous evaluation, within a bar and across bars, and on the first evaluation the value one bar earlier. Crossing up needs a previous value strictly below the level and a current value at or above it, crossing down the reverse; a value that touches the level and stays there fires once. Moving by and volume above average read the bars before the evaluated one, as AlertCondition documents. Moving channels resolve the preceding bar again when a new bar arrives, so edits and skipped updates use that bar’s current geometry. Within a bar they use the previous evaluation.

Frequency. Once fires on the first evaluation that holds and the alert becomes Triggered; a watchlist alert fires once per member and stays active. EveryTime fires on every evaluation that holds, OncePerBar at most once per bar open time, and OncePerBarClose evaluates each completed bar once. OncePerMinute fires at most once per minute of the update time now; moving the clock backwards does not repeat a minute.

Schedule. An alert’s schedule restricts triggers. Outside it the engine keeps observing values for crossings, but does not fire or consume an occurrence. A once alert stays armed.

Expiry. Every update and tick first marks active alerts whose expiry has passed as Expired, so an alert never fires at or after its expiry and expires without data. Disabled, triggered and expired alerts are not evaluated, and saving or removing an alert discards its evaluation state, so a resumed alert starts afresh.

use chrono::{DateTime, Utc};
use egui_charts::model::{Alert, AlertCondition, Bar, Timeframe};
use egui_charts::services::AlertEngine;

let mut alert = Alert::new("AAPL", AlertCondition::CrossingUp(100.0));
alert.timeframe = Some(Timeframe::Min1);
let engine = AlertEngine::new().with_alerts(vec![alert]);
let time = |seconds| DateTime::<Utc>::from_timestamp(seconds, 0).unwrap();
let bar = |seconds, close| Bar::new(time(seconds), close, close, close, close, 1.0);
// The close rises through 100 on the second bar; `update` also takes the chart's source values.
engine.update("AAPL", Timeframe::Min1, &[bar(0, 99.0), bar(60, 101.0)], time(61), |_, _| None);

Implementations§

Source§

impl AlertEngine

Source

pub fn new() -> Self

An engine without alerts. Alerts saved without an id get “1”, “2” and so on, skipping the ids in use.

Source

pub fn on_trigger( self, deliver: impl Fn(&Alert, &AlertEvent) + MaybeSend + 'static, ) -> Self

Calls deliver with the alert and its AlertEvent::TriggeredForSymbol on every trigger, after the event is pushed, so the host can send email, push notifications or web requests. The call comes from the thread that fed the engine and must return at once; it may use the engine.

Source

pub fn with_alerts(self, alerts: Vec<Alert>) -> Self

Starts with alerts as alerts returned them, giving those without an id one after the others.

Source

pub fn alerts(&self) -> Vec<Alert>

The alerts with their current status, for the host to keep.

Source

pub fn subjects(&self, id: &AlertId) -> Vec<String>

Active symbols still armed for id, including watchlist members. A once-per-member alert omits symbols that already fired, so a host can release their subscriptions.

Source

pub fn set_watchlist(&self, id: &str, symbols: Vec<String>)

Sets the members of the watchlist id, as the host’s watchlist holds them. A member that leaves loses its evaluation state, so it starts afresh if it returns.

Source

pub fn update( &self, symbol: &str, timeframe: Timeframe, bars: &[Bar], now: DateTime<Utc>, value: impl Fn(&AlertSource, usize) -> Option<f64>, )

Evaluates every active alert whose subject is symbol on timeframe against the newest of bars, oldest first, at the time now. value resolves a study or drawing source at a bar index of bars, for instance with Chart::alert_value; price and volume come from bars. Call it each frame with the bars of every live chart, but not with a chart in replay.

Source

pub fn update_alert( &self, id: &AlertId, symbol: &str, timeframe: Timeframe, bars: &[Bar], now: DateTime<Utc>, value: impl Fn(&AlertSource, usize) -> Option<f64>, )

Evaluates one alert with its retained source definitions. Other alerts may refer to different study instances with the same chart-local identifiers.

Source

pub fn strategy_fills( &self, run: &str, symbol: &str, timeframe: Timeframe, fills: &[StrategyFill], now: DateTime<Utc>, )

Delivers each new fill of run to matching strategy-fill alerts. Use a unique run id for each Backtest instance, retained for its lifetime, and forward its update batches. Repeated batches are ignored by sequence, including after edits or rearming an alert on the same run and when multiple fills share a timestamp. now gates expiry and notification schedules; event times are the source fill times. Empty messages use the execution side, quantity, price and resulting signed position. Custom messages expand the usual placeholders using a flat bar at the fill price, with its source time and zero volume. Strategy-fill alerts need no price-reader subscription. Delivery callbacks run after unlocking, as they do for price alerts.

Source

pub fn tick(&self, now: DateTime<Utc>)

Marks the alerts whose expiry has passed as expired, without waiting for data. Call it at least once a second.

Trait Implementations§

Source§

impl Alerts for AlertEngine

Source§

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.
Source§

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. Read more
Source§

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.
Source§

fn remove(&self, id: AlertId, reply: Reply<()>)

Deletes the alert id. Answer Ok once it is deleted and push AlertEvent::Remove.
Source§

impl Default for AlertEngine

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts 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 more
Source§

impl<T> MaybeSend for T
where T: Send + Sync + ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

§

fn simd_from(_simd: S, value: T) -> T

§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

§

fn simd_into(self, simd: S) -> T

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.