chart data fixes

This commit is contained in:
2026-04-01 03:09:54 -04:00
parent 9e6a20c218
commit ca44e68f64
7 changed files with 102 additions and 16 deletions

69
bin/dev
View File

@@ -553,6 +553,9 @@ deep_restart() {
# Force restart iceberg-catalog since it depends on postgres and minio # Force restart iceberg-catalog since it depends on postgres and minio
echo -e "${GREEN}→${NC} Force restarting iceberg-catalog (depends on postgres/minio)..." echo -e "${GREEN}→${NC} Force restarting iceberg-catalog (depends on postgres/minio)..."
kubectl delete pod -l app=iceberg-catalog 2>/dev/null || true kubectl delete pod -l app=iceberg-catalog 2>/dev/null || true
# Remove all sandbox deployments and services to free quota
echo -e "${GREEN}→${NC} Removing all sandbox deployments and services..."
kubectl delete deployments,services --all -n dexorder-sandboxes 2>/dev/null || true
;; ;;
*) *)
echo -e "${RED}Error: Unknown service '$service'${NC}" echo -e "${RED}Error: Unknown service '$service'${NC}"
@@ -711,19 +714,75 @@ case "$COMMAND" in
rebuild_images rebuild_images
deploy_services deploy_services
else else
# Multiple services specified # Multiple services specified: rebuild ALL first, then deploy ALL together.
# Deploying one-at-a-time causes each deploy to revert the previous service's
# image tag override (each kubectl apply -k . only carries one tag at a time).
sandbox_requested=0
deploy_services_list=()
for service in "$@"; do for service in "$@"; do
rebuild_images "$service" rebuild_images "$service"
# Special handling for sandbox: delete sandbox deployments instead of applying kustomization
if [ "$service" == "sandbox" ]; then if [ "$service" == "sandbox" ]; then
sandbox_requested=1
else
deploy_services_list+=("$service")
fi
done
# Deploy all non-sandbox services together in one kustomize apply
if [ ${#deploy_services_list[@]} -gt 0 ]; then
if [ -f "$ROOT_DIR/.dev-image-tag" ]; then
source "$ROOT_DIR/.dev-image-tag"
fi
cd "$ROOT_DIR/deploy/k8s/dev"
# Template gateway-config if gateway is in the list
for svc in "${deploy_services_list[@]}"; do
if [ "$svc" == "gateway" ]; then
sed -i "s/SANDBOX_TAG_PLACEHOLDER/$SANDBOX_TAG/g" "$ROOT_DIR/deploy/k8s/dev/configs/gateway-config.yaml"
sed -i "s/SIDECAR_TAG_PLACEHOLDER/$SIDECAR_TAG/g" "$ROOT_DIR/deploy/k8s/dev/configs/gateway-config.yaml"
"$SCRIPT_DIR/config-update" dev
break
fi
done
# Build the images stanza for all services at once
echo "" >> kustomization.yaml
echo "# Image tags (added by bin/dev)" >> kustomization.yaml
echo "images:" >> kustomization.yaml
for svc in "${deploy_services_list[@]}"; do
case "$svc" in
relay) echo " - name: dexorder/ai-relay" >> kustomization.yaml; echo " newTag: $RELAY_TAG" >> kustomization.yaml ;;
ingestor) echo " - name: dexorder/ai-ingestor" >> kustomization.yaml; echo " newTag: $INGEST_TAG" >> kustomization.yaml ;;
flink) echo " - name: dexorder/ai-flink" >> kustomization.yaml; echo " newTag: $FLINK_TAG" >> kustomization.yaml ;;
gateway) echo " - name: dexorder/ai-gateway" >> kustomization.yaml; echo " newTag: $GATEWAY_TAG" >> kustomization.yaml ;;
web) echo " - name: dexorder/ai-web" >> kustomization.yaml; echo " newTag: $WEB_TAG" >> kustomization.yaml ;;
lifecycle-sidecar|sidecar) echo " - name: dexorder/ai-lifecycle-sidecar" >> kustomization.yaml; echo " newTag: $SIDECAR_TAG" >> kustomization.yaml ;;
esac
done
kubectl apply -k .
sed -i '/# Image tags (added by bin\/dev)/,$d' kustomization.yaml
# Restore gateway-config placeholders if gateway was deployed
for svc in "${deploy_services_list[@]}"; do
if [ "$svc" == "gateway" ]; then
sed -i "s/$SANDBOX_TAG/SANDBOX_TAG_PLACEHOLDER/g" "$ROOT_DIR/deploy/k8s/dev/configs/gateway-config.yaml"
sed -i "s/$SIDECAR_TAG/SIDECAR_TAG_PLACEHOLDER/g" "$ROOT_DIR/deploy/k8s/dev/configs/gateway-config.yaml"
break
fi
done
fi
# Handle sandbox separately
if [ "$sandbox_requested" == "1" ]; then
echo -e "${GREEN}→${NC} Deleting user container deployments in dexorder-sandboxes namespace..." echo -e "${GREEN}→${NC} Deleting user container deployments in dexorder-sandboxes namespace..."
kubectl delete deployments --all -n dexorder-sandboxes 2>/dev/null || true kubectl delete deployments --all -n dexorder-sandboxes 2>/dev/null || true
echo -e "${GREEN}✓ User containers will be recreated by gateway on next login${NC}" echo -e "${GREEN}✓ User containers will be recreated by gateway on next login${NC}"
else
deploy_service "$service"
fi fi
done
fi fi
;; ;;
rebuild) rebuild)

