← Trading Systems
Sierra Chart · ACSIL · C++ DLLs

Sierra Chart DLL Studies — LTVI, Logo & Algo

Custom C++ add-ons for Sierra Chart (a trading platform): LTVI draws volume and orderflow on the chart (e.g. where big trades hit and where buying or selling dominated); logo puts a custom image (e.g. branding) on the chart; and a large set of indicators and strategies — from automatic trading based on order-book imbalance and key price levels, to session high/low, smoothing filters (Kalman), overlays, and tools like slippage analysis and signal export/import. The codebase has since grown to ~35 studies organized into suite DLLs, including a licensed member suite shipped to a trading community's paying subscribers.

C++ ACSIL Volume-at-Price Time & Sales GDI+
Sierra logo indicator preview
Built with agentic AI. Development on this project runs through multi-agent Claude Code workflows — developer → independent-reviewer cycles with evidence gates, batched into unattended runs that execute overnight and resume from committed ledgers. How the agent system works →

LTVI — Volume and orderflow on the chart

Time & Sales is the live stream of every trade (price, size, side). These studies use that stream to draw on the chart: e.g. when a single trade is bigger than a threshold, they show the size as a number or “bubble” at that price. Others use volume at price (total buy vs sell volume at each price level) to draw markers for one-sided volume or “absorption” (heavy volume with little price move). So you can see where big trades happened and where buying or selling dominated, without reading raw tick data.

Per-tick volume bubbles

  • For each bar, the study scans the tick stream and finds trades at or above a volume threshold.
  • It draws that volume as large text (or a bubble) at the trade’s price so you can spot big prints at a glance.
  • Different versions support one label per bar, multiple labels, or subgraph-based drawing.

Orderflow-style markers

  • You can choose colors and sizes for “buy” vs “sell” volume, and whether to show bubbles or text.
  • Logic can be “at this price level” (volume at price) or “whole bar”; markers can be sized by how extreme the imbalance is.
  • One study focuses on absorption levels (heavy volume, small move) and draws lines or markers for those.

Logo — Custom image on the chart

A study that draws a custom image (e.g. a logo or watermark) on the chart. The image is stored inside the DLL and rendered with Windows GDI+, scaled to fit the study’s area. So you can brand charts or add a small graphic without loading an external file. The same DLL can also contain other studies (e.g. orderflow drawing).

GDI+ logo drawing (logo.cpp)

logo.cpp – load embedded image and draw
HRSRC hRes = FindResource(hInstance, MAKEINTRESOURCE(IDR_LOGO_IMAGE), RT_RCDATA);
HGLOBAL hResData = LoadResource(hInstance, hRes);
void* pData = LockResource(hResData);
IStream* pStream = SHCreateMemStream((BYTE*)pData, size);
logoImage = Gdiplus::Image::FromStream(pStream);
// ... then draw at (chartLeft + 50, chartTop + 10) with scaling from chart dimensions

What these studies do (plain-language summary)

Sierra Chart is a trading platform; a study is a custom add-on that draws on the chart or runs trading logic. Below, strategies can place and manage orders automatically; indicators only draw signals, levels, or statistics. Descriptions are written so someone outside the project can understand what each one is for.

Strategies — they can place trades

Indicators — they draw on the chart (no auto-trading)

Indicators — smoothing, trend, and chart tools

Unbroken-family (structure + filters)

Suite architecture — shipping DLLs to non-developers

The studies are packaged so that the people who use them never need a compiler, and the developer never needs to touch a member's machine.

One DLL = one suite

  • Each Visual Studio project builds one DLL that appears as a single title in Sierra's Add Custom Study dialog, with every member study in its dropdown.
  • Each study lives in its own namespace so identical helper names never collide when compiled into one binary.
  • Two-flavor build: a test DLL exposes full tuning inputs plus a "Bake" action that writes the tuned settings into a header; the production DLL is a unity shell the study owner compiles inside Sierra Chart itself, with no Visual Studio, from that baked header. Separate license groups guarantee the dev flavor can never leak to members.
  • A hot-reload dev rig releases and re-allows the DLL over Sierra's UDP control interface on every build, with a resident loader study that recalculates the right chart via a chartbook-scoped tag map.

Support built into the product

  • Every stage of a complex study fails silently on a member's machine — so a "Write Diagnostic Report" input dumps one self-contained report file a member can email; whichever stage first reads zero names the cause.
  • Late-added inputs are created at runtime, so a plain DLL swap delivers new features without members rebuilding their chartbooks.
  • Ports of platform built-ins (e.g. the trend study) are verified bar-for-bar against the original — maximum difference 0.000000 over the full test chart — before replacing them.
  • Performance work is measured: the order-block study's replay path was made ~12× faster by keying levels by tick and eliminating per-trade re-sorts.

