feat: show FIP path-smoothness in ticker technicals
Display-only Da/Gurun/Warachka information discreteness on the ticker indicator panel. Shared compute with the backtest harness; not wired into gate or rank.
This commit is contained in:
@@ -2,7 +2,15 @@ import { useQuery } from '@tanstack/react-query';
|
||||
import { getIndicator, getEMACross } from '../../api/indicators';
|
||||
import type { IndicatorResult } from '../../lib/types';
|
||||
|
||||
const INDICATOR_TYPES = ['RSI', 'ADX', 'EMA', 'ATR', 'volume_profile', 'pivot_points'] as const;
|
||||
const INDICATOR_TYPES = [
|
||||
'RSI',
|
||||
'ADX',
|
||||
'EMA',
|
||||
'ATR',
|
||||
'volume_profile',
|
||||
'pivot_points',
|
||||
'fip_id',
|
||||
] as const;
|
||||
|
||||
const INDICATOR_LABELS: Record<string, string> = {
|
||||
RSI: 'RSI',
|
||||
@@ -11,6 +19,7 @@ const INDICATOR_LABELS: Record<string, string> = {
|
||||
ATR: 'ATR · volatility',
|
||||
volume_profile: 'Volume profile',
|
||||
pivot_points: 'Pivot points',
|
||||
fip_id: 'FIP · path smoothness',
|
||||
};
|
||||
|
||||
interface IndicatorSelectorProps {
|
||||
@@ -181,6 +190,22 @@ function interpretation(
|
||||
return { text: 'between pivots', tone: 'text-gray-400' };
|
||||
}
|
||||
|
||||
case 'fip_id': {
|
||||
// Display context only — not a production gate input.
|
||||
const label = typeof v.path_label === 'string' ? v.path_label : null;
|
||||
const path = typeof v.path === 'string' ? v.path : null;
|
||||
if (label) {
|
||||
if (path === 'continuous') return { text: label, tone: 'text-emerald-300' };
|
||||
if (path === 'discrete') return { text: label, tone: 'text-amber-300' };
|
||||
return { text: label, tone: 'text-gray-300' };
|
||||
}
|
||||
const fip = num('fip_id');
|
||||
if (fip == null) return null;
|
||||
if (fip <= -0.25) return { text: 'smooth grind (continuous)', tone: 'text-emerald-300' };
|
||||
if (fip >= 0.25) return { text: 'jumpy path (discrete)', tone: 'text-amber-300' };
|
||||
return { text: 'mixed path', tone: 'text-gray-300' };
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -226,11 +251,16 @@ function IndicatorCard({ symbol, type, refPrice }: { symbol: string; type: strin
|
||||
<h4 className="num text-[10px] uppercase tracking-[0.16em] text-gray-500">
|
||||
{INDICATOR_LABELS[type] ?? type}
|
||||
</h4>
|
||||
{query.data && (
|
||||
{query.data && type.toLowerCase() !== 'fip_id' && (
|
||||
<span className="num text-[10px] text-gray-600" title={`${query.data.bars_used} bars used · normalized score`}>
|
||||
score {query.data.score.toFixed(2)}
|
||||
</span>
|
||||
)}
|
||||
{query.data && type.toLowerCase() === 'fip_id' && (
|
||||
<span className="num text-[10px] text-gray-600" title="Display only — not used by the production gate">
|
||||
context only
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{query.isLoading && (
|
||||
@@ -253,13 +283,25 @@ function IndicatorCard({ symbol, type, refPrice }: { symbol: string; type: strin
|
||||
) : null;
|
||||
})()}
|
||||
<dl className="mt-2.5 space-y-1.5">
|
||||
{Object.entries(query.data.values).map(([key, val]) => (
|
||||
<ValueRow key={key} name={key} val={val} refPrice={refPrice} />
|
||||
))}
|
||||
{Object.entries(query.data.values)
|
||||
.filter(([key]) => {
|
||||
// Hide meta / prose fields already shown in the interpretation line.
|
||||
if (type.toLowerCase() !== 'fip_id') return true;
|
||||
return !['path', 'path_label', 'display_only', 'note'].includes(key);
|
||||
})
|
||||
.map(([key, val]) => (
|
||||
<ValueRow key={key} name={key} val={val} refPrice={refPrice} />
|
||||
))}
|
||||
{Object.keys(query.data.values).length === 0 && (
|
||||
<p className="text-xs text-gray-500">No values.</p>
|
||||
)}
|
||||
</dl>
|
||||
{type.toLowerCase() === 'fip_id' && (
|
||||
<p className="mt-2 text-[11px] leading-snug text-gray-600">
|
||||
How smooth the past ~12-month move was (skip last month). Lower FIP usually
|
||||
means a steadier grind. Not used to qualify or rank trades.
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user