View File

@@ -255,6 +255,19 @@ generatorOptions:

View File

@@ -16,7 +16,6 @@ import {
type SnapshotMessage, type SnapshotMessage,
type PatchMessage, type PatchMessage,
} from '../workspace/index.js'; } from '../workspace/index.js';
import { resolutionToSeconds } from '../types/ohlc.js';
/** /**
* Safe JSON stringifier that handles BigInt values * Safe JSON stringifier that handles BigInt values
@@ -487,7 +486,7 @@ export class WebSocketHandler {
} }
const history = await ohlcService.fetchOHLC( const history = await ohlcService.fetchOHLC(
payload.symbol, payload.symbol,
resolutionToSeconds(payload.resolution), payload.period_seconds,
payload.from_time, payload.from_time,
payload.to_time, payload.to_time,
payload.countback payload.countback

View File

@@ -525,9 +525,9 @@ export class DuckDBClient {
// Check if we have continuous data // Check if we have continuous data
// For now, simple check: if we have any data, assume complete // For now, simple check: if we have any data, assume complete
// TODO: Implement proper gap detection by checking for missing periods // TODO: Implement proper gap detection by checking for missing periods
const periodMicros = BigInt(period_seconds) * 1000000n; const periodNanos = BigInt(period_seconds) * 1_000_000_000n;
// end_time is exclusive, so expected count = (end - start) / period (no +1) // end_time is exclusive, so expected count = (end - start) / period (no +1)
const expectedBars = Number((end_time - start_time) / periodMicros); const expectedBars = Number((end_time - start_time) / periodNanos);
if (data.length < expectedBars * 0.95) { // Allow 5% tolerance if (data.length < expectedBars * 0.95) { // Allow 5% tolerance
this.logger.debug({ this.logger.debug({

View File

@@ -172,7 +172,7 @@ onBeforeUnmount(() => {
} }
.main-splitter :deep(.p-splitter-gutter-handle) { .main-splitter :deep(.p-splitter-gutter-handle) {
background: #1c1c1c !important; background: #2e2e2e !important;
} }
.chart-panel, .chart-panel,

View File

@@ -28,7 +28,7 @@ const rooms = computed(() => [{
avatar: null, avatar: null,
users: [ users: [
{ _id: CURRENT_USER_ID, username: 'You' }, { _id: CURRENT_USER_ID, username: 'You' },
{ _id: AGENT_ID, username: 'AI Agent', status: { state: isConnected.value ? 'online' : 'offline' } } { _id: AGENT_ID, username: 'AI Agent' }
], ],
unreadCount: 0, unreadCount: 0,
typingUsers: isAgentProcessing.value ? [AGENT_ID] : [] typingUsers: isAgentProcessing.value ? [AGENT_ID] : []

View File

@@ -79,6 +79,19 @@ export class WebSocketDatafeed implements IBasicDataFeed {
} }
private handleMessage(message: any): void { private handleMessage(message: any): void {
// On reconnect the server sends a fresh 'connected' message.
// Any pending requests were sent on the old socket and will never be answered,
// so reject them immediately so TradingView can retry on the new connection.
if (message.type === 'connected' && this.pendingRequests.size > 0) {
console.warn('[TradingView Datafeed] WebSocket reconnected — rejecting', this.pendingRequests.size, 'stale pending request(s)')
for (const [requestId, pending] of this.pendingRequests) {
clearTimeout(pending.timeout)
pending.reject(new Error('WebSocket reconnected'))
this.pendingRequests.delete(requestId)
}
return
}
// Handle responses to pending requests // Handle responses to pending requests
if (message.request_id && this.pendingRequests.has(message.request_id)) { if (message.request_id && this.pendingRequests.has(message.request_id)) {
console.log('[TradingView Datafeed] Found pending request for:', message.request_id) console.log('[TradingView Datafeed] Found pending request for:', message.request_id)
@@ -186,10 +199,12 @@ export class WebSocketDatafeed implements IBasicDataFeed {
if (response.symbol_info) { if (response.symbol_info) {
console.log('[TradingView Datafeed] Resolved symbol info:', response.symbol_info) console.log('[TradingView Datafeed] Resolved symbol info:', response.symbol_info)
// Store the denominators for this symbol // Derive scale denominators from Nautilus precision fields.
// price_precision=2 → tick divisor=100 (prices stored as integer cents)
// size_precision=6 → base divisor=1_000_000 (volumes stored as integer micro-units)
const symbolKey = response.symbol_info.ticker || response.symbol_info.name const symbolKey = response.symbol_info.ticker || response.symbol_info.name
const tickDenom = response.symbol_info.tick_denominator || 1 const tickDenom = Math.pow(10, response.symbol_info.price_precision ?? 0)
const baseDenom = response.symbol_info.base_denominator || 1 const baseDenom = Math.pow(10, response.symbol_info.size_precision ?? 0)
this.symbolDenominators.set(symbolKey, { this.symbolDenominators.set(symbolKey, {
tick: tickDenom, tick: tickDenom,
@@ -232,7 +247,7 @@ export class WebSocketDatafeed implements IBasicDataFeed {
this.sendRequest<any>({ this.sendRequest<any>({
type: 'get_bars', type: 'get_bars',
symbol: symbolKey, symbol: symbolKey,
resolution: resolution, period_seconds: intervalToSeconds(resolution),
from_time: periodParams.from, from_time: periodParams.from,
to_time: periodParams.to, to_time: periodParams.to,
countback: periodParams.countBack countback: periodParams.countBack