c4f2673799
New market_regime_service computes a benchmark (SPY) trend from its 50/200-day SMAs, cached in a SystemSetting and refreshed by a nightly job; GET /market/regime exposes it. Dashboard shows a regime banner; setup cards flag a counter-trend caution when a setup fights the regime (LONG in a bearish market / SHORT in a bullish one). Informational only — nothing is suppressed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
45 lines
1.2 KiB
TypeScript
45 lines
1.2 KiB
TypeScript
import type { MarketRegime } from './types';
|
|
|
|
export function regimeColor(label: MarketRegime['label']): string {
|
|
switch (label) {
|
|
case 'bullish':
|
|
return 'text-emerald-400';
|
|
case 'bearish':
|
|
return 'text-red-400';
|
|
case 'neutral':
|
|
return 'text-amber-400';
|
|
default:
|
|
return 'text-gray-400';
|
|
}
|
|
}
|
|
|
|
export function regimeDot(label: MarketRegime['label']): string {
|
|
switch (label) {
|
|
case 'bullish':
|
|
return 'bg-emerald-400';
|
|
case 'bearish':
|
|
return 'bg-red-400';
|
|
case 'neutral':
|
|
return 'bg-amber-400';
|
|
default:
|
|
return 'bg-gray-600';
|
|
}
|
|
}
|
|
|
|
export function regimeHeadline(r: MarketRegime): string {
|
|
const b = r.benchmark ?? 'SPY';
|
|
if (r.label === 'unknown') return `${b} trend unknown`;
|
|
const pct =
|
|
r.pct_above_200 != null
|
|
? ` · ${r.pct_above_200 >= 0 ? '+' : ''}${r.pct_above_200.toFixed(1)}% vs 200-day`
|
|
: '';
|
|
return `${b} ${r.label}${pct}`;
|
|
}
|
|
|
|
/** Whether a setup direction fights the prevailing market regime. */
|
|
export function isCounterTrend(direction: string, label: MarketRegime['label']): boolean {
|
|
if (label === 'bullish') return direction === 'short';
|
|
if (label === 'bearish') return direction === 'long';
|
|
return false;
|
|
}
|