Skip to content

Basic Engine Setup

levi edited this page Nov 6, 2025 · 2 revisions

Basic Engine Setup

Table of Contents

  1. Introduction
  2. Engine Initialization Process
  3. Singleton Pattern Implementation
  4. Indicator Directory Configuration
  5. Engine Execution Flow
  6. Core Component Relationships
  7. Configuration Options and Error Handling
  8. Best Practices for Production Environments

Introduction

This document provides a comprehensive analysis of the basic engine setup demonstrated in the example.py file of the PyTradingView project. The focus is on the initialization and configuration of the TVEngine, which serves as the central component for managing trading indicators within the TradingView ecosystem. The document will explore the implementation details of creating the engine instance, setting up the indicators directory, and running the engine, while also examining the relationships between TVEngine and other core components such as TVBridge and TVWidget. The analysis will cover the step-by-step execution flow, configuration options, error handling mechanisms, and best practices for organizing indicator files in production environments.

Engine Initialization Process

The engine initialization process begins with the creation of a TVEngine instance, which follows a modular inheritance hierarchy designed to separate concerns and improve maintainability. The TVEngine class inherits from TVEngineRuntime, which in turn inherits from other functional mixins that provide specific capabilities such as loading, management, configuration, remote calls, drawing, and runtime control. When the TVEngine constructor is called, it initializes the engine by setting up essential components including the indicator registry, chart context manager, widget configuration, and event bus. The initialization process ensures that the engine is properly configured and ready to handle indicator operations, with thread safety mechanisms in place to prevent race conditions during concurrent access.

classDiagram
class TVEngine {
+setup(indicators_dir, auto_activate, config)
+run(widget_config, indicators_dir, on_port)
}
class TVEngineRuntime {
+setup(indicators_dir, auto_activate, config)
+run(widget_config, indicators_dir, on_port)
+_on_chart_data_ready(widget)
+_initialize_all_charts(widget)
}
class TVEngineDrawing {
+draw_line(points, style)
+draw_shape(shape, points)
+clear_all_drawings()
}
class TVEngineRemote {
+remote_get_status()
+remote_activate_indicator(name)
+remote_deactivate_indicator(name)
}
class TVEngineConfig {
+update(config)
+validate()
+get_config()
}
class TVEngineManager {
+activate_indicator(name, chart_id)
+deactivate_indicator(name, chart_id)
+list_active_indicators()
}
class TVEngineLoader {
+load_indicators_from_directory(path)
+register_indicator(indicator)
+get_indicator(name)
}
TVEngine --> TVEngineRuntime : "inherits"
TVEngineRuntime --> TVEngineDrawing : "inherits"
TVEngineRuntime --> TVEngineRemote : "inherits"
TVEngineRuntime --> TVEngineConfig : "inherits"
TVEngineRuntime --> TVEngineManager : "inherits"
TVEngineRuntime --> TVEngineLoader : "inherits"
Loading

**Diagram sources **

Singleton Pattern Implementation

The TVEngine implements a thread-safe singleton pattern to ensure that only one instance of the engine exists throughout the application lifecycle. This is achieved through the TVEngineSingleton base class, which uses a class-level lock to synchronize access to the instance creation process. The singleton pattern is implemented in the new method, which checks if an instance already exists and creates one only if it doesn't. The get_instance class method provides a convenient way to access the singleton instance, creating it if necessary. This design ensures that all components interact with the same engine instance, maintaining consistency in state and configuration across the application. The singleton implementation also includes a reset method for testing purposes, allowing the instance to be cleared between test runs.

sequenceDiagram
participant Client
participant TVEngine
participant TVEngineSingleton
Client->>TVEngine : TVEngine()
TVEngine->>TVEngineSingleton : __new__(config)
TVEngineSingleton->>TVEngineSingleton : Acquire lock
alt Instance exists
TVEngineSingleton-->>TVEngine : Return existing instance
else Instance doesn't exist
TVEngineSingleton->>TVEngineSingleton : Create new instance
TVEngineSingleton->>TVEngineSingleton : Initialize instance
TVEngineSingleton-->>TVEngine : Return new instance
end
TVEngine-->>Client : TVEngine instance
Client->>TVEngine : get_instance()
TVEngine->>TVEngineSingleton : get_instance(config)
alt Instance exists
TVEngineSingleton-->>TVEngine : Return existing instance
else Instance doesn't exist
TVEngineSingleton->>TVEngine : TVEngine(config)
TVEngine-->>TVEngineSingleton : Return instance
end
TVEngine-->>Client : TVEngine instance
Loading

