Skip to content

Data Isolation and Multi Chart Management

levi edited this page Nov 6, 2025 · 2 revisions

Data Isolation and Multi-Chart Management

Table of Contents

  1. Introduction
  2. Chart Context Architecture
  3. Data Isolation Mechanisms
  4. Chart Context Lifecycle Management
  5. Indicator Management in Multi-Chart Scenarios
  6. Layout Change Event Handling
  7. Common Issues and Best Practices

Introduction

This document provides comprehensive documentation on the data isolation mechanisms in multi-chart scenarios within the PyTradingView framework. It details how the ChartContextManager maintains separate states for different charts within the same layout, ensuring proper data isolation and resource management. The document covers the architecture, lifecycle, and management of chart contexts, with a focus on maintaining chart-specific data such as active indicators, symbol information, and interval settings.

Chart Context Architecture

The chart context system in PyTradingView is designed to provide complete data isolation between multiple charts within the same layout. At the core of this system is the ChartContextManager, which manages individual ChartContext instances for each chart in the layout.

classDiagram
class ChartContext {
+string chart_id
+TVChart chart
+Dict[string, TVIndicator] active_indicators
+string? symbol
+string? interval
+add_indicator(name, indicator)
+remove_indicator(name)
+get_indicator(name)
+has_indicator(name)
+clear_all_indicators()
+get_indicator_names()
+update_symbol_interval(symbol, interval)
}
class ChartContextManager {
+Dict[string, ChartContext] _contexts
+create_context(chart_id, chart)
+get_context(chart_id)
+remove_context(chart_id)
+get_all_contexts()
+get_chart_ids()
+clear_all()
+has_context(chart_id)
+get_charts_with_indicator(indicator_name)
+count_total_indicators()
}
ChartContextManager --> ChartContext : "manages"
Loading

Data Isolation Mechanisms

The ChartContext class serves as a data container for each individual chart, storing chart-specific information and maintaining complete isolation from other charts. Each ChartContext instance contains:

  • chart_id: A unique identifier for the chart (typically in the format "chart_X" where X is the chart index)
  • chart: A reference to the TVChart instance associated with this context
  • active_indicators: A dictionary mapping indicator names to their instances for this specific chart
  • symbol: The current trading instrument symbol being displayed
  • interval: The current time period/interval setting for the chart

The data isolation is achieved through the ChartContextManager, which maintains a dictionary of ChartContext instances indexed by chart_id. This ensures that each chart has its own independent state, preventing any cross-contamination of data between charts.

When accessing chart-specific data, the system follows this pattern:

  1. Retrieve the ChartContextManager instance
  2. Use the chart_id to get the specific ChartContext
  3. Access the desired data from the ChartContext

For example, to get the active indicators for a specific chart:

context = chart_context_manager.get_context("chart_0")
if context:
    indicators = context.active_indicators
    symbol = context.symbol
    interval = context.interval

This architecture ensures that operations on one chart do not affect the state of other charts, providing true data isolation in multi-chart layouts.

Chart Context Lifecycle Management

The lifecycle of chart contexts is tightly integrated with the application's initialization and layout management processes. The lifecycle consists of three main phases: creation, maintenance, and cleanup.

Context Creation

Chart contexts are created during the layout initialization process when the chart data becomes ready. The runtime mixin handles this process through the _initialize_all_charts method:

sequenceDiagram
participant Widget as TVWidget
participant Runtime as TVEngineRuntime
participant Manager as ChartContextManager
Widget->>Runtime : onChartReady
Runtime->>Runtime : _on_chart_data_ready()
Runtime->>Runtime : _initialize_all_charts()
loop For each chart
Runtime->>Manager : create_context(chart_id, chart)
Manager-->>Runtime : ChartContext
Runtime->>Runtime : _activate_default_indicators_for_chart()
Runtime->>Runtime : _setup_chart_data_listener()
end
Loading

The context creation process involves:

  1. Getting the total number of charts in the current layout
  2. Iterating through each chart index
  3. Creating a unique chart_id (e.g., "chart_0", "chart_1")
  4. Retrieving the TVChart instance for the current index
  5. Creating a new ChartContext and storing it in the ChartContextManager

Context Maintenance

Once created, chart contexts are maintained throughout the application's runtime. The ChartContextManager provides several methods for managing contexts:

  • get_context(chart_id): Retrieve a specific chart context
  • get_all_contexts(): Get all active chart contexts
  • get_chart_ids(): Get a list of all chart IDs
  • has_context(chart_id): Check if a context exists for a given chart ID

Chart-specific data such as symbol and interval information is updated through the update_symbol_interval() method, which ensures that each chart maintains its own state independently.

Context Cleanup

When layout changes occur, proper cleanup of chart contexts is essential to prevent memory leaks and ensure a clean state for the new layout. The cleanup process is triggered by the layout change event and follows this sequence:

flowchart TD
A[Layout Change Detected] --> B[Call _handle_layout_changed]
B --> C[Call _cleanup_all_charts]
C --> D[Get all contexts]
D --> E{Any contexts?}
E --> |Yes| F[Iterate through each chart]
F --> G[Get chart context]
G --> H{Context exists?}
H --> |Yes| I[Iterate through indicators]
I --> J[Clear drawings]
J --> K[Call on_destroy]
K --> L[Remove indicator]
L --> M[Next indicator]
M --> I
I --> |No indicators| N[Next chart]
N --> F
F --> |No more charts| O[Clear all contexts]
O --> P[Reinitialize all charts]
P --> Q[Process complete]
E --> |No| Q
Loading

