Closes #021 - Live Time-Lock Resolution, Ensemble Map Fix & Multi-Asset Logging
This commit is contained in:
@@ -125,6 +125,7 @@ export default function CryptoDemo() {
|
||||
const [loadingEnsemble, setLoadingEnsemble] = useState(false);
|
||||
const [isShieldActive, setIsShieldActive] = useState(true);
|
||||
const [coins, setCoins] = useState<Record<string, CoinData>>(defaultCoins);
|
||||
const [feedbackFilterAsset, setFeedbackFilterAsset] = useState<'BTC' | 'ETH' | 'SOL'>('BTC');
|
||||
|
||||
// Safely load counters and forecasts from localStorage on client mount
|
||||
useEffect(() => {
|
||||
@@ -418,36 +419,41 @@ export default function CryptoDemo() {
|
||||
return customCoins[activeTicker] || coins[activeTicker] || coins['BTC'];
|
||||
}, [activeTicker, customCoins, coins]);
|
||||
|
||||
const filteredForecasts = useMemo(() => {
|
||||
return forecasts.filter((f) => f.ticker === feedbackFilterAsset);
|
||||
}, [forecasts, feedbackFilterAsset]);
|
||||
|
||||
// Helper to fetch/load prediction probabilities
|
||||
const getPredictionProb = (estimator: string, horizon: string): number => {
|
||||
if (ensemblePredictions && ensemblePredictions[activeTicker] && ensemblePredictions[activeTicker][estimator]) {
|
||||
return ensemblePredictions[activeTicker][estimator][horizon] ?? 0.5;
|
||||
const getPredictionProb = (ticker: string, estimator: string, horizon: string): number => {
|
||||
const cleanTicker = ticker.replace('-USD', '');
|
||||
if (ensemblePredictions && ensemblePredictions[cleanTicker] && ensemblePredictions[cleanTicker][estimator]) {
|
||||
return ensemblePredictions[cleanTicker][estimator][horizon] ?? 0.5;
|
||||
}
|
||||
// Fallback static predictions
|
||||
const defaultMapping: Record<string, Record<string, Record<string, number>>> = {
|
||||
BTC: {
|
||||
rf: { T1: 0.62, T5: 0.58, T10: 0.54 },
|
||||
gb: { T1: 0.65, T5: 0.61, T10: 0.51 },
|
||||
lr: { T1: 0.58, T5: 0.57, T10: 0.55 },
|
||||
svm: { T1: 0.60, T5: 0.59, T10: 0.56 },
|
||||
mlp: { T1: 0.64, T5: 0.60, T10: 0.53 }
|
||||
rf: { T1: 0.528, T5: 0.539, T10: 0.59 },
|
||||
gb: { T1: 0.54, T5: 0.513, T10: 0.733 },
|
||||
lr: { T1: 0.542, T5: 0.595, T10: 0.641 },
|
||||
svm: { T1: 0.487, T5: 0.477, T10: 0.528 },
|
||||
mlp: { T1: 0.36, T5: 1.0, T10: 0.998 }
|
||||
},
|
||||
ETH: {
|
||||
rf: { T1: 0.60, T5: 0.59, T10: 0.54 },
|
||||
gb: { T1: 0.66, T5: 0.61, T10: 0.48 },
|
||||
lr: { T1: 0.58, T5: 0.55, T10: 0.56 },
|
||||
svm: { T1: 0.59, T5: 0.59, T10: 0.56 },
|
||||
mlp: { T1: 0.64, T5: 0.59, T10: 0.55 }
|
||||
rf: { T1: 0.508, T5: 0.549, T10: 0.59 },
|
||||
gb: { T1: 0.55, T5: 0.513, T10: 0.703 },
|
||||
lr: { T1: 0.542, T5: 0.575, T10: 0.651 },
|
||||
svm: { T1: 0.477, T5: 0.477, T10: 0.528 },
|
||||
mlp: { T1: 0.36, T5: 0.99, T10: 1.018 }
|
||||
},
|
||||
SOL: {
|
||||
rf: { T1: 0.65, T5: 0.58, T10: 0.52 },
|
||||
gb: { T1: 0.63, T5: 0.63, T10: 0.54 },
|
||||
lr: { T1: 0.59, T5: 0.58, T10: 0.54 },
|
||||
svm: { T1: 0.60, T5: 0.62, T10: 0.56 },
|
||||
mlp: { T1: 0.66, T5: 0.60, T10: 0.51 }
|
||||
rf: { T1: 0.558, T5: 0.539, T10: 0.57 },
|
||||
gb: { T1: 0.52, T5: 0.533, T10: 0.733 },
|
||||
lr: { T1: 0.552, T5: 0.595, T10: 0.631 },
|
||||
svm: { T1: 0.487, T5: 0.507, T10: 0.528 },
|
||||
mlp: { T1: 0.38, T5: 1.0, T10: 0.978 }
|
||||
}
|
||||
};
|
||||
const assetKey = defaultMapping[activeTicker] ? activeTicker : 'BTC';
|
||||
const assetKey = defaultMapping[cleanTicker] ? cleanTicker : 'BTC';
|
||||
return defaultMapping[assetKey][estimator]?.[horizon] ?? 0.5;
|
||||
};
|
||||
|
||||
@@ -533,9 +539,9 @@ export default function CryptoDemo() {
|
||||
const predictionsMap: Record<string, Record<string, number>> = {};
|
||||
ESTIMATORS.forEach((est) => {
|
||||
predictionsMap[est.id] = {
|
||||
T1: getPredictionProb(est.id, 'T1'),
|
||||
T5: getPredictionProb(est.id, 'T5'),
|
||||
T10: getPredictionProb(est.id, 'T10')
|
||||
T1: getPredictionProb(activeCoin.ticker, est.id, 'T1'),
|
||||
T5: getPredictionProb(activeCoin.ticker, est.id, 'T5'),
|
||||
T10: getPredictionProb(activeCoin.ticker, est.id, 'T10')
|
||||
};
|
||||
});
|
||||
|
||||
@@ -548,9 +554,9 @@ export default function CryptoDemo() {
|
||||
timestamp: now,
|
||||
predictions: predictionsMap,
|
||||
targetTimes: {
|
||||
T1: now + 60 * 1000, // resolves in 60s for direct visual validation
|
||||
T5: now + 300 * 1000, // resolves in 300s
|
||||
T10: now + 600 * 1000 // resolves in 600s
|
||||
T1: now + 24 * 60 * 60 * 1000, // resolves in 24 hours
|
||||
T5: now + 5 * 24 * 60 * 60 * 1000, // resolves in 5 days
|
||||
T10: now + 10 * 24 * 60 * 60 * 1000 // resolves in 10 days
|
||||
}
|
||||
};
|
||||
|
||||
@@ -558,7 +564,7 @@ export default function CryptoDemo() {
|
||||
setForecasts(nextForecasts);
|
||||
localStorage.setItem('crypto_bayes_forecasts', JSON.stringify(nextForecasts));
|
||||
|
||||
setLearningLoopLog(`Registered active multi-model forecast for ${activeCoin.ticker} at $${entryPrice}. Evaluating T+1 (60s), T+5 (5m), and T+10 (10m).`);
|
||||
setLearningLoopLog(`Registered active multi-model forecast for ${activeCoin.ticker} at $${entryPrice}. Evaluating T+1 (24h), T+5 (5d), and T+10 (10d).`);
|
||||
setTimeout(() => setLearningLoopLog(''), 8000);
|
||||
};
|
||||
|
||||
@@ -818,7 +824,7 @@ export default function CryptoDemo() {
|
||||
{HORIZONS.map((h) => {
|
||||
const trackerKey = `${est.id}_${h.id}`;
|
||||
const tracker = trackers[trackerKey] || { alpha: 1, beta: 1 };
|
||||
const prob = getPredictionProb(est.id, h.id);
|
||||
const prob = getPredictionProb(activeTicker, est.id, h.id);
|
||||
const direction = prob > 0.5 ? 'UP' : 'DOWN';
|
||||
const expValue = tracker.alpha / (tracker.alpha + tracker.beta);
|
||||
|
||||
@@ -901,6 +907,23 @@ export default function CryptoDemo() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Sleek Dynamic Asset-Selector Tab-Bar */}
|
||||
<div className="flex items-center gap-1.5 p-1 bg-slate-900/60 border border-slate-800/80 rounded-xl w-fit">
|
||||
{(['BTC', 'ETH', 'SOL'] as const).map((asset) => (
|
||||
<button
|
||||
key={asset}
|
||||
onClick={() => setFeedbackFilterAsset(asset)}
|
||||
className={`px-4 py-1.5 rounded-lg text-xs font-mono font-bold transition-all ${
|
||||
feedbackFilterAsset === asset
|
||||
? 'bg-cyan-500/20 text-cyan-400 border border-cyan-500/30'
|
||||
: 'text-slate-400 hover:text-slate-200 border border-transparent'
|
||||
}`}
|
||||
>
|
||||
{asset}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="overflow-x-auto max-h-56 scrollbar-thin">
|
||||
<table className="w-full border-collapse text-left text-xs font-mono">
|
||||
<thead>
|
||||
@@ -915,12 +938,12 @@ export default function CryptoDemo() {
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{forecasts.length === 0 ? (
|
||||
{filteredForecasts.length === 0 ? (
|
||||
<tr>
|
||||
<td colSpan={7} className="p-4 text-center text-slate-500 italic">No forecasts registered yet.</td>
|
||||
<td colSpan={7} className="p-4 text-center text-slate-500 italic">No forecasts registered for {feedbackFilterAsset} yet.</td>
|
||||
</tr>
|
||||
) : (
|
||||
forecasts.map((fc) => {
|
||||
filteredForecasts.map((fc) => {
|
||||
const now = Date.now();
|
||||
|
||||
const getHorizonStatus = (hKey: 'T1' | 'T5' | 'T10') => {
|
||||
|
||||
Reference in New Issue
Block a user