VisualHFT Study SDK guide
August 10, 2026 · View on GitHub
This guide accompanies the working Study Plugin Template. Use the template and current base classes as the source of truth for the plugin API.
Purpose
A study derives from BasePluginStudy. It observes shared market data, calculates a metric, and publishes BaseStudyModel values for the dashboard and trigger engine.
Build from the template
- Copy
SDK-StudyTemplatetoVisualHFT.Plugins/Studies.<YourStudy>. - Rename the project, namespace, settings classes, and
TemplateStudyPlugin. - Update the plugin identity fields and tile labels.
- Add settings for the calculation and expose them in the settings view.
- Add the project as a
ProjectReferenceinVisualHFT.csproj.
The host scans the directory containing VisualHFT.exe for plugin DLLs. A source project reference is the normal way to put the compiled study beside the application.
Data flow
The template follows this sequence:
OrderBook callback → OrderBookSnapshot → HelperCustomQueue → calculation → AddCalculation
In StartAsync(), subscribe to HelperOrderBook.Instance. In the callback, filter the order book by the configured provider and symbol, then create an OrderBookSnapshot and enqueue it. The calculation runs in QUEUE_onRead(OrderBookSnapshot) outside the incoming market-data callback.
OrderBook instances are mutable and may be pooled. Do not retain one after its callback. Use a snapshot and return its resources with Dispose() when processing ends.
private void QUEUE_onRead(OrderBookSnapshot snapshot)
{
try
{
double value = CalculateMetric(snapshot);
AddCalculation(new BaseStudyModel
{
Value = (decimal)value,
Timestamp = HelperTimeProvider.Now,
MarketMidPrice = 0
});
}
finally
{
snapshot.Dispose();
}
}
There is no Calculate(List<BookItem>) override in the current study base class. Publish results through AddCalculation(...). It handles the calculation pipeline and invokes its calculated event.
Aggregation and alerts
Override onDataAggregation(List<BaseStudyModel>, BaseStudyModel, int) when the default aggregation does not match the metric. The template implements last-value-wins behavior.
Raise OnAlertTriggered?.Invoke(this, value) only when the study's alert condition is met. Keep threshold and other user-facing values in the settings model.
Settings and UI
LoadSettings(), SaveSettings(), and InitializeDefaultSettings() are required base-class overrides. Keep GetUISettings() aligned with the settings model so a user can configure the provider, symbol, aggregation, and study-specific parameters.
Required license level
The plugin manager reads IPlugin.RequiredLicenseLevel when it loads a DLL. BasePluginStudy defaults to eLicenseLevel.COMMUNITY. Keep that default, or make it explicit, for a study intended for this public repository.
public override eLicenseLevel RequiredLicenseLevel => eLicenseLevel.COMMUNITY;
Before submitting
- Verify provider and symbol filtering with representative market data.
- Return every snapshot to its pool, including error paths.
- Keep market-data callbacks short and avoid blocking work inside them.
- Confirm that published values have the correct timestamp and metric value.
- Build the study and verify it appears when the host starts.
- Add focused tests for the calculation and its edge cases.