Skip to main content

Custom Bar Types

A custom bar type transforms source market data into candles that charts and research workflows can select as a data series.

DifficultyInputApplies to
AdvancedBase candles, trade ticks, or bothHyperionX 1.1.10
Preview packaging status

The stable runtime contract is BarTypeBase/IBarBuilder. Some 1.1.10 installers do not seed the custom-project convenience bases used by the Code Lab templates (CustomBarType and TickCountCustomBarType). The example below derives directly from BarTypeBase so it does not depend on that optional bootstrap source.

Choose the source model first

ModelUse it whenPrimary method
Base-bar transformationEach source candle maps to or contributes to a custom candleProcessBaseBar(ICandle candle)
Tick constructionCandle boundaries depend on individual trades, volume, range, or another tick ruleProcessTick(MarketTick tick)
End-of-stream finalizationA partial candle must be completed when the source endsFlush()

The Metadata declaration tells HyperionX which source the builder needs and how the series should appear in chart configuration.

Minimal pass-through builder

In Tools → Code Lab, select Bar Type → Pass-through bar type.

using System.Collections.Generic;
using HyperionX.Chart.Interfaces;
using HyperionX.Core.DataCalc.Bars;
using HyperionX.Core.Enums;

namespace HyperionX.Custom.BarTypes;

public class MyMinuteBars : BarTypeBase
{
public override string Name => nameof(MyMinuteBars);

public override string DisplayName => "My Minute Bars";

public override string Description => "Passes each source minute candle through unchanged.";

public override BarBuilderMetadata Metadata { get; } = new()
{
BuiltFrom = DataSeriesType.Minute,
SourceRequirement = BarSourceRequirement.BaseBars,
IsTimeBased = true,
IsIntraday = true,
SupportsRemoveLastBar = false,
DefaultDaysToLoad = 5,
DefaultChartStyle = "Candlestick"
};

public override void Reset(BarBuilderContext context)
{
}

public override IReadOnlyList<BarUpdate> ProcessBaseBar(ICandle candle)
{
if (candle == null)
return System.Array.Empty<BarUpdate>();

return new[] { BarUpdate.Add(candle) };
}
}

This example demonstrates the contract; it intentionally does not change the source bars.

Builder contract

MemberResponsibility
NameStable registration name. Keep it unique.
DisplayNameUser-facing name shown in the data-series selector.
DescriptionShort explanation of the construction rule.
MetadataSource, timing, defaults, and chart-style capabilities.
Reset(context)Clear all builder state before processing a new run.
ProcessBaseBar(candle)Consume one source candle and return zero or more updates.
ProcessTick(tick)Consume one trade tick; the base implementation converts it to a candle.
Flush()Emit final updates after the source stream ends.

BarBuilderContext supplies the selected DataSeriesParams and the resolved TickSize. Read those values in Reset(...) and copy only the small immutable settings the builder needs. The same type can be used by multiple charts; never store a context or construction state in static fields.

Metadata

BarBuilderMetadata currently includes:

PropertyMeaning
BuiltFromDefault DataSeriesType used as source.
SourceRequirementWhether the builder needs base bars or trade ticks.
IsTimeBasedWhether candles have a fixed time interpretation.
IsIntradayWhether the resulting series is intraday.
SupportsRemoveLastBarWhether the builder can reverse its most recent published candle.
DefaultDaysToLoadInitial historical-data request size.
DefaultChartStyleSuggested chart renderer.
UsesDataSeriesValueAsBarValueWhether the user's interval value controls the custom rule.
DefaultDataSeriesValueDefault value used when that option is enabled.

Metadata is operational. If a tick-built series declares a base-bar requirement, HyperionX may request the wrong source data and the result will be invalid or empty.

BarSourceRequirement.QuoteTicks exists in the enum, but the current public construction pipeline does not establish a complete quote-tick delivery contract. Do not advertise a quote-built custom bar until the packaged runtime documents and tests that source path.

Returning updates

Each callback returns a list of BarUpdate operations:

FactoryMeaning
BarUpdate.Add(candle)Append a new candle.
BarUpdate.UpdateLast(candle)Update the currently forming last candle.
BarUpdate.ReplaceLast(candle)Replace the last candle with a new finalized representation.
BarUpdate.RemoveLast()Remove the last candle; advertise support in metadata.

A single source event may return no updates, one update, or several updates. Always return updates in the order HyperionX should apply them.

Discovery requirements

The registry loads a type only when it is:

  • Concrete and assignable to the bar-builder contract.
  • Constructible with a public parameterless constructor.
  • Present in the successfully loaded custom assembly.

After a build and custom-assembly refresh, the builder appears as a custom choice using DisplayName. The registry creates a fresh builder instance for each use, so keep state on the instance rather than in static fields.

Registration keys use Name case-insensitively. If two builders publish the same name, the later registration replaces the earlier factory and descriptor. Treat a unique, stable Name as part of the saved-workspace compatibility contract.

Correctness checklist

  • Reset every mutable field in Reset(...).
  • Reject null or invalid source records without throwing.
  • Preserve monotonically ordered candle timestamps.
  • Keep OHLC relationships valid.
  • Define whether volume and trade count accumulate or pass through.
  • Mark completed versus forming candles consistently.
  • Implement Flush() when the final partial candle matters.
  • Do not claim SupportsRemoveLastBar unless RemoveLast behavior is correct.
  • Test historical loads, incremental updates, reloads, and empty input.
  • Compare chart output with research/backtest output on the same source data.

Tick-count shortcut

Code Lab also includes a Tick count bar type template based on the convenience TickCountCustomBarType. Use it when that bootstrap type exists and one candle should complete after the configured number of valid trade ticks. Derive from BarTypeBase and implement ProcessTick(...) directly when the convenience source is absent or the boundary rule is more complex.

Continue with Series and Bars, Market Data, and Build, test, and debug.