# How to Add a New Broker Integration to Fincept Terminal’s Trading Engine

> Learn to add a new broker integration to Fincept Terminal's trading engine. Implement IBroker virtual methods, register your class, and extend InstrumentService for seamless trading.

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

---

**To add a new broker integration to Fincept Terminal, create a C++ class that inherits from `IBroker`, implement the required virtual methods for authentication and trading operations, register the class in `BrokerRegistry::register_all()`, and optionally extend `InstrumentService` to support the broker’s symbol master.**

Fincept Terminal is an open-source trading platform built on a modular plug-in architecture that abstracts broker connectivity through a common interface. If you want to add a new broker integration to Fincept Terminal, you will work within the `fincept-qt/src/trading/` directory to implement a concrete broker class and wire it into the central registry. This guide walks through the complete implementation process using the actual source code structure from the Fincept-Corporation/FinceptTerminal repository.

## 1. Understand the Broker Interface (`IBroker`)

All broker implementations must conform to the pure-virtual API defined in [`fincept-qt/src/trading/BrokerInterface.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/BrokerInterface.h). The `IBroker` interface defines the contract for identity, authentication, order management, portfolio queries, and market data retrieval.

Key methods you must implement include:

- **`BrokerId id() const`** – Returns the unique enum identifier from the `BrokerId` enumeration.
- **`const char* name() const`** – Human-readable broker name for UI display.
- **`const char* base_url() const`** – Base URL for the broker’s REST API endpoints.
- **`BrokerProfile profile() const`** – Metadata struct defining credential fields, supported exchanges, product types, and UI defaults.
- **`TokenExchangeResponse exchange_token(...)`** – Exchanges temporary OAuth codes or credentials for access tokens.
- **Order lifecycle** – `place_order()`, `modify_order()`, and `cancel_order()` handle CRUD operations for orders.
- **Portfolio queries** – `get_orders()`, `get_positions()`, `get_holdings()`, and `get_funds()` retrieve account state.
- **Market data** – `get_quotes()` and `get_history()` fetch real-time and historical price data.
- **`auth_headers()`** – Protected helper that constructs authentication headers for every HTTP request.

The interface also provides helper methods for secure credential storage via `SecureStorage`. Study existing implementations such as `UpstoxBroker` and `ZerodhaBroker` in `fincept-qt/src/trading/brokers/` to understand concrete patterns for error handling and response parsing.

## 2. Create the Broker Class

Create a new header and source file pair under `fincept-qt/src/trading/brokers/<yourbroker>/`. The class must inherit from `IBroker` and implement all pure-virtual methods.

Below is a skeleton structure replacing `<YourBroker>` with your actual broker name:

```cpp
#pragma once
#include "trading/BrokerInterface.h"
#include "trading/brokers/BrokerHttp.h"

namespace fincept::trading {

class <YourBroker> : public IBroker {
  public:
    // Identity
    BrokerId id() const override { return BrokerId::<YourBroker>; }
    const char* name() const override { return "<YourBrokerDisplayName>"; }
    const char* base_url() const override { return "https://api.<yourbroker>.com/v1"; }

    // UI profile metadata
    BrokerProfile profile() const override {
        return BrokerProfile{
            .id = "<yourbroker>",
            .display_name = "<YourBrokerDisplayName>",
            .region = "IN",
            .currency = "INR",
            .credential_fields = {
                {CredentialField::ApiKey, "API KEY", "Enter API Key...", false},
                {CredentialField::ApiSecret, "API SECRET", "Enter API Secret...", true},
                {CredentialField::AuthCode, "AUTH CODE", "Paste auth code...", false},
            },
            .exchanges = {"NSE", "BSE", "NFO"},
            .product_types = {
                {"Intraday (I)", ProductType::Intraday},
                {"Delivery (D)", ProductType::Delivery},
                {"Margin (MTF)", ProductType::Margin},
            },
            .supports_intraday = true,
            .supports_bracket_order = false,
            .supports_cover_order = false,
            .has_native_paper = false,
            .default_paper_balance = 1e6,
            .default_watchlist = {"RELIANCE", "TCS", "INFY"},
            .default_symbol = "RELIANCE",
            .default_exchange = "NSE",
            .brokerage_info = "₹20/order flat",
        };
    }

    // Authentication
    TokenExchangeResponse exchange_token(const QString& api_key,
                                         const QString& api_secret,
                                         const QString& auth_code) override;

    // Order lifecycle
    OrderPlaceResponse place_order(const BrokerCredentials& creds,
                                   const UnifiedOrder& order) override;
    ApiResponse<QJsonObject> modify_order(const BrokerCredentials& creds,
                                          const QString& order_id,
                                          const QJsonObject& mods) override;
    ApiResponse<QJsonObject> cancel_order(const BrokerCredentials& creds,
                                          const QString& order_id) override;

    // Portfolio
    ApiResponse<QVector<BrokerOrderInfo>> get_orders(const BrokerCredentials& creds) override;
    ApiResponse<QJsonObject> get_trade_book(const BrokerCredentials& creds) override;
    ApiResponse<QVector<BrokerPosition>> get_positions(const BrokerCredentials& creds) override;
    ApiResponse<QVector<BrokerHolding>> get_holdings(const BrokerCredentials& creds) override;
    ApiResponse<BrokerFunds> get_funds(const BrokerCredentials& creds) override;

    // Market data
    ApiResponse<QVector<BrokerQuote>> get_quotes(const BrokerCredentials& creds,
                                                 const QVector<QString>& symbols) override;
    ApiResponse<QVector<BrokerCandle>> get_history(const BrokerCredentials& creds,
                                                   const QString& symbol,
                                                   const QString& resolution,
                                                   const QString& from_date,
                                                   const QString& to_date) override;

  protected:
    QMap<QString, QString> auth_headers(const BrokerCredentials& creds) const override;
};

} // namespace fincept::trading

```

Implement the corresponding `.cpp` file following the patterns in [`UpstoxBroker.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/UpstoxBroker.cpp). Use `BrokerHttp::instance()` for all network operations, and implement `checked_error` and `is_token_expired` helpers to handle API errors consistently.