The production unity shell the client compiles inside Sierra

suite shell .cpp (member build)
#define OFC_MEMBER_BUILD
#include "sierrachart.h"
SCDLLName("scalper_suite")
#if __has_include("scalper_suite_settings.h")
#include "scalper_suite_settings.h"          // owner's baked settings
#else
static const char SCALPER_SUITE_BAKED[] = ""; // fresh machine: no settings yet
#endif
#include "scalper_block_chart.cpp"
#include "scalper_iceberg.cpp"
#include "scalper_premium.cpp"
#include "scalper_ob2.cpp"
#include "scalper_momentum.cpp"
#include "scalper_trend.cpp"

Newer study families

Licensed member suite (7 studies)

  • Block Chart — a custom bar builder (inverse flex-renko) written through Sierra's custom-chart-bar API, "correct by construction": bricks complete only from the bar's own committed high/low, so no phantom bars and every close is a price that actually traded.
  • Iceberg — compares traded volume at a price against the next bar's resting depth and bubbles the volume/resting multiplier.
  • OB Max — order blocks with tick-replay-bounded bubbles and the diagnostic-report system above.
  • Premium, Momentum, Trend — reversal-level retest counting, first-touch RSI extreme coloring, and the parity-verified trend port.

The order-flow research family

  • Ten research studies share one statistical engine that scores order-flow behaviour against context-conditioned baselines instead of global averages — the detection logic itself stays private.
  • The shared engine includes explicit safeguards against the classic false-positive modes of adaptive thresholds (quiet-hours artifacts, warmup instability).
  • Members explore volume-distribution, absorption and participation anomalies, all feeding features into the research platform.
  • Notably, candidate edges from this family were tested against matched random controls and refuted where they failed — negative results are kept, the same evidence standard as the quant pipeline.

Representative code

The “Unbroken” structure core: define inputs/subgraphs, draw arrows from stored pivots, and detect new pivots using extrema-based logic.

Unbroken: inputs + arrow drawing (structure + pivots)

unbroken_class.h – SetupUnbrokenInputs + DrawArrows
inline void SetupUnbrokenInputs(SCStudyInterfaceRef sc) {
    SCInputRef FractalPeriod = sc.Input[0];
    SCInputRef ShowArrows = sc.Input[1];
    ShowArrows.Name = "Show Arrows";
    ShowArrows.SetCustomInputStrings("None;Pivots;Unbroken;Sunbroken;IndexUnbMinMaxPP;MinmaxPP");
    ShowArrows.SetCustomInputIndex(0);
}

inline void DrawArrows(SCStudyInterfaceRef sc,
                        SCSubgraphRef& LongArrows,
                        SCSubgraphRef& ShortArrows,
                        SCInputRef& ShowArrows,
                        Unbroken* unb_long,
                        Unbroken* unb_short) {
    if (ShowArrows.GetIndex() == 1) { // pivots
        for (size_t k = 0; k < unb_long->pivot.size(); ++k) {
            int b = unb_long->pivot_seq[k];
            if (b >= 0 && b < sc.ArraySize) {
                LongArrows[b] = -(static_cast<float>(unb_long->pivot[k]));
            }
        }
        for (size_t k = 0; k < unb_short->pivot.size(); ++k) {
            int b = unb_short->pivot_seq[k];
            if (b >= 0 && b < sc.ArraySize) {
                ShortArrows[b] = static_cast<float>(unb_short->pivot[k]);
            }
        }
    }
}

about_pivots: extrema-based pivot detection

unbroken_class.cpp – Unbroken::about_pivots core
void Unbroken::about_pivots(void*,
                              float price,
                              SCDateTimeMS time,
                              int seq,
                              int subindex,
                              float gz) {
    if (seq >= fractal_period && extrema.GetArraySize() > seq) {
        float ext = 0.0f;

        if (direction == "Short") {
            ext = *std::max_element(&extrema[seq - fractal_period],
                                     &extrema[seq]);
        } else {
            ext = *std::min_element(&extrema[seq - fractal_period],
                                     &extrema[seq]);
        }

        // Candidate pivot management (pop/append) based on structure conditions
        if (true && !pivot.empty() && !unbroken_seq.empty()
            && seq - unbroken_seq.back() > fractal_period) {
            pivot.pop_back();
            pivot_time.pop_back();
            // pivot.push_back(unbroken.back()); (in the “append” branch)
        }
    }
}