Static Data Provider
Overview
A static data provider is a custom application that connects to KeySquare platform and feeds reference data into Static Data Server (SDS). Rather than entering instruments, calendars, and fixings manually through the UI, a data provider automates this by connecting to an external source (a database, REST API, file, or internal feed) and publishing that data directly to SDS.
The data-provider-api library provides the StaticDataProvider base class, which wraps all the low-level platform interactions and lets you focus entirely on the data itself.
This guide focuses on implementing a custom data provider. Before continuing, ensure you have:
- A working Java project connected to the platform. See Java Setup and Session.
- A running SDS instance. See Static Data Server.
Maven Dependency
data-provider-api-all-{version}.jaris an uber jar containingkeysquare-apias well as any required models (ks-model-canonical,ks-model-static-data-server). Please reach out to us if you don't have thie file
Add the data-provider-api artifact to your project:
<dependency>
<groupId>trading.keysquare</groupId>
<artifactId>data-provider-api-all</artifactId>
<version>${version}</version>
</dependency>
Implementing a Static Data Provider
Extend StaticDataProvider and implement two abstract methods that SDS calls when it needs to look up instruments on demand.
import trading.keysquare.data.provider.StaticDataProvider;
import trading.keysquare.sds.model.sbe.GetInstrumentRequestDto;
import trading.keysquare.sds.model.sbe.SearchInstrumentRequestDto;
import trading.keysquare.sds.model.sbe.SearchInstrumentResponseDto.ResultEntryDto;
import trading.keysquare.model.canonical.sbe.InstrumentDto;
import trading.keysquare.util.session.KeySessionUtil;
import java.util.Collection;
import java.util.function.Consumer;
public class MyStaticDataProvider extends StaticDataProvider {
public MyStaticDataProvider(KeySessionUtil keySessionUtil) {
super(keySessionUtil, "static-data-server");
}
/*
* static-data-server will call 'search instrument' if it's internal search yields no results
*/
@Override
public void handleSearchInstrumentRequest(SearchInstrumentRequestDto search,
Consumer<Collection<ResultEntryDto>> resultsListener) throws Exception {
// Query your data source using search.text() and return descriptors.
// Each result only needs an id and a human-readable description.
SearchResult localResult = doLocalSearch(search); // your search function
ResultEntryDto result = new ResultEntryDto();
result.instrumentId(localResult.instrumentId());
result.description(localResult.description());
resultsListener.accept(List.of(result));
}
/*
* Given a search result, static-data-server will call GetInstrument using instrument id from the search result
*/
@Override
public void handleGetInstrumentRequest(GetInstrumentRequestDto request,
Consumer<InstrumentDto> resultListener) throws Exception {
// Fetch the full instrument by request.instrumentId() from your data source
// and pass it to the listener.
InstrumentDto instrument = doLocalGetInstrument(request.instrumentId()); // your get instrument function
resultListener.accept(instrument);
}
}
Publishing Instruments at Startup
Once connected, call publish(InstrumentDto) for every instrument you want SDS to store. SDS will assign each one an instrumentId if it is new, or update the existing record if a matching identifier (ISIN, CUSIP, FIGI, etc.) is already known.
public void init() throws Exception {
for (InstrumentDto instrument : loadAllFromMySource()) {
publish(instrument);
}
}
publish sends the instrument over the platform. SDS subscribes to your topic on a CACHED_AND_LIVE basis, so any instrument you publish after startup will also be received.
See Instrument Lifecycle for how SDS processes incoming instruments and what fields are required.
Handling Wish-List Requests
When a user searches for an instrument in Key UI that SDS does not yet hold, SDS sends an InstrumentWishDto to your provider. Override handleAddInstrumentRequest to react to these on-demand requests:
@Override
public void handleAddInstrumentRequest(KeyMessage<InstrumentWishDto> wishMessage) {
InstrumentWishDto wish = wishMessage.payload();
String instrumentId = wish.instrumentId();
try {
InstrumentDto instrument = doLocalGetInstrument(instrumentId);
publish(instrument);
} catch (Exception e) {
log.error("Could not load instrument: {}", instrumentId, e);
}
}
Wish-list messages are only delivered when subscribeToWishList is true in the constructor (which is the default behaviour).
Publishing Other Data Types
StaticDataProvider also exposes methods for the other data types SDS manages. These use a request/response pattern — call the method and supply a callback that receives the acknowledgement.
Holiday Calendars
Create a calendar and optionally add holiday dates to it:
// Define a new calendar
HolidayCalendarDto calendar = new HolidayCalendarDto();
calendar.name("LON");
calendar.weekend(Weekend.SAT_SUN);
addHolidayCalendar(calendar, ack -> log.info("Calendar ack: {}", ack));
// Add explicit holiday dates to an existing calendar
addHolidaysToCalendar("LON", List.of(LocalDate.of(2025, 12, 25)), ack -> log.info("Dates ack: {}", ack));
See Holiday Calendars for the full data model.
Reference Indices and Fixings
Publish a reference index definition first, then submit fixings for it:
// Add the index (must exist before any fixing can be added)
IndexDto index = new IndexDto();
index.name("SOFR");
index.currency(Currency.USD);
addIndex(index, ack -> log.info("Index ack: {}", ack));
// Add a historical fixing
IndexFixingDto fixing = new IndexFixingDto();
fixing.index("SOFR");
fixing.date(20250619); // YYYYMMDD integer
fixing.rate(5.31);
addIndexFixing(fixing, ack -> log.info("Fixing ack: {}", ack));
See Indices & Fixings for the full data model.
Permissions
Two sets of permissions must be configured in KeyAccess: one for your data provider application and one for the SDS instance it feeds.
Your Data Provider Application
| PUB/SUB | Schema | Source | Group |
|---|---|---|---|
| PUB | KsCanonical.Instrument | {your-app-name} | * |
| PUB | KsStaticDataServer.* (RPC responses) | {your-app-name} | * |
| SUB | KsStaticDataServer.* (RPC requests) | * | {your-app-name} |
| SUB | KsStaticDataServer.InstrumentWish | static-data-server | * |
Replace {your-app-name} with the application name you registered in KeyAccess.
If you are only publishing instruments (no wish-list handling), you can omit the InstrumentWish subscription. Set subscribeToWishList to false in the StaticDataProvider constructor.
Static Data Server
SDS must be told about your provider so it subscribes to your instrument topic. Add an entry to KS_SDS_INSTRUMENT_SOURCES in the SDS configuration:
KS_SDS_INSTRUMENT_SOURCES=[
{
"name": "My Data Provider",
"topicSource": "my-data-provider",
"topicGroup": ""
}
]
| Property | Description |
|---|---|
name | Human-readable label used in SDS logs |
topicSource | Must match your application name exactly |
topicGroup | Leave empty to receive all instrument groups |
SDS also needs to be permissioned to subscribe to your instrument topic and to send RPC requests back to your provider:
| PUB/SUB | Schema | Source | Group |
|---|---|---|---|
| SUB | KsCanonical.Instrument | {your-app-name} | * |
| SUB | KsStaticDataServer.* (RPC responses) | {your-app-name} | * |
| PUB | KsStaticDataServer.* (RPC requests) | * | {your-app-name} |
See the full SDS entitlements reference in Static Data Server — Entitlements.