59 lines
2 KiB
TypeScript
59 lines
2 KiB
TypeScript
/**
|
|
* Returns Top source % and HHI-based traffic light (HHI hidden from UI)
|
|
* Uses Herfindahl-Hirschman Index internally but only exposes traffic light color
|
|
*/
|
|
export const useConcentration = () => {
|
|
const calculateTopSourcePct = (revenueShares: number[]): number => {
|
|
if (revenueShares.length === 0) return 0
|
|
return Math.max(...revenueShares)
|
|
}
|
|
|
|
const calculateHHI = (revenueShares: number[]): number => {
|
|
// HHI = sum of squared market shares (as percentages)
|
|
return revenueShares.reduce((sum, share) => sum + (share * share), 0)
|
|
}
|
|
|
|
const getConcentrationStatus = (topSourcePct: number, hhi: number): 'green' | 'yellow' | 'red' => {
|
|
// Primary threshold based on top source %
|
|
if (topSourcePct > 50) return 'red'
|
|
if (topSourcePct > 35) return 'yellow'
|
|
|
|
// Secondary check using HHI for more nuanced analysis
|
|
if (hhi > 2500) return 'red' // Highly concentrated
|
|
if (hhi > 1500) return 'yellow' // Moderately concentrated
|
|
|
|
return 'green'
|
|
}
|
|
|
|
const getConcentrationMessage = (status: 'green' | 'yellow' | 'red'): string => {
|
|
switch (status) {
|
|
case 'red':
|
|
return 'Most of your money comes from one place. Add another stream to reduce risk.'
|
|
case 'yellow':
|
|
return 'Revenue somewhat concentrated. Consider diversifying further.'
|
|
case 'green':
|
|
return 'Good revenue diversification.'
|
|
}
|
|
}
|
|
|
|
const analyzeConcentration = (revenueStreams: Array<{ targetPct: number }>) => {
|
|
const shares = revenueStreams.map(stream => stream.targetPct || 0)
|
|
const topSourcePct = calculateTopSourcePct(shares)
|
|
const hhi = calculateHHI(shares)
|
|
const status = getConcentrationStatus(topSourcePct, hhi)
|
|
|
|
return {
|
|
topSourcePct,
|
|
status,
|
|
message: getConcentrationMessage(status)
|
|
// Note: HHI is deliberately not exposed in return
|
|
}
|
|
}
|
|
|
|
return {
|
|
calculateTopSourcePct,
|
|
getConcentrationStatus,
|
|
getConcentrationMessage,
|
|
analyzeConcentration
|
|
}
|
|
}
|