## 3. Register the Broker in `BrokerRegistry`

After implementing the broker class, you must register it so the application can discover and instantiate it. Open [`fincept-qt/src/trading/BrokerRegistry.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/BrokerRegistry.cpp) and modify the `register_all()` method.

First, include your broker header:

```cpp
#include "trading/brokers/<yourbroker>/<YourBroker>.h"

```

Then add the registration inside `register_all()`:

```cpp
brokers_["<yourbroker>"] = std::make_unique<<YourBroker>>();

```

The string key `"<yourbroker>"` must exactly match the `id` field returned by your `BrokerProfile::id` method. This key is used throughout the UI and when fetching instrument data.

## 4. Implement Instrument Download and Parsing (Optional)

If your broker provides an instrument master file (CSV, JSON, or proprietary format), you should extend `InstrumentService` to download and parse it. This enables symbol search and validation in the UI.

### 4.1 Add Download Logic

Locate [`fincept-qt/src/trading/instruments/InstrumentService.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/instruments/InstrumentService.cpp) and find the `do_refresh()` method. Add a branch for your broker:

```cpp
} else if (broker_id == "<yourbroker>") {
    payload = download_<yourbroker>_instruments(creds);
}

```

Implement `download_<yourbroker>_instruments` as a static method or private function within `InstrumentService`. Use `BrokerHttp` for authenticated endpoints, or create a dedicated `QNetworkAccessManager` for large public files to avoid blocking the shared HTTP client.

### 4.2 Parse the Payload

