-
Notifications
You must be signed in to change notification settings - Fork 1
Indicator Lifecycle Management
- Indicator Lifecycle Overview
- Registration Process
- Lifecycle Callback Methods
- Activation and Chart Context Management
- False Breakout Indicator Example
- State Management and Common Issues
- Performance Considerations
The indicator lifecycle management system provides a comprehensive framework for creating, managing, and executing trading indicators within the TradingView environment. The lifecycle begins with registration using the @register_indicator decorator and progresses through initialization, activation, execution, and destruction phases. Each indicator inherits from the TVIndicator base class, which defines the core lifecycle methods and state management patterns.
The lifecycle is designed to support multi-chart scenarios through the ChartContextManager, which maintains isolated state for each chart instance. This architecture enables indicators to operate independently across multiple charts while sharing common configuration and registration mechanisms. The system handles asynchronous operations through coroutine-based methods, ensuring non-blocking execution during data loading and drawing operations.
flowchart TD
A[Register with @register_indicator] --> B[Create Instance]
B --> C[Activate via TVEngine]
C --> D[Initialize on_init]
D --> E[Data Loaded on_data_loaded]
E --> F[Calculate Start on_calculate_start]
F --> G[Execute calculate]
G --> H[Calculate End on_calculate_end]
H --> I[Draw Start on_draw_start]
I --> J[Execute draw]
J --> K[Draw End on_draw_end]
K --> L[Wait for Events]
L --> M[Deactivate on_destroy]
M --> N[Destroy Instance]
Indicator registration is accomplished through the @register_indicator decorator, which automatically registers indicator classes with the IndicatorRegistry singleton. The decorator accepts optional parameters for specifying the indicator name and enabling status. When a class is decorated, it is validated to ensure it inherits from TVIndicator and then stored in the registry with its configuration metadata.
The IndicatorRegistry maintains a global collection of all registered indicators, providing methods to create instances, check registration status, and manage enabled/disabled states. This centralized registry enables the TVEngine to discover and instantiate indicators dynamically at runtime. The registry also supports listing all registered indicators and retrieving detailed information about each indicator's configuration.
classDiagram
class IndicatorRegistry {
+_instance : IndicatorRegistry
+_indicators : Dict[str, Type[TVIndicator]]
+_enabled_indicators : Dict[str, bool]
+get_instance() IndicatorRegistry
+register(indicator_class, name, enabled) void
+create_instance(name) TVIndicator
+get(name) Type[TVIndicator]
+list_enabled() List[str]
}
class TVIndicator {
+get_config() IndicatorConfig
+calculate(df) Tuple[List[TVSignal], List[TVDrawable]]
+draw(chart, df, signals, drawables) void
}
IndicatorRegistry --> TVIndicator : manages
register_indicator <-- TVIndicator : decorates
The TVIndicator base class defines several lifecycle callback methods that are invoked at specific points during an indicator's execution. These methods provide hooks for custom logic at each stage of the lifecycle, from initialization to destruction.
The on_init method is called when an indicator is first initialized with a widget, chart, and optional chart ID. This method establishes the indicator's context by storing references to the widget and chart objects, retrieving the indicator configuration, and setting up any initial state. The method is typically called when a chart becomes available or when an indicator is activated.
The on_data_loaded callback is invoked when historical market data has been successfully loaded for the chart. This method receives a pandas DataFrame containing OHLC (Open, High, Low, Close) data and can be used to perform initial data processing or validation before calculation begins.
These methods serve as lifecycle hooks before and after the main calculation process. on_calculate_start is called immediately before the calculate method executes, allowing for setup operations or logging. on_calculate_end is invoked after calculation completes, receiving the generated signals and drawable elements. These callbacks are useful for performance monitoring and debugging.
These drawing lifecycle methods are called before and after the rendering process. on_draw_start precedes the draw method execution and can be used to prepare drawing resources or clear previous visual elements. on_draw_end marks the completion of the drawing phase and is ideal for cleanup operations or final adjustments.
The on_destroy method is called when an indicator is being deactivated or destroyed. This callback provides an opportunity to release resources, clear drawings, and perform any necessary cleanup operations. It ensures that indicators can gracefully terminate their execution and maintain a clean state.
sequenceDiagram
participant Engine as TVEngine
participant Registry as IndicatorRegistry
participant Indicator as TVIndicator
participant Chart as TVChart
Engine->>Registry : create_instance("FalseBreakout")
Registry-->>Engine : TVIndicator instance
Engine->>Indicator : activate_indicator(name, chart_id)
Indicator->>Indicator : set_chart_id(chart_id)
Engine->>Indicator : on_init(widget, chart, chart_id)
Chart->>Indicator : onDataLoaded callback
Indicator->>Indicator : on_data_loaded(df)
Indicator->>Indicator : on_calculate_start()
Indicator->>Indicator : calculate(df)
Indicator->>Indicator : on_calculate_end(signals, drawables)
Indicator->>Indicator : on_draw_start()
Indicator->>Indicator : draw(chart, df, signals, drawables)
Indicator->>Indicator : on_draw_end()
Engine->>Indicator : deactivate_indicator(name, chart_id)
Indicator->>Indicator : on_destroy()
The TVEngine manages indicator activation through the activate_indicator method, which establishes the chart context for indicator instances. When an indicator is activated, the engine creates or retrieves a ChartContext that maintains isolated state for that specific chart. This context contains references to the chart object, active indicators, and chart-specific metadata such as symbol and interval information.
The ChartContextManager serves as the central coordinator for multi-chart scenarios, tracking contexts for all active charts in the layout. It provides methods to create, retrieve, and remove chart contexts as users switch between different chart configurations. This architecture enables seamless transitions between layouts while preserving indicator state within each chart context.
When a new chart layout is detected, the engine performs a cleanup of existing contexts and reinitializes all charts with their respective indicators. This process ensures that indicators are properly initialized with the correct chart references and that any previous drawings are cleared before new calculations begin. The context manager also supports querying which charts have specific indicators activated, enabling targeted operations across multiple charts.
classDiagram
class ChartContextManager {
+_contexts : Dict[str, ChartContext]
+create_context(chart_id, chart) ChartContext
+get_context(chart_id) ChartContext
+remove_context(chart_id) ChartContext
+get_all_contexts() Dict[str, ChartContext]
+get_charts_with_indicator(name) List[str]
}
class ChartContext {
+chart_id : str
+chart : TVChart
+active_indicators : Dict[str, TVIndicator]
+symbol : Optional[str]
+interval : Optional[str]
+add_indicator(name, indicator) void
+remove_indicator(name) TVIndicator
+has_indicator(name) bool
}
class TVEngine {
+activate_indicator(name, chart_id) bool
+deactivate_indicator(name, chart_id) bool
+chart_context_manager : ChartContextManager
}
ChartContextManager --> ChartContext : contains
TVEngine --> ChartContextManager : uses
ChartContext --> TVIndicator : contains
The FalseBreakoutIndicator provides a concrete implementation of the indicator lifecycle, demonstrating proper handling of configuration, calculation, and drawing operations. Registered with the @register_indicator decorator, this indicator detects false breakout patterns in price action by identifying instances where price creates a new high or low and then reverses direction.
The indicator's get_config method defines its parameters, including the false breakout period, minimum and maximum periods for signal validity, and smoothing options. These inputs allow users to customize the indicator's sensitivity and behavior. The configuration also includes style definitions for visual elements, specifying colors and line properties for upward and downward false breakout signals.
During the calculation phase, the indicator processes OHLC data to identify potential false breakout patterns, applying configurable smoothing algorithms such as WMA (Weighted Moving Average) or HMA (Hull Moving Average). When a valid pattern is detected, the indicator generates TVSignal objects representing buy or sell signals and TVDrawable objects for visual elements like trend lines and arrows. The drawing implementation creates horizontal trend lines at the breakout price level, styled according to the indicator's configuration.
flowchart TD
A[FalseBreakoutIndicator] --> B[Configuration]
B --> C[Period: 20]
B --> D[Min Period: 5]
B --> E[Max Period: 5]
B --> F[Smoothing: Diamond/WMA/HMA]
B --> G[Aggressive Mode: Boolean]
A --> H[Calculation Logic]
H --> I[Detect New Highs/Lows]
I --> J[Apply Smoothing]
J --> K[Check Breakout Conditions]
K --> L[Validate Min/Max Periods]
L --> M[Generate Signals]
A --> N[Drawing Elements]
N --> O[Horizontal Trend Lines]
O --> P[Style: Color, Width, Transparency]
N --> Q[Buy/Sell Arrows]
Q --> R[Style: Color, Size]
A --> S[Lifecycle Management]
S --> T[on_init: Setup Context]
S --> U[on_data_loaded: Process Data]
S --> V[on_calculate_start/end: Performance Logging]
S --> W[on_draw_start/end: Drawing Management]
S --> X[on_destroy: Cleanup]
Effective state management is critical for maintaining indicator integrity across the lifecycle. The TVIndicator base class provides several state properties, including _cached_df for storing historical data, _last_signals and _last_drawables for caching calculation results, and _drawn_entities for tracking created visual elements. These properties enable efficient recalculation and prevent redundant operations when configuration changes occur.
A common issue in indicator development is improper state management across lifecycle stages, particularly when handling asynchronous initialization. The recalculate_and_redraw method addresses this by coordinating the calculation and drawing phases, ensuring that drawings are cleared before new elements are created. The _needs_recalculate flag tracks whether configuration changes require recalculation, preventing unnecessary processing.
Another frequent challenge is managing resources in multi-chart scenarios, where indicators may be activated and deactivated as users switch layouts. The ChartContextManager resolves this by isolating state per chart and providing proper cleanup during layout transitions. The clear_all_drawings method ensures that all visual elements are properly removed from the chart before deactivation, preventing orphaned graphics.
For asynchronous initialization, the system uses coroutine patterns to handle data loading and drawing operations without blocking the main thread. The on_data_loaded callback is designed to work with TradingView's asynchronous data export mechanism, allowing indicators to process data as it becomes available. This approach ensures responsive performance even with large datasets.
flowchart TD
A[State Management Issues] --> B[Improper State Persistence]
B --> C[Data not cached between calculations]
B --> D[Signals not preserved across updates]
B --> E[Drawings not tracked for cleanup]
A --> F[Asynchronous Challenges]
F --> G[Data loading race conditions]
F --> H[Drawing operations on uninitialized charts]
F --> I[Callback timing issues]
A --> J[Solutions]
J --> K[Use _cached_df for data persistence]
J --> L[Store _last_signals and _last_drawables]
J --> M[Track _drawn_entities for cleanup]
J --> N[Use async/await for operations]
J --> O[Validate chart/widget references]
J --> P[Implement recalculate_and_redraw]
Efficient lifecycle management is essential for high-frequency scenarios where indicators must process data and update visuals rapidly. The system incorporates several performance optimizations, including data caching, selective recalculation, and batched drawing operations. By caching the input DataFrame in _cached_df, indicators avoid redundant data loading operations when recalculating due to configuration changes.
The recalculate_and_redraw method optimizes performance by combining calculation and drawing into a single coordinated operation, minimizing chart interactions. This approach reduces the overhead of multiple round-trips between the indicator engine and the TradingView chart interface. The method also includes error handling to prevent crashes during high-frequency updates, ensuring system stability under heavy load.
For high-frequency scenarios, indicators should minimize expensive operations in their lifecycle callbacks. The on_calculate_start and on_calculate_end methods should avoid complex computations, reserving intensive processing for the main calculate method. Similarly, drawing operations should be optimized by batching entity creation and minimizing the number of chart API calls.
Memory management is another critical consideration, particularly in multi-chart scenarios. The ChartContextManager helps control memory usage by isolating state per chart and properly cleaning up resources during layout transitions. Indicators should release large data structures when deactivated and avoid creating circular references that could prevent garbage collection.
flowchart TD
A[Performance Optimization] --> B[Data Caching]
B --> C[Store _cached_df]
B --> D[Cache calculation results]
B --> E[Minimize data reloading]
A --> F[Efficient Recalculation]
F --> G[Use _needs_recalculate flag]
F --> H[Batch calculation and drawing]
F --> I[Avoid redundant operations]
A --> G[Drawing Optimization]
G --> H[Batch entity creation]
G --> I[Minimize chart API calls]
G --> J[Clear drawings efficiently]
A --> K[Memory Management]
K --> L[Isolate state per chart]
K --> M[Clean up on deactivation]
K --> N[Release large data structures]