Skip to content

Buffer style indicators for incremental processing ​

Buffer list style provides efficient incremental processing for growing datasets. Use this when bars arrive sequentially and you need to add them one at a time without the overhead of a full hub infrastructure.

When to use buffer lists ​

Ideal for:

  • Building up historical data incrementally
  • Processing data feeds where bars arrive sequentially
  • Self-managed incremental calculations
  • Scenarios without multi-indicator coordination needs
  • Memory-efficient processing with auto-pruning

Not ideal for:

Basic usage ​

Buffer lists maintain incremental state as you add new bars:

csharp
using FacioQuo.Stock.Indicators;

// create buffer list with lookback period
SmaList smaList = new(lookbackPeriods: 20);

// add bars incrementally (e.g., from a data feed)
foreach (Bar bar in bars)
{
    smaList.Add(bar);

    // safely get latest result
    if (smaList.Count > 0)
    {
        SmaResult r = smaList[^1];

        // use result (SMA is null during warmup period)
        if (r.Sma is not null)
        {
            Console.WriteLine($"{r.Timestamp:d}: SMA = {r.Sma:N2}");
        }
    }
}

🚩 Add bars in chronological order

A buffer list is a single-pass accumulator: every Add assumes the new value is the newest one. It does not reorder input, detect duplicates, or correct revised values — feeding an out-of-order, repeated, or late-arriving bar produces silently incorrect results. If your data can arrive out of order (e.g. a raw WebSocket feed, or merging two sources), sort by timestamp before adding, or use a Stream hub instead — stream hubs are built for late arrivals, same-timestamp corrections, and rollback.

Key features ​

List interface ​

Buffer lists are read-only result lists you append to. The base BufferList<TResult> implements IReadOnlyList<TResult> — so you get indexer access, Count, and enumeration — plus indicator-specific Add overloads for feeding new values and a small set of list helpers (Clear, Contains, CopyTo):

csharp
SmaList smaList = new(20);

// add individual bars
smaList.Add(bar);

// or add batches
smaList.Add(barList);

// read-only list access
int count = smaList.Count;
bool isEmpty = smaList.Count == 0;
SmaResult latest = smaList[^1];

Note that a buffer list is not a general-purpose mutable collection: it does not implement ICollection<TResult>, so there is no Remove, no insert-at-index, and Add appends a computed result rather than an arbitrary item. Pruning of old results is automatic (see Memory management).

Automatic buffer management ​

Buffer lists automatically manage internal buffers needed for calculations:

  • Maintains lookback periods internally
  • No manual state management required
  • Efficient incremental updates (typically O(1) or O(log n))

Memory management ​

Control memory usage with MaxListSize:

csharp
SmaList smaList = new(20)
{
    MaxListSize = 1000  // keep only last 1000 results
};

When the list exceeds MaxListSize, older results are automatically pruned. Default is 100,000 elements.

Chaining indicators ​

Chain buffer lists for derived indicators. For the broader concept, see Chaining indicators.

Operator-orchestrated

Unlike series or stream-hub chaining, this is orchestrated by you rather than the library: you manually take each result from one list and add it to the next. The library does not coordinate the cascade.

csharp
// create OBV buffer list
ObvList obvList = new();

// add bars to OBV
foreach (var bar in bars)
{
    obvList.Add(bar);
}

// chain RSI from OBV results
RsiList rsiList = new(14);
foreach (var obvResult in obvList)
{
    rsiList.Add(obvResult);
}

// get latest RSI of OBV
if (rsiList.Count > 0)
{
    RsiResult latest = rsiList[^1];
}

Performance characteristics ​

  • Overhead: ~10-20% slower than batch style for equivalent datasets
  • Memory: Maintains internal buffers for lookback periods
  • Latency: Optimized for per-bar updates, typically O(1) or O(log n)
  • Thread safety: Not thread-safe; synchronize external access if needed

Usage patterns ​

Simulating a data stream ​

csharp
SmaList smaList = new(20);

foreach (var bar in streamingBars)
{
    // add new bar
    smaList.Add(bar);

    // list auto-adds incremental SMA value
    if (smaList.Count > 0)
    {
        SmaResult latest = smaList[^1];
        Console.WriteLine($"{latest.Timestamp:d}: SMA = {latest.Sma:N2}");
    }
}

Batch addition with incremental updates ​

csharp
SmaList smaList = new(20);

// add initial batch
smaList.Add(historicalBars);

// then add new bars incrementally
while (newBar = GetNextBar())
{
    smaList.Add(newBar);
    if (smaList.Count > 0)
    {
        ProcessLatestResult(smaList[^1]);
    }
}

See also ​