kiteconnect_async_wasm/models/portfolio/
holdings.rs1use crate::models::common::{Exchange, Product};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, Serialize, Deserialize)]
6pub struct Holding {
7 pub account_id: String,
9
10 #[serde(rename = "tradingsymbol")]
12 pub trading_symbol: String,
13
14 pub exchange: Exchange,
16
17 pub isin: String,
19
20 pub product: Product,
22
23 #[serde(rename = "instrument_token")]
25 pub instrument_token: u32,
26
27 pub quantity: i32,
29
30 #[serde(rename = "t1_quantity")]
32 pub t1_quantity: i32,
33
34 #[serde(rename = "realised_quantity")]
36 pub realised_quantity: i32,
37
38 #[serde(rename = "authorised_quantity")]
40 pub authorised_quantity: i32,
41
42 #[serde(rename = "authorised_date")]
44 pub authorised_date: Option<String>,
45
46 #[serde(rename = "opening_quantity")]
48 pub opening_quantity: i32,
49
50 #[serde(rename = "collateral_quantity")]
52 pub collateral_quantity: i32,
53
54 #[serde(rename = "collateral_type")]
56 pub collateral_type: Option<String>,
57
58 #[serde(rename = "collateral_update_quantity")]
60 pub collateral_update_quantity: i32,
61
62 pub discrepancy: bool,
64
65 #[serde(rename = "average_price")]
67 pub average_price: f64,
68
69 #[serde(rename = "last_price")]
71 pub last_price: f64,
72
73 #[serde(rename = "close_price")]
75 pub close_price: f64,
76
77 #[serde(rename = "price_change")]
79 pub price_change: f64,
80
81 pub pnl: f64,
83
84 #[serde(rename = "day_change")]
86 pub day_change: f64,
87
88 #[serde(rename = "day_change_percentage")]
90 pub day_change_percentage: f64,
91
92 #[serde(rename = "used_quantity")]
94 pub used_quantity: i32,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
99pub struct HoldingsSummary {
100 pub total_value: f64,
102
103 pub total_investment: f64,
105
106 pub total_pnl: f64,
108
109 pub total_day_change: f64,
111
112 pub total_day_change_percentage: f64,
114
115 pub holdings_count: usize,
117}
118
119#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct PortfolioProfile {
122 #[serde(rename = "user_id")]
124 pub user_id: String,
125
126 #[serde(rename = "equity_used")]
128 pub equity_used: f64,
129
130 #[serde(rename = "equity_available")]
132 pub equity_available: f64,
133
134 #[serde(rename = "commodity_used")]
136 pub commodity_used: f64,
137
138 #[serde(rename = "commodity_available")]
140 pub commodity_available: f64,
141}
142
143impl Holding {
144 pub fn market_value(&self) -> f64 {
146 self.last_price * self.quantity as f64
147 }
148
149 pub fn investment_value(&self) -> f64 {
151 self.average_price * self.quantity as f64
152 }
153
154 pub fn pnl_percentage(&self) -> f64 {
156 let investment = self.investment_value();
157 if investment > 0.0 {
158 (self.pnl / investment) * 100.0
159 } else {
160 0.0
161 }
162 }
163
164 pub fn is_profitable(&self) -> bool {
166 self.pnl > 0.0
167 }
168
169 pub fn is_loss(&self) -> bool {
171 self.pnl < 0.0
172 }
173
174 pub fn available_quantity(&self) -> i32 {
176 self.realised_quantity + self.t1_quantity
177 }
178
179 pub fn can_sell_today(&self) -> bool {
181 self.realised_quantity > 0
182 }
183
184 pub fn sellable_today(&self) -> i32 {
186 self.realised_quantity
187 }
188
189 pub fn sellable_tomorrow(&self) -> i32 {
191 self.t1_quantity
192 }
193
194 pub fn has_discrepancy(&self) -> bool {
196 self.discrepancy
197 }
198
199 pub fn change_from_close(&self) -> f64 {
201 self.last_price - self.close_price
202 }
203
204 pub fn change_percentage_from_close(&self) -> f64 {
206 if self.close_price > 0.0 {
207 ((self.last_price - self.close_price) / self.close_price) * 100.0
208 } else {
209 0.0
210 }
211 }
212
213 pub fn is_pledged(&self) -> bool {
215 self.used_quantity > 0
216 }
217
218 pub fn unpledged_quantity(&self) -> i32 {
220 self.quantity - self.used_quantity
221 }
222}
223
224impl HoldingsSummary {
225 pub fn from_holdings(holdings: &[Holding]) -> Self {
227 let total_value = holdings.iter().map(|h| h.market_value()).sum();
228 let total_investment = holdings.iter().map(|h| h.investment_value()).sum();
229 let total_pnl = holdings.iter().map(|h| h.pnl).sum();
230 let total_day_change = holdings.iter().map(|h| h.day_change).sum();
231
232 let total_day_change_percentage = if total_investment > 0.0 {
233 (total_day_change / total_investment) * 100.0
234 } else {
235 0.0
236 };
237
238 Self {
239 total_value,
240 total_investment,
241 total_pnl,
242 total_day_change,
243 total_day_change_percentage,
244 holdings_count: holdings.len(),
245 }
246 }
247
248 pub fn pnl_percentage(&self) -> f64 {
250 if self.total_investment > 0.0 {
251 (self.total_pnl / self.total_investment) * 100.0
252 } else {
253 0.0
254 }
255 }
256
257 pub fn is_profitable(&self) -> bool {
259 self.total_pnl > 0.0
260 }
261
262 pub fn is_loss(&self) -> bool {
264 self.total_pnl < 0.0
265 }
266}