summaryrefslogtreecommitdiff
path: root/frontend
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-06-29 01:41:26 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-06-29 01:41:26 -0700
commitca54e9313894600feac548b13da8fab335db2905 (patch)
tree7eff74d8d77eecbbf68640d3bbb5776db5cdbb69 /frontend
parent53e7bce26a21ab3853712ab53a38c6760b4ab25a (diff)
feat: update frontend API types, client and formatters
Diffstat (limited to 'frontend')
-rw-r--r--frontend/lib/api.ts7
-rw-r--r--frontend/lib/format.ts31
-rw-r--r--frontend/types/api.ts50
3 files changed, 80 insertions, 8 deletions
diff --git a/frontend/lib/api.ts b/frontend/lib/api.ts
index 2635af5..a584241 100644
--- a/frontend/lib/api.ts
+++ b/frontend/lib/api.ts
@@ -1,4 +1,4 @@
-import type { FilingsResponse, FinancialsResponse, HistoryPoint, InsidersResponse, MarketIndex, NewsResponse, RatiosResponse, SearchResult, TickerOverview, ValuationResponse, WatchlistResponse } from "@/types/api";
+import type { FilingsResponse, FinancialsResponse, HistoryPoint, InsidersResponse, MarketIndex, NewsResponse, RatiosResponse, SearchResult, TickerOverview, ValuationResponse, WaccResponse, WatchlistResponse } from "@/types/api";
const API_BASE = (process.env.NEXT_PUBLIC_API_BASE_URL || "").trim().replace(/\/$/, "");
@@ -59,6 +59,11 @@ export const api = {
`/api/tickers/${encodeURIComponent(symbol)}/valuation`
);
},
+ wacc(symbol: string) {
+ return request<WaccResponse>(
+ `/api/tickers/${encodeURIComponent(symbol)}/wacc`
+ );
+ },
ratios(symbol: string) {
return request<RatiosResponse>(
`/api/tickers/${encodeURIComponent(symbol)}/ratios`
diff --git a/frontend/lib/format.ts b/frontend/lib/format.ts
index 6a1fcc2..e4bae13 100644
--- a/frontend/lib/format.ts
+++ b/frontend/lib/format.ts
@@ -1,6 +1,22 @@
-export function fmtCurrency(value?: number | null, decimals = 2): string {
+const CURRENCY_SYMBOLS: Record<string, string> = {
+ USD: "$",
+ CAD: "C$",
+ GBP: "£",
+ EUR: "€",
+ JPY: "¥",
+ AUD: "A$",
+ CHF: "CHF ",
+ CNY: "CN¥",
+ HKD: "HK$",
+};
+
+function currencySymbol(currency = "USD"): string {
+ return CURRENCY_SYMBOLS[currency.toUpperCase()] || `${currency.toUpperCase()} `;
+}
+
+export function fmtCurrency(value?: number | null, decimals = 2, currency = "USD"): string {
if (value === null || value === undefined || Number.isNaN(value)) return "-";
- return `$${value.toLocaleString(undefined, { maximumFractionDigits: decimals, minimumFractionDigits: decimals })}`;
+ return `${currencySymbol(currency)}${value.toLocaleString(undefined, { maximumFractionDigits: decimals, minimumFractionDigits: decimals })}`;
}
export function fmtNumber(value?: number | null, decimals = 2): string {
@@ -8,14 +24,15 @@ export function fmtNumber(value?: number | null, decimals = 2): string {
return value.toLocaleString(undefined, { maximumFractionDigits: decimals, minimumFractionDigits: decimals });
}
-export function fmtLarge(value?: number | null): string {
+export function fmtLarge(value?: number | null, currency = "USD"): string {
if (value === null || value === undefined || Number.isNaN(value)) return "-";
const abs = Math.abs(value);
const sign = value < 0 ? "-" : "";
- if (abs >= 1e12) return `${sign}$${(abs / 1e12).toFixed(2)}T`;
- if (abs >= 1e9) return `${sign}$${(abs / 1e9).toFixed(2)}B`;
- if (abs >= 1e6) return `${sign}$${(abs / 1e6).toFixed(1)}M`;
- return `${sign}$${abs.toLocaleString(undefined, { maximumFractionDigits: 0 })}`;
+ const symbol = currencySymbol(currency);
+ if (abs >= 1e12) return `${sign}${symbol}${(abs / 1e12).toFixed(2)}T`;
+ if (abs >= 1e9) return `${sign}${symbol}${(abs / 1e9).toFixed(2)}B`;
+ if (abs >= 1e6) return `${sign}${symbol}${(abs / 1e6).toFixed(1)}M`;
+ return `${sign}${symbol}${abs.toLocaleString(undefined, { maximumFractionDigits: 0 })}`;
}
export function fmtPct(value?: number | null, decimals = 2, signed = false): string {
diff --git a/frontend/types/api.ts b/frontend/types/api.ts
index 8143d56..3b2cd70 100644
--- a/frontend/types/api.ts
+++ b/frontend/types/api.ts
@@ -25,6 +25,8 @@ export type Signal = {
};
export type TickerOverview = {
+ currency: string;
+ currency_warning: string | null;
profile: {
symbol: string;
name: string;
@@ -115,12 +117,33 @@ export type FinancialStatement = {
};
export type FinancialsResponse = {
+ currency: string;
+ currency_warning: string | null;
period: "annual" | "quarterly";
income: FinancialStatement;
balance: FinancialStatement;
cash_flow: FinancialStatement;
};
+export type AdvancedDcfInputs = {
+ base_revenue: number;
+ revenue_growth: number[];
+ ebitda_margin: number[];
+ dna_pct_revenue: number[];
+ capex_pct_revenue: number[];
+ nwc_chg_pct_delta_rev: number[];
+ tax_rate: number[];
+ wacc: number;
+ terminal_growth: number;
+ projection_years: number;
+};
+
+export type SensitivityMatrix = {
+ wacc: number[];
+ terminal_growth: number[];
+ implied_prices: (number | null)[][];
+};
+
export type DcfResult = {
available: boolean;
error?: string | null;
@@ -137,6 +160,8 @@ export type DcfResult = {
wacc: number;
terminal_growth: number;
projection_years: number;
+ sensitivity?: SensitivityMatrix | null;
+ advanced_inputs?: AdvancedDcfInputs | null;
};
export type MultipleResult = {
@@ -149,6 +174,8 @@ export type MultipleResult = {
};
export type ValuationResponse = {
+ currency: string;
+ currency_warning: string | null;
symbol: string;
current_price?: number | null;
shares_outstanding?: number | null;
@@ -158,6 +185,27 @@ export type ValuationResponse = {
price_to_book: MultipleResult;
};
+export type WaccResponse = {
+ currency: string;
+ currency_warning: string | null;
+ symbol: string;
+ available: boolean;
+ wacc?: number | null;
+ cost_of_equity?: number | null;
+ after_tax_cost_of_debt?: number | null;
+ risk_free_rate: number;
+ beta: number;
+ equity_risk_premium: number;
+ cost_of_debt: number;
+ tax_rate: number;
+ market_cap?: number | null;
+ total_debt?: number | null;
+ cash?: number | null;
+ net_debt?: number | null;
+ equity_weight?: number | null;
+ debt_weight?: number | null;
+};
+
export type RatioPoint = {
value: number | null;
spark: (number | null)[];
@@ -230,6 +278,8 @@ export type FilingsResponse = {
};
export type RatiosResponse = {
+ currency: string;
+ currency_warning: string | null;
pe_ttm: RatioPoint;
ev_ebitda: RatioPoint;
gross_margin: RatioPoint;