---
url: /utilities/bars.md
description: >-
  Utilities for preparing and transforming historical price bars before using
  them with indicators.
package: FacioQuo.Stock.Indicators
docs_version: v3
canonical: https://dotnet.stockindicators.dev/utilities/bars
generated: 2026-09-30T04:41:06.055Z
commit: ae1f432eaa0b03ae9f39e032c69434b557efa4a2
---

# Bar utilities

Utilities for preparing and transforming historical price bars before using them with indicators.

## Use alternate price

`bars.Use()` selects which price element to analyze before most indicator calls — for example the median (`HL2`) or typical (`HLC3`) price instead of `Close`. It cannot be used with indicators that require the full OHLCV bar profile.

```csharp
// median price (HL2) into an SMA
var results = bars
  .Use(CandlePart.HL2)
  .ToSma(20);
```

**`candlePart`** — the price element to use for calculations.

#### `CandlePart` enum options

| enum | `int` | description |
| :--- | :---: | :---------- |
| `CandlePart.Open`   | 0 | `Open` price              |
| `CandlePart.High`   | 1 | `High` price              |
| `CandlePart.Low`    | 2 | `Low` price               |
| `CandlePart.Close`  | 3 | `Close` price             |
| `CandlePart.Volume` | 4 | `Volume`                  |
| `CandlePart.HL2`    | 5 | `(High+Low)/2`            |
| `CandlePart.HLC3`   | 6 | `(High+Low+Close)/3`      |
| `CandlePart.OC2`    | 7 | `(Open+Close)/2`          |
| `CandlePart.OHL3`   | 8 | `(Open+High+Low)/3`       |
| `CandlePart.OHLC4`  | 9 | `(Open+High+Low+Close)/4` |

