98 lines
3.5 KiB
TypeScript
98 lines
3.5 KiB
TypeScript
import type { Signal, AssetType, RateRegime } from '../types';
|
||
|
||
export const SIGNAL = {
|
||
STRONG_BUY: '✅ Strong Buy' as Signal,
|
||
MOMENTUM: '⚡ Momentum' as Signal,
|
||
SPECULATION: '⚠️ Speculation' as Signal,
|
||
NEUTRAL: '🔄 Neutral' as Signal,
|
||
AVOID: '❌ Avoid' as Signal,
|
||
};
|
||
|
||
export const ASSET_TYPE = {
|
||
STOCK: 'STOCK' as AssetType,
|
||
ETF: 'ETF' as AssetType,
|
||
BOND: 'BOND' as AssetType,
|
||
CRYPTO: 'crypto',
|
||
};
|
||
|
||
// ── Why some constants use `as const` and others don't ────────────────────
|
||
//
|
||
// SIGNAL / ASSET_TYPE / REGIME — each member is individually cast to its
|
||
// named type (e.g. `'✅ Strong Buy' as Signal`). TypeScript already knows
|
||
// the exact literal type of each value, so `as const` on the object would
|
||
// be redundant.
|
||
//
|
||
// SECTOR / SCORE_MODE / CAP_CATEGORY / GROWTH_CATEGORY — these use
|
||
// `as const` because their public type aliases are *derived* from the
|
||
// object itself via `(typeof X)[keyof typeof X]`. Without `as const`,
|
||
// TypeScript widens every value to `string`, and the derived union
|
||
// collapses to `string` instead of `'TECHNOLOGY' | 'REIT' | ...`.
|
||
// ──────────────────────────────────────────────────────────────────────────
|
||
|
||
export const SECTOR = {
|
||
TECHNOLOGY: 'TECHNOLOGY',
|
||
REIT: 'REIT',
|
||
FINANCIAL: 'FINANCIAL',
|
||
ENERGY: 'ENERGY',
|
||
HEALTHCARE: 'HEALTHCARE',
|
||
COMMUNICATION: 'COMMUNICATION',
|
||
CONSUMER_STAPLES: 'CONSUMER_STAPLES',
|
||
CONSUMER_DISCRETIONARY: 'CONSUMER_DISCRETIONARY',
|
||
GENERAL: 'GENERAL',
|
||
} as const;
|
||
|
||
export type Sector = (typeof SECTOR)[keyof typeof SECTOR];
|
||
|
||
export const SCORE_MODE = {
|
||
FUNDAMENTAL: 'FUNDAMENTAL',
|
||
INFLATED: 'INFLATED',
|
||
} as const;
|
||
|
||
export const REGIME = {
|
||
LOW: 'LOW' as RateRegime,
|
||
NORMAL: 'NORMAL' as RateRegime,
|
||
HIGH: 'HIGH' as RateRegime,
|
||
};
|
||
|
||
export const YAHOO_MODULES: string[] = [
|
||
'assetProfile',
|
||
'financialData',
|
||
'defaultKeyStatistics',
|
||
'price',
|
||
'summaryDetail',
|
||
];
|
||
|
||
export const SIGNAL_ORDER: Record<string, number> = {
|
||
[SIGNAL.STRONG_BUY]: 0,
|
||
[SIGNAL.MOMENTUM]: 1,
|
||
[SIGNAL.NEUTRAL]: 2,
|
||
[SIGNAL.SPECULATION]: 3,
|
||
[SIGNAL.AVOID]: 4,
|
||
};
|
||
|
||
// ── Market capitalisation tiers ───────────────────────────────────────────
|
||
// Thresholds follow institutional convention (MSCI/Russell definitions).
|
||
export const CAP_CATEGORY = {
|
||
MEGA: 'Mega Cap', // > $200B
|
||
LARGE: 'Large Cap', // $10B – $200B
|
||
MID: 'Mid Cap', // $2B – $10B
|
||
SMALL: 'Small Cap', // $300M – $2B
|
||
MICRO: 'Micro Cap', // < $300M
|
||
} as const;
|
||
|
||
export type CapCategory = (typeof CAP_CATEGORY)[keyof typeof CAP_CATEGORY];
|
||
|
||
// ── Growth / style classification ─────────────────────────────────────────
|
||
// Derived from revenue growth, earnings growth, and dividend yield.
|
||
// Used for display and to contextualise signals within each cap tier.
|
||
export const GROWTH_CATEGORY = {
|
||
HIGH_GROWTH: 'High Growth', // rev >15% or earnings >20%
|
||
MODERATE_GROWTH: 'Growth', // rev 5–15%
|
||
STABLE: 'Stable', // low growth, modest or no dividend
|
||
VALUE: 'Value', // low growth + dividend yield ≥ 3%
|
||
TURNAROUND: 'Turnaround', // negative earnings, positive revenue
|
||
DECLINING: 'Declining', // negative revenue growth
|
||
} as const;
|
||
|
||
export type GrowthCategory = (typeof GROWTH_CATEGORY)[keyof typeof GROWTH_CATEGORY];
|