Skip to content

Custom Datafeed Implementation

levi edited this page Nov 6, 2025 · 2 revisions

Custom Datafeed Implementation

Table of Contents

  1. Introduction
  2. Core Interfaces Overview
  3. onReady Implementation
  4. resolveSymbol Implementation
  5. getBars Implementation
  6. subscribeBars and unsubscribeBars Implementation
  7. Subscriber Lifecycle Management
  8. Error Handling and Common Issues
  9. Best Practices for High-Frequency Scenarios

Introduction

This document provides comprehensive guidance for implementing a custom datafeed by extending the TVDatafeed class. The implementation requires proper handling of abstract methods from the TVIExternalDatafeed, TVIDatafeedChartApi, and TVIDatafeedQuotesApi interfaces to enable seamless integration with TradingView's charting library. The document covers the complete workflow from configuration initialization through symbol resolution, historical data retrieval, and real-time data streaming.

Core Interfaces Overview

The custom datafeed implementation must satisfy three core interfaces that define the contract between the data provider and TradingView's charting library:

  1. TVIExternalDatafeed: Provides configuration information to the library
  2. TVIDatafeedChartApi: Handles chart-related data operations including symbol search, resolution, and historical data retrieval
  3. TVIDatafeedQuotesApi: Manages real-time quote data subscription and delivery

These interfaces are implemented in the base TVDatafeed class, which serves as the foundation for custom implementations. The BADatafeed class provides a concrete example of how to extend this base implementation.

classDiagram
class TVIExternalDatafeed {
<<interface>>
+onReady(callback : TVOnReadyCallback) void
}
class TVIDatafeedChartApi {
<<interface>>
+searchSymbols(userInput : str, exchange : str, symbolType : str, onResult : TVSearchSymbolsCallback) void
+resolveSymbol(symbolName : str, onResolve : TVResolveCallback, onError : TVDatafeedErrorCallback, extension : TVSymbolResolveExtension) void
+getBars(symbolInfo : TVLibrarySymbolInfo, resolution : ResolutionString, periodParams : TVPeriodParams, onResult : TVHistoryCallback, onError : TVDatafeedErrorCallback) void
+subscribeBars(symbolInfo : TVLibrarySymbolInfo, resolution : ResolutionString, onTick : TVSubscribeBarsCallback, listenerGuid : str, onResetCacheNeededCallback : Callable[[], None]) void
+unsubscribeBars(listenerGuid : str) void
}
class TVIDatafeedQuotesApi {
<<interface>>
+getQuotes(symbols : List[str], onDataCallback : TVQuotesCallback, onErrorCallback : TVQuotesErrorCallback) void
+subscribeQuotes(symbols : List[str], fastSymbols : List[str], onRealtimeCallback : TVQuotesCallback, listenerGUID : str) void
+unsubscribeQuotes(listenerGUID : str) void
}
class TVDatafeed {
-_configuration : Optional[TVDatafeedConfiguration]
-_subscribers : Dict[str, Any]
-_quote_subscribers : Dict[str, Any]
+__init__() void
}
class BADatafeed {
+__init__() void
+onReady(callback : TVOnReadyCallback) void
+searchSymbols(userInput : str, exchange : str, symbolType : str, onResult : TVSearchSymbolsCallback) void
+resolveSymbol(symbolName : str, onResolve : TVResolveCallback, onError : TVDatafeedErrorCallback, extension : TVSymbolResolveExtension) void
+getBars(symbolInfo : TVLibrarySymbolInfo, resolution : ResolutionString, periodParams : TVPeriodParams, onResult : TVHistoryCallback, onError : TVDatafeedErrorCallback) void
+subscribeBars(symbolInfo : TVLibrarySymbolInfo, resolution : ResolutionString, onTick : TVSubscribeBarsCallback, listenerGuid : str, onResetCacheNeededCallback : Callable[[], None]) void
}
TVIExternalDatafeed <|-- TVDatafeed
TVIDatafeedChartApi <|-- TVDatafeed
TVIDatafeedQuotesApi <|-- TVDatafeed
TVDatafeed <|-- BADatafeed
Loading

