Skip to main content

Lifecycle Reference

HyperionX scripts are state-driven. Most script setup belongs in OnStateChanged(). Calculation logic belongs in OnBarUpdate().

State Values

The runtime state enum currently includes:

StateMeaning
UndefinedScript is not initialized or has been stopped.
SetDefaultsSet name, version, default parameters, and default plot definitions.
ConfiguredAllocate runtime series, add plots/panes, add extra data series, and create child indicators.
HistoricalHistorical calculation is running.
FinalizedDeclared enum value. The general 1.1.10 calculation host does not reliably notify scripts of this state.
CalculatedCalculation finished.
PlaybackPlayback/replay mode is running.
RealTimeLive calculation is running.
DataLoadedData has loaded.
TransitionRuntime is moving between states.
TerminatedDeclared enum value. No reliable general script termination callback was verified in the reviewed host.

Standard Pattern

public override void OnStateChanged()
{
if (State == State.SetDefaults)
{
Name = "My Script";
Version = "1.0";
}
else if (State == State.Configured)
{
// Allocate series, child indicators, panes, plots, and extra series.
}
}

public override void OnBarUpdate()
{
if (CurrentBar < 20)
return;

// Per-bar logic.
}

Setup Responsibilities

Use State.SetDefaults for stable defaults:

  • Name
  • Version
  • [HyperionXProperty] default values
  • plot appearance defaults
  • non-runtime constants

Use State.Configured for runtime objects:

  • Series<double> instances
  • AddSeries(...)
  • AddPane(...)
  • AddPanePlot(...)
  • plot DataSource assignment
  • child indicators such as SMA(20)
  • AddDataSeries(...)

Update Methods

MethodPurpose
OnBarUpdate()Main per-bar calculation.
OnTickUpdate(ICandle candle, ICandle tick)Tick update hook when tick data is available.
OnMarketData(MarketDataEventArgs marketData)Market data update hook with price, volume, bid/ask volume, and trade count fields.
OnMarketDepth(MarketDepthEventArgs marketDepth)Depth snapshot hook after depth data is requested or subscribed.
OnAfterBarUpdate()Runtime post-update hook. Most scripts do not override it.
OnConnectionStatusChanged(ConnectionStatus oldStatus, ConnectionStatus newStatus, string connectionName)Connection state changes.

Bar Guards

Always check CurrentBar before reading prior bars.

if (CurrentBar < Period + 1)
return;

double prior = Close[1];
double older = Close[Period];

The indexer uses bars ago. Close[0] is the current bar. Close[1] is one bar ago.

Internally, CurrentBar behaves as the count of processed bars, and series translate [0] to the latest processed absolute index. Out-of-range reads can return a default value such as 0 instead of throwing, so a plausible number does not prove the requested bar existed. Guards remain mandatory.

Multi-Series Timing

BarsInProgress identifies the series currently being processed. Primary series is 0. Extra data series use indexes starting at 1.

if (BarsInProgress != 0)
return;

Use CurrentBars[seriesIndex] before reading extra series values.

During a secondary-series callback, read the matching collection member—for example, Closes[BarsInProgress][0]—rather than assuming the primary Close series represents the series that triggered the update.

Calculation Mode

Scripts expose Calculate, which is a CalculateMode value. The default is OnBarClose.

ModeBehavior
CalculateMode.OnBarCloseRuns after each completed bar. Use this for stable historical and backtest logic.
CalculateMode.OnEachTickRuns on every tick when tick data is available.
CalculateMode.OnPriceChangeRuns when the current trade price changes, which avoids duplicate same-price tick work.

For tick-aware scripts, override OnTickUpdate(ICandle candle, ICandle tick). candle is the active bar and tick is the incoming tick. Use tick.IsFirstTickOfBar when the script must reset per-bar real-time counters.

Live tick delivery to OnTickUpdate(...) and OnMarketData(...) is independent of Calculate. The calculation mode controls whether additional OnBarUpdate() calls occur on bar close, each tick, or price change; it does not subscribe or unsubscribe the dedicated tick/market-data callbacks. Keep each callback idempotent enough to avoid counting the same event twice.

The current chart/data context determines when real-time or playback scripts receive updates. Strategy developers should explicitly test the same mode they intend to trade.

Cleanup Boundary

Do not depend on State.Finalized or State.Terminated for required cleanup. The values exist in the enum, but the reviewed general calculation host does not provide a reliable native callback for them.

Use an explicitly documented host-specific cleanup contract where one exists. For example, an add-on receives OnUnload() after a successful load, but an add-on whose OnLoad() throws must roll back its own partial registrations before rethrowing because a later unload callback is not guaranteed. Avoid long-lived threads, event subscriptions, timers, or unmanaged resources unless their owning host has a verified release path.