**Diagram sources **

Indicator Directory Configuration

The indicator directory configuration is handled through the setup method of the TVEngine class, which accepts an optional indicators_dir parameter specifying the path to the directory containing indicator files. When a directory path is provided, the engine loads all indicator modules from that directory, making them available for activation and use. The setup method also supports automatic activation of enabled indicators, which can be controlled through the auto_activate parameter. This configuration process is designed to be flexible, allowing developers to specify different indicator directories for different environments or use cases. The engine validates the directory path and handles any file system errors that may occur during the loading process, providing appropriate error messages to aid in troubleshooting.

flowchart TD
Start([Engine Setup]) --> ValidateInput["Validate indicators_dir parameter"]
ValidateInput --> PathValid{"Path Valid?"}
PathValid --> |No| ReturnEngine["Return engine instance"]
PathValid --> |Yes| CheckDirectory["Check if directory exists"]
CheckDirectory --> DirExists{"Directory Exists?"}
DirExists --> |No| HandleError["Raise FileNotFoundError"]
DirExists --> |Yes| CheckPermissions["Check directory read permissions"]
CheckPermissions --> HasPermissions{"Has Read Permissions?"}
HasPermissions --> |No| HandlePermissionError["Raise PermissionError"]
HasPermissions --> |Yes| LoadIndicators["Load indicators from directory"]
LoadIndicators --> ProcessFiles["Process each indicator file"]
ProcessFiles --> IsValidPython{"Valid Python file?"}
IsValidPython --> |No| SkipFile["Skip file"]
IsValidPython --> |Yes| ImportModule["Import module"]
ImportModule --> ModuleLoaded{"Module loaded successfully?"}
ModuleLoaded --> |No| LogError["Log import error"]
ModuleLoaded --> |Yes| RegisterIndicator["Register indicator with registry"]
RegisterIndicator --> NextFile["Process next file"]
NextFile --> EndLoop{"All files processed?"}
EndLoop --> |No| ProcessFiles
EndLoop --> |Yes| AutoActivate["Check auto_activate flag"]
AutoActivate --> ShouldActivate{"auto_activate=True?"}
ShouldActivate --> |No| ReturnEngine
ShouldActivate --> |Yes| ActivateEnabled["Activate enabled indicators"]
ActivateEnabled --> ReturnEngine
ReturnEngine --> End([Setup Complete])
Loading

**Diagram sources **

Engine Execution Flow

The engine execution flow is initiated by calling the run method on the TVEngine instance, which starts the main entry point for the indicator engine. The run method performs several critical steps to establish communication between the Python backend and the TradingView frontend. First, it handles any runtime configuration updates and validates the widget configuration. Then, it loads indicators from the specified directory if provided. Next, it sets up widget callbacks by registering the configuration provider and chart ready callback with the TVBridge. The engine also subscribes to chart ready events through the event bus. Finally, it starts the bridge service, which establishes an HTTP server for communication with the TradingView widget. This execution flow ensures that all components are properly initialized and connected before the engine begins processing indicator data.

sequenceDiagram
participant Main
participant TVEngine
participant TVBridge
participant Widget
Main->>TVEngine : setup('./indicators')
TVEngine->>TVEngine : Update configuration
TVEngine->>TVEngine : Load indicators from directory
TVEngine->>TVEngine : Activate enabled indicators
TVEngine-->>Main : Return engine instance
Main->>TVEngine : run()
TVEngine->>TVEngine : Merge runtime configuration
TVEngine->>TVEngine : Validate configuration
TVEngine->>TVEngine : Load indicators (if specified)
TVEngine->>TVBridge : register_config_provider(config)
TVEngine->>TVBridge : register_chart_ready_callback(callback)
TVEngine->>EventBus : subscribe(CHART_READY, handler)
TVEngine->>TVEngine : Publish BRIDGE_STARTED event
TVEngine->>TVBridge : run(on_port)
TVBridge->>TVBridge : start_http_server(on_port)
TVBridge->>TVBridge : Connect to Node server
TVBridge-->>Widget : Bridge ready
Widget->>TVBridge : chartDataReady event
TVBridge->>TVEngine : _on_chart_data_ready(widget)
TVEngine->>TVEngine : Initialize charts
TVEngine->>TVEngine : Set up data listeners
Loading

