# How to Implement Custom Data Connectors for Fincept’s 100+ Data Sources

> Learn to implement custom data connectors for Fincept s 100 data sources using the plug-in style connector registry and DataHub for seamless data integration.

- Repository: [Fincept Corporation/FinceptTerminal](https://github.com/Fincept-Corporation/FinceptTerminal)
- Tags: how-to-guide
- Published: 2026-04-20

---

**Fincept Terminal exposes a plug-in style connector registry that lets you add new data sources by declaring a `ConnectorConfig`, registering it statically, and implementing a lightweight service that publishes data via the `DataHub`.**

Fincept Terminal manages its extensive ecosystem of data providers through a **data-driven connector architecture**. Whether you are integrating a proprietary market feed, a cloud time-series database, or an internal REST API, the process follows the same three-layer pattern used by the 100+ built-in sources. This guide walks you through implementing custom data connectors for Fincept using the exact structures found in the repository.

## Understanding the Connector Architecture

### The Three-Layer Pattern

Every connector in `FinceptTerminal` is composed of three distinct layers:

1. **Connector Definition** – A declarative `ConnectorConfig` object (ID, UI label, category, input fields, and defaults).
2. **Registration** – A static initialization block that pushes the configuration into the global `ConnectorRegistry` at program startup.
3. **Data Retrieval** – A service (C++ or Python) that communicates with the external system and publishes results via `DataHub` for streaming or returns batch payloads.

This architecture decouples the UI from the implementation. The `DataSourcesScreen` automatically generates configuration dialogs from the field list, allowing you to swap service implementations without touching interface code.

### Key Components

**`ConnectorRegistry`** ([`fincept-qt/src/screens/data_sources/ConnectorRegistry.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/data_sources/ConnectorRegistry.h))  
A singleton that stores all `ConnectorConfig` objects. Access it via `ConnectorRegistry::instance()` and call `add()` to register new connectors.

**`ConnectorConfig`** ([`fincept-qt/src/screens/data_sources/DataSourceTypes.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/data_sources/DataSourceTypes.h))  
Defines the schema for a connector, including `id`, `name`, `category`, `color`, and a `QVector<FieldConfig>` describing UI inputs (URLs, passwords, dropdowns).

**`DataHub`** ([`fincept-qt/src/datahub/DataHub.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/datahub/DataHub.h))  
The internal pub/sub bus. Services publish data using `DataHub::instance().publish(topic, QVariant::fromValue(payload))`, and consumers (charts, watchlists) subscribe to topics like `market:quote:AAPL`.

**`PythonRunner`** ([`fincept-qt/src/python/PythonRunner.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/python/PythonRunner.cpp))  
Executes custom Python scripts for data extraction, returning JSON that the C++ side wraps as `QVariant`. This provides an alternative to writing C++ services.

## Step-by-Step Implementation Guide

### Step 1 – Define the Connector Configuration

Create a new file in [`fincept-qt/src/screens/data_sources/connectors/YourConnector.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/data_sources/connectors/YourConnector.cpp). Define a function that returns a `QVector<ConnectorConfig>` containing your data source metadata and field definitions.

```cpp
// IOOPlusConnector.cpp
#include "screens/data_sources/ConnectorRegistry.h"
#include "screens/data_sources/DataSourceTypes.h"

namespace fincept::screens::datasources {

static QVector<ConnectorConfig> ioo_plus_configs() {
    return {
        { "ioo-plus",
          "IOO+ Data Feed",
          "ioo-plus",
          Category::MarketData,
          "I",
          "#009688",
          "Custom IOO+ endpoint supporting realtime quotes and historic bars",
          true,
          false,
          {
            {"baseUrl",  "Base URL",  FieldType::Url,      "https://api.iooplus.com", true, "", {}},
            {"apiKey",   "API Key",   FieldType::Password, "",                       true, "", {}},
            {"symbols",  "Symbols",   FieldType::Text,     "AAPL,MSFT,GOOGL",       false, "", {}},
            {"interval", "Interval",  FieldType::Select,   "",                       false, "1d",
               { {"1 minute","1m"}, {"5 minutes","5m"}, {"1 hour","1h"}, {"1 day","1d"} } }
          }
        }
    };
}

} // namespace

```

### Step 2 – Register with ConnectorRegistry

Use a static initialization lambda to push your configurations into the registry. This pattern ensures the linker includes your translation unit and the connector appears at startup.

```cpp
// Add to the same IOOPlusConnector.cpp file
static bool registered = []{
    for (auto &c : ioo_plus_configs())
        ConnectorRegistry::instance().add(std::move(c));
    return true;
}();

```

This self-registration pattern is identical to the implementation in [`TimeSeriesDatabases.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/TimeSeriesDatabases.cpp) and [`MarketData.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketData.cpp).

### Step 3 – Implement the Data Retrieval Service

Create a service class that handles HTTP requests or WebSocket connections. In [`fincept-qt/src/services/iooplus/IOOPlusService.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/services/iooplus/IOOPlusService.cpp):

```cpp
#include "services/iooplus/IOOPlusService.h"
#include "core/network/http/HttpClient.h"
#include "datahub/DataHub.h"

using namespace fincept::core::network;

namespace fincept::services::iooplus {

void IOOPlusService::fetchQuotes(const QString &baseUrl,
                                 const QString &apiKey,
                                 const QStringList &symbols,
                                 std::function<void(bool, const QJsonArray&)> cb)
{
    QUrl url(baseUrl + "/quotes");
    QUrlQuery query;
    query.addQueryItem("symbols", symbols.join(','));
    url.setQuery(query);

    HttpClient client;
    client.setHeader(QByteArrayLiteral("Authorization"),
                    QByteArrayLiteral("Bearer ") + apiKey.toUtf8());

    client.get(url, [cb](Result<QByteArray> res){
        if (!res) { cb(false, {}); return; }
        QJsonDocument doc = QJsonDocument::fromJson(*res);
        cb(true, doc.array());
    });
}

void IOOPlusService::publishQuotes(const QJsonArray &quotes) {
    for (const QJsonValue &v : quotes) {
        QString symbol = v.toObject()["symbol"].toString();
        QString topic = QStringLiteral("market:quote:%1").arg(symbol);
        DataHub::instance().publish(topic, QVariant::fromValue(v.toObject()));
    }
}

} // namespace

```

Alternatively, use the `PythonRunner` for rapid prototyping by placing a script in [`fincept-qt/python/ioo_plus_fetcher.py`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/python/ioo_plus_fetcher.py) and invoking it via `PythonRunner::runScript()`.

### Step 4 – Build and Verify

Add your new files to [`fincept-qt/CMakeLists.txt`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/CMakeLists.txt):

```cmake
target_sources(fincept-qt PRIVATE
    src/screens/data_sources/connectors/IOOPlusConnector.cpp
    src/services/iooplus/IOOPlusService.cpp
)

```

Build the project, launch Fincept Terminal, and navigate to **Settings → Data Sources**. Your **IOO+ Data Feed** connector will appear automatically. Configure the endpoint, save, and trigger a fetch to verify data flows through `DataHub` to your subscribed screens.

## Summary

- **Custom data connectors for Fincept** are implemented via a declarative `ConnectorConfig` object that defines UI fields and metadata.
- **Static registration** via `ConnectorRegistry::instance().add()` ensures connectors self-register at program startup without modifying central lists.
- **Data retrieval** is handled by services (C++ or Python) that communicate with external APIs and publish results through the `DataHub` pub/sub system.
- **Zero UI changes** are required; the `DataSourcesScreen` dynamically generates configuration dialogs from the `FieldConfig` vector.
- **Reference implementations** in [`MarketData.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/MarketData.cpp) and [`TimeSeriesDatabases.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/TimeSeriesDatabases.cpp) provide proven templates for new connectors.

## Frequently Asked Questions

### What is the ConnectorRegistry in Fincept Terminal?

The `ConnectorRegistry` is a singleton class defined in [`fincept-qt/src/screens/data_sources/ConnectorRegistry.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/screens/data_sources/ConnectorRegistry.h) that stores all available `ConnectorConfig` objects. It provides static initialization hooks that allow new connectors to self-register at startup by calling `ConnectorRegistry::instance().add()`, eliminating the need to edit central configuration files when adding new data sources.

### Do I need to modify the UI code to add a new data connector?

No. The `DataSourcesScreen` automatically reads all entries from `ConnectorRegistry::instance().all()` and constructs the configuration table and dialogs dynamically based on the `FieldConfig` vector inside each `ConnectorConfig`. As long as you properly define your fields (URL, password, text, select dropdowns), the UI will render the appropriate input controls without any manual QML or Qt Widgets modifications.

### Can I use Python instead of C++ for the data retrieval service?

Yes. Fincept Terminal includes a `PythonRunner` component in [`fincept-qt/src/python/PythonRunner.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/python/PythonRunner.cpp) that can execute Python scripts for data extraction and analytics. You can place your integration script in `fincept-qt/python/` and invoke it via `PythonRunner::runScript()`, which returns JSON that the C++ side wraps as `QVariant` and publishes through `DataHub`. This is ideal for rapid prototyping or when integrating with Python-native APIs.