data fixes, partial custom indicator support

This commit is contained in:
2026-04-08 21:28:31 -04:00
parent b701554996
commit a70dcd954f
81 changed files with 5438 additions and 1852 deletions

View File

@@ -4,9 +4,11 @@ import Card from 'primevue/card'
import { createTradingViewDatafeed } from '../composables/useTradingViewDatafeed'
import { useTradingViewShapes } from '../composables/useTradingViewShapes'
import { useTradingViewIndicators } from '../composables/useTradingViewIndicators'
import { useCustomIndicators, getCustomIndicatorsGetter } from '../composables/useCustomIndicators'
import { useChartStore } from '../stores/chart'
import type { IChartingLibraryWidget } from '../types/tradingview'
import { intervalToSeconds } from '../utils'
import { wsManager } from '../composables/useWebSocket'
// Convert seconds to TradingView interval string
function secondsToInterval(seconds: number): string {
@@ -22,12 +24,25 @@ let datafeed: any = null
let isUpdatingFromChart = false // Flag to prevent circular updates
let shapeCleanup: (() => void) | null = null // Cleanup function for shape sync
let indicatorCleanup: (() => void) | null = null // Cleanup function for indicator sync
let customIndicatorCleanup: (() => void) | null = null // Cleanup for custom TV studies
let chartInitialized = false // Guard against double-init on reconnect
const maybeInitChart = () => {
if (chartInitialized || !chartContainer.value) return
chartInitialized = true
initChart()
}
onMounted(() => {
if (!chartContainer.value) return
// Wait for workspace to be ready (persistent stores loaded from container)
// before initializing TradingView, so stores are populated when onChartReady fires.
watch(wsManager.sessionStatus, (status) => {
if (status === 'ready') maybeInitChart()
}, { immediate: true })
})
// Wait for TradingView library to load
const initChart = () => {
// Wait for TradingView library to load
function initChart() {
if (!window.TradingView) {
setTimeout(initChart, 100)
return
@@ -43,16 +58,23 @@ onMounted(() => {
container: chartContainer.value!,
library_path: '/charting_library/',
locale: 'en',
// Register the two generic custom study dispatch types.
// Must be provided here — TV has no dynamic study registration API.
custom_indicators_getter: getCustomIndicatorsGetter(),
disabled_features: [
'use_localstorage_for_settings',
'header_symbol_search',
'symbol_search_hot_key'
],
enabled_features: [],
// Restrict indicators to only those supported by both TA-Lib and TradingView
// Restrict indicators to only those supported by both TA-Lib and TradingView.
// Custom AI-generated indicators (from custom_indicators_getter) must also be listed here.
studies_access: {
type: 'white',
tools: [
// AI custom indicator dispatch studies
{ name: 'dxo_customstudy_overlay' },
{ name: 'dxo_customstudy_pane' },
// Overlap Studies (14)
{ name: 'Moving Average' },
{ name: 'Moving Average Exponential' },
@@ -150,15 +172,13 @@ onMounted(() => {
if (tvWidget) {
shapeCleanup = useTradingViewShapes(tvWidget)
indicatorCleanup = useTradingViewIndicators(tvWidget)
customIndicatorCleanup = useCustomIndicators(tvWidget)
}
})
} catch (error) {
console.error('Failed to initialize TradingView widget:', error)
}
}
initChart()
})
}
function initializeVisibleRange() {
if (!tvWidget) return
@@ -281,6 +301,12 @@ onBeforeUnmount(() => {
indicatorCleanup = null
}
// Cleanup custom TV studies
if (customIndicatorCleanup) {
customIndicatorCleanup()
customIndicatorCleanup = null
}
if (tvWidget) {
tvWidget.remove()
tvWidget = null

View File

@@ -238,14 +238,7 @@ const handleMessage = (data: WebSocketMessage) => {
// Stop agent processing
const stopAgent = () => {
// Send empty message to trigger interrupt without new agent round
const wsMessage = {
type: 'agent_user_message',
session_id: SESSION_ID,
content: '',
attachments: []
}
wsManager.send(wsMessage)
wsManager.send({ type: 'agent_stop', session_id: SESSION_ID })
isAgentProcessing.value = false
removeToolCallBubble()
lastSentMessageId = null
@@ -586,7 +579,9 @@ onUnmounted(() => {
}
.workspace-loading {
flex: 1;
position: fixed;
inset: 0;
z-index: 9999;
display: flex;
flex-direction: column;
align-items: center;
@@ -639,7 +634,7 @@ onUnmounted(() => {
.stop-button-container {
position: absolute;
bottom: 80px;
left: 20px;
right: 20px;
z-index: 1000;
}