OnlineCalculatable Implementation Guide
This guide covers implementing the OnlineCalculatable interface for indicators that support both historical scrollback and real-time updates.
Overviewโ
Two Computation Modesโ
The OnlineCalculatable interface requires supporting two distinct calculation modes:
| Mode | Method | When Used |
|---|---|---|
| Historical Range | calculateValuesInRange() | Scrollback, replay, initial load |
| Real-time Updates | createOnlineValueCalculator() | Live data as it arrives |
Why Both Are Neededโ
- Historical: User scrolls back, replays data, or initially loads the chart
- Real-time: Live data streams in during trading
Indicator Registrationโ
Using the Builder Patternโ
Layer1ApiUserMessageModifyIndicator message = Layer1ApiUserMessageModifyIndicator
.builder(MyStrategy.class, indicatorName)
.setIsAdd(true)
.setGraphType(GraphType.PRIMARY)
.setOnlineCalculatable(this)
.setIndicatorColorScheme(colorScheme)
.setIndicatorLineStyle(IndicatorLineStyle.NONE)
.build();
indicatorsFullNameToUserName.put(message.fullName, message.userName);
provider.sendUserMessage(message);
Name Managementโ
private Map<String, String> indicatorsFullNameToUserName = new HashMap<>();
private Map<String, String> indicatorsUserNameToFullName = new HashMap<>();
// After registration
indicatorsFullNameToUserName.put(message.fullName, message.userName);
indicatorsUserNameToFullName.put(message.userName, message.fullName);
calculateValuesInRange Implementationโ
Method Signatureโ
void calculateValuesInRange(
String indicatorName, // fullName of the indicator
String indicatorAlias, // Instrument alias
long t0, // Start time (nanoseconds)
long intervalWidth, // Interval duration (nanoseconds)
int intervalsNumber, // Number of intervals
CalculatedResultListener listener
)
Complete Exampleโ
@Override
public void calculateValuesInRange(String indicatorName, String alias,
long t0, long intervalWidth, int intervalsNumber, CalculatedResultListener listener) {
if (dataStructureInterface == null) {
listener.setCompleted();
return;
}
String userName = indicatorsFullNameToUserName.get(indicatorName);
// Request trade data
ArrayList<TreeResponseInterval> data = dataStructureInterface.get(
t0, intervalWidth, intervalsNumber, alias,
new StandardEvents[] { StandardEvents.TRADE }
);
// Get initial price from snapshot (element 0)
TradeAggregationEvent snapshot = (TradeAggregationEvent) data.get(0)
.events.get(StandardEvents.TRADE.toString());
double lastPrice = snapshot.lastPrice;
// Process each interval (1 through N)
for (int i = 1; i <= intervalsNumber; ++i) {
TradeAggregationEvent trades = (TradeAggregationEvent) data.get(i)
.events.get(StandardEvents.TRADE.toString());
if (!Double.isNaN(trades.lastPrice)) {
lastPrice = trades.lastPrice;
}
// Return marker or value
if (!trades.askAggressorMap.isEmpty() || !trades.bidAggressorMap.isEmpty()) {
listener.provideResponse(new Marker(lastPrice, -8, -8, tradeIcon));
} else {
listener.provideResponse(lastPrice);
}
}
listener.setCompleted();
}
Key Rulesโ
- Provide exactly
intervalsNumberresponses - Skip element 0 (it's the snapshot)
- Always call
listener.setCompleted() - Check
listener.isCancelled()for expensive calculations
createOnlineValueCalculator Implementationโ
Method Signatureโ
OnlineValueCalculatorAdapter createOnlineValueCalculator(
String indicatorName,
String indicatorAlias,
long time,
Consumer<Object> listener,
InvalidateInterface invalidateInterface
)
Complete Exampleโ
@Override
public OnlineValueCalculatorAdapter createOnlineValueCalculator(
String indicatorName, String indicatorAlias, long time,
Consumer<Object> listener, InvalidateInterface invalidateInterface) {
String userName = indicatorsFullNameToUserName.get(indicatorName);
invalidateInterfaceMap.put(userName, invalidateInterface);
return new OnlineValueCalculatorAdapter() {
@Override
public void onTrade(String alias, double price, int size, TradeInfo tradeInfo) {
if (alias.equals(indicatorAlias)) {
listener.accept(new Marker(price, -8, -8, tradeIcon));
}
}
@Override
public void onIntervalWidth(long intervalWidth) {
// Handle zoom changes
}
};
}
OnlineValueCalculatorAdapter Callbacksโ
| Callback | Use Case |
|---|---|
onTrade() | Trade-based indicators |
onDepth() | Depth-based indicators |
onOrderUpdated() | Order tracking |
onOrderExecuted() | Execution markers |
onUserMessage() | Custom events |
onIntervalWidth() | Zoom level changes |
onRealTimeDataStart() | Historical รขโ โ live transition |
InvalidateInterface Usageโ
Store the interface for later recalculation:
private Map<String, InvalidateInterface> invalidateInterfaceMap = new ConcurrentHashMap<>();
// In createOnlineValueCalculator
invalidateInterfaceMap.put(userName, invalidateInterface);
// When settings change
public void onSettingsChanged() {
InvalidateInterface ii = invalidateInterfaceMap.get(INDICATOR_NAME);
if (ii != null) {
ii.invalidate();
}
}
Response Typesโ
| Type | Description |
|---|---|
Double | Line value |
Double.NaN | No value (gap) |
Marker | Single icon |
List<Marker> | Multiple icons |
DataCoordinateMarker | Data-bound graphic |
Cross-Referencesโ
- OnlineCalculatable - Base interface
- OnlineValueCalculatorAdapter - Real-time adapter
- CalculatedResultListener - Result callback
- InvalidateInterface - Recalculation trigger
- DataStructureInterface - Data retrieval
- ChartVisualizationGuide - Rendering markers