Skip to main content

coinbase_advanced/models/
portfolio.rs

1//! Portfolio-related types.
2
3use serde::{Deserialize, Serialize};
4
5/// Portfolio type.
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
7#[serde(rename_all = "UPPERCASE")]
8pub enum PortfolioType {
9    /// User's default portfolio.
10    Default,
11    /// Portfolios created by the user.
12    Consumer,
13    /// International Exchange portfolios.
14    Intx,
15    /// Unknown/undefined portfolio type.
16    #[serde(other)]
17    Undefined,
18}
19
20/// A user's portfolio.
21#[derive(Debug, Clone, Deserialize)]
22pub struct Portfolio {
23    /// Name of the portfolio.
24    pub name: String,
25    /// UUID of the portfolio.
26    pub uuid: String,
27    /// Type of the portfolio.
28    #[serde(rename = "type")]
29    pub portfolio_type: PortfolioType,
30    /// Whether the portfolio is deleted.
31    #[serde(default)]
32    pub deleted: bool,
33}
34
35/// Balance information.
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct PortfolioBalance {
38    /// The balance value.
39    pub value: String,
40    /// The currency.
41    pub currency: String,
42}
43
44/// Portfolio balances breakdown.
45#[derive(Debug, Clone, Deserialize)]
46pub struct PortfolioBalances {
47    /// Total balance.
48    pub total_balance: PortfolioBalance,
49    /// Total futures balance.
50    #[serde(default)]
51    pub total_futures_balance: Option<PortfolioBalance>,
52    /// Total cash equivalent balance.
53    #[serde(default)]
54    pub total_cash_equivalent_balance: Option<PortfolioBalance>,
55    /// Total crypto balance.
56    #[serde(default)]
57    pub total_crypto_balance: Option<PortfolioBalance>,
58    /// Futures unrealized PnL.
59    #[serde(default)]
60    pub futures_unrealized_pnl: Option<PortfolioBalance>,
61    /// Perpetuals unrealized PnL.
62    #[serde(default)]
63    pub perp_unrealized_pnl: Option<PortfolioBalance>,
64}
65
66/// Spot position in a portfolio.
67#[derive(Debug, Clone, Deserialize)]
68pub struct SpotPosition {
69    /// The asset symbol (e.g., BTC, ETH).
70    pub asset: String,
71    /// The account UUID.
72    pub account_uuid: String,
73    /// Total balance in fiat.
74    #[serde(default)]
75    pub total_balance_fiat: f64,
76    /// Total balance in crypto.
77    #[serde(default)]
78    pub total_balance_crypto: f64,
79    /// Available to trade in fiat.
80    #[serde(default)]
81    pub available_to_trade_fiat: f64,
82    /// Portfolio allocation percentage.
83    #[serde(default)]
84    pub allocation: f64,
85    /// Cost basis.
86    #[serde(default)]
87    pub cost_basis: Option<PortfolioBalance>,
88    /// Asset image URL.
89    #[serde(default)]
90    pub asset_img_url: Option<String>,
91    /// Whether this is a cash position.
92    #[serde(default)]
93    pub is_cash: bool,
94}
95
96/// Portfolio breakdown with positions.
97#[derive(Debug, Clone, Deserialize)]
98pub struct PortfolioBreakdown {
99    /// The portfolio.
100    pub portfolio: Portfolio,
101    /// Portfolio balances.
102    #[serde(default)]
103    pub portfolio_balances: Option<PortfolioBalances>,
104    /// Spot positions.
105    #[serde(default)]
106    pub spot_positions: Vec<SpotPosition>,
107    /// Perpetual positions (raw JSON for flexibility).
108    #[serde(default)]
109    pub perp_positions: Vec<serde_json::Value>,
110    /// Futures positions (raw JSON for flexibility).
111    #[serde(default)]
112    pub futures_positions: Vec<serde_json::Value>,
113}
114
115/// Response containing a list of portfolios.
116#[derive(Debug, Clone, Deserialize)]
117pub struct ListPortfoliosResponse {
118    /// The portfolios.
119    pub portfolios: Vec<Portfolio>,
120}
121
122/// Response containing a portfolio breakdown.
123#[derive(Debug, Clone, Deserialize)]
124pub struct GetPortfolioBreakdownResponse {
125    /// The breakdown.
126    pub breakdown: PortfolioBreakdown,
127}
128
129/// Response containing a single portfolio.
130#[derive(Debug, Clone, Deserialize)]
131pub struct PortfolioResponse {
132    /// The portfolio.
133    pub portfolio: Portfolio,
134}
135
136/// Parameters for listing portfolios.
137#[derive(Debug, Clone, Default, Serialize)]
138pub struct ListPortfoliosParams {
139    /// Filter by portfolio type.
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub portfolio_type: Option<String>,
142}
143
144impl ListPortfoliosParams {
145    /// Create new list portfolios parameters.
146    pub fn new() -> Self {
147        Self::default()
148    }
149
150    /// Filter by portfolio type.
151    pub fn portfolio_type(mut self, portfolio_type: impl Into<String>) -> Self {
152        self.portfolio_type = Some(portfolio_type.into());
153        self
154    }
155}
156
157/// Request to create a portfolio.
158#[derive(Debug, Clone, Serialize)]
159pub struct CreatePortfolioRequest {
160    /// The portfolio name.
161    pub name: String,
162}
163
164impl CreatePortfolioRequest {
165    /// Create a new create portfolio request.
166    pub fn new(name: impl Into<String>) -> Self {
167        Self { name: name.into() }
168    }
169}
170
171/// Request to edit a portfolio.
172#[derive(Debug, Clone, Serialize)]
173pub struct EditPortfolioRequest {
174    /// The new portfolio name.
175    pub name: String,
176}
177
178impl EditPortfolioRequest {
179    /// Create a new edit portfolio request.
180    pub fn new(name: impl Into<String>) -> Self {
181        Self { name: name.into() }
182    }
183}
184
185/// Funds to move between portfolios.
186#[derive(Debug, Clone, Serialize)]
187pub struct MoveFunds {
188    /// The amount value.
189    pub value: String,
190    /// The currency.
191    pub currency: String,
192}
193
194impl MoveFunds {
195    /// Create new funds.
196    pub fn new(value: impl Into<String>, currency: impl Into<String>) -> Self {
197        Self {
198            value: value.into(),
199            currency: currency.into(),
200        }
201    }
202}
203
204/// Request to move funds between portfolios.
205#[derive(Debug, Clone, Serialize)]
206pub struct MoveFundsRequest {
207    /// The funds to move.
208    pub funds: MoveFunds,
209    /// Source portfolio UUID.
210    pub source_portfolio_uuid: String,
211    /// Target portfolio UUID.
212    pub target_portfolio_uuid: String,
213}
214
215impl MoveFundsRequest {
216    /// Create a new move funds request.
217    pub fn new(
218        funds: MoveFunds,
219        source_portfolio_uuid: impl Into<String>,
220        target_portfolio_uuid: impl Into<String>,
221    ) -> Self {
222        Self {
223            funds,
224            source_portfolio_uuid: source_portfolio_uuid.into(),
225            target_portfolio_uuid: target_portfolio_uuid.into(),
226        }
227    }
228}
229
230/// Response from moving funds.
231#[derive(Debug, Clone, Deserialize)]
232pub struct MoveFundsResponse {
233    /// Source portfolio UUID.
234    pub source_portfolio_uuid: String,
235    /// Target portfolio UUID.
236    pub target_portfolio_uuid: String,
237}