Skip to main content

fyuz/models/
analytics.rs

1//! Token analytics, wallet performance and portfolios.
2//!
3//! Everything in this module is a server-side aggregate and arrives as JSON
4//! numbers, so `f64` is the faithful model here — unlike balances, which stay
5//! decimal strings.
6
7use serde::Deserialize;
8
9/// Holder concentration and flow analytics for one token.
10#[derive(Debug, Clone, Deserialize)]
11#[serde(rename_all = "camelCase")]
12pub struct TokenAnalytics {
13    /// Token contract address.
14    pub token_address: String,
15    /// Chain slug.
16    pub network: String,
17    /// Number of addresses with a positive balance.
18    pub holder_count: i64,
19    /// Share of supply held by the top 10 holders.
20    pub top10_pct: f64,
21    /// Share of supply held by the creator.
22    pub creator_pct: f64,
23    /// Lifetime buy count.
24    pub buys: i64,
25    /// Lifetime sell count.
26    pub sells: i64,
27    /// Lifetime USD volume.
28    pub volume_usd: f64,
29    /// Progress toward the $30,000 graduation target, 0-100.
30    pub graduation_pct: f64,
31    /// `true` once graduated to a DEX pair.
32    pub launched: bool,
33    /// Addresses that bought in the launch block.
34    pub bundle_buyers: i64,
35    /// `true` when the launch-block buying pattern looks like a bundle.
36    pub bundle_flag: bool,
37}
38
39/// One of a token's most profitable traders.
40#[derive(Debug, Clone, Deserialize)]
41#[serde(rename_all = "camelCase")]
42pub struct TopTrader {
43    /// Wallet address.
44    pub address: String,
45    /// Display name, when set.
46    #[serde(default)]
47    pub username: Option<String>,
48    /// Avatar URL, when set.
49    #[serde(default)]
50    pub avatar: Option<String>,
51    /// Realised PnL in USD.
52    pub realized_pnl_usd: f64,
53    /// Unrealised PnL in USD on the still-held position.
54    pub unrealized_pnl_usd: f64,
55    /// Realised plus unrealised PnL in USD.
56    pub total_pnl_usd: f64,
57    /// USD volume traded in this token.
58    pub volume_usd: f64,
59    /// `true` when this wallet launched the token.
60    pub is_creator: bool,
61}
62
63/// Average-cost performance for a wallet, rolled up across every token traded.
64#[derive(Debug, Clone, Deserialize)]
65#[serde(rename_all = "camelCase")]
66pub struct WalletStats {
67    /// Wallet address.
68    pub address: String,
69    /// Display name, when set.
70    #[serde(default)]
71    pub username: Option<String>,
72    /// Avatar URL, when set.
73    #[serde(default)]
74    pub avatar: Option<String>,
75    /// Lifetime USD volume.
76    pub volume_usd: f64,
77    /// Realised PnL in USD.
78    pub realized_pnl_usd: f64,
79    /// Unrealised PnL in USD.
80    pub unrealized_pnl_usd: f64,
81    /// Realised plus unrealised PnL in USD.
82    pub total_pnl_usd: f64,
83    /// Return on invested capital, percent.
84    pub roi_pct: f64,
85    /// Share of traded tokens that are net profitable, 0-1.
86    pub win_rate: f64,
87    /// Distinct tokens traded.
88    pub tokens_traded: i64,
89    /// Lifetime trade count.
90    pub trade_count: i64,
91    /// USD value of everything still held.
92    pub holding_value_usd: f64,
93}
94
95/// One token still held by an address.
96///
97/// Average-cost basis. Dust positions (balance <= 1e-6) are omitted by the
98/// server.
99#[derive(Debug, Clone, Deserialize)]
100#[serde(rename_all = "camelCase")]
101pub struct PortfolioPosition {
102    /// Token contract address.
103    pub token_address: String,
104    /// Token name.
105    pub name: String,
106    /// Token ticker.
107    pub symbol: String,
108    /// Token image URL.
109    #[serde(default)]
110    pub image: Option<String>,
111    /// Chain slug.
112    pub network: String,
113    /// Net tokens held (buys minus sells), in whole tokens.
114    pub balance: f64,
115    /// Current token price in USD.
116    pub current_price_usd: f64,
117    /// Current position value in USD.
118    pub value_usd: f64,
119    /// Cost basis of the position in USD.
120    pub cost_usd: f64,
121    /// Average buy price in USD.
122    pub avg_buy_price_usd: f64,
123    /// Unrealised PnL in USD.
124    pub unrealized_pnl_usd: f64,
125    /// Unrealised PnL, percent of cost.
126    pub unrealized_pnl_pct: f64,
127    /// Realised PnL in USD on this token.
128    pub realized_pnl_usd: f64,
129}
130
131/// Live average-cost PnL for an address.
132///
133/// An address with no trades returns zeroed totals and an empty
134/// [`positions`](Self::positions) array rather than a 404.
135#[derive(Debug, Clone, Deserialize)]
136#[serde(rename_all = "camelCase")]
137pub struct Portfolio {
138    /// Wallet address.
139    pub address: String,
140    /// USD value of everything held.
141    pub total_value_usd: f64,
142    /// USD cost basis of everything held.
143    pub total_cost_usd: f64,
144    /// Unrealised PnL in USD.
145    pub unrealized_pnl_usd: f64,
146    /// Realised PnL in USD.
147    pub realized_pnl_usd: f64,
148    /// Realised plus unrealised PnL in USD.
149    pub total_pnl_usd: f64,
150    /// Return on invested capital, percent.
151    pub roi_pct: f64,
152    /// Open positions, highest value first.
153    pub positions: Vec<PortfolioPosition>,
154}