**Diagram sources **

Core Component Relationships

The TVEngine maintains critical relationships with other core components in the PyTradingView architecture, particularly TVBridge and TVWidget. The TVBridge serves as the communication layer between the Python backend and the JavaScript frontend, handling HTTP requests and responses, managing the connection to the Node server, and routing remote procedure calls. The TVEngine registers its configuration provider and chart ready callback with the TVBridge, establishing a two-way communication channel. The TVWidget represents the TradingView chart widget in the Python code, providing an interface to interact with the chart's features and data. When the chart is ready, the TVBridge invokes the chart ready callback registered by the TVEngine, passing the TVWidget instance. This allows the engine to initialize chart contexts, set up event listeners, and begin processing indicator data based on the chart's state.

classDiagram
class TVEngine {
-registry : IndicatorRegistry
-chart_context_manager : ChartContextManager
-config : TVWidgetConfig
-event_bus : EventBus
+setup()
+run()
}
class TVBridge {
-bridge_port : int
-bridge_http_app : FastAPI
-start_event : Event
-config_provider : TVWidgetConfig
-chart_ready_callback : Callable
+register_config_provider()
+register_chart_ready_callback()
+run()
}
class TVWidget {
-object_id : str
-onShortcutInfos : list[dict]
-event_callbacks : Dict[str, List[CallBackParams]]
+activeChart()
+activeChartIndex()
+createButton()
+createDropdown()
+onChartReady()
}
class IndicatorRegistry {
-indicators : Dict[str, TVIndicator]
-enabled_indicators : Set[str]
+get_instance()
+register_indicator()
+get_indicator()
+list_enabled()
}
class ChartContextManager {
-contexts : Dict[str, ChartContext]
+create_context()
+get_context()
+get_all_contexts()
+clear_all()
}
class TVWidgetConfig {
-symbol : str
-interval : str
-timezone : str
-theme : str
+update()
+validate()
+to_dict()
}
class EventBus {
-subscribers : Dict[EventType, List[Callable]]
-event_queue : asyncio.Queue
+get_instance()
+subscribe()
+subscribe_async()
+publish()
+publish_sync()
}
TVEngine --> TVBridge : "registers callbacks"
TVEngine --> TVWidget : "interacts with"
TVEngine --> IndicatorRegistry : "uses"
TVEngine --> ChartContextManager : "uses"
TVEngine --> TVWidgetConfig : "uses"
TVEngine --> EventBus : "uses"
TVBridge --> TVWidgetConfig : "stores reference"
TVBridge --> TVWidget : "invokes callbacks"
Loading

**Diagram sources **

Configuration Options and Error Handling

The TVEngine provides several configuration options for the setup method, allowing developers to customize the engine's behavior according to their specific requirements. The primary configuration parameters include the indicators_dir for specifying the directory containing indicator files, auto_activate for controlling whether enabled indicators are automatically activated, and config for providing additional widget configuration options. The engine implements comprehensive error handling to address potential issues such as module import errors, directory permission problems, and engine initialization conflicts. When importing indicator modules, the engine catches import exceptions and logs appropriate error messages. For directory operations, it validates the path existence and read permissions, raising specific exceptions when these checks fail. The singleton pattern implementation prevents multiple engine initializations, ensuring consistent state management across the application.

Best Practices for Production Environments

For production environments, it is recommended to organize indicator files in a structured directory hierarchy that reflects the functional categories of the indicators. Each indicator should be implemented in a separate Python file with a clear and descriptive name, following consistent naming conventions across the codebase. The indicators directory should include an init.py file to make it a proper Python package, allowing for easy imports and module discovery. Indicator files should be thoroughly tested and documented, with clear comments explaining the algorithm logic and configuration options. It is also advisable to implement version control for indicator configurations, allowing for easy rollback to previous versions if needed. Regular code reviews and static analysis should be performed to ensure code quality and maintainability. Additionally, monitoring and logging should be implemented to track indicator performance and detect any issues in real-time.

Clone this wiki locally