The cleanup process ensures that:

  1. All indicator drawings are cleared from the charts
  2. The on_destroy callback is called for each indicator (allowing for proper cleanup)
  3. All chart contexts are removed from the ChartContextManager
  4. Memory is properly released

Indicator Management in Multi-Chart Scenarios

The indicator management system in PyTradingView is designed to work seamlessly with the multi-chart architecture, allowing for both chart-specific and global indicator operations.

Indicator Activation and Deactivation

Indicators can be activated and deactivated on a per-chart basis using the ChartContext system. The process for activating an indicator on a specific chart is:

sequenceDiagram
participant Manager as TVEngineManager
participant ContextManager as ChartContextManager
participant Context as ChartContext
participant Registry as IndicatorRegistry
Manager->>ContextManager : get_context(chart_id)
ContextManager-->>Manager : ChartContext
Manager->>Context : has_indicator(name)
Context-->>Manager : Boolean
Manager->>Registry : create_instance(name)
Registry-->>Manager : TVIndicator
Manager->>TVIndicator : set_chart_id(chart_id)
Manager->>TVIndicator : on_init(widget, chart, chart_id)
Manager->>Context : add_indicator(name, indicator)
Loading

The activation process ensures that:

  1. The chart context exists
  2. The indicator is not already active on the chart
  3. A new indicator instance is created from the registry
  4. The indicator is initialized with the appropriate chart context
  5. The indicator is added to the chart's active_indicators dictionary

Deactivation follows a similar pattern, with the additional step of calling the indicator's on_destroy method to allow for proper cleanup before removal.

Cross-Chart Operations

The ChartContextManager also supports operations that span multiple charts:

  • get_charts_with_indicator(indicator_name): Returns a list of chart IDs that have a specific indicator activated
  • count_total_indicators(): Counts the total number of indicators across all charts
  • get_all_contexts(): Provides access to all chart contexts for batch operations

These methods enable global operations while maintaining the data isolation principles of the architecture.

Layout Change Event Handling

The system handles layout changes through a well-defined event handling mechanism that ensures proper cleanup and reinitialization of chart contexts.

Event Subscription

The layout change event is subscribed to during the chart initialization process:

sequenceDiagram
participant Widget as TVWidget
participant Runtime as TVEngineRuntime
participant Event as on_layout_changed_sync
Runtime->>Runtime : _subscribe_layout_changed_event()
Runtime->>Widget : subscribe('layout_changed', on_layout_changed_sync)
Widget-->>Runtime : Subscription confirmed
alt Layout Change Occurs
Widget->>Event : Trigger layout_changed
Event->>Runtime : Create async task
Event->>Runtime : _handle_layout_changed()
end
Loading

The event subscription process:

  1. Defines a synchronous wrapper function (on_layout_changed_sync)
  2. Subscribes this function to the 'layout_changed' event on the TVWidget
  3. When triggered, the wrapper creates an asynchronous task to handle the layout change

Reinitialization Process

When a layout change is detected, the system follows a strict reinitialization process:

flowchart TD
A[Layout Change Detected] --> B[Log layout change]
B --> C[Call _cleanup_all_charts]
C --> D[Clean up all indicators]
D --> E[Clear all contexts]
E --> F[Call _initialize_all_charts]
F --> G[Get new chart count]
G --> H[Create new contexts]
H --> I[Activate default indicators]
I --> J[Set up data listeners]
J --> K[Process complete]
Loading

The reinitialization ensures that:

  1. All old chart contexts are properly cleaned up
  2. New chart contexts are created for the new layout
  3. Default indicators are activated on the new charts
  4. Data loading listeners are set up for the new charts

This process maintains data integrity and prevents resource leaks when users switch between different chart layouts.

Common Issues and Best Practices

Stale Chart References

One common issue in multi-chart applications is the use of stale chart references. This can occur when:

  • A layout change happens while an asynchronous operation is in progress
  • Chart references are stored in variables that outlive the chart context
  • Event listeners are not properly cleaned up during layout changes

To avoid stale references:

  1. Always retrieve the current chart context using get_context(chart_id) before performing operations
  2. Use the chart_id rather than storing direct references to TVChart instances
  3. Implement proper cleanup in indicator's on_destroy methods

Resource Cleanup

Proper resource cleanup is critical for maintaining application stability. Best practices include:

  • Always calling clear_all() on the ChartContextManager when switching layouts
  • Ensuring all indicator drawings are cleared through clear_all_drawings()
  • Properly handling the on_destroy lifecycle callback
  • Avoiding circular references between components

Performance Considerations

When working with multiple charts, consider these performance optimizations:

  • Batch operations when possible using get_all_contexts()
  • Use get_charts_with_indicator() to target specific charts rather than iterating through all charts
  • Minimize the number of active indicators per chart
  • Implement efficient data processing in indicators to handle multiple chart updates

Error Handling

Robust error handling should include:

  • Checking for context existence before operations
  • Handling cases where chart_id may no longer be valid
  • Graceful degradation when indicators fail to activate
  • Proper logging of context creation and cleanup operations

By following these best practices, developers can ensure stable and efficient multi-chart applications with proper data isolation and resource management.

Clone this wiki locally