Create a parser class (e.g., `<YourBroker>InstrumentParser`) that converts the raw payload into `QVector<Instrument>`. The `Instrument` struct is defined in [`fincept-qt/src/trading/instruments/InstrumentTypes.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/instruments/InstrumentTypes.h) and requires these fields:

- `symbol` – The standard trading symbol
- `exchange` – Exchange code (e.g., "NSE", "BSE")
- `instrument_token` – Broker-specific unique identifier
- `brsymbol` – Broker-formatted symbol
- `brexchange` – Broker exchange code
- `broker_id` – Your broker ID string

Integrate the parser in `InstrumentService::do_refresh()`:

```cpp
} else if (broker_id == "<yourbroker>") {
    instruments = <YourBroker>InstrumentParser::parse(payload);
}

```

If your broker does not provide an instrument list, skip this step. The UI will allow users to manually enter symbols.

## 5. Build and Test Your Integration

After implementing the code changes, you must rebuild the application and verify functionality.

### 5.1 Rebuild the Project

Fincept Terminal uses CMake presets. Run the following from the repository root:

```bash
cmake --preset default
cmake --build --preset default

```

### 5.2 Unit Testing

Locate existing broker tests under `fincept-qt/tests/` and create a new test case for your broker. Mock HTTP responses using the `BrokerHttp` testing utilities to verify:
- Token exchange parsing
- Order placement request formatting
- Error handling for expired tokens

### 5.3 Manual UI Testing

Launch the application and complete the following checklist:
1. Verify your broker appears in the "Add Broker" dialog
2. Enter test credentials and confirm successful authentication
3. Test instrument refresh (if implemented) or manual symbol entry
4. Place a test order and verify it appears in the order book
5. Check that positions and funds display correctly

## 6. Complete Example: Minimal DemoBroker

Below is a minimal, functional implementation that demonstrates the required overrides without making external API calls. This is useful for prototyping or creating a paper-trading broker.

```cpp
// fincept-qt/src/trading/brokers/demo/DemoBroker.h
#pragma once
#include "trading/BrokerInterface.h"
#include "trading/brokers/BrokerHttp.h"

namespace fincept::trading {

class DemoBroker : public IBroker {
  public:
    BrokerId id() const override { return BrokerId::Demo; }
    const char* name() const override { return "DemoBroker"; }
    const char* base_url() const override { return "https://api.demo.com/v1"; }

    BrokerProfile profile() const override {
        return BrokerProfile{
            .id = "demo",
            .display_name = "Demo Broker",
            .region = "IN",
            .currency = "INR",
            .credential_fields = {
                {CredentialField::ApiKey, "API KEY", "Enter API Key...", false},
                {CredentialField::ApiSecret, "API SECRET", "Enter API Secret...", true},
            },
            .exchanges = {"NSE"},
            .product_types = {
                {"Intraday (I)", ProductType::Intraday},
                {"Delivery (D)", ProductType::Delivery},
            },
            .supports_intraday = true,
            .has_native_paper = false,
            .default_watchlist = {"RELIANCE"},
            .default_symbol = "RELIANCE",
            .default_exchange = "NSE",
        };
    }

    TokenExchangeResponse exchange_token(const QString&, const QString&, const QString&) override {
        return {true, "demo-access-token", "", "demo-user", "", ""};
    }

    OrderPlaceResponse place_order(const BrokerCredentials&, const UnifiedOrder&) override {
        return {true, "DEMO12345", ""};
    }

    QMap<QString, QString> auth_headers(const BrokerCredentials& creds) const override {
        return {{"Authorization", "Bearer " + creds.access_token}};
    }
};

} // namespace fincept::trading

```

Register this demo broker in [`fincept-qt/src/trading/BrokerRegistry.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/BrokerRegistry.cpp):

```cpp
#include "trading/brokers/demo/DemoBroker.h"
// ...
brokers_["demo"] = std::make_unique<DemoBroker>();

```

## 7. Key Source Files to Reference

When implementing your broker, consult these files in the Fincept-Corporation/FinceptTerminal repository:

