Persistent variables
ACSIL state slots that survive across study function calls — typed accessors such as `sc.GetPersistentInt`, `sc.GetPersistentFloat`, and `sc.GetPersistentString` let a study remember values from one bar (or one tick) to the next without using subgraphs or external files.
What it is
Persistent variables are ACSIL state slots that survive across study function calls. A custom study's scsf_ function is invoked many times — once per bar in auto-looping mode, or repeatedly as new ticks arrive — and ordinary C++ local variables vanish at the end of each call. Persistent variables solve that problem by giving the study a small per-instance memory region that the platform preserves between calls.
The mechanism is exposed through a family of typed accessor functions: sc.GetPersistentInt, sc.GetPersistentFloat, sc.GetPersistentDouble, sc.GetPersistentString, and several pointer variants for more advanced uses. Each accessor takes a numeric key that the study chooses, and returns a reference to the persistent slot — read it, modify it, and the modification is still there on the next call.
Why it matters
Without persistent variables, a study cannot remember anything from one bar to the next without going through subgraphs or external files. Many useful patterns — tracking a running count of events, holding a state machine across bars, caching expensive intermediate calculations, deduplicating alerts — require state that lives outside the local stack frame. Persistent variables are the idiomatic way to do that in ACSIL.
Practical uses include:
- Storing the index of the last bar on which a signal fired, to suppress duplicate alerts on the same bar.
- Holding a state-machine enum across bars in a multi-bar pattern detector.
- Caching the result of an expensive computation that only needs to run once per chart load.
- Maintaining cumulative counters (event counts, custom delta accumulators) without polluting subgraphs.
How it's used in ACSIL code
The typical pattern is to declare a key constant near the top of the study function, then access the persistent slot through one of the typed accessors. For example, int& LastSignalBar = sc.GetPersistentInt(1); gives the study a writable reference to a slot keyed at 1; assigning to LastSignalBar writes through to the persistent store. Pointer-typed accessors like sc.GetPersistentPointer allow studies to hold references to heap-allocated objects across calls, with the study itself responsible for allocation and cleanup.
Persistent variables are per-study-instance, not per-chart. Two copies of the same study on the same chart have independent persistent slots.
Common patterns / pitfalls
- Persistent variables reset when the study is recompiled, the chartbook is reloaded, or the study is removed and re-added. Logic that depends on long-term persistence needs an external backing store (file, database, or
sc.GetPersistentPointerwith manual serialization). - Forgetting to free heap memory held in a persistent pointer leaks across study reloads. Use the
sc.LastCallToFunctionflag to perform cleanup on the final invocation. - Mixing up the key numbers for different persistent slots is a classic bug source. Define named constants for each key rather than scattering magic numbers through the code.
- Persistent variables are not synchronized across threads — they are owned by the calling study instance and should not be accessed from background threads without explicit synchronization.
Related SCS studies
Most non-trivial SCS custom studies use persistent variables internally — for deduping alerts, tracking state machines, caching expensive lookups, and holding cross-bar references. The mechanism is foundational to ACSIL development rather than a feature of any single packaged product.
See also
About the acsil & development category
Sierra Chart's Advanced Custom Study Interface and Language — the C++ surface SCS studies are built on.
Browse the full glossary