> [!WARNING]
> **🚩 Incompatible indicators**
>
> Some indicators require the full OHLCV bar profile and cannot be used with `.Use()`:
>
> * Indicators that explicitly use multiple price points (ATR, Stochastic, etc.)
> * Volume-based indicators (OBV, CMF, etc.) unless using `CandlePart.Volume`
> * Candlestick pattern indicators
>   :::
>
> The bar-part selector also has incremental and live streaming variants that emit `TimeValue` results:
>
> ```csharp
> // BufferList — incremental, single-threaded
> BarPartList parts = bars.ToBarPartList(CandlePart.HL2);
>
> // StreamHub — chain into a live pipeline
> BarHub barHub = new();
> BarPartHub partHub = barHub.ToBarPartHub(CandlePart.HLC3);
> EmaHub emaHub = partHub.ToEmaHub(20);  // chain downstream indicators
> ```
>
> See [Buffer lists](/guide/styles/buffer.md) and [Stream hubs](/guide/styles/stream.md) for full usage guides.
>
> ## Sort bars
>
> `bars.ToSortedList()` sorts any collection of `TBar` (or `ISeries`) and returns an `IReadOnlyList` ordered by ascending `Timestamp`. Library indicators expect chronological bars, so use this when you cannot guarantee the sort order from your data source.
>
> ```csharp
> // sort, then use inline with indicators
> var results = bars
>   .ToSortedList()
>   .ToRsi(14);
> ```
>
> > [!NOTE]
> > **Pre-sorted data**
> >
> > Most providers already return bars in chronological order. Sorting large datasets has a cost, so skip this step when the order is guaranteed.
>
> ## Validate bar history
>
> `bars.Validate()` is an advanced check of your `IReadOnlyList<IBar>`. It detects duplicate timestamps and out-of-sequence (non-ascending) dates, throwing an `InvalidBarsException` if either is found. On success it returns the validated collection, so it can be used inline.
>
> ```csharp
> try
> {
>   var results = bars
>     .Validate()
>     .ToRsi(14);
> }
> catch (InvalidBarsException ex)
> {
>   Console.WriteLine($"Invalid bars: {ex.Message}");
> }
> ```
>
> > [!NOTE]
> > **When to use**
> >
> > `.Validate()` performs thorough checks and has a cost. Use it when data quality is uncertain — importing from untrusted sources, production data-quality gates, or debugging unexpected results — but avoid re-validating the same dataset repeatedly. To simply fix ordering, use [Sort bars](#sort-bars) instead.
>
> ## Resize bar history
>
> `bars.Aggregate()` combines intraday bars into larger timeframes — minute to hourly, hourly to daily, or any custom `TimeSpan`.
>
> ```csharp
> // using the BarInterval enum
> IReadOnlyList<Bar> hourlyBars = minuteBars.Aggregate(BarInterval.OneHour);
>
> // using a custom TimeSpan
> IReadOnlyList<Bar> customBars = minuteBars.Aggregate(TimeSpan.FromMinutes(45));
> ```
>
> | param | type | description |
> | ----- | ---- | ----------- |
> | `newSize` | `BarInterval` | Target period size: `Month`, `Week`, `Day`, `FourHours`, `TwoHours`, `OneHour`, `ThirtyMinutes`, `FifteenMinutes`, `FiveMinutes`, `ThreeMinutes`, `TwoMinutes`, `OneMinute`. |
> | `timeSpan` | `TimeSpan` | Any value greater than `TimeSpan.Zero`, for custom periods. |
>
> Each aggregated bar takes the first **Open**, highest **High**, lowest **Low**, last **Close**, summed **Volume**, and the period's starting **Timestamp**.
>
> > [!WARNING]
> > **🚩 Partially populated periods**
> >
> > Partial period windows at the start, end, or market open/close can be misleading. For example, a lone 4:00pm minute bar aggregated into 15-minute bars yields a 4:00pm bar holding just one minute of data, while the prior 3:45pm bar holds the full 15 minutes. Filter out partial periods if they could skew your analysis.
>
> ### Streaming aggregator hubs
>
> For live feeds, the aggregator hubs convert small bars or raw ticks into larger period bars in real time. Both accept a `BarInterval` or custom `TimeSpan` (`BarInterval.Month` is not supported in streaming — use the `TimeSpan` overload):
>
> ```csharp
> // bar → bar (e.g. 1-minute bars to 5-minute bars)
> BarHub barHub = new();
> BarAggregatorHub fiveMinHub = barHub.ToBarAggregatorHub(BarInterval.FiveMinutes);
>
> // tick → bar (raw trades to 1-minute OHLCV)
> TradeTickHub tickHub = new();
> TradeTickAggregatorHub oneMinHub = tickHub.ToTradeTickAggregatorHub(BarInterval.OneMinute);
> ```
>
> Both aggregator hubs accept an optional `fillGaps` flag (default `false`): when `true`, synthetic zero-volume bars bridge silent buckets, carrying the prior bar's `Close` into `Open`, `High`, `Low`, and `Close`. Consumers needing a different gap policy should pre-process the upstream stream; a native `GapFillMode` enum is on the v3.1 roadmap.
>
> ## Extended candle properties
>
> `bar.ToCandle()` and `bars.ToCandles()` convert a bar into an extended `CandleProperties` format with additional calculated candle measurements (body size, wicks, etc.).
>
> ```csharp
> // single bar
> CandleProperties candle = bar.ToCandle();
>
> // collection of bars
> IReadOnlyList<CandleProperties> candles = bars.ToCandles();
>
> // access extended properties
> decimal? bodySize = candle.Body;
> decimal? upperWick = candle.UpperWick;
> bool isBullish = candle.IsBullish;
> ```
>
> #### `CandleProperties`
>
> The `CandleProperties` record class extends the basic `Bar` type with calculated properties.
>
> | property       | type         | description            |
> | -------------- | ------------ | ---------------------- |
> | `Timestamp`    | *`DateTime`* | Close date             |
> | `Open`         | *`decimal`*  | Open price             |
> | `High`         | *`decimal`*  | High price             |
> | `Low`          | *`decimal`*  | Low price              |
> | `Close`        | *`decimal`*  | Close price            |
> | `Volume`       | *`decimal`*  | Volume                 |
> | `Size`         | *`decimal`*  | `High-Low`             |
> | `Body`         | *`decimal`*  | `\|Open-Close\|`       |
> | `UpperWick`    | *`decimal`*  | Upper wick size        |
> | `LowerWick`    | *`decimal`*  | Lower wick size        |
> | `BodyPct`      | *`double`*   | `Body/Size`            |
> | `UpperWickPct` | *`double`*   | `UpperWick/Size`       |
> | `LowerWickPct` | *`double`*   | `LowerWick/Size`       |
> | `IsBullish`    | *`bool`*     | `Close>Open` direction |
> | `IsBearish`    | *`bool`*     | `Close<Open` direction |
>
> ## See also
>
> * [Result utilities](/utilities/results.md) — work with indicator results after calculation
> * [Additional helper utilities](/utilities/helpers.md) — math and numerical methods for custom indicators
> * [Indicator catalog](/utilities/catalog.md) — discover indicator metadata programmatically
>