onReady Implementation

The onReady method provides essential configuration information to the TradingView library. This callback is invoked when the charting library is ready to receive configuration data. The implementation must provide a TVDatafeedConfiguration object that defines the capabilities and options supported by the datafeed.

The configuration includes supported exchanges, resolutions, and various feature flags. The BADatafeed example demonstrates proper configuration with Binance and OKEx exchanges and multiple time resolutions. The onReady callback should be implemented to return the pre-configured TVDatafeedConfiguration object, ensuring the charting library understands the datafeed's capabilities.

sequenceDiagram
participant ChartingLibrary
participant Datafeed
participant Configuration
ChartingLibrary->>Datafeed : Request configuration
Datafeed->>Datafeed : Check if configuration exists
alt Configuration not initialized
Datafeed->>Configuration : Create default configuration
end
Datafeed->>ChartingLibrary : Return configuration via callback
Loading

resolveSymbol Implementation

The resolveSymbol method is responsible for providing complete symbol metadata to the charting library. This method must return a fully populated TVLibrarySymbolInfo object containing all necessary information about the requested symbol. The implementation should handle both successful resolution and error conditions appropriately.

The TVLibrarySymbolInfo object requires several mandatory fields including name, description, type, session, exchange, timezone, format, pricescale, and minmov. Additional optional fields provide enhanced functionality such as supported resolutions, volume precision, and classification data. The BADatafeed example demonstrates proper construction of the symbol info object with appropriate metadata for cryptocurrency trading pairs.

flowchart TD
Start([resolveSymbol called]) --> ValidateInput["Validate symbolName parameter"]
ValidateInput --> LookupSymbol["Lookup symbol metadata"]
LookupSymbol --> SymbolFound{"Symbol exists?"}
SymbolFound --> |Yes| ConstructInfo["Construct TVLibrarySymbolInfo object"]
ConstructInfo --> SetRequired["Set required fields: name, description, type, session, exchange, listed_exchange, timezone, format, pricescale, minmov"]
SetRequired --> SetOptional["Set optional fields: has_intraday, supported_resolutions, volume_precision, etc."]
SetOptional --> CallOnResolve["Call onResolve callback with symbol info"]
SymbolFound --> |No| HandleError["Call onError callback with error message"]
HandleError --> End([Method complete])
CallOnResolve --> End
Loading

getBars Implementation

The getBars method handles historical data retrieval for chart rendering. This method receives a TVLibrarySymbolInfo object, resolution string, and TVPeriodParams containing the time range and other parameters for the requested data. The implementation must return historical bar data through the onResult callback, along with metadata about the data availability.

The TVPeriodParams object contains important information including the time range (from_ and to), countBack (number of bars to retrieve), and firstDataRequest (indicating if this is the initial data request). The response should include a list of TVBar objects with time, open, high, low, close, and optional volume data. The TVHistoryMetadata object should indicate whether no more data is available on the server.

flowchart TD
Start([getBars called]) --> ExtractParams["Extract parameters: symbolInfo, resolution, periodParams"]
ExtractParams --> ValidateParams["Validate input parameters"]
ValidateParams --> FetchData["Retrieve historical data from source"]
FetchData --> DataRetrieved{"Data retrieved successfully?"}
DataRetrieved --> |Yes| ProcessData["Process and format bar data"]
ProcessData --> CreateBars["Create TVBar objects for each data point"]
CreateBars --> CreateMetadata["Create TVHistoryMetadata object"]
CreateMetadata --> CallOnResult["Call onResult callback with bars and metadata"]
DataRetrieved --> |No| HandleError["Call onError callback with error message"]
HandleError --> End([Method complete])
CallOnResult --> End
Loading

subscribeBars and unsubscribeBars Implementation

