client.alerts manages price alerts. An alert watches one market's last traded price or index
price and fires once when the price crosses its level. Above fires at or above the level, Below at or below it. A fired alert is delivered in-app, by Telegram, or both.
Alerts belong to the Main Account: use an API key of the Main Account. A key scoped to a sub-account
is refused with Error::PermissionDenied and code SUBACCOUNT_KEY_REFUSED.
Methods
create(params)
Create an alert; returnsPriceAlertlist(opts)
One page of alerts, newest first; returnsPriceAlertsPageall(opts)
A stream over every pageupdate(params)
Change direction, price, or channels; returnsUpdateAlertResultcancel(alert_id)
Cancel an alert; returns thePriceAlert
Create an alert
use polyester::models::{AlertChannel, AlertDirection, AlertPriceSource, CreateAlertParams};
use polyester::Price;
let params = CreateAlertParams::new(
"BTC-USDT",
AlertDirection::Above,
Price::from_decimal_str("100000", Some("BTC-USDT".into()))?,
vec![AlertChannel::InApp],
)
.with_price_source(AlertPriceSource::LastPrice)
.with_idempotency_key("btc-above-100k");
let alert = client.alerts.create(params).await?;
println!("{} {} armed={}", alert.alert_id, alert.status, alert.armed);Prices are exact Price values, as for orders. Without a price source, the alert watches the index
price where the market has one, and the last traded price otherwise. The current price is recorded
as reference_price. An alert whose condition already holds starts unarmed and fires only after the
price moves away and crosses back.
The input types are built with constructors (CreateAlertParams::new, for_symbol_id, UpdateAlertParams::new) and with_... setters, because fields may be added in minor releases. ListAlertsOptions starts from Default::default().
List, update, and cancel
use polyester::models::{AlertStatus, ListAlertsOptions, UpdateAlertParams};
use polyester::Price;
let mut opts = ListAlertsOptions::default();
opts.statuses = vec![AlertStatus::Active, AlertStatus::Triggered];
let page = client.alerts.list(opts).await?;
if let Some(alert) = page.alerts.first() {
let update = UpdateAlertParams::new(alert.alert_id.clone(), alert.revision)
.with_price(Price::from_decimal_str("105000", None)?)
.with_idempotency_key("btc-above-105k");
let result = client.alerts.update(update).await?;
println!("{} {}", result.outcome, result.alert.revision);
client.alerts.cancel(&result.alert.alert_id).await?;
}updatesends only the fields you set, with the alert's last-readrevisionasexpected_revision. A stale revision is refused withREVISION_CONFLICT: read the alert again.- An update that sets no field sets a fired alert again and leaves an active one unchanged.
outcomeis"applied","unchanged"or"replayed". Tell a retry from a fresh change byoutcome, not byrevision.- Statuses keep the API spelling
"cancelled", unlike the triggers'canceled.
Errors and retries
Refusals keep their codes in polyester::errors::alert_codes:
PRICE_UNAVAILABLE: the market's price could not be read. Nothing changed; it is retryable.SERVICE_UNAVAILABLE: the outcome of a create, update, or cancel is unknown. Send it again with the same idempotency key (cancel is idempotent), or read the alerts back.REVISION_CONFLICT,IDEMPOTENCY_CONFLICT,ALERT_LIMIT_REACHED,ALERT_UPDATE_LIMIT_REACHEDandALERT_NOT_FOUNDare final.