Price Data Provider
Overview
A price data provider is a custom application that connects to the KeySquare platform and publishes live market prices for consumption by Price Engine. Rather than entering prices manually, a data provider connects to an external feed (a market data vendor, internal system, exchange, or file) and streams price updates directly to the platform.
Price Engine subscribes to these updates and uses them as the raw input for the SOURCE and BENCHMARK pricing models.
The data-provider-api library provides the PriceDataProvider base class, which handles all low-level topic routing and session interactions so you can focus entirely on the data.
This guide focuses on implementing a custom price data provider in Java.
Before continuing, ensure you have:
- A working Java project connected to the platform. See Java Setup and Session.
- A running Price Engine instance. See Price Engine Installation.
Maven Dependency
Add the data-provider-api artifact to your project:
<dependency>
<groupId>trading.keysquare</groupId>
<artifactId>data-provider-api-all</artifactId>
<version>${version}</version>
</dependency>
data-provider-api-all-{version}.jaris an uber jar containingkeysquare-apiand all required models (ks-model-canonical,ks-model-static-data-server,ks-model-pricing). Please reach out to us if you do not have this file.
Implementing a Price Data Provider
Extend PriceDataProvider and implement your feed logic. The base class handles topic construction, session publishing, and result validation automatically.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import trading.keysquare.api.session.KeySession;
import trading.keysquare.api.session.Result;
import trading.keysquare.data.provider.PriceDataProvider;
import trading.keysquare.model.canonical.sbe.PriceDto;
public class MyPriceProvider extends PriceDataProvider {
private static final Logger log = LoggerFactory.getLogger(MyPriceProvider.class);
public MyPriceProvider(KeySession session) {
super(session);
}
public void onFeedUpdate(String isin, double bidPrice, double askPrice) {
PriceDto price = new PriceDto();
price.priceSource("MY_FEED"); // must match topicSource in KS_PE_PRICE_SOURCES
price.priceType(LIVE);
price.instrumentId(isin);
price.bidPrice(bidPrice);
price.askPrice(askPrice);
price.midPrice((bidPrice + askPrice) / 2.0);
price.ok(true);
Result result = publish(price);
if (result.isFailure()) {
log.warn("Publish failed: [{}] for instrument: {}", result, isin);
}
}
}
PriceDataProvider.publish(PriceDto) derives the topic automatically from the dto:
| Topic component | Taken from |
|---|---|
topicSource | dto.priceSource() (falls back to application name if blank) |
topicGroup | dto.priceType().name() (e.g. LIVE, EOD) |
topicId | dto.instrumentId() |
Price Engine uses the instrumentIdType configured in KS_PE_PRICE_SOURCES to resolve topicId back to a canonical platform instrument.
Publishing Yields Instead of Prices
If your feed provides yields rather than clean prices, populate the yield fields and set priceType. Price Engine uses the spreadType on each PriceControl to decide whether to use price or yield as its input:
PriceDto price = new PriceDto();
price.priceSource("MY_FEED");
price.instrumentId(isin);
price.bidYield(bidYield);
price.askYield(askYield);
price.midYield((bidYield + askYield) / 2.0);
price.ok(true);
Result result = publish(price);
Marking a Price as Invalid
If your feed cannot provide a valid price (no data, stale, or error condition), publish with ok=false and a human-readable message. Price Engine propagates this status and displays it in the Error column in Key UI:
PriceDto price = new PriceDto();
price.priceSource("MY_FEED");
price.instrumentId(isin);
price.ok(false);
price.message("No data available from feed");
publish(price);
Registering Your Provider with Price Engine
Tell Price Engine to subscribe to your prices by adding an entry to KS_PE_PRICE_SOURCES in the Price Engine configuration:
KS_PE_PRICE_SOURCES=[
{
"name": "MY_FEED",
"topicSource": "my-data-provider",
"topicGroup": "MY_FEED",
"instrumentIdType": "ISIN",
"instrumentIdSource": ""
}
]
| Property | Description |
|---|---|
name | Display name shown in the Price Source dropdown in Key UI |
topicSource | Must match your application's registered name in KeyAccess exactly |
topicGroup | Must match the priceSource field you set on published PriceDto objects |
instrumentIdType | How your topicId (i.e. instrumentId on the dto) maps to platform instruments |
instrumentIdSource | For ALIAS type: restrict lookup to a specific alias source. Leave empty to match any. |
Instrument ID Types
instrumentIdType | Description |
|---|---|
STATIC_DATA_SERVER | instrumentId is the platform-assigned instrument ID (e.g. BUSD00001) |
ISIN | instrumentId is the ISIN (e.g. US0378331005) |
CUSIP | instrumentId is the CUSIP (9-character) |
FIGI | instrumentId is the Bloomberg FIGI |
ALIAS | instrumentId is a custom alias registered in Static Data Server |
Price Engine uses the instrument ID reverse-mapping published by Static Data Server to resolve instrumentId values to canonical instrument IDs at runtime.
Permissions
Two sets of permissions must be configured in KeyAccess: one for your data provider application and one for the Price Engine instance.
Your Data Provider Application
| PUB/SUB | Schema | Source | Group |
|---|---|---|---|
| PUB | KsCanonical.Price | {your-app-name} | * |
Replace {your-app-name} with the application name you registered in KeyAccess.
Price Engine
Price Engine must be permissioned to subscribe to your prices topic:
| PUB/SUB | Schema | Source | Group |
|---|---|---|---|
| SUB | KsCanonical.Price | {your-app-name} | * |
This is in addition to the standard Price Engine entitlements listed in Price Engine — Entitlements.
Multiple Data Providers
Price Engine supports multiple simultaneous data providers. Each entry in KS_PE_PRICE_SOURCES is an independent subscription. A single instrument can receive prices from multiple providers; each PriceControl specifies which provider to use for its calculations via the Price Source field.
Benchmark Prices
If a price control uses model=BENCHMARK, Price Engine needs a price for the benchmark instrument. This is sourced from the provider configured in benchmarkPriceSource on the PriceControl. If no benchmark price source is set, Price Engine uses its own internally computed price for the benchmark.
For benchmark pricing to work correctly, the benchmark instrument's price must include a valid yield. If the benchmark provider only publishes clean prices, ensure spreadType=PRICE is not set on the benchmark instrument's own PriceControl so that Price Engine can compute its yield via Analytics Engine.