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

71
bin/dev
View File

@@ -553,6 +553,9 @@ deep_restart() {
# Force restart iceberg-catalog since it depends on postgres and minio
echo -e "${GREEN}→${NC} Force restarting iceberg-catalog (depends on postgres/minio)..."
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}"
@@ -711,19 +714,75 @@ case "$COMMAND" in
rebuild_images
deploy_services
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
rebuild_images "$service"
# Special handling for sandbox: delete sandbox deployments instead of applying kustomization
if [ "$service" == "sandbox" ]; then
echo -e "${GREEN}→${NC} Deleting user container deployments in dexorder-sandboxes namespace..."
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}"
sandbox_requested=1
else
deploy_service "$service"
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..."
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}"
fi
fi
;;
rebuild)

View File

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

View File

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

View File

@@ -525,9 +525,9 @@ export class DuckDBClient {
// Check if we have continuous data
// For now, simple check: if we have any data, assume complete
// 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)
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
this.logger.debug({

View File

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

View File

@@ -28,7 +28,7 @@ const rooms = computed(() => [{
avatar: null,
users: [
{ _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,
typingUsers: isAgentProcessing.value ? [AGENT_ID] : []

View File

@@ -79,6 +79,19 @@ export class WebSocketDatafeed implements IBasicDataFeed {
}
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
if (message.request_id && this.pendingRequests.has(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) {
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 tickDenom = response.symbol_info.tick_denominator || 1
const baseDenom = response.symbol_info.base_denominator || 1
const tickDenom = Math.pow(10, response.symbol_info.price_precision ?? 0)
const baseDenom = Math.pow(10, response.symbol_info.size_precision ?? 0)
this.symbolDenominators.set(symbolKey, {
tick: tickDenom,
@@ -232,7 +247,7 @@ export class WebSocketDatafeed implements IBasicDataFeed {
this.sendRequest<any>({
type: 'get_bars',
symbol: symbolKey,
resolution: resolution,
period_seconds: intervalToSeconds(resolution),
from_time: periodParams.from,
to_time: periodParams.to,
countback: periodParams.countBack