This commit is contained in:
Dobromir Popov
2025-12-10 00:45:41 +02:00
parent c21d8cbea1
commit fadfa8c741
5 changed files with 256 additions and 117 deletions

View File

@@ -3059,30 +3059,37 @@ class ChartManager {
let targetPrice = currentPrice;
// CRITICAL FIX: Check if price_delta is normalized (< 1.0) or real price change
if (trendVector.price_delta !== undefined && trendVector.price_delta !== null) {
const priceDelta = parseFloat(trendVector.price_delta);
// If price_delta is very small (< 1.0), it's likely normalized - scale it
if (Math.abs(priceDelta) < 1.0) {
// Normalized value - treat as percentage of current price
targetPrice = currentPrice * (1 + priceDelta);
// CRITICAL FIX: Use calculated_direction and calculated_steepness from trend_vector
// The price_delta in trend_vector is the pivot range, not the predicted change
// We should use direction and steepness to estimate the trend
const direction = parseFloat(trendVector.calculated_direction) || 0; // -1, 0, or 1
const steepness = parseFloat(trendVector.calculated_steepness) || 0;
// Steepness is in price units, but we need to scale it reasonably
// If steepness is > 100, it's likely in absolute price units (too large)
// Scale it down to a reasonable percentage move
let priceChange = 0;
if (steepness > 0) {
// If steepness is large (> 10), treat it as absolute price change but cap it
if (steepness > 10) {
// Cap at 2% of current price
const maxChange = 0.02 * currentPrice;
priceChange = Math.min(steepness, maxChange) * direction;
} else {
// Real price delta - add directly
targetPrice = currentPrice + priceDelta;
// Small steepness - use as percentage
priceChange = (steepness / 100) * currentPrice * direction;
}
} else {
// Fallback: Use direction and steepness
const direction = trendVector.direction === 'up' ? 1 :
(trendVector.direction === 'down' ? -1 : 0);
const steepness = parseFloat(trendVector.steepness) || 0; // 0 to 1
// Estimate price change based on steepness (max 1% move per projection period)
const maxChange = 0.01 * currentPrice;
const projectedChange = maxChange * steepness * direction;
targetPrice = currentPrice + projectedChange;
// Fallback: Use angle if available
const angle = parseFloat(trendVector.calculated_angle) || 0;
// Angle is in radians, convert to price change
// Small angle = small change, large angle = large change
priceChange = Math.tan(angle) * currentPrice * 0.01; // Scale down
}
targetPrice = currentPrice + priceChange;
// Sanity check: Don't let target price go to 0 or negative
if (targetPrice <= 0 || !isFinite(targetPrice)) {
console.warn('Invalid target price calculated:', targetPrice, 'using current price instead');

View File

@@ -57,28 +57,42 @@ class LiveUpdatesPolling {
}
_poll() {
// Poll each subscription
// OPTIMIZATION: Batch all subscriptions into a single API call
// Group by symbol to reduce API calls from 4 to 1
const symbolGroups = {};
this.subscriptions.forEach(sub => {
fetch('/api/live-updates', {
if (!symbolGroups[sub.symbol]) {
symbolGroups[sub.symbol] = [];
}
symbolGroups[sub.symbol].push(sub.timeframe);
});
// Make one call per symbol with all timeframes
Object.entries(symbolGroups).forEach(([symbol, timeframes]) => {
fetch('/api/live-updates-batch', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
symbol: sub.symbol,
timeframe: sub.timeframe
symbol: symbol,
timeframes: timeframes
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Handle chart update (even if null, predictions should still be processed)
if (data.chart_update && this.onChartUpdate) {
this.onChartUpdate(data.chart_update);
// Handle chart updates for each timeframe
if (data.chart_updates && this.onChartUpdate) {
// chart_updates is an object: { '1s': {...}, '1m': {...}, ... }
Object.entries(data.chart_updates).forEach(([timeframe, update]) => {
if (update) {
this.onChartUpdate(update);
}
});
}
// CRITICAL FIX: Handle prediction update properly
// data.prediction is already in format { transformer: {...}, dqn: {...}, cnn: {...} }
// Handle prediction update (single prediction for all timeframes)
// data.prediction is in format { transformer: {...}, dqn: {...}, cnn: {...} }
if (data.prediction && this.onPredictionUpdate) {
// Log prediction data for debugging
console.log('[Live Updates] Received prediction data:', {
has_transformer: !!data.prediction.transformer,
has_dqn: !!data.prediction.dqn,
@@ -88,10 +102,7 @@ class LiveUpdatesPolling {
has_predicted_candle: !!data.prediction.transformer?.predicted_candle
});
// Pass the prediction object directly (it's already in the correct format)
this.onPredictionUpdate(data.prediction);
} else if (!data.prediction) {
console.debug('[Live Updates] No prediction data in response');
}
} else {
console.debug('[Live Updates] Response not successful:', data);