The subscribeBars and unsubscribeBars methods manage real-time data streaming for chart updates. The subscribeBars method establishes a subscription for real-time bar updates, while unsubscribeBars terminates the subscription. These methods work together to manage the lifecycle of real-time data feeds.

The subscribeBars implementation stores subscription information in the _subscribers dictionary using the listenerGuid as the key. The stored information includes the symbol details, resolution, callback function for delivering updates, and cache reset callback. When new data becomes available, the onTick callback is invoked with the updated TVBar object. The unsubscribeBars method removes the subscription from the dictionary, effectively stopping the data stream.

sequenceDiagram
participant ChartingLibrary
participant Datafeed
participant RealTimeSource
participant Subscriber
ChartingLibrary->>Datafeed : subscribeBars(symbolInfo, resolution, onTick, listenerGuid)
Datafeed->>Datafeed : Store subscription in _subscribers
Datafeed->>RealTimeSource : Establish real-time connection
loop Data Streaming
RealTimeSource->>Datafeed : New bar data available
Datafeed->>Datafeed : Validate subscription exists
Datafeed->>Subscriber : Call onTick callback with new bar
end
ChartingLibrary->>Datafeed : unsubscribeBars(listenerGuid)
Datafeed->>Datafeed : Remove subscription from _subscribers
Datafeed->>RealTimeSource : Close connection if no more subscribers
Loading

Subscriber Lifecycle Management

Proper management of subscriber lifecycle is critical for efficient resource utilization and preventing memory leaks. The TVDatafeed class maintains two dictionaries: _subscribers for bar updates and _quote_subscribers for quote updates. Each subscription is identified by a unique GUID provided by the charting library.

When implementing subscribeBars, the method should store all necessary subscription information including the symbol details, resolution, callback functions, and any additional context needed for data delivery. The unsubscribeBars method must clean up these resources by removing the subscription from the dictionary. In production implementations, this is often coupled with closing WebSocket connections or other real-time data sources when no more subscribers remain for a particular symbol and resolution combination.

The BADatafeed implementation demonstrates proper lifecycle management by calling the parent class's subscribeBars method and adding custom logging. This pattern allows for extension while maintaining the core functionality. Error handling should be implemented to gracefully handle cases where unsubscribe is called for a non-existent subscription.

Error Handling and Common Issues

Effective error handling is essential for robust datafeed implementation. Each method that can fail should implement proper error callbacks to communicate issues to the charting library. The TVDatafeedErrorCallback should be invoked with descriptive error messages that can help diagnose issues.

Common issues include:

  • Symbol resolution failures: Occur when requested symbols don't exist or metadata cannot be retrieved. Implement proper validation and descriptive error messages.
  • Missing historical data: Happens when the data source doesn't have data for the requested time range. Use TVHistoryMetadata with noData flag to indicate this condition.
  • Connection issues: Network problems or service outages should be handled gracefully with appropriate retry mechanisms.
  • Invalid parameters: Validate all input parameters and provide meaningful error messages.

The implementation should include comprehensive logging to aid in debugging and monitoring. The BADatafeed example demonstrates proper error handling with try-catch blocks and logging of exceptions before calling the onError callback.

Best Practices for High-Frequency Scenarios

For high-frequency data scenarios, several best practices should be followed to ensure optimal performance and reliability:

  1. Thread Safety: Implement thread-safe data structures and synchronization mechanisms when multiple threads access shared data.
  2. Asynchronous Processing: Use asynchronous programming patterns to prevent blocking operations from affecting real-time data delivery.
  3. Connection Pooling: Maintain persistent connections to data sources rather than creating new connections for each request.
  4. Data Caching: Implement caching strategies for frequently requested data to reduce load on data sources.
  5. Batch Processing: Group multiple updates into batches when possible to reduce overhead.
  6. Resource Management: Properly manage memory and other resources to prevent leaks during long-running operations.

The implementation should also consider rate limiting, backpressure handling, and graceful degradation under high load conditions. Monitoring and metrics collection are essential for identifying performance bottlenecks and optimizing the datafeed implementation.

Clone this wiki locally