Skip to main content

longbridge/dca/
types.rs

1use rust_decimal::Decimal;
2use serde::{Deserialize, Serialize};
3
4use crate::types::Market;
5
6/// Response for [`crate::DCAContext::list`] and write operations
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct DcaList {
9    /// DCA plans
10    pub plans: Vec<DcaPlan>,
11}
12
13/// One DCA (dollar-cost averaging) investment plan
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct DcaPlan {
16    /// Plan ID
17    pub plan_id: String,
18    /// Status
19    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
20    pub status: DCAStatus,
21    /// Security symbol
22    pub symbol: String,
23    /// Member ID
24    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
25    pub member_id: String,
26    /// Account ID
27    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
28    pub aaid: String,
29    /// Account channel
30    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
31    pub account_channel: String,
32    /// Display account
33    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
34    pub display_account: String,
35    /// Market
36    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
37    pub market: Market,
38    /// Investment amount per period
39    #[serde(default, with = "crate::serde_utils::decimal_empty_is_0")]
40    pub per_invest_amount: Decimal,
41    /// Investment frequency
42    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
43    pub invest_frequency: DCAFrequency,
44    /// Day of week for weekly plans (e.g. `"Mon"`)
45    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
46    pub invest_day_of_week: String,
47    /// Day of month for monthly plans
48    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
49    pub invest_day_of_month: String,
50    /// Whether margin finance is allowed
51    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
52    pub allow_margin_finance: bool,
53    /// Reminder notification hours before execution (API may return integer or
54    /// string)
55    #[serde(
56        default,
57        deserialize_with = "crate::serde_utils::deserialize_string_or_int_as_string"
58    )]
59    pub alter_hours: String,
60    /// Creation time
61    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
62    pub created_at: String,
63    /// Last updated time
64    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
65    pub updated_at: String,
66    /// Next investment date
67    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
68    pub next_trd_date: String,
69    /// Security name
70    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
71    pub stock_name: String,
72    /// Cumulative invested amount
73    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
74    pub cum_amount: Option<Decimal>,
75    /// Number of completed investment periods
76    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
77    pub issue_number: i64,
78    /// Average cost
79    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
80    pub average_cost: Option<Decimal>,
81    /// Cumulative profit/loss
82    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
83    pub cum_profit: Option<Decimal>,
84}
85
86/// Response for [`crate::DCAContext::stats`]
87#[derive(Debug, Clone, Default, Serialize, Deserialize)]
88pub struct DcaStats {
89    /// Number of active plans
90    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
91    pub active_count: String,
92    /// Number of finished plans
93    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
94    pub finished_count: String,
95    /// Number of suspended plans
96    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
97    pub suspended_count: String,
98    /// Nearest upcoming plans
99    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
100    pub nearest_plans: Vec<DcaPlan>,
101    /// Days until next investment
102    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
103    pub rest_days: String,
104    /// Total invested amount
105    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
106    pub total_amount: Option<Decimal>,
107    /// Total profit/loss
108    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
109    pub total_profit: Option<Decimal>,
110}
111
112/// Response for [`crate::DCAContext::check_support`]
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct DcaSupportList {
115    /// Support info per security
116    pub infos: Vec<DcaSupportInfo>,
117}
118
119/// DCA support info for one security
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct DcaSupportInfo {
122    /// Security symbol
123    pub symbol: String,
124    /// Whether DCA is supported for this security
125    pub support_regular_saving: bool,
126}
127
128/// Response for [`crate::DCAContext::history`]
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct DcaHistoryResponse {
131    /// Execution history records
132    pub records: Vec<DcaHistoryRecord>,
133    /// Whether more records exist
134    #[serde(default, deserialize_with = "crate::serde_utils::null_as_default")]
135    pub has_more: bool,
136}
137
138/// One DCA execution record
139#[derive(Debug, Clone, Serialize, Deserialize)]
140pub struct DcaHistoryRecord {
141    /// Execution time
142    pub created_at: String,
143    /// Associated order ID
144    pub order_id: String,
145    /// Status
146    pub status: String,
147    /// Action type
148    pub action: String,
149    /// Order type
150    pub order_type: String,
151    /// Executed quantity
152    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
153    pub executed_qty: Option<Decimal>,
154    /// Executed price
155    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
156    pub executed_price: Option<Decimal>,
157    /// Executed amount
158    #[serde(default, with = "crate::serde_utils::decimal_opt_str_is_none")]
159    pub executed_amount: Option<Decimal>,
160    /// Rejection reason (if any)
161    pub rejected_reason: String,
162    /// Security symbol
163    pub symbol: String,
164}
165
166/// DCA investment frequency
167#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Default)]
168pub enum DCAFrequency {
169    /// Daily investment
170    #[serde(rename = "Daily")]
171    Daily,
172    /// Weekly investment
173    #[serde(rename = "Weekly")]
174    Weekly,
175    /// Fortnightly (every two weeks) investment
176    #[serde(rename = "Fortnightly")]
177    Fortnightly,
178    /// Monthly investment
179    #[default]
180    #[serde(rename = "Monthly")]
181    Monthly,
182}
183
184/// Response for [`crate::DCAContext::create`] and [`crate::DCAContext::update`]
185#[derive(Debug, Clone, Serialize, Deserialize)]
186pub struct DcaCreateResult {
187    /// The plan ID of the created or updated plan
188    pub plan_id: String,
189}
190
191/// Response for [`crate::DCAContext::calc_date`]
192#[derive(Debug, Clone, Serialize, Deserialize)]
193pub struct DcaCalcDateResult {
194    /// Next projected trade date (unix timestamp string)
195    pub trade_date: String,
196}
197
198/// DCA plan status
199#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Default)]
200pub enum DCAStatus {
201    /// Active plan
202    #[default]
203    #[serde(rename = "Active")]
204    Active,
205    /// Suspended plan
206    #[serde(rename = "Suspended")]
207    Suspended,
208    /// Finished plan
209    #[serde(rename = "Finished")]
210    Finished,
211}