| File | Purpose |
|------|---------|
| [`fincept-qt/src/trading/BrokerInterface.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/BrokerInterface.h) | Abstract broker contract defining all virtual methods and data structures |
| [`fincept-qt/src/trading/BrokerRegistry.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/BrokerRegistry.cpp) | Central registry where broker instances are created and stored |
| [`fincept-qt/src/trading/brokers/upstox/UpstoxBroker.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/brokers/upstox/UpstoxBroker.h) and `.cpp` | Full-featured reference implementation showing authentication, orders, and market data |
| [`fincept-qt/src/trading/brokers/zerodha/ZerodhaBroker.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/brokers/zerodha/ZerodhaBroker.cpp) | Example of token expiry handling and CSV instrument download |
| [`fincept-qt/src/trading/instruments/InstrumentService.cpp`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/instruments/InstrumentService.cpp) | Instrument download, parsing, caching, and database persistence logic |
| [`fincept-qt/src/trading/instruments/InstrumentTypes.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/fincept-qt/src/trading/instruments/InstrumentTypes.h) | Data model for instruments including `symbol`, `instrument_token`, and `broker_id` |

## Summary

- **Subclass `IBroker`** and implement identity (`id`, `name`, `base_url`), UI profile (`profile`), authentication (`exchange_token`), order lifecycle (`place_order`, `modify_order`, `cancel_order`), portfolio queries (`get_orders`, `get_positions`, `get_holdings`, `get_funds`), and market data (`get_quotes`, `get_history`).
- **Use `BrokerHttp`** for all network requests and follow existing error-handling patterns using `checked_error` and `is_token_expired` helpers.
- **Register your broker** in `BrokerRegistry::register_all()` by adding a `std::make_unique` call with a string key matching your `BrokerProfile::id`.
- **Extend `InstrumentService`** if your broker provides a symbol master, implementing a download function and parser that populates the `Instrument` struct defined in [`InstrumentTypes.h`](https://github.com/Fincept-Corporation/FinceptTerminal/blob/main/InstrumentTypes.h).
- **Build with CMake presets** and verify functionality through unit tests and manual UI validation.

## Frequently Asked Questions

### Do I need to modify the UI code to add a new broker integration to Fincept Terminal?

No. The Fincept Terminal UI dynamically populates broker lists, credential forms, and exchange selectors based on the `BrokerProfile` struct returned by your `IBroker` implementation. As long as you correctly populate the `credential_fields`, `exchanges`, and `product_types` vectors in `profile()`, the UI will render appropriate input fields and dropdowns automatically.

### How do I handle OAuth 2.0 authentication flows?

Implement the `exchange_token()` method to exchange the temporary authorization code for an access token. Use `BrokerHttp::instance()` to POST to the broker’s token endpoint, passing the `api_key` and `api_secret` as headers or body parameters depending on the broker’s specification. Return a `TokenExchangeResponse` containing the `access_token`, `refresh_token` (if applicable), and user identifier. Store sensitive tokens using the `SecureStorage` helpers available in `IBroker`.

### What if my broker doesn't provide an instrument list API?

If the broker does not expose a downloadable symbol master, you can skip the `InstrumentService` extension. The Fincept Terminal UI allows users to manually type symbols. Simply ensure your `profile()` method returns an empty `default_watchlist` or populates it with commonly traded symbols as hints. When `get_quotes()` or `place_order()` receives a symbol string, validate it against the broker’s API directly rather than a local cache.

### How do I test my broker implementation without a live account?

Create a “DemoBroker” implementation that inherits `IBroker` but returns hardcoded responses instead of making HTTP calls. Override `exchange_token()` to return a fake token, `place_order()` to return a dummy order ID like `"DEMO12345"`, and market data methods to return static quote structures. Register this implementation in `BrokerRegistry` under a `"demo"` key. This allows you to validate the UI flow, order ticket formatting, and position tracking without network latency or real credentials.