Skip to main content

longbridge/alert/
types.rs

1use rust_decimal::Decimal;
2use serde::{Deserialize, Serialize};
3
4/// Response for [`crate::AlertContext::list`]
5#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct AlertList {
7    /// Alert groups per security
8    pub lists: Vec<AlertSymbolGroup>,
9}
10
11/// Alert items for one security
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub struct AlertSymbolGroup {
14    /// Security symbol
15    pub symbol: String,
16    /// Ticker code (without market)
17    pub code: String,
18    /// Market, e.g. `"HK"`
19    pub market: String,
20    /// Security name
21    pub name: String,
22    /// Latest price
23    #[serde(with = "crate::serde_utils::decimal_opt_str_is_none")]
24    pub price: Option<Decimal>,
25    /// Day change amount
26    #[serde(with = "crate::serde_utils::decimal_opt_str_is_none")]
27    pub chg: Option<Decimal>,
28    /// Day change percentage
29    #[serde(with = "crate::serde_utils::decimal_opt_str_is_none")]
30    pub p_chg: Option<Decimal>,
31    /// Product type (may be empty)
32    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
33    pub product: String,
34    /// Alert items
35    pub indicators: Vec<AlertItem>,
36}
37
38/// One price alert
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct AlertItem {
41    /// Alert ID
42    pub id: String,
43    /// Condition: "1"=price_rise, "2"=price_fall, "3"=pct_rise, "4"=pct_fall
44    pub indicator_id: String,
45    /// Whether the alert is active
46    pub enabled: bool,
47    /// Frequency: 1=daily, 2=every_time, 3=once
48    pub frequency: i32,
49    /// Scope
50    pub scope: i32,
51    /// Display text, e.g. "价格涨到 600"
52    pub text: String,
53    /// Trigger state flags
54    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
55    pub state: Vec<i32>,
56    /// Trigger value, e.g. `{"price":"500"}` or `{"chg":"5"}`
57    pub value_map: AlertValueMap,
58}
59
60/// Trigger value of a price alert.
61///
62/// Exactly one field is populated, depending on the alert condition: `price`
63/// for absolute-price alerts ([`AlertCondition::PriceRise`] /
64/// [`AlertCondition::PriceFall`]), `chg` for percentage-change alerts
65/// ([`AlertCondition::PercentRise`] / [`AlertCondition::PercentFall`]).
66#[derive(Debug, Clone, Default, Serialize, Deserialize)]
67pub struct AlertValueMap {
68    /// Absolute price threshold, e.g. `500`.
69    #[serde(
70        default,
71        with = "crate::serde_utils::decimal_opt_str_is_none",
72        skip_serializing_if = "Option::is_none"
73    )]
74    pub price: Option<Decimal>,
75    /// Percentage-change threshold, e.g. `5`.
76    #[serde(
77        default,
78        with = "crate::serde_utils::f64_opt_str",
79        skip_serializing_if = "Option::is_none"
80    )]
81    pub chg: Option<f64>,
82}
83
84/// Alert condition
85#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
86pub enum AlertCondition {
87    /// Price rises above threshold
88    #[serde(rename = "1")]
89    PriceRise = 1,
90    /// Price falls below threshold
91    #[serde(rename = "2")]
92    PriceFall = 2,
93    /// Percentage rise above threshold
94    #[serde(rename = "3")]
95    PercentRise = 3,
96    /// Percentage fall below threshold
97    #[serde(rename = "4")]
98    PercentFall = 4,
99}
100
101/// Alert trigger frequency
102#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
103pub enum AlertFrequency {
104    /// Trigger once per day
105    #[serde(rename = "1")]
106    Daily = 1,
107    /// Trigger every time condition is met
108    #[serde(rename = "2")]
109    EveryTime = 2,
110    /// Trigger only once
111    #[serde(rename = "3")]
112    Once = 3,
113}