The factory

Market data connections

The factory INTERFACE

The factory is the public face of your connection: it names the venue, declares which credentials the host should collect, and turns those credentials into a live provider.

What the factory is

IDataProviderFactory exists so the host can describe your provider before any credentials are entered. It carries a stable Key that identifies the venue across sessions, a DisplayName for the provider list, and a list of RequiredCredentials that the host turns directly into a form. Nothing connects yet — the factory is pure metadata plus one construction method.

IDataProviderFactory.csusing System.Collections.Generic;

namespace TradeStrike.Pipeline.Providers;

public interface IDataProviderFactory
{
    // Stable lower-case id, e.g. "polygon". Matches IDataProvider.Key.
    string Key { get; }

    // Shown in the host's provider list.
    string DisplayName { get; }

    // Fields the host must collect before Create can be called. Ordered for UI display.
    IReadOnlyList<ProviderCredentialField> RequiredCredentials { get; }

    // Validate + construct. The provider starts Disconnected; the host calls
    // ConnectAsync to bring it online. Throws ArgumentException on a missing/empty
    // required field.
    IDataProvider Create(IReadOnlyDictionary<string, string> credentials);
}

Declaring credential fields

Each ProviderCredentialField describes one input row. Kind drives how the host renders it — a Secret field is masked, a Url field validates shape, a Toggle becomes a checkbox — while Placeholder and Required tune the editor. Keep each field's Key stable, because it doubles as the dictionary key you read back in Create.

ProviderCredentialField.csnamespace TradeStrike.Pipeline.Providers;

public sealed record ProviderCredentialField(
    string Key,
    string DisplayName,
    ProviderCredentialKind Kind,
    string? Placeholder = null,
    bool Required = true);

public enum ProviderCredentialKind
{
    Plain,   // free-text box
    Secret,  // masked (password / API secret)
    Choice,  // single-choice from a fixed list
    Toggle,  // boolean checkbox
    Url,     // URL field, rendered with URL validation
}

Creating the provider

When the user submits the form, the host calls Create(credentials) with the collected values as a IReadOnlyDictionary<string, string> keyed by each field's Key. This is the right place to validate — a missing API key or a malformed URL should throw ArgumentException here, so the failure surfaces in the credentials dialog rather than later during a connection attempt. The contract requires you to reject every empty Required field before constructing. On success you return a fully constructed, still disconnected IDataProvider; the host calls ConnectAsync afterwards.

PolygonDataFactory.csusing System;
using System.Collections.Generic;
using TradeStrike.Pipeline.Providers;

public sealed class PolygonDataFactory : IDataProviderFactory
{
    public string Key => "polygon";
    public string DisplayName => "Polygon.io";

    public IReadOnlyList<ProviderCredentialField> RequiredCredentials => new[]
    {
        new ProviderCredentialField("ApiKey", "API key", ProviderCredentialKind.Secret),
        new ProviderCredentialField("BaseUrl", "Base URL", ProviderCredentialKind.Url,
            Placeholder: "https://api.polygon.io", Required: false),
    };

    public IDataProvider Create(IReadOnlyDictionary<string, string> credentials)
    {
        // Validate every Required field BEFORE constructing — the contract.
        if (!credentials.TryGetValue("ApiKey", out var apiKey) || string.IsNullOrWhiteSpace(apiKey))
            throw new ArgumentException("ApiKey is required.", nameof(credentials));

        credentials.TryGetValue("BaseUrl", out var baseUrl);   // optional
        return new PolygonDataProvider(apiKey, baseUrl ?? "https://api.polygon.io");
    }
}
Key consistency. The factory's Key and the provider's Key must match (here, "polygon"). The host uses it as the registry key, and as the prefix when building fully-qualified instrument identifiers across providers (the host's convention, e.g. "polygon:AAPL").