VoltRouter Webhook BuilderBuild PulseWire alert webhook payloads for VoltRouter — a signal routing service that executes your PulseWire strategy alerts directly at your broker. $0.07/signal, pay-as-you-go, no subscription required .
Supports: market, limit, stop, bracket (TP+SL), trailing stop, FLAT, and cancel-all.
How to use:
1. Sign up at voltrouter.com and connect your broker
2. Import this library in your strategy
3. Paste the output into a PulseWire alert → Webhook URL field
Setup: voltrouter.com
import VoltRouterWebhook as vr
// In your strategy alert message field:
vr.market("MNQM26", "buy", 1, "ibkr", "my_strategy")
vr.bracket("MNQM26", "sell", 1, close + 10, close - 5)
vr.flat("MNQM26") Library

RandomForestLibraryRandomForestLibrary is a self-contained Random Forest library for Pine Script v6 that other Pine developers can import and use to build their own machine learning indicators and strategies.
What Makes This Different
Random Forest is one of the most widely used ensemble methods in applied machine learning. Until now, Pine Script developers wanting to use it had only two choices: call out to an external Python / ONNX pipeline, or hand-roll a single decision tree inline. This library closes that gap by providing a complete Random Forest implementation — CART trees, bootstrap aggregation, Gini / MSE splitting, out-of-bag scoring, weighted feature importance — reachable with a few lines of import code.
The API intentionally mirrors scikit-learn's RandomForestClassifier and RandomForestRegressor (init → fit → predict → evaluate), so practitioners already familiar with scikit-learn can translate existing logic directly.
What This Library Provides
Binary classification: fit(X, y) , predict , predict_proba , predict_batch , oob_score
Multi-output regression: fit_regressor(X, Y) , predict_multi , predict_multi_per_tree , oob_r2 , oob_residual_std
Weighted Gini / MSE feature importance: feature_importance()
Deterministic Park-Miller RNG for reproducible forests
Exported Types
Forest — the ensemble model. Holds all trees, hyperparameters, training data references, OOB accumulators, and feature importances.
Tree — a single decision tree with its node array, max depth, leaf count, and split-failure count.
Node — a single node storing feature index, threshold, children indices, leaf label / probability, Gini impurity (or MSE in regressor mode), sample count, and a per-horizon output array for regression.
RNG — a Park-Miller linear congruential generator with a=48271, m=2^31-1. Deterministic given the same seed.
Exported Methods
Initialization and training
init(n_estimators, max_depth, max_features, min_samples_leaf, n_threshold_candidates, seed) — configure hyperparameters. max_features=0 auto-selects ceil(sqrt(n_features)) for classification and ceil(n_features/3) for regression.
fit(X, y) — train classifier on a feature matrix X (rows = samples, columns = features) and integer label array y (values 0 or 1).
fit_regressor(X, Y) — train multi-output regressor. Y is a matrix whose columns are separate regression horizons / targets.
Inference
predict(sample) — classify a single sample via soft voting (threshold 0.5).
predict_proba(sample) — average class-1 probability across all trees.
predict_batch(X) — classify every row of a matrix.
predict_multi(sample) — regressor output: averaged per-horizon predictions.
predict_multi_per_tree(sample) — per-tree, per-horizon predictions for custom uncertainty analysis.
tree_predict , tree_predict_proba , tree_predict_multi — single-tree inference for advanced use.
Evaluation
oob_score() — classification out-of-bag accuracy (0.0 to 1.0), computed by soft voting on samples not selected in each tree's bootstrap.
oob_r2() — regression out-of-bag R^2, averaged across horizons.
oob_residual_std() — per-horizon standard deviation of OOB residuals. Useful for prediction interval construction (Wager, Hastie, and Efron 2014).
feature_importance() — normalized weighted Gini (or MSE) decrease per feature, averaged across trees. Sums to approximately 1.0.
How It Works
Tree construction (CART, iterative, level-by-level)
Each tree is built top-down, one depth level at a time, using complete binary tree indexing ( left = 2i+1 , right = 2i+2 ). At every internal node:
A random subset of features of size max_features is drawn without replacement.
For each feature, n_threshold_candidates thresholds are sampled uniformly between the feature's min and max on the samples at that node.
For classification, the split minimizing weighted Gini impurity is chosen. For regression, the split minimizing weighted MSE (summed over all horizons) is chosen.
A node becomes a leaf when it is pure (classification), too small ( n < 2 * min_samples_leaf ), at max depth, or when no valid split exists.
Bootstrap aggregation and OOB
Each tree is trained on a bootstrap sample (same size as the training set, sampled with replacement). Samples that were not drawn for a given tree become its out-of-bag set and are used to compute unbiased performance estimates ( oob_score / oob_r2 ) and residual variance ( oob_residual_std ), avoiding the need for a separate holdout.
Feature importance
Each split records its weighted impurity decrease ( n_node * impurity_node - n_left * impurity_left - n_right * impurity_right ). Per-tree importances are normalized to sum to 1, then averaged across trees — matching scikit-learn's definition.
Quick Start
//@version=6
indicator("My RF Indicator")
import ShigemiQuant/RandomForestLibrary/2 as RF
// 1. Build feature matrix X and label array y over recent bars
// (not shown: accumulate features into a matrix)
// 2. Initialize and train
var RF.Forest model = RF.Forest.new().init(
n_estimators = 10,
max_depth = 4,
seed = 42)
if barstate.islast
model.fit(X, y)
// 3. Predict on current bar
array sample = array.from(rsi_val, atr_pct, cci_val, adx_val)
float prob = model.predict_proba(sample)
// 4. Evaluate
float oob = model.oob_score()
label.new(bar_index, close, "prob=" + str.tostring(prob, "#.##") + " oob=" + str.tostring(oob, "#.##"))
Compatibility Notes
scikit-learn parity : same init → fit → predict / predict_proba workflow, same default for max_features , OOB uses soft voting, importances use weighted Gini decrease.
Determinism : given identical seed , training set, and hyperparameters, the resulting forest and all predictions are bit-identical across reruns.
Binary classification only in fit() : labels must be 0 or 1. Multi-class is not yet supported.
Numeric features only : all columns of X must be float .
Limitations
This is a machine-learning library , not a trading signal. Indicators built with it make no guarantee of profit, do not predict the future, and depend entirely on the quality of the features, labels, and hyperparameters that the caller supplies.
Binary classification only in fit() (labels must be 0 or 1); multi-class is not supported. Regression via fit_regressor() supports multi-output targets but assumes they are numeric float values.
PulseWire runtime budget limits tree size. A reasonable starting point is n_estimators between 5 and 20 with max_depth between 3 and 6. Total node budget per tree is 2^(max_depth+1) - 1 — depth 6 allows up to 127 nodes per tree, and 15 trees means up to roughly 1,905 nodes total.
Large training sets combined with deep trees (thousands of bars × depth 6) can hit Pine Script's loop iteration caps. Start small and scale up while watching compile / runtime warnings.
OOB metrics ( oob_score , oob_r2 , oob_residual_std ) are valid only when each sample is out-of-bag in at least one tree. For very small training sets or very few estimators, some samples may never be OOB and those metrics will be biased or undefined.
Overfitting is the caller's responsibility. The library exposes standard controls ( max_depth , min_samples_leaf , max_features , n_estimators ) but applies no automatic regularization. Trees that are too deep on a noisy training window will memorize noise.
Features must be stationary enough to generalize. Raw price levels or unnormalized indicators that drift with the market will cause training-test distribution shift. Prefer bounded or ratio-based features (RSI, ATR%, percentile ranks).
Training happens on the chart's own bar history. There is no external data upload; the library cannot import pre-trained models, and the forest must be rebuilt whenever the script recomputes. Designs that rely on very large historical context may conflict with Pine Script's bar-history window.
References
Breiman, L. (2001). Random Forests. Machine Learning, 45(1), 5–32.
Wager, S., Hastie, T., and Efron, B. (2014). Confidence Intervals for Random Forests: The Jackknife and the Infinitesimal Jackknife. Journal of Machine Learning Research, 15, 1625–1651.
Disclaimer
This library is an educational and research tool. It does not constitute financial advice. All trading decisions based on code built with this library are the sole responsibility of the user. Past model performance does not guarantee future results. Library

Library

si_continuation_live_summary_v5Library "si_continuation_live_summary_v5"
Lane-owned live summary entrypoint for the continuation prototype. Staged for future host wiring without moving continuation logic into the meta layer.
calc_continuation_live_summary(regime_fast_length_input, regime_slow_length_input, regime_compression_length_input, regime_compression_threshold_input, structure_pivot_left_input, structure_pivot_right_input, structure_basis_length_input, structure_displacement_atr_input, fair_value_atr_length_input, fair_value_extreme_atr_input, continuation_pullback_min_input, continuation_pullback_max_input, continuation_hold_buffer_atr_input, continuation_break_buffer_atr_input, continuation_reaccept_buffer_atr_input, continuation_body_ratio_min_input, continuation_close_quality_min_input, continuation_memory_bars_input, continuation_resumption_window_input)
Public host-callable live continuation summary surface. Returns the standardized 10-field primitive tuple.
Parameters:
regime_fast_length_input (simple int)
regime_slow_length_input (simple int)
regime_compression_length_input (int)
regime_compression_threshold_input (float)
structure_pivot_left_input (int)
structure_pivot_right_input (int)
structure_basis_length_input (simple int)
structure_displacement_atr_input (float)
fair_value_atr_length_input (simple int)
fair_value_extreme_atr_input (float)
continuation_pullback_min_input (float)
continuation_pullback_max_input (float)
continuation_hold_buffer_atr_input (float)
continuation_break_buffer_atr_input (float)
continuation_reaccept_buffer_atr_input (float)
continuation_body_ratio_min_input (float)
continuation_close_quality_min_input (float)
continuation_memory_bars_input (int)
continuation_resumption_window_input (int) Library

Pivot_Labels_Output_UtilitiesThis library contains reusable pivot label output helpers for Pine scripts that already have their own pivot, structure, or signal logic but want a shared label-rendering layer.
It centralizes the parts of the workflow that tend to get rewritten across label-heavy scripts: label-size resolution, compact percent and price formatting, one-shot pivot label plotting, live directional label management, confirmed/local/current-RSI text builders, early-label emoji output, and live-stack text / object helpers.
On the example chart, the visible label workflows are materially driven by the library, whether through the confirmed pivot label text, the local pivot label text, the current RSI + SMA above-bar label, the early directional labels, or the live stack text and label-object lifecycle helpers used to keep those outputs updated cleanly on the chart.
How to use
Import the library near the top of your script in global scope, alongside any other imports, before you start calling its helpers.
Typical placement:
// @version=6
indicator(...) or strategy(...)
import MYNAMEISBRANDON/PivotLabelsOutput_Utilities/1 as PLutils
This library does not confirm pivots, resolve structure tags, or choose label colors for you. Instead, it expects your script to already know the values it wants to display, then uses those resolved inputs to build the output layer.
For more information on libraries and incorporating them into your scripts, see the Libraries section of the Pine Script User Manual.
➖Label Size Helpers➖
These helpers convert simple UI-facing size strings into Pine label-size enums so scripts can keep one consistent size resolver across confirmed pivot labels, local pivot labels, current RSI labels, early labels, and live stack labels.
labelSizeFromString(sizeIn)
Resolves a Pine label size from a string input.
Parameters:
sizeIn (simple string): Size string. Expected values: "Tiny", "Small", "Normal", "Large", or "Huge"
Returns:
Pine label size enum
➖Numeric Formatting Helpers➖
These helpers handle compact numeric formatting for label-driven scripts. They let a script calculate percent change safely, format that change in a label-friendly way, and convert larger price values into compact significant-figure style text.
labelPercentChange(curr, prev)
Returns percent change from prev to curr.
Parameters:
curr (float): Current value
prev (float): Previous reference value
Returns:
Percent change or na when invalid
labelFormatPercent(p)
Formats a percent value for compact label output.
Parameters:
p (float): Percent value
Returns:
Formatted percent string
labelFormatCompactNumber(x, sig)
Formats a number using significant-figure style suffix output.
Parameters:
x (float): Value to format
sig (simple int): Significant figures to preserve
Returns:
Compact number string
➖Static Label Plot Helpers➖
These helpers create one-shot label outputs for scripts that want to place confirmed or local pivot labels on historical pivot bars, or simple above-bar informational labels, without managing a live label object afterward.
plotPivotLabel(x, y, txt, textColor, isHigh, sizeIn)
Creates a pivot label on a specific bar.
Parameters:
x (int): Label x position
y (float): Label y position
txt (string): Label text
textColor (color): Label text color
isHigh (bool): True for a high-side label, false for a low-side label
sizeIn (simple string): Label size string
Returns:
Created label reference
plotAboveBarLabel(x, y, txt, textColor, sizeIn)
Creates an above-bar informational label.
Parameters:
x (int): Label x position
y (float): Label y position
txt (string): Label text
textColor (color): Label text color
sizeIn (simple string): Label size string
Returns:
Created label reference
➖Directional Label Object Helpers➖
These helpers manage the lifecycle of live high-side and low-side label objects so scripts can create, update, or delete directional labels without repeating the same object-management logic each time.
manageDirectionalLabel(lbl, show, x, y, txt, textColor, isHigh, sizeIn)
Creates, updates, or deletes a directional label object.
Parameters:
lbl (label): Existing label reference
show (bool): Whether the label should exist
x (int): Label x position
y (float): Label y position
txt (string): Label text
textColor (color): Label text color
isHigh (bool): True for a high-side label, false for a low-side label
sizeIn (simple string): Label size string
Returns:
Updated label reference
➖Pivot Text Helpers➖
These helpers build the final text used by confirmed pivot labels, local pivot labels, confirmed pivot alerts, and the current RSI / SMA above-bar label. In other words, this region keeps the script’s visible wording consistent while leaving structure resolution and color decisions to the calling script.
buildMajorPivotLabelText(mode, priceText, priceStruct, rsiText, oscStruct, percentText, pivotLen, showLen)
Builds confirmed pivot label text.
Parameters:
mode (simple string): Label mode. Expected values: "Full" or "RSI Only"
priceText (string): Formatted pivot price
priceStruct (string): Price-side structure tag
rsiText (string): Formatted pivot RSI
oscStruct (string): RSI-side structure tag
percentText (string): Formatted percent-change text
pivotLen (int): Pivot length value
showLen (bool): Whether pivot length should be shown
Returns:
Confirmed pivot label text
buildLocalPivotLabelText(priceText, priceStruct, rsiText, rsiStruct, pivotLen, showPrice, showLen)
Builds local pivot label text.
Parameters:
priceText (string): Formatted local pivot price
priceStruct (string): Price-side structure tag
rsiText (string): Formatted local pivot RSI
rsiStruct (string): RSI-side structure tag
pivotLen (int): Pivot length value
showPrice (bool): Whether the price line should be shown
showLen (bool): Whether pivot length should be shown
Returns:
Local pivot label text
buildPivotAlertText(isHigh, priceText, pctText, rsiText, structTag, rsiValue, rsiOB, rsiOS)
Builds confirmed pivot alert text.
Parameters:
isHigh (bool): True for a high pivot, false for a low pivot
priceText (string): Formatted pivot price
pctText (string): Formatted percent-change text
rsiText (string): Formatted pivot RSI
structTag (string): RSI-side structure tag
rsiValue (float): Raw RSI value at the pivot
rsiOB (int): Overbought level
rsiOS (int): Oversold level
Returns:
Alert message text
buildCurrentRsiAboveBarText(currRsiText, structTag, smaText)
Builds current RSI / SMA above-bar label text.
Parameters:
currRsiText (string): Formatted current RSI text
structTag (string): Current live structure tag
smaText (string): Formatted SMA text
Returns:
Current RSI above-bar label text
➖Early Pivot Label Helpers➖
These helpers provide the reusable output primitive used by early pivot labels. This region intentionally stops at emoji selection so scripts with different structure-tag models and color logic can still reuse the same active-vs-carried-forward label cue.
earlyPivotEmoji(isHigh, isCurrentCandidateBar)
Returns the early-pivot emoji for the active side and candidate state.
Parameters:
isHigh (bool): True for a high-side early label, false for a low-side early label
isCurrentCandidateBar (bool): True when the candidate bar is the current bar
Returns:
Early-pivot emoji
➖Live Stack Text Helpers➖
These helpers build the reusable text layer behind live stack labels. They handle padded line construction, signed delta wording, movement glyphs, and the multi-line center block used to display price, anchor tag, RSI, RSI delta, SMA, and SMA delta.
stackSignedRoundText(x)
Returns a rounded signed text value for live-stack display.
Parameters:
x (float): Value to round
Returns:
Signed rounded text
stackMoveGlyph(delta)
Returns the move glyph used by live-stack delta text.
Parameters:
delta (float): Delta value
Returns:
Move glyph
stackDeltaText(change, structTag, isPercent, pad)
Builds padded delta text for the live stack.
Parameters:
change (float): Delta value
structTag (string): Structure tag to append
isPercent (bool): Whether the delta should be formatted as a percent
pad (int): EM-space padding count
Returns:
Padded delta text
stackRsiDiffText(delta, structTag, pad)
Builds padded RSI-delta text for the live stack.
Parameters:
delta (float): RSI delta value
structTag (string): Structure tag to append
pad (int): EM-space padding count
Returns:
Padded RSI-delta text
stackCenterText(price, rsiVal, rsiDelta, rsiSma, rsiSmaDelta, anchorTag, pad, sigFigs)
Builds the live-stack center block text.
Parameters:
price (float): Current price
rsiVal (float): Current RSI value
rsiDelta (float): Current bar-to-bar RSI delta
rsiSma (float): Current RSI SMA value
rsiSmaDelta (float): Current bar-to-bar RSI SMA delta
anchorTag (string): Active anchor tag such as "➜H" or "➜L"
pad (int): EM-space padding count
sigFigs (simple int): Significant figures used for price formatting
Returns:
Center live-stack text block
➖Live Stack Label Object Helpers➖
These helpers manage the lifecycle of live center-style stack labels so scripts can create, update, or delete the visible stack objects without repeatedly rewriting that object-management logic.
manageCenterLabel(lblPrev, show, yVal, txt, textColor, xPos, linesBefore, linesAfter, sizeIn)
Creates, updates, or deletes a center-style live-stack label.
Parameters:
lblPrev (label): Existing label reference
show (bool): Whether the label should exist
yVal (float): Label y position
txt (string): Label text
textColor (color): Label text color
xPos (int): Label x position
linesBefore (int): Blank lines inserted before the text block
linesAfter (int): Blank lines inserted after the text block
sizeIn (simple string): Label size string
Returns:
Updated label reference
Local Pivot label demo (with pin emoji)— shows the library’s smaller same-side pivot label format on its own for a cleaner view of the local-label workflow.
Library

si_squeeze_live_summaryLibrary "si_squeeze_live_summary"
Lane-owned live summary entrypoint for the squeeze / expansion prototype. Staged for future host wiring without moving squeeze logic into the meta layer.
calc_squeeze_live_summary(regime_fast_length, regime_slow_length, regime_compression_length, regime_atr_length, regime_compression_threshold, structure_pivot_left, structure_pivot_right, structure_basis_length, structure_displacement_atr, fair_value_atr_length, fair_value_extreme_atr)
Public host-callable live squeeze summary surface. Returns the standardized 10-field primitive tuple.
Parameters:
regime_fast_length (simple int)
regime_slow_length (simple int)
regime_compression_length (int)
regime_atr_length (simple int)
regime_compression_threshold (float)
structure_pivot_left (int)
structure_pivot_right (int)
structure_basis_length (simple int)
structure_displacement_atr (float)
fair_value_atr_length (simple int)
fair_value_extreme_atr (float) Library

PivotStructureOutline_UtilitiesThis library contains reusable pivot structure outline helpers for Pine scripts that already work with confirmed pivot highs and lows. It is designed to provide the reusable outline and anchor-box layer for scripts that already have their own pivot-confirmation logic, so those scripts can keep their structure visuals consistent without repeatedly rebuilding the same framework.
It brings together the parts of the workflow that are often rewritten in structure-based scripts: resolving pivot-close anchors, selecting wick vs close anchor behavior, building live outline geometry, building pivot structure anchor-box geometry, and managing the line and box objects that render those visuals.
Everything on the example chart is materially driven by the library, whether through the selected outline anchor source, the outline geometry itself, the midpoint-start logic, the pivot structure anchor boxes, or the shared line/box lifecycle helpers used to keep those visuals updated cleanly on the chart.
How to use
Import the library near the top of your script in global scope, alongside any other imports, before you start calling its helpers. This mirrors the import-first usage pattern shown on your recent library page.
Typical placement:
//@version=6
indicator(...) or strategy(...)
import MYNAMEISBRANDON/PivotStructureOutline_Utilities/1 as PSOutils
This library is engine-agnostic. It does not confirm pivots for you. Instead, it expects your script to already know its confirmed high/low pivot indexes and anchor values, then uses those resolved inputs to build the outline and anchor-box layer.
➖Outline Line Style Helpers➖
These helpers convert simple UI-facing style strings into Pine line style enums so scripts can keep one consistent style resolver across outline lines, midpoint lines, and connector lines.
outlineLineStyle(styleIn)
Resolves a Pine line style from a string input.
Parameters:
styleIn (simple string): Style string. Expected values: "Solid", "Dashed", or "Dotted"
Returns:
Pine line style enum
➖Pivot Structure Outline Helpers➖
These helpers build the actual pivot structure outline framework from already-confirmed high/low pivot anchors. They let a script resolve a pivot-close anchor, choose whether the outline should use wick or close anchors, and generate the live geometry needed for the top line, bottom line, midpoint, and left-side connectors.
outlinePivotCloseFromIdx(pivotIdx, closeValue)
Returns the close value belonging to a confirmed pivot index.
Parameters:
pivotIdx (int): Confirmed pivot bar_index
closeValue (float): Close series
Returns:
Confirmed pivot close value
outlineSelectedAnchors(anchorMode, highWickAnchor, lowWickAnchor, highCloseAnchor, lowCloseAnchor)
Selects the active outline anchors from Wick or Close mode.
Parameters:
anchorMode (simple string): Anchor mode. Expected values: "Wick" or "Close"
highWickAnchor (float): Confirmed high-side wick anchor
lowWickAnchor (float): Confirmed low-side wick anchor
highCloseAnchor (float): Confirmed high-side close anchor
lowCloseAnchor (float): Confirmed low-side close anchor
Returns:
Selected high anchor, selected low anchor, is outline-valid
outlineGeometry(highPivotIdx, lowPivotIdx, highAnchor, lowAnchor, connectorSourceMode, midlineStartMode, highValue, lowValue, closeValue)
Returns the live geometry for the pivot structure outline system.
Parameters:
highPivotIdx (int): Confirmed high pivot bar_index
lowPivotIdx (int): Confirmed low pivot bar_index
highAnchor (float): Selected top outline anchor
lowAnchor (float): Selected bottom outline anchor
connectorSourceMode (simple string): Connector source mode. Expected values: "Wick" or "Close"
midlineStartMode (simple string): Midline start mode. Expected values: "Most Recent Pivot" or "Left Outline"
highValue (float): High series
lowValue (float): Low series
closeValue (float): Close series
Returns:
ok, leftX, rightX, midX1, topY, bottomY, midY, leftTopConnectorY, leftBottomConnectorY
➖Pivot Structure Anchor Box Helpers➖
These helpers build directional top and bottom pivot structure anchor boxes from confirmed pivot bars. They let a script choose whether those boxes use wick-only extension from the candle body or the full candle body, then return the live coordinates needed to render those boxes forward to the current bar.
outlineAnchorBoxGeometry(highPivotIdx, lowPivotIdx, boxAreaMode, openValue, highValue, lowValue, closeValue)
Returns the live geometry for top and bottom pivot structure anchor boxes.
Parameters:
highPivotIdx (int): Confirmed high pivot bar_index
lowPivotIdx (int): Confirmed low pivot bar_index
boxAreaMode (simple string): Box area mode. Expected values: "Wick" or "Body"
openValue (float): Open series
highValue (float): High series
lowValue (float): Low series
closeValue (float): Close series
Returns:
showHighBox, showLowBox, highLeftX, lowLeftX, boxRightX, highTopY, highBottomY, lowTopY, lowBottomY
➖Line Object Helpers➖
These helpers manage the lifecycle of live line objects so scripts can create, update, or delete outline-related lines without rewriting that object-management logic each time.
outlineManageLine(enabled, ln, x1, y1, x2, y2, col, width, style)
Creates, updates, or deletes a line object.
Parameters:
enabled (bool): Whether the line should exist
ln (line): Existing line reference
x1 (int): Start x position
y1 (float): Start y position
x2 (int): End x position
y2 (float): End y position
col (color): Line color
width (int): Line width
style (string): Line style
Returns:
Updated line reference
➖Box Object Helpers➖
These helpers manage the lifecycle of live box objects so scripts can create, update, or delete pivot structure anchor boxes without repeating the same box-management code in every script.
outlineManageBox(enabled, bx, left, top, right, bottom, bgColor, borderColor, borderStyle, borderWidth)
Creates, updates, or deletes a box object.
Parameters:
enabled (bool): Whether the box should exist
bx (box): Existing box reference
left (int): Left x position
top (float): Top y position
right (int): Right x position
bottom (float): Bottom y position
bgColor (color): Box background color
borderColor (color): Box border color
borderStyle (string): Box border style
borderWidth (int): Box border width
Returns:
Updated box reference
Library

Pine3D: A Native 3D Graphical Rendering EnginePine3D is a full 3D rendering engine for PulseWire, powered by Pine Script™ v6.
Pine3D pushes forward the frontier of PulseWire 3D rendering capabilities, providing a fully fledged graphical engine under an intuitive, chainable, object oriented API. Build meshes, transform them in world space, light them, cast shadows, project them through a perspective camera, and render the result directly on your chart, all without ever bothering about trigonometry synchronization or optimization.
The library brings forth a streamlined process for anyone that wishes to visualize data in 3D, without needing to know anything about the complex math that has previously gatekept such indicators. Pine3D does all the heavy lifting, including extreme optimization techniques designed for production ready indicators.
The entire API is chainable and tag addressable, so spawning a mesh, registering it, pointing the camera at it, and rendering the frame is a four line affair:
Mesh mybox = cube(40.0, color.orange).setTag("hero").rotateBy(0.0, 45.0, 0.0)
scene.add(mybox)
scene.lookAt("hero")
render(scene)
🔷 SURFACES: CONTOUR BAND RENDERING
Pine Script imposes a hard ceiling of 100 polylines and 500 lines per indicator . On the surface this looks fatal for dense 3D meshes: every triangle drawn naively burns one of those 100 slots, or two of the 500, and the budget evaporates within a few hundred faces.
The conventional escape hatch is strip stitching , tracing a polyline forward along one row of a grid and back along the next, packing a ribbon of quads into a single drawing slot. It buys a meaningful multiplier, but it pays for that multiplier with two structural constraints baked into the geometry itself:
One color per strip. A polyline carries a single stroke and fill color, so every cell along the ribbon must share the same shade. The moment you want per cell lighting, contour banding, or value driven gradients, every color change forces a new polyline and the budget collapses.
One contiguous ribbon per slot. Strips can only describe topologically connected runs of cells. Disjoint regions, holes, islands, and value clustered fragments scattered across the surface each demand their own polyline.
Pine3D breaks both constraints at once.
At the core of the engine sits an innovation that redefines the limits for visual fidelity: contour band rendering using degenerate bridge stitching . The technique quantizes a surface's elevation into colored bands, then collapses every cell that falls inside the same band, no matter where it sits on the screen , into one continuous, hole aware polyline path per band, threading invisible zero width bridges between disjoint islands so that a single polyline can carry thousands of polygon equivalent fragments scattered across the geometry.
The result:
A single polyline can render up to 2,000 disconnected triangle equivalents , spread across arbitrarily separated regions of the surface.
Theoretical ceiling of around 200,000 disconnected faces inside the 100 polyline budget, a regime that strip based stitching cannot enter at any color count above one.
A 40 x 40 heightmap (around 3,000 triangles) renders inside the budget with full per band contour coloring and room to spare. Stress harnesses have run 40 x 80 grids .
Each band's path is depth sorted and near plane culled, and cached between bars , so once geometry is built only the screen space projection runs per frame.
This algorithm enables scenes with extreme detail relative to the 100 polyline limit, and shifts the optimization focus from "drawing limits" to "CPU limits", which Pine3D natively handles with aggressive caching at every layer of the pipeline. The contour technique is currently integrated into the surface() function, with the same compression strategy generalizable to any mesh class and ultimately full scene rendering in future versions.
Non-uniform grids out of the box. surface() accepts optional axisX and axisZ arrays that override the default uniform spacing with custom column and row positions. This means logarithmic strike spacing on an option volatility surface, irregular timestamp spacing on a market depth heatmap, or any other non-evenly-sampled grid renders correctly without resampling the data first. The contour band engine, axis ticks, and gridBox cage all snap to the custom positions automatically.
A full contour surface is just a handful of lines; the damped ripple below builds once and never needs updating:
//@version=6
indicator("Pine3D - Contour Surface", overlay = false, max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var p3d.Mesh heatmap = na
if barstate.isfirst
// Damped cosine ripple
int N = 20
matrix data = matrix.new(N, N, 0.0)
for r = 0 to N - 1
for c = 0 to N - 1
float dx = c - (N - 1) / 2.0
float dz = r - (N - 1) / 2.0
float d = math.sqrt(dx * dx + dz * dz) * 0.7
data.set(r, c, math.cos(d) * math.exp(-d * 0.12) * 50.0)
heatmap := p3d.surface(data, 200.0, color.blue, color.red, 24)
.gridBox()
.gridLabels(color.white, "X", "Amplitude", "Z")
scene.add(heatmap)
scene.camera.orbit(35.0, 25.0, 380.0)
if barstate.islast
p3d.render(scene, lighting = true)
🔷 TRAIL3D: STREAMED OSCILLATOR PATHS
Trail3D is a first class streaming primitive built for visualizing two correlated time series as a 3D ribbon evolving through time. You give it a rolling buffer capacity and push (u, v) samples bar by bar; the primitive maintains the buffer, builds the ribbon geometry, and renders it inside a normalized bounding cube so the path always fits cleanly in view regardless of the underlying data range.
Under the hood, Trail3D is a coordinated bundle of polylines: one for the main ribbon, two for optional shadow projections onto the back wall and floor, and one for the wireframe cage. All four are depth sorted and occlusion clipped against the rest of the scene, and the primitive auto normalizes incoming samples against the rolling window's min/max so streaming data always fills the cube without manual scaling.
This enables a class of visualizations that would otherwise require dozens of polylines and manual buffer management: phase space portraits, Lissajous figures, oscillator pair correlations, attractor trajectories, and any "two indicators evolving together over time" study. The demo above shows a sine and cosine pair pushing samples each bar to trace a clean spiral inside the cage, the same pattern you would use to plot RSI vs MFI, momentum vs volatility, or any custom (u, v) signal pair.
A full streamed scene is a handful of lines:
//@version=6
indicator("Pine3D - Trail3D", overlay = false, max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var p3d.Trail3D trail = na
if barstate.isfirst
trail := p3d.trail3D(220.0, 200, color.yellow)
.cage(true)
.axisLabels("sin", "cos", color.white)
trail._uProj.col := #00ffff69
trail._vProj.col := #ff00ff71
scene.add(trail)
scene.camera.orbit(215.0, 20.0, 360.0)
float phase = bar_index * 0.15
float sinX = math.sin(phase) * 100.0
float cosY = math.cos(phase) * 100.0
if barstate.isconfirmed
trail.pushSample(sinX, cosY)
p3d.render(scene)
🔷 BARS3D: CATEGORICAL 3D BAR CHARTS
bars3D() turns any series of values into a fully lit, depth sorted 3D bar chart in a single call. Each bar is height mapped to its value, color graded between a low and high color, and packed into one combined mesh with per bar depth grouping so individual bars sort correctly even inside the merged geometry. The companion updateBars() mutator refreshes heights, colors, and labels in place every bar without rebuilding geometry, making it suitable for live rankings, rolling windows, and animated comparisons.
The chainable barLabels(catNames, valNames) helper attaches category labels at the base of each bar and value labels at the top, both depth sorted with the rest of the scene. Category labels are set once at build time, while value labels can be passed to updateBars(values, valLabels = ...) each frame to reflect live data. Combined with wireGrid() for the floor and a contour surface() in the background, bars3D() becomes the centerpiece of dashboards comparing assets, sectors, timeframes, or any categorical metric.
Negative values are handled automatically: bars below zero extrude downward from the base plane with reversed face winding, so signed series like PnL, delta, or momentum histograms render correctly without any extra setup.
A complete labeled bar chart is just a few lines:
//@version=6
indicator("Pine3D - Bars3D", overlay = false, max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var p3d.Mesh bars = na
array values = array.from(volume - volume , volume - volume , volume - volume , volume - volume , volume - volume , volume - volume )
array names = array.from("ΔV0", "ΔV-1", "ΔV-2", "ΔV-3", "ΔV-4", "ΔV-5")
if barstate.isfirst
bars := p3d.bars3D(values, 30.0, 30.0, 10.0, color.blue, color.red, 200.0)
.barLabels(names)
scene.add(bars)
p3d.wireGrid(scene, 300.0, 300.0, 6, 6, color.new(color.gray, 80))
scene.camera.orbit(215.0, 25.0, 360.0)
if barstate.islast
bars.updateBars(values)
p3d.render(scene, lighting = true)
Omitting valLabels in updateBars() tells the engine to auto format each numeric value via str.tostring() . Pass valLabels only when you need custom strings.
🔷 SCATTER CLOUDS: POINTS IN 3D SPACE
Pine3D treats scatter clouds as a first class use case without needing a dedicated scatter API. Because Label3D is the primitive and scene.add(array) is a single batch operation, you can scatter up to 500 points anywhere in 3D space, each with independent color, symbol, size, and tooltip , and have them depth sorted and occlusion clipped against the rest of the scene automatically.
Each point is a fully addressable Label3D with mutable fields. You can change position , textColor , bgColor , labelStyle (any label.style_* glyph including circles, squares, diamonds, triangles, crosses, arrows, flags), labelSize (any size.* preset), and text per point per bar. The renderer reads these mutations every frame, so animation is just direct field assignment.
This unlocks a wide class of visualizations: clustered data scatter, K means visualizations, particle systems, parametric surfaces sampled as point clouds, gradient colored attractors, multi class classification overlays, and structured curves like the demo above. The double helix demo plots two intertwined parametric strands as ~500 points with alternating colors and per point sizing, all inside the standard scene.add(array) pipeline.
The pattern is straightforward: build the array once in barstate.isfirst , add it to the scene, then mutate point fields per bar to animate.
//@version=6
indicator("Pine3D - Scatter Cloud", overlay = false, max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var array points = array.new()
if barstate.isfirst
for i = 0 to 499
p3d.Vec3 pos = p3d.vec3(0.0, 0.0, 0.0)
points.push(p3d.Label3D.new(position = pos, txt = "•"))
scene.add(points)
scene.camera.orbit(35.0, 20.0, 400.0)
if barstate.islast
for i = 0 to points.size() - 1
float t = i * 0.05 + bar_index * 0.01
p3d.Label3D pt = points.get(i)
pt.position := p3d.vec3(80.0 * math.cos(t), i * 0.4 - 100.0, 80.0 * math.sin(t))
pt.textColor := i % 2 == 0 ? color.aqua : color.fuchsia
p3d.render(scene)
----------------------------------------------------------------------------------------------------------------
🔷 TWO LAYER ARCHITECTURE
Pine3D ships as a clean, two layer library:
🔸 Layer 1 - DIY API. First principle building blocks ( Vec3 , Mesh , Camera , Light , Scene , plus world space overlay primitives) for total creative control. Author your own geometry, camera behavior, lighting setup, and scene graph from scratch.
🔸 Layer 2 - High Level Helpers. Production ready wrappers like surface() , bars3D() , trail3D() , updateBars() , updateSurface() , sphere() , torus() , cylinder() , and wireGrid() , plus chainable contour helpers gridBox() and gridLabels() that wrap the primitives into a few lines of code. Scatter clouds use the standard Label3D primitive directly.
The object model is chainable and scene oriented, so complex setups still read cleanly.
🔷 FEATURE LIST
Contour Surface Rendering - The most powerful 3D surface engine ever released for Pine Script. Render tens of thousands of polygon equivalent faces using a single polyline per contour band, delivering smooth, continuous terrain with natural ridges and valleys.
Adaptive Rail Sharing - Solid meshes drawn with the default linefill backend reuse one edge line between adjacent coplanar faces, averaging roughly 1.6 lines per face instead of the naive two, pushing practical mesh capacity up to ~360 faces depending on topology.
Interior Face Culling on Merge - mergeMeshes(meshes, removeInterior = true) detects coincident faces with opposing normals and strips them, so voxel style scenes (stacked cubes, block walls, lattice geometry) ship only their exterior shell and spend no budget on hidden interior faces.
True Perspective Camera System - Full 3D camera with position, target, fov, and orbit() controls. Supports cinematic camera movement, lookAt by mesh tag, and realistic depth.
Real Time Lighting and Shadows - Directional and point lights with configurable ambient, shadow strength, self shadowing, and a spatial grid acceleration structure for fast shadow queries.
High Performance Update System - updateSurface() and updateBars() let you animate massive datasets bar by bar without rebuilding geometry, keeping CPU usage minimal.
Rich Primitive Library - Cubes, cuboids, spheres, cylinders, tori, pyramids, planes, discs, circles, custom meshes, and the groundbreaking bars3D() with automatic labels.
Streamed Trail Primitive - trail3D() maintains a rolling buffer of (u, v) samples and renders them as a 3D ribbon inside a bounding cube, with optional projections onto the back wall and floor and a wireframe cage.
Depth Sorted Overlays - 3D labels, lines, polylines, wire grids, and trails, all correctly occluded and painter sorted against the rest of the scene.
Professional Contour Helpers - gridBox() and gridLabels() automatically add clean bounding boxes and axis titles, ticks, and series names that refresh on every updateSurface() call.
Tag Based Scene Graph - Every Mesh , Label3D , Line3D , and Polyline3D can carry a string tag. Scene exposes getMesh() , getLabel() , getLine() , getPolyline() , lookAt() , and remove() by tag, turning your scene into a lookup by name graph instead of an index juggling exercise.
Chainable, Intuitive API - Everything is designed for maximum readability and speed of development. Build complex scenes in just a few lines.
Production Ready Optimizations - World vertex caching, view projection caching, face preprocessing cache, shadow grid cache, and contour geometry cache, all managed automatically.
----------------------------------------------------------------------------------------------------------------
🔷 THE RENDERER
Every frame is produced by a single call to render(scene, ...) . The renderer runs the full pipeline: world transform, camera transform, back face culling, occlusion culling, depth sort, directional or point lighting with shadows, and perspective projection.
⚠ render() clears the entire chart drawing pool at the start of every call - every polyline , line , label , and linefill on the chart is deleted before Pine3D redraws, not just the ones it created. If you mix Pine3D with manual label.new() , line.new() , or similar calls, those drawings must be emitted after render() or they will be wiped every frame.
🔸 Setup Requirements. Pine3D consumes polylines, lines, and labels simultaneously, so your indicator() declaration must raise all three budgets, and the library must be imported under an alias:
indicator("My 3D Scene", overlay = false,
max_polylines_count = 100,
max_lines_count = 500,
max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
🔸 render() parameters.
maxFaces (int, default 100). Hard cap on solid faces drawn per frame. Contour bands, wireframe edges, labels, lines, and overlay polylines are not counted against this cap, and are bounded only by PulseWire's global 100 polyline / 500 line / 500 label budgets.
culling (bool, default true). Enable back face culling.
lighting (bool, default false). Enable diffuse shading. Reads scene.light if set; otherwise falls back to the render() args.
lightDir (Vec3). Overrides scene.light.direction when provided. Points toward the light.
ambient (float, default 0.3). Minimum brightness for shadowed faces (0.0-1.0).
wireframe (bool, default false). Force outline only output for the entire scene.
occlusion (bool, default true). Sparse raster pass that drops hidden faces before drawing. Major perf win on dense scenes.
occlusionRaster (int, default 768). Raster resolution of the occlusion buffer. Lower = faster but coarser; higher = stricter hidden face rejection.
Explicit render() args always win over scene.light , which makes render() the right place for ad hoc, per frame lighting tweaks.
----------------------------------------------------------------------------------------------------------------
🔷 MESH DRAWING MODES
Two independent axes control how a mesh appears on the chart:
🔸 Style (via mesh.setStyle(...) ) - what gets drawn:
"solid" . Filled faces. Default.
"wireframe" . All edges, no fill. Shows interior geometry.
"wireframe_front" . Only front facing edges. Cleaner silhouette for convex meshes.
🔸 Draw Mode (via mesh.drawMode ) - which PulseWire primitive carries the solid faces:
"linefill" (default). Uses the line and linefill budgets. An adaptive rail sharing optimization reuses one edge line between adjacent coplanar faces, pushing practical capacity up to ~360 faces per mesh depending on topology. Supports in place updates via updateSurface() and updateBars() . Rails are drawn transparent, so solid faces in this mode have no visible outline - use a wireframe style or "poly" drawMode if you need stroked edges. Recommended for all new code.
"poly" . Legacy polyline backend. Capacity ~100 faces, no in place updates, but renders the face outline using mesh.lineStyle and mesh.lineWidth . Use only when you need styled solid face outlines.
Wireframe styles always render with line primitives regardless of drawMode. Stroke width and style on edges (and on poly mode face outlines) come from mesh.lineWidth and mesh.lineStyle , which you mutate by direct field assignment.
----------------------------------------------------------------------------------------------------------------
🔷 QUICK START
The best practice lifecycle is simple:
Create one persistent Scene with newScene() .
Build meshes and helper overlays once in barstate.isfirst .
On later bars, mutate objects in place with transforms or helper mutators like updateBars() and updateSurface() .
Call render(scene, ...) once per frame. It automatically clears the previous chart drawings.
A complete, lit, animated 3D scene is still a handful of lines:
//@version=6
indicator("My First 3D Scene", overlay = false, max_polylines_count = 100, max_lines_count = 500, max_labels_count = 500)
import Alien_Algorithms/Pine3D/1 as p3d
var p3d.Scene scene = p3d.newScene()
var p3d.Mesh sun = na
if barstate.isfirst
scene.setLightDir(1.0, -1.0, 0.5).setAmbient(0.3)
sun := p3d.sphere(50.0, 16, 12, color.orange).setTag("sun")
scene.add(sun)
p3d.wireGrid(scene, 300.0, 300.0, 6, 6, color.new(color.gray, 80))
scene.camera.orbit(35.0, 25.0, 220.0)
if barstate.islast
sun.rotateBy(0.0, 1.5, 0.0)
p3d.render(scene, lighting = true)
----------------------------------------------------------------------------------------------------------------
🔷 RECOMMENDED USAGE PATTERN
Use your Scene and major meshes in var .
Build geometry once in barstate.isfirst .
Use updateSurface() and updateBars() on later bars instead of rebuilding meshes.
Use scene level helpers like wireGrid() when you want overlays added immediately.
Use trail3D() when you want a streamed oscillator style path with built in wall projections and cage geometry.
For scatter clouds, build an array once, hand it to scene.add(pts) , then mutate pt.position , pt.textColor , etc. each bar to animate.
Use mesh level gridBox() and gridLabels() (contour) and barLabels() (bars) to attach overlays to the mesh setup chain. They are drained into the scene by scene.add(mesh) .
🔷 CONSIDERATIONS
scene.clear() vs render(). scene.clear() removes objects from the scene graph (meshes, labels, lines, polylines). render() only clears the previous frame's PulseWire drawings and redraws from the current scene graph. You almost never need scene.clear() in the build once and update pattern.
Global scope series for updateSurface() / updateBars(). If your data uses Pine's history operator ( ) or calls functions like ta.rsi() , ta.atr() , request.security() , those must be declared at global scope so Pine tracks their bar by bar history. Calling them inside barstate.islast produces inconsistent results or compiler errors.
gridLabels() tick values auto refresh. When you call updateSurface() , any tick value labels created by gridLabels() are automatically updated to reflect the new data range. Axis titles and positions stay constant. You don't need to rebuild them.
barLabels() value labels via updateBars(). Create category labels once with mesh.barLabels(catNames) at build time, then pass valLabels to updateBars() on each frame. Value labels are refreshed automatically. Don't call barLabels() again.
Lighting convenience methods are chainable. scene.setLightDir() , setLightPos() , setLightMode() , setAmbient() , setShadowStrength() , and showLightSource() all return Scene and can be chained: scene.setLightMode("point").setLightPos(0, 200, 150).setAmbient(0.25) .
Mesh transforms return Mesh. moveTo() , moveBy() , rotateTo() , rotateBy() , scaleTo() , scaleUniform() , setTag() , setStyle() , setColor() , show() , hide() all return Mesh for chaining: mesh.moveTo(0, -20, 0).rotateTo(0, 45, 0).setStyle("solid") .
Degrees vs radians. rotateTo() and rotateBy() on Mesh expect degrees. The low level Vec3.rotateX/Y/Z() methods expect radians.
scene.lookAt() is tag only. scene.lookAt(t) accepts a string tag and points the camera at that mesh. To aim the camera at an arbitrary Vec3 , call scene.camera.lookAt(vec) directly.
remove(tag) removes one object. The search order is meshes, then labels, then lines, then polylines, and the first hit wins. Avoid reusing tags across primitive types if you intend to delete by tag.
Shadow grid acceleration is directional light only. The spatial shadow grid is only built when lightMode == "directional" . Point lights fall back to a linear O(M) scan, so heavy shadow scenes are fastest in directional mode.
guiShift and yOffset. scene.guiShift and scene.yOffset position the 3D viewport on the chart without consuming historical bar slots. Increase guiShift to push the scene rightward into future bar space; adjust yOffset to slide it vertically in price units.
bar_time projection. All chart drawings are emitted with xloc.bar_time , so the scene can sit arbitrarily far left or right of bar_index without forcing Pine to extend its history buffer. This is what keeps the engine stable on long charts and future projected scenes.
barLabels() without values. When you call mesh.barLabels(catNames) and omit value labels, every later updateBars(values) auto formats the numeric values via str.tostring() . Pass valLabels only when you need custom strings.
Direct mesh.vertices mutation requires invalidateCache(). Transform mutators ( moveTo , rotateBy , scaleTo , etc.) invalidate the world vertex cache on their own. Only raw index writes like mesh.vertices.set(i, newVec) need a manual mesh.invalidateCache() call to force re-projection. Skipping it will make the renderer draw stale geometry.
Drawing budgets fail silently. If a scene emits more than 100 polylines, 500 lines, or 500 labels in a single frame, PulseWire silently drops the overflow without raising a runtime error. Missing geometry almost always means a budget overrun - lower maxFaces , drop a contour level, or simplify overlay primitives to bring the frame back inside the caps.
render() deletes non Pine3D drawings too. Every render() call clears polyline.all , line.all , label.all , and linefill.all before redrawing. Any manual label.new() , line.new() , etc. issued before render() in the same frame will be wiped. Issue custom drawings after the render call if you need them to persist.
mergeMeshes() preserves depth grouping. When every source mesh passed into mergeMeshes() has the same vertex and face count (e.g. identical primitives in a voxel grid), the merged mesh auto derives depth group boundaries so the combined geometry still sorts correctly per original instance. Mixing primitives with different topologies disables the grouping.
CPU timeouts: knobs to turn. Pine Script enforces a per bar execution budget, and dense scenes can trip it before the drawing budget ever does. If a scene compiles but times out at runtime, reach for these levers in order: lower occlusionRaster (e.g. 768 -> 384) for the biggest single perf win, reduce maxFaces to cap the solid face pool, drop levels on contour surfaces, simplify sphere/torus segment counts, and gate heavy work behind barstate.islast so history bars only build geometry rather than render it.
----------------------------------------------------------------------------------------------------------------
🔷 MORE EXAMPLES
The following scenes were all built entirely in Pine Script™ v6 using Pine3D as the rendering layer. They exist to demonstrate that the library is a real engine capable of complex, production grade visualizations.
🔸 4D Hypercube (Tesseract). A rotating tesseract, projected from 4D to 3D to 2D in real time using a custom 4D rotation matrix layered on top of Pine3D's standard projection pipeline.
🔸 Solar System. Following the publication of my 3D Solar System back in 2024, which introduced new graphical rendering concepts into Pine Script, we have seen a wave of various interpretations of the underlying vector classes, ranging from tutorials to niche specific integrations using hardcoded math. It became clear that a unified architecture was needed, one that would lower the barrier to entry while simultaneously handling the optimization process, which is both complex and error prone to do manually.
That architecture is what Pine3D delivers. Below is a re-creation of the classic 3D Solar System rebuilt entirely on top of the library. It uses a fraction of the original code , renders roughly 5x faster , and adds real lighting cast directly from the Sun , all while consuming only a third of the available drawing budget thanks to the occlusion and culling mechanisms Pine3D handles out of the box.
----------------------------------------------------------------------------------------------------------------
🔷 API REFERENCE
🔸 Top Level Entry Points. newScene() creates a ready to use Scene with a default camera and light. render(scene, ...) draws the current frame and auto clears the previous frame's chart drawings; see the Renderer section above for the full parameter list. vec3(x, y, z) creates a Vec3. colorBrightness() is an exported color utility helper.
🔸 Mesh Factories.
Primitives - cube() , cuboid() , pyramid() , plane() , sphere() , cylinder() , torus() , grid() , disc() , circle() for ready made geometry.
customMesh(verts, faces) - Low level escape hatch for authoring your own topology.
mergeMeshes(meshes, tag, removeInterior) - Bakes transforms and combines many meshes into one. With removeInterior = true , coincident faces with opposing normals (e.g. shared walls between adjacent cubes in a grid) are culled so only the exterior shell survives, a major optimization for dense voxel style scenes.
surface(heights, size, lowCol, highCol, levels, axisX, axisZ) - Creates a contour surface mesh.
bars3D(values, barWidth, barDepth, spacing, lowCol, highCol, maxHeight) - Creates a combined 3D bar chart mesh; add labels with the chainable barLabels(names, values) method.
🔸 UDT Constructors. Overlay primitives and face descriptors are plain UDTs. Because these types have many fields, always instantiate them with named arguments rather than positional, e.g. Label3D.new(position = pos, txt = "•") :
Face - fields: vi (array of vertex indices into the parent mesh), col . Used when authoring customMesh() topology; every face must have at least 3 indices and should be planar.
Label3D - fields: position , txt , textColor , bgColor , labelStyle , labelSize , fontFamily , tooltip , visible , tag . Only position is required.
Line3D - fields: start , end , col , width , visible , tag , lineStyle .
Polyline3D - fields: points , col , fillColor , width , closed , visible , tag , lineStyle .
Vec3.new(x, y, z) or the vec3(x, y, z) shorthand.
🔸 Trail Primitive. trail3D(size, capacity, trailCol, minSamples) creates a streamed Trail3D primitive with a main trail, two projection polylines, and a cage polyline. capacity is internally clamped to 300 samples to keep the rolling buffer inside Pine's execution budget; passing a larger value silently resolves to 300. minSamples (default 60) is the sample count at which the cage reaches its full cube width: below that the cage stays cube shaped and samples stretch across it; above that the cage grows rightward at a fixed step until capacity is hit. scene.add(trail) registers the sub primitives into the scene. Trail3D methods: pushSample() , axisLabels() , cage() , moveTo() , show() , hide() .
🔸 Mesh Methods.
Transform - moveTo() , moveBy() , rotateTo() , rotateBy() , scaleTo() , scaleUniform() .
Appearance - setColor() , setFaceColor() , setStyle() , show() , hide() , setTag() .
Stroke styling (direct) - mesh.lineWidth := 3 and mesh.lineStyle := line.style_dashed control width and style of every visible mesh edge in wireframe modes and the outline of solid faces in drawMode = "poly" .
Shadow opt out (direct) - mesh.castShadow := false excludes the mesh from shadow casting while still receiving light. Useful for ghost overlays, debug geometry, or semi transparent meshes you do not want occluding the scene.
Lifecycle - clone() , faceCount() , invalidateCache() .
Data mutation - updateSurface() and updateBars() refresh persistent meshes in place. updateBars() refreshes any bar label positions automatically; pass catLabels / valLabels to also update the text.
Contour helpers - gridBox() and gridLabels() queue overlays on the mesh and hand them to the scene when you call scene.add(mesh) .
Bar helpers - barLabels() is chainable on a bars3D() mesh and queues its category and value labels for the next scene.add(mesh) .
Note: rotateTo() and rotateBy() expect degrees. The low level Vec3.rotateX/Y/Z() methods work in radians.
🔸 Scene Methods.
Lighting - setLightDir() , setLightPos() , setLightMode() , setAmbient() , setShadowStrength() , showLightSource() .
Scene graph - add(mesh) , add(label) , add(array) , add(line) , add(polyline) , add(trail) , remove(index) , remove(tag) , clear() .
Lookup and navigation - getMesh() , getLabel() , getLine() , getPolyline() , lookAt() , totalFaces() .
Cache control - invalidateLightCache() after mutating light direction or scene bounds externally; invalidateAllCaches() to also invalidate every mesh's world vertex cache (use after directly mutating mesh.vertices ).
Note: scene.clear() clears the scene graph itself. render() only clears the previous frame's PulseWire drawings.
🔸 Camera Methods. setPosition(x, y, z) moves the camera. lookAt(x, y, z) / lookAt(vec3) points at a world space target. orbit(angleX, angleY, distance) does a spherical orbit around the current target. setFov(val) sets the perspective scale factor. Camera fields ( position , target , fov ) are also directly mutable via assignment when you need to tune them outside the provided setters, e.g. scene.camera.fov := 1200.0 .
🔸 Light Field Mutation. In addition to the scene level convenience setters, every field on scene.light is directly mutable for fine grained tuning: scene.light.selfShadow := true enables self shadowing, scene.light.shadowBias := 0.2 adjusts the shadow acne offset, scene.light.shadowStrength and scene.light.ambient are also exposed. Mutate them after newScene() or between frames; the renderer reads them every call.
🔸 Vec3 Methods. Core math: add() , sub() , scale() , negate() , dot() , cross() , length() , normalize() , distanceTo() , lerp() . Rotation and helpers: rotateX() , rotateY() , rotateZ() , copy() , toString() .
🔸 Overlay Primitive Methods.
Label3D - moveTo() , moveBy() , setText() , setTextColor() , setTooltip() , show() , hide() , setTag() .
Line3D - setStart() , setEnd() , setPoints() , setColor() , show() , hide() , setTag() .
Polyline3D - setColor() , show() , hide() , setTag() .
Every UDT field is mutable via direct assignment for properties without a chainable setter:
Label3D - bgColor , labelStyle (label.style_*), labelSize (size.*), fontFamily (font.family_*), visible .
Line3D - width , lineStyle (line.style_solid / _dashed / _dotted / _arrow_left / _arrow_right / _arrow_both), visible .
Polyline3D - width , lineStyle (line.style_solid / _dashed / _dotted only; arrow styles are not supported by PulseWire's polyline primitive), fillColor , closed , visible .
Mutations are read per frame by the renderer, so they animate freely.
🔸 High Level Scene Helpers. wireGrid(scene, w, d, divX, divZ, col) adds a depth sorted ground grid. scene.add(array) adds a batch of labels in one call - the idiomatic way to push a scatter cloud into the scene.
🔸 Mesh Level Chainable Overlays. mesh.barLabels(names, values, ...) adds category and value labels on a bars3D() mesh. mesh.gridBox(col, divs) adds a wireframe bounding box cage on a surface() mesh. mesh.gridLabels(col, xName, yName, zName, ticks, fmt) adds axis titles and tick value labels on a surface() mesh; tick values auto refresh on updateSurface() . All three are queued on the mesh and drained into the scene by scene.add(mesh) .
----------------------------------------------------------------------------------------------------------------
This work is licensed under (CC BY-NC-SA 4.0) , meaning usage is free for non-commercial purposes given that Alien_Algorithms is credited in the description for the underlying software. For commercial use licensing, contact Alien_Algorithms
Library

PriceActionLibrary "PriceAction"
Will draw out the market structure for the disired pivot length.
SetBarIndices(pivotHigh, pivotLow)
Sets the 'BarIndex' value of the 'Pivot' object. Useful if the pivot is from an other timeframe.
Parameters:
pivotHigh (Pivot) : The 'Pivot' object for the high pivot.
pivotLow (Pivot) : The 'Pivot' object for the low pivot.
Alert(turtleSoupsContext, settings)
Will fire off an alert if there is one. To be used lastly in the calling script.
Parameters:
turtleSoupsContext (TurtleSoups) : The context of all turtle soups.
settings (TurtleSoupSettings) : The settings for turtle soups.
VisualizeTurtleSoups(pivots, turtleSoups, turtleSoupsContext, settings)
Will visulize found turtle soups and add alert messages for it.
Parameters:
pivots (array) : All current pivots (high or low).
turtleSoups (array) : All bullish or bearish turtle soups.
turtleSoupsContext (TurtleSoups) : The context of all turtle soups.
settings (TurtleSoupSettings) : The settings for turtle soups.
GetPivots(settings)
Will get available pivots. Can be called from another timeframe.
Parameters:
settings (TurtleSoupSettings) : The settings for turtle soups.
Returns: A tuple of high and then low pivots.
SetPivots(turtleSoupsContext, settings, pivotHigh, pivotLow)
Will set the new pivots in turtleSoupsContext.
Parameters:
turtleSoupsContext (TurtleSoups) : The context of all turtle soups.
settings (TurtleSoupSettings) : The settings for turtle soups.
pivotHigh (Pivot) : The 'Pivot' object for the high pivot.
pivotLow (Pivot) : The 'Pivot' object for the low pivot.
Confirm(turtleSoups, turtleSoupsContext, settings, previousStructureBreakBarIndex, screener)
Will visualize turtle soups. To be called if 'TurtleSoupSettings.Confirmation' is true.
Parameters:
turtleSoups (array) : All bullish or bearish turtle soups.
turtleSoupsContext (TurtleSoups) : The context of all turtle soups.
settings (TurtleSoupSettings) : The settings for turtle soups.
previousStructureBreakBarIndex (int) : The bar index of the previous structure break (BOS/CHoCH/CHoCH+).
screener (Screener) : The 'Screener' object to be used for Pine Screening by Tradingview. The function will set 'TurtleSoupUntilBarIndex' if there's a confirmed turtle soup.
Liqudity(liquidity)
Will draw liquidity.
Parameters:
liquidity (Liquidity) : The 'PriceAction.Liquidity' object.
Pivot(structure)
Sets the pivots in the structure.
Parameters:
structure (Structure)
PivotLabels(structure)
Draws labels for the pivots found.
Parameters:
structure (Structure)
EqualHighOrLow(structure)
Draws the boxes for equal highs/lows. Also creates labels for the pivots included.
Parameters:
structure (Structure)
BreakOfStructure(structure)
Will create lines when a break of strycture occures.
Parameters:
structure (Structure)
Returns: The 'Pivot' that caused the break of structure, na otherwise.
ChangeOfCharacter(structure)
Will create lines when a change of character occures. This line will have a label with "CHoCH" or "CHoCH+".
Parameters:
structure (Structure)
Returns: The 'Pivot' that caused the change of character, na otherwise.
VisualizeCurrent(structure)
Will create a box with a background for between the latest high and low pivots. This can be used as the current trading range (if the pivots broke strucure somehow).
Parameters:
structure (Structure)
StructureBreak
Holds drawings for a structure break.
Fields:
Line (series line) : The line object.
Label (series label) : The label object.
Pivot
Holds all the values for a found pivot.
Fields:
Price (series float) : The price of the pivot.
BarIndex (series int) : The bar_index where the pivot occured.
Type (series int) : The type of the pivot (-1 = low, 1 = high).
Time (series int) : The time where the pivot occured.
BreakOfStructureBroken (series bool) : Sets to true if a break of structure has happened.
LiquidityBroken (series bool) : Sets to true if a liquidity of the price level has happened.
ChangeOfCharacterBroken (series bool) : Sets to true if a change of character has happened.
Structure
Holds all the values for the market structure.
Fields:
LeftLength (series int) : Define the left length of the pivots used.
RightLength (series int) : Define the right length of the pivots used.
Type (series Type) : Set the type of the market structure. Two types can be used, 'internal' and 'swing' (0 = internal, 1 = swing).
Trend (series int) : This will be set internally and can be -1 = downtrend, 1 = uptrend.
EqualPivotsFactor (series float) : Set how the limits are for an equal pivot. This is a factor of the Average True Length (ATR) of length 14. If a low pivot is considered to be equal if it doesn't break the low pivot (is at a lower value) and is inside the previous low pivot + this limit.
ExtendEqualPivotsZones (series bool) : Set to true if you want the equal pivots zones to be extended.
ExtendEqualPivotsStyle (series string) : Set the style of equal pivot zones.
ExtendEqualPivotsColor (series color) : Set the color of equal pivot zones.
EqualHighs (array) : Holds the boxes for zones that contains equal highs.
EqualLows (array) : Holds the boxes for zones that contains equal lows.
BreakOfStructures (array) : Holds all the break of structures within the trend (before a change of character).
Pivots (array) : All the pivots in the current trend, added with the latest first, this is cleared when the trend changes.
FontSize (series int) : Holds the size of the font displayed.
AlertChangeOfCharacter (series bool) : Holds true or false if a change of character should be alerted or not.
AlertBreakOfStructure (series bool) : Holds true or false if a break of structure should be alerted or not.
AlerEqualPivots (series bool) : Holds true or false if equal highs/lows should be alerted or not.
Liquidity
Holds all the values for liquidity.
Fields:
LiquidityPivotsHigh (array) : All high pivots for liquidity.
LiquidityPivotsLow (array) : All low pivots for liquidity.
LiquidityConfirmationBars (series int) : The number of bars to confirm that a liquidity is valid.
LiquidityPivotsLookback (series int) : A number of pivots to look back for.
FontSize (series int) : Holds the size of the font displayed.
PriceAction
Holds all the values for the general price action and the market structures.
Fields:
Liquidity (Liquidity)
Swing (Structure) : Placeholder for all objects used for the swing market structure.
Internal (Structure) : Placeholder for all objects used for the internal market structure.
TurtleSoupSettings
Holds sll the values for the settings for turtle soups.
Fields:
PivotLeftLenght (series int) : Define the left length of the pivots used.
PivotRightLenght (series int) : Define the right length of the pivots used.
Lookback (series int) : Set how many pivots back that will be used.
Confirmation (series bool) : Set if you want confirmation to be needed for q turtle soup to be formed (e g. a CHoCH).
Color (series color) : The color of turtle soups.
ScreenerKeep (series int) : Set the number of bars that the plot 'Turtle soup' will have a value after a turtle soup is found.
AlertFrequency (series string) : Set the frequency of alerts, possible values are 'alert.freq_all', 'alert.freq_once_per_bar' or 'alert.freq_once_per_bar_close'.
TurtleSoup
To be used when a turtle soup is found and holds all values needed for it.
Fields:
Line (series line) : The line object between the pivot and the turtle soup.
Box (series box) : The bos for the turtle soup.
Start (series int) : The first bar of the turtle soup.
End (series int) : The last bar of the turtle soup.
Pivot (Pivot) : The pivot which liquidity was taken by the turtle soup.
Screener
Holds all values to be used in the Pine Screener by Tradingview.
Fields:
TurtleSoupUntilBarIndex (series int) : Pine Screener value for turtle soups.
TurtleSoups
TurtleSoups The entire context for all turtle soups.
Fields:
Highs (array) : The high pivots.
Lows (array) : The low pivots.
Bullish (array) : Bullish turtle soups.
Bearish (array) : Bearish turtle soups.
AlertMessages (array) : All messages for the current iteration. Library

Library

EntropyLibLibrary "EntropyLib"
Entropy Library - Composite entropy calculation for oscillators with binary and ternary modes
f_clamp(x, lo, hi)
Clamp value to range
Parameters:
x (float) : Value to clamp
lo (float) : Lower bound
hi (float) : Upper bound
Returns: Clamped value
f_binary_entropy(x, length)
Calculate Shannon binary entropy from a series
Parameters:
x (float) : Input series (oscillator, price changes, etc.)
length (int) : Lookback period for entropy calculation
Returns: Binary entropy value where 0=deterministic, 1=maximum uncertainty
f_ternary_entropy(x, length, flatPct)
Calculate ternary entropy (up/down/flat states)
Parameters:
x (float) : Input series
length (int) : Lookback period for entropy calculation
flatPct (simple float) : Percentile threshold for flat zone (e.g., 55.0 means middle 55% is "flat")
Returns: Ternary entropy value
f_composite_entropy(osc, price, volume, length, osc_weight, price_weight, vol_weight, mode, flatPct)
Calculate composite entropy from oscillator, price, and volume components
Parameters:
osc (float) : Primary oscillator series
price (float) : Price series (typically close)
volume (float) : Volume series
length (int) : Lookback period for entropy calculation
osc_weight (float) : Weight for oscillator entropy component (e.g., 0.4)
price_weight (float) : Weight for price entropy component (e.g., 0.4)
vol_weight (float) : Weight for volume entropy component (e.g., 0.2)
mode (string) : Entropy mode: "binary" or "ternary"
flatPct (simple float) : Percentile for ternary flat zone (only used if mode="ternary", default 55.0)
Returns: Composite entropy
f_composite_entropy_simple(osc, length, mode, flatPct)
Simplified composite entropy using only oscillator
Parameters:
osc (float) : Oscillator series
length (int) : Lookback period
mode (string) : Entropy mode: "binary" or "ternary"
flatPct (simple float) : Percentile for ternary flat zone (default 55.0)
Returns: Composite entropy
f_composite_entropy_standard(osc, price, length, mode, flatPct)
Standard composite entropy with oscillator + price (50/50 split, no volume)
Parameters:
osc (float) : Oscillator series
price (float) : Price series
length (int) : Lookback period
mode (string) : Entropy mode: "binary" or "ternary"
flatPct (simple float) : Percentile for ternary flat zone (default 55.0)
Returns: Composite entropy
f_entropy_weighted_signal(signal, entropy)
Apply entropy weighting to a signal (REOS-style formula)
Parameters:
signal (float) : Input signal/oscillator
entropy (float) : Entropy value
Returns: Entropy-weighted signal: sign(signal) * |signal| * (1 - entropy)
f_detect_true_pivots(osc_series, price_series, pivot_left, pivot_right, entropy_len, max_entropy)
Detects true structural pivots by filtering out high-entropy noise
Parameters:
osc_series (float) : The oscillator series to evaluate
price_series (float) : The underlying price series
pivot_left (int) : Bars to the left of the pivot
pivot_right (int) : Bars to the right of the pivot
entropy_len (int) : Lookback window for entropy calculation (usually 8-14)
max_entropy (float) : The maximum allowed joint entropy for a valid pivot (e.g., 0.4)
Returns: - True pivot flags and pivot values
f_detect_spring(osc_series, price_series, chaos_len, osc_overbought, osc_oversold, min_chaos)
Detects extreme market compression (chaos) at oscillator extremes
Parameters:
osc_series (float) : The oscillator series to evaluate
price_series (float) : The underlying price series
chaos_len (int) : Ultra-short lookback window (e.g., 3, 4, or 5 bars)
osc_overbought (float) : The upper extreme threshold (e.g., 90)
osc_oversold (float) : The lower extreme threshold (e.g., 10)
min_chaos (float) : The minimum joint entropy required to signal compression (e.g., 0.8)
Returns: - Spring flag and chaos intensity
f_optimize_thresholds(osc_series, base_ob, base_os, entropy_len, expansion_factor)
Dynamically adjusts OB/OS levels based on background entropy
Parameters:
osc_series (float) : The oscillator series
base_ob (float) : The baseline overbought level (e.g., 80)
base_os (float) : The baseline oversold level (e.g., 20)
entropy_len (int) : Lookback for the background entropy evaluation (e.g., 30)
expansion_factor (float) : How much the bands can expand/contract (e.g., 10.0 points)
Returns: - Adaptive overbought and oversold thresholds Library

rangeBreakoutLibrary "rangeBreakout"
markRange(trackTimePeriod, drawTimePeriod, highLineColor, lowLineColor, middleLineColor, maxLookbackDays)
Parameters:
trackTimePeriod (simple string) : - Time range for which the high and low values are tracked. This is the range; any breakout above/below this period can indicate a potential long/short entry condition.
drawTimePeriod (simple string) : - Time range for which the range is valid, this is typically from the end of the `trackTimePeriod` to the end of the day (or session) for security.
highLineColor (color)
lowLineColor (color)
middleLineColor (color)
maxLookbackDays (simple int) : - Number of historic days to retain the range value.
Returns: - Values to print the range values, and a boolean indicator that indicates if the current time is within the tracking time period.
The library can then be forward integrated into other indicators, strategies, and other libraries of PulseWire, thus one function can be used globally. Library

KalmanEngineLibKalmanEngineLib
A Pine Script v6 library that provides a reusable engine for multi-state Kalman filtering, symmetric covariance packing, sequential scalar measurement updates, Mahalanobis gating, adaptive noise estimation, online coupling estimation, multi-scale trajectory storage, covariance-derived confidence bands, and k-step covariance propagation.
What it does
Implements a generic N-state Kalman filter where the posterior covariance P is stored as a packed upper triangle (n*(n+1)/2 elements), saving ~47% memory vs a full matrix.new(n,n) at n=14.
Supports block-diagonal transition matrices via separate sub-blocks (3×3 kinematics, 6×6 z-score dynamics, 5×5 Mahalanobis, 3×5 cross-coupling Γ_lag) instead of a single n×n F matrix.
Provides a sequential scalar measurement update in Joseph form for numerical stability; calling it once per observation is equivalent to a batch update but avoids allocating an m×n H matrix.
Core components
UDTs: KalmanState_N, TransitionConfig, TrajectoryStore, ConceptConfig — callers own all persistent state; library functions are stateless transforms.
Triangle primitives: f_tri_idx, f_tri_get, f_tri_set, f_tri_new, f_tri_diag, f_tri_add_outer_product for packed symmetric matrix arithmetic.
Prediction: f_predict_block, f_predict_identity, f_P_predict_diag, f_P_predict_cross.
Update: f_sequential_update returning for external diagnostics.
Gating: f_mahalanobis_3d (analytic 3×3 inverse with Ledoit-Wolf shrinkage and diagonal fallback near singularity), f_nis_test, f_gating_gain_mod.
Adaptive noise: f_adaptive_Q_scalar (windowed MLE), f_adaptive_R_scalar (innovation z-score ratchet).
Coupling: f_gamma_lag_update (scalar 1-D Kalman β-tracker for Γ_lag elements).
Trajectory: f_traj_init, f_traj_update, f_traj_xcorr — circular buffers at Δ={3,5,7} bar skips with Pearson cross-correlation for lag calibration.
Bands and projection: f_covariance_band_width, f_confidence_envelope, f_k_step_cov_propagation, f_z_spread.
Derived outputs: KMEMA (adaptive EMA modulated by innovation shock, TE confidence, velocity), online OLS beta update, execution-score helpers.
Architecture notes
All functions are stateless transforms operating on UDTs passed by the caller; no var declarations inside library functions.
Element budget: ~3,600 for the core engine; ~1,800 for TrajectoryStore at depth=100, n_feat=6. Total ~22K elements under Pine's 100K limit.
Self-healing: f_state_sanitize resets na or overflow entries in x and P diagonals to caller-supplied defaults.
Usage pattern
Declare a var KalmanState_N state = f_init_regression(n, P0, Q0, R0) in the indicator.
Each bar: call f_predict_block → f_P_predict_diag/f_P_predict_cross → one or more f_sequential_update per scalar observation → optional f_mahalanobis_3d/f_adaptive_Q_scalar/f_adaptive_R_scalar → read outputs via f_z_spread, f_confidence_envelope, f_k_step_cov_propagation.
Scope
General-purpose Kalman infrastructure; no market-specific logic, no signals, no thresholds embedded. Intended as a dependency for indicators and strategies that need rigorous multi-state filtering with adaptive noise and regime-aware gating.
License
Mozilla Public License 2.0. Library

lib_pickmytradeLibrary "lib_pickmytrade"
a simple helper to create webhook messages for alert webhooks to pickmytrade
alert_msg_exit(account_id, token)
generates a json formatted EXIT message string for an alert() call, simply closing any open trade
Parameters:
account_id (string) : the pickmytrade account id
token (string) : the pickmytrade token
Returns: a json formatted message string for the alert() call
alert_msg_trail_sl(account_id, token, is_long, trail_sl)
generates a json formatted TRAIL STOP LOSS message string for an alert() call
Parameters:
account_id (string) : the pickmytrade account id
token (string) : the pickmytrade token
is_long (bool) : trade direction
trail_sl (float) : new stop loss level
Returns: a json formatted message string for the alert() call
alert_msg_entry(account_id, token, is_long, tp1, qty1, tp2, qty2, tp3, qty3, sl, tp1_be_offset, limit_price, limit_cancel_time)
generates a json formatted ENTRY message string for an alert() call
Parameters:
account_id (string) : the pickmytrade account id
token (string) : the pickmytrade token
is_long (bool) : trade direction
tp1 (float) : tp1 target
qty1 (int) : tp1 quantity (optional)
tp2 (float) : tp2 target
qty2 (int) : tp2 quantity (optional)
tp3 (float) : tp3 target
qty3 (int) : tp3 quantity (optional)
sl (float) : sl stop
tp1_be_offset (float) : sl to be when hitting tp1, with this offset (optional, must be >= 0)
limit_price (float) : limit entry target (optional)
limit_cancel_time (int) : limit entry cancel time, if not filled (gtc) (optional)
Returns: a json formatted message string for the alert() call Library

Library

OriginLifecycleLibrary "OriginLifecycle"
Strict Highlander v7 origin lifecycle for engulfing indicators.
Exports enums, an OriginCandidate UDT, and four helper functions
used by engulfing_opportunities_v20.6+ to detect, track, promote,
invalidate, and consume origin levels discovered on lower
timeframes inside an engulfment zone.
Published-as-library rationale: the engulfing indicator is already at Pine v6's
top-level-declaration limit (CE10295). Moving these types and functions into a
library frees ~7 declarations in the main script without changing semantics.
Reference: highlander_v7.pine:212-293 for the state-transition rules this
implementation mirrors.
tickStateMachine(c, bO, bH, bL, bC, bTime)
Pure state-transition function. One closed LTF bar in,
updated candidate out. Mirrors highlander_v7.pine:212-293.
Parameters:
c (OriginCandidate) : The current candidate state.
bO (float) : Bar open.
bH (float) : Bar high.
bL (float) : Bar low.
bC (float) : Bar close.
bTime (int) : Bar start time in ms.
Returns: Updated OriginCandidate with `lastProcessedTime := bTime`.
Caller is responsible for:
- Only passing CLOSED LTF bars.
- Skipping bars whose time <= c.lastProcessedTime.
- On BROKEN_BSUT, looking for a retest in subsequent bars to delete.
scanForBreakCandidates(isBullish, zoneLow, zoneHigh, prevO, prevH, prevL, prevC, prevT, currO, currH, currL, currC, currT, ltfValid, ltfMin, tfLabel, outCandidates)
Find new BREAK pairs in the engulfment zone and push
them to `outCandidates` if not already tracked. De-dup
key is (price, createdTime, tfLabel).
Parameters:
isBullish (bool) : true -> look for SUPPORT (green-green) pairs;
false -> look for RESISTANCE (red-red) pairs.
zoneLow (float) : Lower bound of the engulfment zone (inclusive).
zoneHigh (float) : Upper bound of the engulfment zone (inclusive).
prevO (array)
prevH (array)
prevL (array)
prevC (array)
prevT (array)
currO (array)
currH (array)
currL (array)
currC (array)
currT (array)
ltfValid (bool) : Pre-computed validity flag for this LTF.
ltfMin (int) : LTF length in minutes (baked into each new candidate).
tfLabel (string) : Display string, e.g. "1H".
outCandidates (array) : The per-pattern candidate array to push into.
Returns: Nothing (mutates outCandidates).
processNewLTFBars(candidates, ltfMin, prevO, prevH, prevL, prevC, prevT, currO, currH, currL, currC, currT, ltfValid)
Drive the state machine across unprocessed LTF bars for every
candidate whose `ltfMinutes == ltfMin`. Removes candidates
that reach BROKEN_BSUT AND see a retest within the buffer.
Parameters:
candidates (array) : The per-pattern candidate array to update.
ltfMin (int) : The LTF length this buffer represents; candidates with a
different ltfMinutes are skipped.
prevO (array)
prevH (array)
prevL (array)
prevC (array)
prevT (array)
currO (array)
currH (array)
currL (array)
currC (array)
currT (array)
ltfValid (bool) : Validity flag.
Returns: Nothing (mutates candidates).
applyConsumedOnTouch(candidates, greedyEntries, greedyConsumedFlags, isBullish, curLow, curHigh)
Per-tick sweep. Marks CONFIRMED origins and
untouched greedy entries as consumed once price
wicks into them. Caller passes `curLow`/`curHigh`
because library functions cannot reference the
`low`/`high` chart globals directly.
Parameters:
candidates (array) : Per-pattern origin-candidate array.
greedyEntries (array) : Per-pattern greedy-entry price array.
greedyConsumedFlags (array) : Parallel bool array — resized lazily to match
greedyEntries size.
isBullish (bool) : Drives the touch check for greedy entries
(origins use their own per-candidate dir).
curLow (float) : Current bar low (pass `low` from caller).
curHigh (float) : Current bar high (pass `high` from caller).
Returns: Nothing (mutates both arrays).
OriginCandidate
A single tracked origin candidate.
Fields:
tfLabel (series string) : Display string ("1H", "5m" etc.).
ltfMinutes (series int) : Lower-timeframe length in minutes; used for the
price (series float) : The origin level price.
dir (series OriginDir) : UP (support) or DOWN (resistance).
state (series OriginState) : Current lifecycle state.
firstTouchTime (series int) : ms timestamp of first touch (0 if `touchSeen == false`).
touchSeen (series bool) : True once this candidate has been touched at least once.
createdTime (series int) : ms timestamp of the d1 bar that formed the BREAK pair.
lastProcessedTime (series int) : ms timestamp of the last LTF bar fed through the
consecutiveDirCount (series int) : Counter for 2-bar CONFIRMED confirmation, 0-2. Library

HeikinAshiTrendUtilities
Library HeikinAshiTrendUtilities
This library contains reusable Heikin Ashi helpers for building Pine scripts that use Heikin Ashi as more than a candle style.
It centralizes the Heikin Ashi foundation, HA-based oscillator engines, streak and confirmed-trend logic, Pressure Meter helpers, max-move scanning, Fib Backbone structure helpers, and Primary Trend helpers so those parts do not need to be rewritten across multiple scripts.
Everything on the example chart is materially driven by the library, whether through the Heikin Ashi calculations themselves, the HA-based oscillator and pressure engine, the predictive close logic, the smoothed HA overlay, the Fib Backbone context window, or the structure geometry used to project key analytical visuals.
How to use
Import the library near the top of your script in global scope, alongside any other imports, before you start calling its helpers.
Typical placement:
• //@version=6
• indicator(...) or strategy(...)
• import MYNAMEISBRANDON/HeikinAshiTrendUtilities/1 as haUtils
For more information on libraries and incorporating them into your scripts, see the Libraries section of the Pine Script User Manual: www.pulsewire.com
➖Heikin Ashi Core Helpers➖
These helpers handle the basic building blocks of Heikin Ashi. They let a script create standard HA candles, estimate the price needed to flip the current HA candle, and generate a smoothed HA version for a cleaner trend view. In other words, this region provides the core HA math used to build the rest of the library’s trend, engine, and structure tools.
heikinAshi(openValue, closeValue, highValue, lowValue, haOpenPrev, haClosePrev)
Builds one Heikin Ashi candle from real OHLC and prior HA state
Parameters:
openValue (float): Real open
closeValue (float): Real close
highValue (float): Real high
lowValue (float): Real low
haOpenPrev (float): Prior Heikin Ashi open
haClosePrev (float): Prior Heikin Ashi close
Returns: HA open, HA close, HA high, HA low, is HA up, is HA down
haPredictClose(haOpen, openValue, highValue, lowValue)
Estimates the real close price needed to flip the current HA candle
Parameters:
haOpen (float): Current Heikin Ashi open
openValue (float): Real open
highValue (float): Real high
lowValue (float): Real low
Returns: Predicted real close needed to flip the HA candle
smoothedHeikinAshi(openValue, highValue, lowValue, closeValue, len1, len2)
Builds double-smoothed Heikin Ashi values from real OHLC inputs
Parameters:
openValue (float): Real open
highValue (float): Real high
lowValue (float): Real low
closeValue (float): Real close
len1 (simple int): First EMA smoothing length applied to real OHLC
len2 (simple int): Second EMA smoothing length applied to HA OHLC
Returns: Smoothed HA open, smoothed HA high, smoothed HA low, smoothed HA close, is smoothed HA up, is smoothed HA down
➖HA Oscillator Foundation Helpers➖
These helpers turn raw Heikin Ashi candle movement into a usable oscillator foundation. They measure the HA candle’s bullish or bearish range, normalize that movement so it can be compared more consistently across bars, and build upper/lower guide levels that help a script judge when that oscillator is stretching into stronger trend pressure. In other words, this region creates the base signal that the HA Blend, HA Range Base, color engine, and Pressure Meter can build from.
haSignedRangePct(haHigh, haLow, haClose, haIsBull, haIsBear)
Returns the signed HA range-percent foundation used by the oscillator engine
Parameters:
haHigh (float): Heikin Ashi high
haLow (float): Heikin Ashi low
haClose (float): Heikin Ashi close
haIsBull (bool): True when the current HA candle is bullish
haIsBear (bool): True when the current HA candle is bearish
Returns: Signed HA range-percent foundation
haPreparedOscSource(signedSrc, normLen, useClamp, clampRange)
Returns the normalized / optionally clamped HA oscillator source
Parameters:
signedSrc (float): Signed HA foundation
normLen (simple int): Normalization lookback length
useClamp (simple bool): Whether the normalized result should be clamped
clampRange (float): Absolute clamp boundary when useClamp is true
Returns: Prepared HA oscillator source
haOscGuides(src, lookback, guideFactor)
Returns upper and lower threshold guides from an oscillator series
Parameters:
src (float): Oscillator series
lookback (simple int): Guide lookback window
guideFactor (float): Scaling factor applied to the highest/lowest values
Returns: Upper guide, lower guide
➖HA Blend Engine Helpers➖
These helpers take the prepared HA oscillator source and turn it into a smoother trend engine by blending multiple EMA pairs together. They let the script choose a faster, more balanced, or slower blend profile, then optionally smooth that final output one more time. In other words, this region builds the more layered, trend-following version of the HA oscillator engine.
haBlendPairStackText(pairSet)
Returns the active EMA pair-stack text for the selected HA Blend pair set
Parameters:
pairSet (simple string): Pair-set label. Expected values: "Fast", "Balanced", or "Slow"
Returns: Pair-stack text
haBlendEngineCore(src, pairSet)
Returns the raw HA Blend engine core before final smoothing
Parameters:
src (float): Prepared HA signed source used by the blend engine
pairSet (simple string): Pair-set label. Expected values: "Fast", "Balanced", or "Slow"
Returns: Raw HA Blend engine core
haBlendEngine(src, pairSet, useFinalSmooth, finalSmoothLen, finalSmoothType)
Returns the final HA Blend engine with optional final smoothing
Parameters:
src (float): Prepared HA signed source used by the blend engine
pairSet (simple string): Pair-set label. Expected values: "Fast", "Balanced", or "Slow"
useFinalSmooth (simple bool): Whether final smoothing should be applied
finalSmoothLen (simple int): Final smoothing length
finalSmoothType (simple string): Final smoothing type. Expected values: "EMA" or "SMA"
Returns: Final HA Blend engine
➖HA Range Base Engine Helpers➖
These helpers take the prepared HA oscillator source and smooth it in a more direct way than the Blend engine. Instead of combining multiple EMA pairs, they use one selected smoothing length and MA type to create a cleaner base trend signal, with the option to smooth that result one more time. In other words, this region builds the simpler, more straightforward version of the HA oscillator engine.
haRangeEngineCore(src, rangeLen, rangeMaType)
Returns the raw HA Range Base engine core before final smoothing
Parameters:
src (float): Prepared HA signed source used by the Range Base engine
rangeLen (simple int): Core smoothing length used by the Range Base engine
rangeMaType (simple string): Core smoothing type. Expected values: "EMA" or "SMA"
Returns: Raw HA Range Base engine core
haRangeEngine(src, rangeLen, rangeMaType, useFinalSmooth, finalSmoothLen, finalSmoothType)
Returns the final HA Range Base engine with optional final smoothing
Parameters:
src (float): Prepared HA signed source used by the Range Base engine
rangeLen (simple int): Core smoothing length used by the Range Base engine
rangeMaType (simple string): Core smoothing type. Expected values: "EMA" or "SMA"
useFinalSmooth (simple bool): Whether final smoothing should be applied
finalSmoothLen (simple int): Final smoothing length
finalSmoothType (simple string): Final smoothing type. Expected values: "EMA" or "SMA"
Returns: Final HA Range Base engine
➖HA Threshold Color Helpers➖
This helper takes centered oscillator behavior and turns it into a usable visual color state. It helps a script decide when the HA-based oscillator is rising or falling above or below its guide levels so candles, rows, or other visuals can reflect stronger or weaker trend pressure.
haThresholdStateColor(src, upperGuide, lowerGuide, aboveUpperRiseColor, aboveZeroRiseColor, aboveZeroFallColor, belowZeroFallColor, belowLowerFallColor, belowZeroRiseColor)
Resolves a visual color from centered-oscillator threshold state
Parameters:
src (float): Source series
upperGuide (float): Upper threshold guide
lowerGuide (float): Lower threshold guide
aboveUpperRiseColor (color): Color used when src is above the upper guide and rising
aboveZeroRiseColor (color): Color used when src is above zero and rising
aboveZeroFallColor (color): Color used when src is above zero and falling
belowZeroFallColor (color): Color used when src is below zero and falling
belowLowerFallColor (color): Color used when src is below the lower guide and falling
belowZeroRiseColor (color): Color used when src is below zero and rising
Returns: Resolved visual color
➖HA Structure Scan Helpers➖
This helper scans a chosen lookback window and finds the strongest completed move inside it. It compares bullish and bearish candidates in the same scan, then returns whichever move was stronger along with the start and end anchors. In other words, this region gives a script a reusable way to locate the dominant move that can later be used for Fib Backbone structure, Primary Max Move logic, or other trend-structure work. :contentReference {index=0} :contentReference {index=1}
haScanMaxMove(lookback, includeCurrentBar, highSeries, lowSeries)
Scans a lookback window for the strongest upward or downward percentage move
Parameters:
lookback (simple int): Number of bars to scan
includeCurrentBar (simple bool): Whether bar 0 should be included in the scan
highSeries (float): High series used for upward and downward move detection
lowSeries (float): Low series used for upward and downward move detection
Returns: Winning direction, winning percent move, winning start bars-ago, winning end bars-ago, winning span bars
➖HA Streak Helpers➖
These helpers let a script keep track of active Heikin Ashi streaks. They determine whether the current HA sequence is bullish or bearish, count how long that streak has been running, assign a tier color based on streak length, and measure how far price has moved from the streak’s starting point. In other words, this region helps turn raw HA trend runs into usable streak state, color, and percent-move data for candles, rows, labels, and trend readouts. :contentReference {index=0}
haStreakState(haOpen, haClose, bullCountPrev, bearCountPrev)
Resolves raw HA bull/bear state, streak counts, and streak start offset
Parameters:
haOpen (float): Current Heikin Ashi open
haClose (float): Current Heikin Ashi close
bullCountPrev (int): Prior bullish streak count
bearCountPrev (int): Prior bearish streak count
Returns: is HA bullish, is HA bearish, bullish streak count, bearish streak count, current streak length, streak start bars-ago
haStreakTierColor(isHaBull, isHaBear, bullCount, bearCount, streakTierBars, bullTier1, bullTier2, bullTier3, bullTier4, bearTier1, bearTier2, bearTier3, bearTier4, neutralColor)
Returns the active streak-tier color from bull/bear streak counts
Parameters:
isHaBull (bool): True when the current HA streak is bullish
isHaBear (bool): True when the current HA streak is bearish
bullCount (int): Current bullish streak count
bearCount (int): Current bearish streak count
streakTierBars (simple int): Number of bars required before advancing to the next tier
bullTier1 (color): Bullish tier 1 color
bullTier2 (color): Bullish tier 2 color
bullTier3 (color): Bullish tier 3 color
bullTier4 (color): Bullish tier 4 color
bearTier1 (color): Bearish tier 1 color
bearTier2 (color): Bearish tier 2 color
bearTier3 (color): Bearish tier 3 color
bearTier4 (color): Bearish tier 4 color
neutralColor (color): Fallback color when no active streak is available
Returns: Active streak-tier color
haStreakPct(isHaBull, isHaBear, streakBars, highSeries, lowSeries)
Returns the wick-based percent move from the streak start to the current bar
Parameters:
isHaBull (bool): True when the current HA streak is bullish
isHaBear (bool): True when the current HA streak is bearish
streakBars (int): Current active streak length
highSeries (float): High series used for streak measurement
lowSeries (float): Low series used for streak measurement
Returns: Wick-based streak percent move
➖Confirmed HA Trend Helpers➖
These helpers let a script work with a slower, confirmation-based HA trend instead of flipping immediately on the first opposite HA candle. They track the currently confirmed direction, count how many opposite candles are building toward the next possible flip, project the confirmed trend using regular-price body or wick anchors, and measure how far that confirmed trend has moved from its confirmed start. In other words, this region helps scripts build a more stable HA trend model that filters out some of the noise of raw HA flips. :contentReference {index=0} :contentReference {index=1}
haConfirmedTrendState(enabled, rawDir, confirmBars, dirPrev, oppCountPrev, startBarPrev, firstOppBarPrev)
Resolves confirmed trend direction, build count, and confirmed start bar
Parameters:
enabled (simple bool): Whether the confirmed-trend engine is active
rawDir (int): Current raw HA direction: +1 bull, -1 bear, 0 neutral
confirmBars (simple int): Consecutive opposite raw HA bars required to confirm a flip
dirPrev (int): Prior confirmed direction
oppCountPrev (int): Prior opposite-side build count
startBarPrev (int): Prior confirmed trend start bar index
firstOppBarPrev (int): Prior first opposite raw HA bar index
Returns: Confirmed direction, opposite-side build count, confirmed start bar index, first opposite raw HA bar index, confirmed leg bars, confirmed start bars-ago
haConfirmedTrendProjection(confirmedDir, startOffset, openValue, highValue, lowValue, closeValue, anchorMode, pathMode, forwardBars)
Returns confirmed trend projection geometry from body/wick anchor rules
Parameters:
confirmedDir (int): Confirmed direction: +1 bull, -1 bear, 0 neutral
startOffset (int): Confirmed start bars-ago offset
openValue (float): Regular-price open
highValue (float): Regular-price high
lowValue (float): Regular-price low
closeValue (float): Regular-price close
anchorMode (simple string): Projection anchor mode: "Body" or "Wick"
pathMode (simple string): Projection path mode: "Same Side" or "Opposite Side"
forwardBars (simple int): Number of bars forward for projection
Returns: Has valid projection, start Y, current Y, future Y, slope
haConfirmedTrendPct(confirmedDir, startOffset, highSeries, lowSeries)
Returns confirmed streak percent movement from the confirmed start bar
Parameters:
confirmedDir (int): Confirmed direction: +1 bull, -1 bear, 0 neutral
startOffset (int): Confirmed start bars-ago offset
highSeries (float): HA high series used for confirmed move measurement
lowSeries (float): HA low series used for confirmed move measurement
Returns: Confirmed streak percent move
➖HA Pressure Meter Helpers➖
These helpers take the HA-based oscillator engine and convert it into an easier 0–100 pressure reading. They help a script decide when bullish or bearish pressure is becoming active, assign matching tier colors for rows or other visuals, and return the color state for a pressure strip or similar chart-edge signal. In other words, this region turns the HA oscillator into a simpler pressure model that is easier to read at a glance.
haPressureMeter(rawOsc, bullAnchor, bearAnchor)
Normalizes a raw oscillator value into a 0-100 Pressure Meter
Parameters:
rawOsc (float): Raw oscillator value
bullAnchor (float): Raw oscillator value that should map to 100
bearAnchor (float): Raw oscillator value that should map to 0
Returns: Pressure Meter value in the 0-100 range
haPressureState(pressureMeter, bullThreshold, bearThreshold)
Resolves bullish, bearish, and neutral threshold state from the Pressure Meter
Parameters:
pressureMeter (float): Normalized Pressure Meter value
bullThreshold (float): Meter level where bullish pressure becomes active
bearThreshold (float): Meter level where bearish pressure becomes active
Returns: Bull-active, bear-active, neutral-between
haPressureTierColors(pressureMeter, bullTier1, bullTier2, bullTier3, bullTier4, bearTier1, bearTier2, bearTier3, bearTier4, fallbackBg)
Returns tier-based pressure-row background and readable text color
Parameters:
pressureMeter (float): Normalized Pressure Meter value
bullTier1 (color): Bull tier 1 color
bullTier2 (color): Bull tier 2 color
bullTier3 (color): Bull tier 3 color
bullTier4 (color): Bull tier 4 color
bearTier1 (color): Bear tier 1 color
bearTier2 (color): Bear tier 2 color
bearTier3 (color): Bear tier 3 color
bearTier4 (color): Bear tier 4 color
fallbackBg (color): Fallback background when the meter is na
Returns: Row background color, row text color
haPressureStripColor(pressureMeter, bullThreshold, bearThreshold, bullTier1, bullTier2, bullTier3, bullTier4, bearTier1, bearTier2, bearTier3, bearTier4, neutralColor, activeTransp, neutralTransp)
Returns active or neutral strip color from the Pressure Meter state
Parameters:
pressureMeter (float): Normalized Pressure Meter value
bullThreshold (float): Meter level where bullish pressure becomes active
bearThreshold (float): Meter level where bearish pressure becomes active
bullTier1 (color): Bull tier 1 color
bullTier2 (color): Bull tier 2 color
bullTier3 (color): Bull tier 3 color
bullTier4 (color): Bull tier 4 color
bearTier1 (color): Bear tier 1 color
bearTier2 (color): Bear tier 2 color
bearTier3 (color): Bear tier 3 color
bearTier4 (color): Bear tier 4 color
neutralColor (color): Neutral-zone base color
activeTransp (int): Transparency used when bull or bear pressure is active
neutralTransp (int): Transparency used inside the neutral zone
Returns: Strip color
➖Fib Backbone Structure Helpers➖
These helpers take a winning max-move scan and turn it into the structure a script can use for Fib Backbone analysis. They define the backbone’s start and end anchors, determine the related support/resistance anchor geometry, calculate Fib level prices between those anchors, and measure how far current price is from those levels. In other words, this region helps convert a dominant move into a reusable backbone structure that can support diagonals, S/R anchors, boxes, and Fib-based readouts.
haFibBackboneStructure(dir, startBA, endBA, openValue, highValue, lowValue, closeValue)
Returns backbone coordinates, S/R anchors, and anchor-box geometry
Parameters:
dir (int): Winning move direction: +1 bull, -1 bear, 0 none
startBA (int): Winning move start bars-ago
endBA (int): Winning move end bars-ago
openValue (float): Regular-price open
highValue (float): Regular-price high
lowValue (float): Regular-price low
closeValue (float): Regular-price close
Returns: ok, xStart, xEnd, yStart, yEnd, startIsRes, endIsRes, anchorTopS, anchorBotS, anchorTopE, anchorBotE, isTopS, isTopE
haFibLevelPrice(yStart, yEnd, fibLevel)
Returns the price of one fib level between the backbone anchors
Parameters:
yStart (float): Backbone start anchor price
yEnd (float): Backbone end anchor price
fibLevel (float): Fib level such as 0.236, 0.382, 0.50, 0.618, 0.786
Returns: Fib level price
haFibPctFromClose(closeValue, fibPrice)
Returns percent distance from close to a fib level
Parameters:
closeValue (float): Current close
fibPrice (float): Fib level price
Returns: Percent from close to fib level
➖Fib Backbone Context Window Helpers➖
These helpers build the larger context window around the active Fib Backbone lookback. They let a script define the left/right range of that window, calculate its current high and low bounds, and find the midpoint of the same structure. In other words, this region helps frame the broader area that the active backbone move is being selected from, so the move can be viewed in context rather than in isolation.
haFibContextWindow(lookback, includeCurrentBar, sourceMode, highValue, lowValue, closeValue)
Returns the active Fib Backbone context window geometry
Parameters:
lookback (simple int): Context-window lookback length
includeCurrentBar (simple bool): Whether the current bar participates in the active window
sourceMode (simple string): Source selection. Expected values: "Wicks" or "Closes"
highValue (float): Regular-price high
lowValue (float): Regular-price low
closeValue (float): Regular-price close
Returns: ok, leftX, rightX, windowBars, windowHigh, windowLow, leftHigh, leftLow
haFibContextMidpoint(ok, windowHigh, windowLow)
Returns the midpoint of the active Fib Backbone context window
Parameters:
ok (bool): Whether the context window is valid
windowHigh (float): Active context-window high
windowLow (float): Active context-window low
Returns: Context-window midpoint
➖Primary Trend Window Helpers➖
These helpers scan a lookback window to find the strongest completed HA streak and turn that winner into usable trend information. They identify the winning streak, assign it the correct tier color, and return the anchor coordinates needed to project that streak as a chart-side diagonal. In other words, this region helps a script reduce a larger HA trend window down to its most important completed streak structure.
haPrimaryTrendWinner(lookback, haBull, haBear, bullCount, bearCount, haHigh, haLow)
Returns the strongest completed HA streak inside the lookback window
Parameters:
lookback (simple int): Number of bars to scan
haBull (bool): Bullish HA state series
haBear (bool): Bearish HA state series
bullCount (int): Bullish HA streak-count series
bearCount (int): Bearish HA streak-count series
haHigh (float): HA high series used for wick-based streak measurement
haLow (float): HA low series used for wick-based streak measurement
Returns: Winning streak length, winning direction, winning percent move, winning start bars-ago, winning end bars-ago, winning validity state
haPrimaryTrendTierColor(dir, streakLen, streakTierBars, bullTier1, bullTier2, bullTier3, bullTier4, bearTier1, bearTier2, bearTier3, bearTier4, fallbackBg)
Returns the winning Primary Trend tier color
Parameters:
dir (int): Winning streak direction: +1 bull, -1 bear, 0 none
streakLen (int): Winning streak length
streakTierBars (simple int): Number of bars required before advancing to the next tier
bullTier1 (color): Bullish tier 1 color
bullTier2 (color): Bullish tier 2 color
bullTier3 (color): Bullish tier 3 color
bullTier4 (color): Bullish tier 4 color
bearTier1 (color): Bearish tier 1 color
bearTier2 (color): Bearish tier 2 color
bearTier3 (color): Bearish tier 3 color
bearTier4 (color): Bearish tier 4 color
fallbackBg (color): Fallback background when no valid winner exists
Returns: Winning tier color
haPrimaryTrendCoords(dir, startBA, endBA, highSeries, lowSeries)
Returns diagonal coordinates from the winning streak anchors
Parameters:
dir (int): Winning streak direction: +1 bull, -1 bear, 0 none
startBA (int): Winning start bars-ago
endBA (int): Winning end bars-ago
highSeries (float): High series used for line anchors
lowSeries (float): Low series used for line anchors
Returns: ok, x1, x2, y1, y2
NOTES
This is a Heikin-Ashi-specific utility library. It is meant to provide the reusable HA math, state, and structure layer. Final rendering choices such as plot style, line objects, boxes, labels, tables, and overall UI layout are expected to remain script-level decisions.
Thanks to SimpleCryptoLife for the open-source HA core functions heikinAshi() & haPredictClose() and thus the inspiration that they've given me to create HA-based indicators for the HA trader enthusiast.
Library

Vantage_PairedSizingVantage_PairedSizing — Position sizing for strategies that pair a primary trade with a recovery trade under a daily loss budget.
─────────────────────────────────────────
WHAT IT DOES
Answers the question "how many contracts can I take on the primary trade so that, if it stops out, a correctly-sized recovery trade still fits within my daily loss limit?" The library scans candidate quantities top-down and returns the largest one whose worst case (primary stop + recovery stop) stays inside the budget, subject to one of four risk-reward modes.
─────────────────────────────────────────
WHAT IT PROVIDES
A single entry-point auto-sizer that takes the primary leg's entry/stop/target, the recovery leg's entry/stop/target, a daily loss budget, and a sizing mode — and returns a result record with primary quantity, recovery quantity, per-leg dollar risk, worst-case dollar exposure, and net-if-recovery-wins. The scan falls through a mode ladder (MatchPrimaryProfit → MatchPct → NetGreen) and a no-recovery fallback before giving up, so callers get a usable answer in marginal cases instead of a flat rejection.
Four named sizing modes covering the common risk-reward shapes: largest size under a drawdown cap, largest size where the recovery win leaves the session net-green, largest size where the recovery win matches the primary's target profit, and a percentage variant of the match mode.
Two utility functions for the dollar math — risk and profit for a given quantity between two prices — so strategies don't have to redo the tick-size / point-value arithmetic themselves.
─────────────────────────────────────────
HOW TO USE
A complete example call is in the comment block at the top of the source file — import the library, copy the pattern, plug in your primary and recovery price levels. Hover any exported type, enum, or function in the Pine Editor for per-parameter documentation. Library

Library

Library

KernelLens🟦 KernelLens is a professional kernel regression library for Pine Script v6, providing eight mathematically rigorous Nadaraya–Watson estimators, a three-mode filter layer, a unified string dispatcher, and a suite of trading utilities — all built from the ground up on correct non-parametric statistics. Unlike existing Pine smoothing libraries — which inherit a decade-old loop-bound bug that silently reduces every kernel window to a handful of bars, regardless of the bandwidth parameter — KernelLens is built with auditable math, NA-safe iteration, input validation at every entry point, and academic references cited inline next to the formulas they describe.
The library integrates eight independent kernel families — Rational Quadratic, Gaussian, Periodic, Locally Periodic, Epanechnikov, Tricube, Triangular, and Cosine — behind a consistent API, with every raw estimator wrapped in a filter layer (None / Smooth / Zero Lag), a unified dispatcher for dropdown-driven kernel selection, and five utility exports covering slope detection, trend state, crossover signaling, residual confidence bands, and Silverman's rule-of-thumb bandwidth recommendation. Every public function validates its inputs, raises descriptive runtime errors on misuse, and returns `na` only when there is genuinely no data — never as a silent fallback.
🟦 MATHEMATICAL FOUNDATION
**The Nadaraya–Watson Estimator**
Given a source series `y_t` and a symmetric kernel `K` with scale parameter `ℓ` (the "bandwidth"), the Nadaraya–Watson estimator of the regression function `m(x) = E ` evaluated at the current bar is:
```
Σᵢ K(dᵢ / ℓ) · y_{t−i}
ŷ(t) = ───────────────────────
Σᵢ K(dᵢ / ℓ)
```
where `dᵢ` is the bar-distance from the kernel center and the sum runs over a finite window determined by the effective support of `K`.
The estimator is a locally weighted average: bars close to the kernel center contribute heavily, distant bars contribute proportionally less, and bars outside the support contribute nothing. It is asymptotically unbiased up to `O(ℓ²)` for twice-differentiable `m`, with variance of order `(n·ℓ)⁻¹` — the classical bias–variance trade-off that defines all non-parametric smoothers.
**Why Kernel Regression Beats Rolling Means**
A simple moving average gives every bar in the window the same weight. Kernel regression gives each bar a weight that decays smoothly with distance, producing:
- **Smoother output** — no step artifacts when bars enter / leave the window
- **Better bias control** — the peak of the kernel sits exactly on the point being estimated
- **Kernel-specific behavior** — compact-support kernels eliminate tail contamination entirely; Rational Quadratic's `α` parameter exposes multi-scale mixing; Periodic kernels resonate with known cycle lengths
The math has been the academic standard for non-parametric regression since Nadaraya (1964) and Watson (1964). KernelLens brings it to Pine Script v6 in its correct, bug-free form.
🟦 THE EIGHT KERNELS
All eight kernels implement the Nadaraya–Watson weighting scheme. They differ in support (compact versus infinite), smoothness (how many times differentiable), and how weight decays with distance.
| # | Kernel | Formula | Support | Smoothness | Character |
|---|---|---|---|---|---|
| 1 | **Rational Quadratic** | `(1 + d² / (2·α·ℓ²))^(−α)` | ℝ | C∞ | Multi-scale mixer — `α` controls stretch versus wiggle |
| 2 | **Gaussian (RBF)** | `exp(−d² / (2·ℓ²))` | ℝ | C∞ | The canonical smoother — smoothest possible with L² optimality |
| 3 | **Periodic** | `exp(−2·sin²(π·d/p) / ℓ²)` | ℝ | C∞ | Resonates with repetition distance `p` — ideal for cycles |
| 4 | **Locally Periodic** | Periodic · Gaussian | ℝ | C∞ | Seasonal patterns that slowly drift with trend |
| 5 | **Epanechnikov** | `(3/4)(1 − u²) · 𝟙{|u|≤1}` | | C⁰ | Asymptotically MSE-optimal (Watson 1964) — no tail contamination |
| 6 | **Tricube** | `(70/81)(1 − \|u\|³)³ · 𝟙{|u|≤1}` | | C² | The LOWESS standard — near-Gaussian with compact support |
| 7 | **Triangular** | `(1 − \|u\|) · 𝟙{|u|≤1}` | | C⁰ | Simplest non-uniform kernel — fastest to compute |
| 8 | **Cosine** | `(π/4)·cos(π·u/2) · 𝟙{|u|≤1}` | | C¹ | Raised-cosine taper — smoother boundary than Epanechnikov |
where `u = d/ℓ` and `𝟙` is the indicator function.
**Infinite-Support vs Compact-Support — Why Both Matter**
| | Infinite Support (RQ, Gauss, Periodic, LocPeriodic) | Compact Support (Epa, Tricube, Triangular, Cosine) |
|---|---|---|
| **Tail weight** | Never exactly zero | Exactly zero beyond ±ℓ |
| **Loop depth** | `3·ℓ` (3-σ cutoff, ≈99.7% mass) | Exactly `ℓ` |
| **Bar contamination** | Distant bars still pull the estimate a tiny amount | Distant bars cannot affect the estimate at all |
| **Best for** | Smooth trends, Gaussian-process intuition | Robust regression, outlier resistance |
KernelLens picks the correct loop depth automatically based on kernel family: `_depthInfinite` for Gaussian-family kernels, `_depthCompact` for bounded kernels, `_depthPeriodic` for Periodic (which must span enough cycles to reach stable weights).
**Why Eight, Not Four**
Most Pine kernel libraries ship only the four kernels from MacKay's Gaussian process tutorial. KernelLens adds the four compact-support classical kernels because:
- **Epanechnikov** minimises asymptotic mean squared error among all non-negative kernels of bounded support (Watson 1964) — it is the MSE-optimal baseline against which all other kernels are measured
- **Tricube** is the kernel used by LOWESS (Cleveland 1979), the de-facto standard for robust locally weighted scatterplot smoothing
- **Triangular** is the cheapest non-uniform compact kernel — useful when loop-budget matters on intraday charts with huge dataset size
- **Cosine** is C¹-continuous at the support boundary, unlike Epanechnikov's C⁰ discontinuity, producing visibly smoother transitions at kernel edges
Adding them makes the library an academically complete toolkit, not just a Pine port of one tutorial.
🟦 FILTER LAYER — NONE / SMOOTH / ZERO LAG
Every kernel export accepts a `_filter` parameter with three valid values. The filter layer is implemented identically across all eight kernels, so switching kernel families does not change filter behavior.
**"No Filter" — Single-Pass Raw Estimate**
```
ŷ = K(y)
```
One Nadaraya–Watson pass over the source. Cheapest mode, most reactive, fully represents the underlying kernel. Use this when you want the kernel's raw behavior with no additional smoothing or lag correction.
**"Smooth" — Double-Pass Estimate**
```
ŷ = K(K(y))
```
The kernel is applied once to the source, then applied again to its own output using the same bandwidth and the same parameters. The result is a more strongly smoothed curve at the cost of one extra loop pass per bar.
This is mathematically equivalent to convolving the kernel with itself — the effective kernel is wider and flatter, pulling longer-range context into each estimate without requiring the user to double the bandwidth.
**"Zero Lag" — Ehlers De-Lagged Estimate**
```
ŷ = 2·K(y) − K(K(y))
```
The ZLEMA identity from Ehlers (*Rocket Science for Traders*, 2000): subtract the smoothing lag from the raw estimate, effectively shifting the output back in time to match the source more closely.
The intuition: `K(y)` lags `y` by some amount; `K(K(y))` lags `K(y)` by the same amount; so `K(y) − K(K(y))` is an estimate of the lag itself, and adding it back to `K(y)` cancels out. The result tracks the source more tightly than either pass alone, at the cost of slightly noisier turning points.
**Lazy Evaluation — No Wasted Cycles**
In `"No Filter"` mode, the second pass is skipped entirely — it never runs. The filter branch uses an `if` block (not a ternary), so Pine's short-circuit semantics prevent the unused computation. A single kernel call costs one pass; `"Smooth"` or `"Zero Lag"` costs two. You only pay for what you use.
🟦 KERNEL CENTER OFFSET — THE `_phase` PARAMETER
Every KernelLens kernel takes a `_phase` parameter that shifts the kernel center into the past by `_phase` bars. It is the library's non-repainting knob.
**_phase = 0 — Live Estimate**
The kernel is centered on the current bar. The most recent price has maximum weight, and the estimate is as fresh as possible. Suitable for live signal generation, but the most recent bar can re-evaluate as it develops within its interval — standard Pine real-time behavior.
**_phase > 0 — Non-Repainting Historical Estimate**
The kernel center is moved `_phase` bars into the past. The estimate becomes the smoothed value *at that historical bar*, not the current bar. Once the bar at `bar_index − _phase` is fully confirmed (`barstate.isconfirmed`), its estimate cannot change again.
This is the standard trick for publishing kernel indicators that do not repaint: you get a stable, historically accurate curve at the cost of shifting the entire output `_phase` bars to the right on the chart. A `_phase = 25` call gives a curve that lags live price by 25 bars but is guaranteed stable for every past bar.
**Why It Belongs in the Library, Not the Caller**
Pushing `_phase` into the kernel's own loop is not the same as evaluating the kernel at a shifted source (`K(src )`). Shifting the source just uses a stale input with a current-bar-centered kernel, which still produces a fresh estimate of a stale series. KernelLens's `_phase` genuinely moves the kernel center, producing a historical-bar estimate that computes over the correct surrounding window.
🟦 NON-REPAINTING BEHAVIOR
Repainting is the single most-asked question about any Pine indicator, and the single most common source of silent failure when a retail trader moves from backtest to live. A strategy that looks flawless on historical bars and then bleeds money the moment it is deployed is almost always suffering from some form of repainting. KernelLens is engineered from first principles to eliminate every class of repainting by construction — not by patching symptoms, but by removing the dependencies that cause repainting in the first place.
**The Two Forms of Repainting**
| Form | Symptom | Typical Cause |
|---|---|---|
| **Historical repainting** | A bar that was closed days or weeks ago silently changes its plotted value when the chart is refreshed or scrolled | `request.security()` with `lookahead = barmerge.lookahead_on`, un-gated higher-timeframe data, or incorrect array rotation that reads into future bars |
| **Real-time repainting** | The plotted value on the live (current developing) bar flickers tick-by-tick as new price ticks arrive, then freezes at a final value when the bar closes | The indicator reads `close ` (or any current-bar value) inside a weighted sum — the current-bar weight changes every tick |
KernelLens avoids the first kind **entirely and unconditionally**: the library contains no `request.security` calls, no higher-timeframe lookups, no `lookahead_on` usage, and no array rotation that could leak future bars into the window. Every historical bar plotted by any KernelLens kernel is computed exclusively from bars that existed at the time that bar was closed. The plotted history is immutable.
Real-time repainting is controlled explicitly by the `_phase` parameter — it is the user's choice whether to accept tick-by-tick flicker on the live bar in exchange for zero lag (`_phase = 0`) or to eliminate the flicker entirely at the cost of a small fixed lag (`_phase ≥ 1`).
**Why Kernel Regression Normally Repaints (And How KernelLens Stops It)**
A traditional Nadaraya–Watson call centered on the current bar evaluates:
```
ŷ(t) = Σᵢ K(dᵢ/ℓ) · y_{t−i} for i = 0 … depth
```
On the live bar, the term `y_{t−0} = close ` is the current real-time price — which changes on every tick. Every tick moves the weighted sum, every tick moves the estimate, and the trader watching the chart sees the kernel plot flicker as the bar develops. The historical bars (where `close ` for that past bar is now fixed) are stable, but the live plot is unstable.
KernelLens's `_phase` parameter shifts the loop so the kernel runs over `i = _phase … _phase + depth`. With `_phase = 2`:
```
ŷ(t) = Σᵢ K((i−2)/ℓ) · y_{t−i} for i = 2 … 2 + depth
```
The sum no longer touches `close ` or `close ` — every bar it reads is already confirmed and cannot change. The live-bar kernel output is therefore identical from the first tick of the bar to the last tick of the bar, and identical again when the bar finally closes. There is no flicker and nothing to repaint.
**The Lag / Stability Trade-Off**
| `_phase` | Lag on Live Bar | Live-Bar Flicker | Historical Repainting | Best For |
|---|---|---|---|---|
| **0** | 0 bars | Yes (real-time only; history is stable) | None | Scalping, academic research, calibration |
| **1** | 1 bar | None | None | Fast day-trading; minimum acceptable lag for a live trading desk |
| **2** | 2 bars | None | None | Default for most users — the sweet spot between freshness and stability |
| **3** | 3 bars | None | None | Swing trading — extra margin against false flickers from erratic ticks |
| **5+** | 5+ bars | None | None | Position trading, long-term chart analysis, published signal marks |
Even at `_phase = 0`, **historical repainting never occurs** — only the live bar flickers during its own development. Once a bar closes, its plotted value is final; scrolling away and back, refreshing the chart, or re-opening PulseWire will never change that historical plot. The flicker is exclusively a live-bar tick-by-tick phenomenon.
**KernelLens as a Non-Repainting Primitive**
KernelLens exposes real-time flicker as an explicit, user-controlled trade-off rather than a hidden behavior. The caller picks any point on the spectrum from "fully live" (`_phase = 0`, maximum reactivity with tick-by-tick flicker) to "fully confirmed" (`_phase ≥ 1`, one or more bars of lag in exchange for a curve that never redraws) with a single integer parameter. Historical repainting — the dangerous form that silently rewrites past plots — is eliminated unconditionally regardless of `_phase`.
**How to Verify Non-Repainting Yourself**
Do not trust the word "non-repainting" from any library — always verify. KernelLens can be verified in about thirty seconds:
1. Load a chart with KernelLens on it using `_phase = 2` (or any value > 0).
2. Take a screenshot at any specific historical bar.
3. Scroll far to the left, refresh the chart, or reload the indicator.
4. Return to the same bar. The plotted value at that bar must be pixel-identical to the screenshot — because the computation on that bar used only the bars before it, which have not changed.
5. Repeat with `_phase = 0`. The historical bars must still be pixel-identical — only the live bar's plot can differ between observations, and only because the live bar's `close` is now a different number than it was when you took the screenshot.
For a stricter test, use PulseWire's **Bar Replay** mode. Enable Bar Replay, step forward one bar at a time, and watch the kernel plot on each newly-closed bar. With `_phase ≥ 1`, the value plotted on each newly-closed bar will exactly match what the indicator shows after you exit replay mode and view the same bar normally. This is the gold-standard test — Bar Replay reproduces live-bar tick arrival in a controlled way.
**Common Misconceptions**
> *"Any Pine indicator that uses `close` repaints."*
False. Using `close` on a confirmed bar does not repaint — the confirmed bar's close is locked. What can repaint is using `close` on the live bar, and only within that live bar's interval. KernelLens with `_phase > 0` never reads the live-bar close at all.
> *"`lookahead = barmerge.lookahead_on` is always wrong."*
Context-dependent. `lookahead_on` is used correctly in some multi-timeframe indicators to request a higher-TF value that is already settled on the lower TF. KernelLens does not use `request.security` at all, so this question does not apply — but for libraries that do, `lookahead_on` is only problematic when it leaks values from bars that were not yet closed at the lower-TF time of evaluation.
> *"Non-repainting means zero lag."*
False. Zero lag and non-repainting are orthogonal properties. KernelLens `_phase = 0` is zero lag with real-time flicker; `_phase = 2` is two-bar lag with no flicker. You can have any combination of the two, and the right choice depends on the trading style.
> *"The `FILTER_ZEROLAG` mode makes the indicator non-repainting."*
False. `FILTER_ZEROLAG` is an Ehlers-style de-lagging filter applied to the kernel output; it reduces the perceived lag of the estimate, but it does not affect whether the live bar flickers. Non-repainting is controlled exclusively by `_phase`. Choose `_phase` for repainting behavior, and `_filter` for smoothness / lag shape — they are independent knobs.
**When to Accept Real-Time Flicker (`_phase = 0`)**
Despite everything above, there are legitimate reasons to deliberately use `_phase = 0`:
- **Academic research and backtesting** — you want the kernel mathematics in its classical form, centered on the point being estimated, with no phase adjustment
- **Scalping on very short timeframes** — a 2-bar lag on a 1-minute chart is a 2-minute delay, which can matter when you are exiting within a 4-minute window
- **Visual calibration** — when you are choosing a bandwidth by eye, the live-bar flicker actually helps: you see how sensitive the curve is to each incoming tick, which is diagnostic information
- **Indicators that read the kernel output only on `barstate.isconfirmed`** — if your signal logic is gated by `if barstate.isconfirmed`, then live-bar flicker is invisible to your signal (it sees only the frozen close-of-bar value), and you can safely use `_phase = 0` with no practical consequence
For every other case — and especially for any live alert or automated trading system — use `_phase ≥ 1`. Two bars of lag on a clean, stable curve is almost always worth more than zero lag on a curve that redraws itself several times per bar.
🟦 UNIFIED DISPATCHER — `estimate()`
For indicators where the user picks a kernel from a dropdown, writing eight separate ternary branches is tedious and error-prone. KernelLens ships with a unified dispatcher that routes to the correct kernel based on a string argument:
```pine
import a_jabbaroff/KernelLens/1 as kl
line = kl.estimate(
kernelType = kl.KERNEL_GAUSS,
src = close,
bandwidth = 32,
shapeAlpha = 1.0,
period = 1,
phase = 2,
filter = kl.FILTER_SMOOTH)
```
The dispatcher forwards to the matching typed export, so there is no performance penalty versus calling the kernel directly — it is a compile-time routing pass. Unknown kernel names raise a descriptive `runtime.error` naming every valid alternative, so typos fail loudly instead of silently returning `na`.
**Public Constants**
KernelLens exposes its string constants so callers never type the magic values by hand:
| Constant | Value |
|---|---|
| `FILTER_NONE` | `"No Filter"` |
| `FILTER_SMOOTH` | `"Smooth"` |
| `FILTER_ZEROLAG` | `"Zero Lag"` |
| `KERNEL_RQ` | `"Rational Quadratic"` |
| `KERNEL_GAUSS` | `"Gaussian"` |
| `KERNEL_PERIODIC` | `"Periodic"` |
| `KERNEL_LOCPER` | `"Locally Periodic"` |
| `KERNEL_EPA` | `"Epanechnikov"` |
| `KERNEL_TRICUBE` | `"Tricube"` |
| `KERNEL_TRIANG` | `"Triangular"` |
| `KERNEL_COSINE` | `"Cosine"` |
Using the constants in your caller code means the Pine compiler — not a runtime string compare — catches typos at edit time.
🟦 UTILITY LAYER — FIVE PROFESSIONAL HELPERS
KernelLens ships with five utility exports that complement the core estimators. They are the functions you almost always write immediately after getting a smoothed line, factored out so you don't rewrite them in every indicator.
**`slope(estimate, step)` — Discrete First Derivative**
Returns `(y_t − y_{t−step}) / step`, the normalized rate of change over `step` bars. Use it to detect whether a kernel output is trending up, flat, or down — the foundation for any trend-following signal built on top of KernelLens.
```pine
rising = kl.slope(line, 3) > 0.0
```
**`trendState(estimate, step)` — Ternary Trend Indicator**
Returns `+1` if the estimate is rising, `−1` if falling, `0` if exactly flat over the window. A single-call replacement for hand-rolled `line > line ? 1 : line < line ? -1 : 0` ladders.
**`crossSignal(fast, slow)` — Bi-directional Crossover**
Returns `+1` on the bar where `fast` crosses above `slow` (bullish), `−1` on a bearish cross, and `0` otherwise. Built on `ta.crossover` / `ta.crossunder`, so the signal is non-repainting once the bar is confirmed.
**`confidenceBand(src, estimate, window)` — Residual Standard Deviation**
Computes the rolling standard deviation of `(src − estimate)` over a user-defined window. Use the return value as the half-width of a confidence band around the estimate:
```pine
est = kl.gaussian(close, 32, 2, kl.FILTER_SMOOTH)
sigma = kl.confidenceBand(close, est, 50)
upper = est + 1.96 * sigma
lower = est - 1.96 * sigma
```
This is a computationally cheap proxy for the full kernel-weighted local variance — ideal when you need visual bands without paying for a second weighted pass.
**`silvermanBandwidth(src, window)` — Optimal ℓ Suggestion**
Returns the Silverman rule-of-thumb bandwidth:
```
h ≈ 1.06 · σ · n^(−1/5)
```
where `σ` is the rolling standard deviation of the source and `n` is the window size. This is the classical starting point for Gaussian-family bandwidths in academic texts (Silverman 1986). Because Pine requires `simple int` for kernel bandwidth, the returned value is intended for diagnostic display — plot it, read it off the chart, then hard-code the rounded integer into the kernel call.
🟦 INPUT VALIDATION — FAIL LOUDLY, FAIL EARLY
Every public function in KernelLens validates its inputs through a set of internal `_assert*` helpers. Invalid arguments never produce silent `na` fallbacks or buried zero-divisions — they raise `runtime.error` with a descriptive message identifying the function, the parameter, and the expected range.
| Helper | Checks | Raises On |
|---|---|---|
| `_assertFilter` | Filter string is `FILTER_NONE`, `FILTER_SMOOTH`, or `FILTER_ZEROLAG` | Typos like `"No FIlter"` (capital I) — a bug that exists in at least one published kernel indicator |
| `_assertBandwidth` | Bandwidth is a strictly positive integer | Negative or zero bandwidth, which would cause division by zero or infinite loops |
| `_assertPeriod` | Period is a strictly positive integer | Zero period, which would cause `sin(π·d/0)` in Periodic kernels |
| `_assertAlpha` | Rational Quadratic shape parameter is strictly positive | Zero or negative `α`, which would invert the RQ formula |
Error messages are prefixed `KernelLens:` (or `KernelLens.:`) so they are easy to spot in the PulseWire runtime log. Every message names the parameter that failed, the value that was passed, and the set of valid alternatives — so a misconfigured chart tells you exactly what to fix.
🟦 LOOP DEPTH — THE BUG FIX THAT MOTIVATED KERNELLENS
The two most popular Pine kernel libraries on PulseWire share the same fatal bug: both compute their loop depth as
```pine
_size = array.size(array.from(_src))
```
where `array.from(_src)` creates a **one-element array containing the current value of `_src`**, so `_size` is always `1`. The loop then runs `for i = 0 to 1 + startAtBar`, effectively using only `startAtBar + 2` bars — completely ignoring the user's bandwidth. Every published kernel indicator built on those libraries inherits this silent miscalculation.
KernelLens replaces the broken helper with three explicit depth selectors:
| Helper | Depth | Used By |
|---|---|---|
| `_depthInfinite(bw)` | `max(bw · 3, 4)` | Gaussian, Rational Quadratic, Locally Periodic |
| `_depthCompact(bw)` | `max(bw, 4)` | Epanechnikov, Tricube, Triangular, Cosine |
| `_depthPeriodic(bw, p)` | `max(bw · 3, p · 10, 4)` | Periodic |
For Gaussian-family kernels, the `3·ℓ` cutoff captures approximately 99.7% of the kernel mass (the three-sigma rule). For compact-support kernels, the depth equals the bandwidth exactly — the loop terminates at the kernel's natural zero point. For Periodic kernels, the depth is the larger of the scale-based and cycle-based minima, so the loop always spans enough periods to produce a stable weighted average.
The loop counter `i` runs over bar offsets starting at `_phase`, every bar lookup is NA-checked before being incorporated into the sum, and the final `num / den` division is guarded against zero denominators. On a fresh chart, the kernel gracefully returns `na` for bars where the window extends past available history, rather than producing poisoned sums from implicit NA arithmetic.
🟦 API REFERENCE
**Core Kernel Estimators — Eight Exports**
| Export | Signature |
|---|---|
| `rationalQuadratic` | `(src, bandwidth, shapeAlpha, phase, filter) → float` |
| `gaussian` | `(src, bandwidth, phase, filter) → float` |
| `periodic` | `(src, bandwidth, period, phase, filter) → float` |
| `locallyPeriodic` | `(src, bandwidth, period, phase, filter) → float` |
| `epanechnikov` | `(src, bandwidth, phase, filter) → float` |
| `tricube` | `(src, bandwidth, phase, filter) → float` |
| `triangular` | `(src, bandwidth, phase, filter) → float` |
| `cosineKernel` | `(src, bandwidth, phase, filter) → float` |
**Unified Dispatcher**
| Export | Signature |
|---|---|
| `estimate` | `(kernelType, src, bandwidth, shapeAlpha, period, phase, filter) → float` |
**Utility Layer — Five Exports**
| Export | Signature |
|---|---|
| `slope` | `(estimate, step) → float` |
| `trendState` | `(estimate, step) → int` |
| `crossSignal` | `(fast, slow) → int` |
| `confidenceBand` | `(src, estimate, window) → float` |
| `silvermanBandwidth` | `(src, window) → float` |
**Parameter Types**
| Name | Pine Type | Description |
|---|---|---|
| `src` | `series float` | Source series (close, hl2, ohlc4, or any other price-derived series) |
| `bandwidth` | `simple int` | Kernel scale `ℓ`, must be `> 0` |
| `shapeAlpha` | `simple float` | Rational Quadratic shape parameter, must be `> 0` |
| `period` | `simple int` | Periodic repetition distance, must be `> 0` |
| `phase` | `simple int` | Kernel center offset in bars, must be `≥ 0` |
| `filter` | `simple string` | One of `FILTER_NONE`, `FILTER_SMOOTH`, `FILTER_ZEROLAG` |
| `kernelType` | `simple string` | One of the eight `KERNEL_*` constants |
| `step` | `simple int` | Finite-difference step for `slope` / `trendState`, must be `≥ 1` |
| `window` | `simple int` | Rolling window for `confidenceBand` / `silvermanBandwidth`, must be `≥ 2` |
🟦 USAGE EXAMPLES
**Minimal — One Gaussian Curve**
```pine
//@version=6
indicator("KernelLens — Gaussian Demo", overlay = true)
import a_jabbaroff/KernelLens/1 as kl
line = kl.gaussian(close, 32, 2, kl.FILTER_SMOOTH)
plot(line, "Gaussian", color = color.orange, linewidth = 2)
```
**Fast / Slow Crossover System**
```pine
//@version=6
indicator("KernelLens — RQ Crossover", overlay = true)
import a_jabbaroff/KernelLens/1 as kl
fast = kl.rationalQuadratic(close, 8, 1.0, 2, kl.FILTER_NONE)
slow = kl.rationalQuadratic(close, 32, 1.0, 2, kl.FILTER_SMOOTH)
cross = kl.crossSignal(fast, slow)
plot(fast, "Fast", color = color.aqua, linewidth = 2)
plot(slow, "Slow", color = color.orange, linewidth = 2)
plotshape(cross == 1, "Bull", location = location.belowbar,
color = color.lime, style = shape.triangleup, size = size.tiny)
plotshape(cross == -1, "Bear", location = location.abovebar,
color = color.red, style = shape.triangledown, size = size.tiny)
```
**Confidence Band Envelope**
```pine
//@version=6
indicator("KernelLens — Confidence Band", overlay = true)
import a_jabbaroff/KernelLens/1 as kl
est = kl.tricube(close, 48, 2, kl.FILTER_SMOOTH)
sigma = kl.confidenceBand(close, est, 50)
k = 1.96
upper = est + k * sigma
lower = est - k * sigma
plot(est, "Estimate", color = color.orange, linewidth = 2)
p1 = plot(upper, "+1.96σ", color = color.new(color.aqua, 70))
p2 = plot(lower, "−1.96σ", color = color.new(color.aqua, 70))
fill(p1, p2, color = color.new(color.aqua, 92))
```
**Dropdown-Driven Kernel Selection**
```pine
//@version=6
indicator("KernelLens — Dropdown", overlay = true)
import a_jabbaroff/KernelLens/1 as kl
kernelType = input.string(kl.KERNEL_GAUSS, "Kernel",
options = )
bandwidth = input.int(32, "Bandwidth", minval = 2)
alphaRQ = input.float(1.0,"RQ Alpha", minval = 0.01, step = 0.25)
period = input.int(20, "Period", minval = 1)
phase = input.int(2, "Phase", minval = 0)
filter = input.string(kl.FILTER_SMOOTH, "Filter",
options = )
line = kl.estimate(kernelType, close, bandwidth, alphaRQ, period, phase, filter)
plot(line, "KernelLens", color = color.orange, linewidth = 2)
```
🟦 TIMEFRAME PRESETS — BANDWIDTH BY STYLE
Kernel bandwidth is the single most important parameter. It controls the trade-off between reactivity (small `ℓ`, tight fit, noisier) and stability (large `ℓ`, smooth curve, slower to react). The presets below are tested starting points — adjust by ±25 % to taste.
---
**SCALPER — 1m / 3m / 5m**
| Parameter | Value |
|---|---|
| Bandwidth (ℓ) | 8 |
| Phase | 1 |
| Filter | `FILTER_NONE` |
| Best Kernel | Rational Quadratic or Gaussian |
| RQ shapeAlpha | 1.0 |
**Why:** Short bandwidth means the kernel reacts within a handful of bars. `FILTER_NONE` removes the double-pass lag, so the estimate tracks price as tightly as possible. Phase 1 keeps the estimate nearly live while still avoiding the current-bar tick noise.
---
**DAY TRADER — 15m / 30m / 1H**
| Parameter | Value |
|---|---|
| Bandwidth (ℓ) | 16 |
| Phase | 2 |
| Filter | `FILTER_SMOOTH` |
| Best Kernel | Gaussian or Tricube |
| RQ shapeAlpha | 1.0 |
**Why:** Balanced reactivity — the 16-bar Gaussian is the default Silverman range for intraday price data, and `FILTER_SMOOTH` removes most of the bar-to-bar chop without significantly increasing lag. Tricube provides near-identical behaviour with strict compact support and is preferred on noisy assets where outlier bars should not influence the curve.
---
**SWING TRADER — 4H / 1D**
| Parameter | Value |
|---|---|
| Bandwidth (ℓ) | 32 |
| Phase | 3 |
| Filter | `FILTER_SMOOTH` |
| Best Kernel | Rational Quadratic |
| RQ shapeAlpha | 2.0 |
**Why:** Swing trades need structural signals, not intraday noise. Rational Quadratic with `α = 2.0` mixes medium and long length scales, producing a curve that ignores transient spikes but catches genuine regime shifts. Phase 3 shifts the estimate three bars back so each swing decision is made against a fully confirmed kernel output.
---
**POSITION / LONG-TERM — 1D / 1W / 1M**
| Parameter | Value |
|---|---|
| Bandwidth (ℓ) | 64 |
| Phase | 5 |
| Filter | `FILTER_SMOOTH` or `FILTER_ZEROLAG` |
| Best Kernel | Gaussian or Locally Periodic |
| Period (if LP) | 52 (weekly cycle) |
**Why:** Position traders care about the macro trajectory. A Gaussian with ℓ = 64 produces a curve that only turns on genuine multi-month inflections. Locally Periodic with `period = 52` is the ideal choice when a clear seasonal cycle is present — it uses both the long-range Gaussian envelope and the 52-bar periodicity to highlight cycle turns that align with trend.
---
**RESEARCH — Academic / Backtest**
| Parameter | Value |
|---|---|
| Bandwidth (ℓ) | Compute via `silvermanBandwidth(src, 200)` |
| Phase | 0 |
| Filter | `FILTER_NONE` |
| Best Kernel | Epanechnikov |
**Why:** Epanechnikov is the MSE-optimal kernel; `FILTER_NONE` keeps the estimator in its classical single-pass form; `phase = 0` centers the kernel on the bar being evaluated. This is the configuration that matches the statistical literature exactly — use it when publishing research, running Monte-Carlo studies, or calibrating against reference implementations.
🟦 BANDWIDTH SELECTION
Bandwidth `ℓ` is the single most consequential choice in kernel regression. Too small and the estimate overfits local noise; too large and it flattens real structure. KernelLens exposes two helpers to support both manual and semi-automated bandwidth selection.
**Manual — Start with ℓ ≈ √n**
A practical starting point for financial time series: set `ℓ ≈ √window_of_interest`. If you care about 100-bar structure, try `ℓ = 10`. If you care about 400-bar structure, try `ℓ = 20`. Adjust by ±25 % based on how noisy the result looks.
**Silverman's Rule of Thumb**
The closed-form optimal bandwidth for Gaussian-family kernels under Gaussian source assumptions:
```
h ≈ 1.06 · σ · n^(−1/5)
```
Call `silvermanBandwidth(src, window)` to compute this value live. Because Pine requires `simple int` bandwidth at compile time, the returned value is for diagnostic use — plot it, read the stable value off the chart, then hard-code the rounded integer into your kernel calls.
**Leave-One-Out Cross-Validation (Manual)**
For academic rigor, compute the leave-one-out mean squared error for a range of bandwidths and pick the minimum. KernelLens does not automate this (it would require `series int` bandwidth, which Pine does not support inside kernel loops), but the formula is straightforward:
```
LOOCV(ℓ) = (1/n) · Σᵢ (yᵢ − ŷᵢ⁻ⁱ(ℓ))²
```
where `ŷᵢ⁻ⁱ` is the kernel estimate at bar `i` computed without including bar `i` in the sum. Evaluate offline, pick the minimum, hard-code the result.
🟦 FILTER SELECTION — WHEN TO USE EACH
| Filter | Best For | Avoid When |
|---|---|---|
| `FILTER_NONE` | Live signal generation, research / calibration, compact-support kernels on noisy data | Choppy markets where you need extra smoothing |
| `FILTER_SMOOTH` | Swing and position trades, confidence band midlines, most day-trading setups | Scalping — the double pass adds measurable lag |
| `FILTER_ZEROLAG` | Regime detection, crossover systems that need the curve to track price tightly | Low-volume assets — Zero Lag amplifies high-frequency noise |
The three filters use the same underlying kernel with the same bandwidth, so switching between them does not require re-tuning. Default to `FILTER_SMOOTH` when in doubt — it is the best-behaved option across the widest range of assets and timeframes.
🟦 COMPATIBILITY
KernelLens targets Pine Script v6 and runs on every PulseWire chart — no exchange, asset class, or timeframe restriction.
- **Crypto** — Spot, futures, perpetual contracts
- **Forex** — All majors, minors, and exotics
- **Equities** — Stocks, ETFs, indices
- **Commodities** — Metals, energy, agriculture
- **Timeframes** — 1 minute through Monthly
The library is deterministic — given the same source and parameters, every bar of every symbol produces the same estimate. No calibration is needed across assets; the bandwidth parameter alone controls smoothness, and the kernel formulas are scale-free in the source dimension. Silverman's bandwidth helper automatically adapts to each asset's volatility.
🟦 TECHNICAL NOTES
- **Pine Script v6** — uses the modern type system, strict type checking, and the `switch` expression in the unified dispatcher
- **Non-repainting** — kernel outputs for any confirmed bar depend only on that bar's history; there is no look-ahead, no `request.security` with lookahead, and no dependency on the unconfirmed current bar unless `_phase = 0` is deliberately chosen
- **NA-safe iteration** — every bar lookup inside a kernel loop is guarded by `if not na(y)`, so chart history gaps and warm-up bars cannot poison the weighted sum
- **Division-by-zero protection** — every kernel's final division checks `den > 0.0` and returns `na` if the denominator collapses (which can only happen on truly empty windows)
- **Input validation** — every public function asserts its preconditions up front via `_assertFilter`, `_assertBandwidth`, `_assertPeriod`, `_assertAlpha`, and raises `runtime.error` with a descriptive message on misuse — no silent `na` fallbacks
- **Lazy filter evaluation** — the `"No Filter"` path never executes the second kernel pass; the `if`-branch check short-circuits, so single-pass mode is as cheap as a raw kernel call
- **Correct loop bounds** — `_depthInfinite`, `_depthCompact`, and `_depthPeriodic` compute the correct window size per kernel family, fixing the silent `_size = 1` bug that plagues every other published Pine kernel library
- **No persistent state** — the library is purely functional: no `var`, no arrays, no history buffers that grow over time; every export is a pure expression of `(inputs) → output`, so Pine's `max_*_count` limits cannot be exceeded and the library cannot leak memory
- **O(bandwidth) per bar per kernel call** — the loop depth is bounded by the constants in Section 0; there is no hidden quadratic behavior and the cost scales linearly with the user-chosen bandwidth
- **Unicode-safe comments** — the source uses academic notation (`σ`, `ℓ`, `α`, `ŷ`, `ℝ`) where it improves readability; all strings are plain ASCII for runtime compatibility
🟦 ACADEMIC REFERENCES
Every kernel and every formula in KernelLens is cited inline in the source. The combined bibliography:
- **Nadaraya, E. A. (1964).** On estimating regression. *Theory of Probability & Its Applications*, 9(1), 141–142.
- **Watson, G. S. (1964).** Smooth regression analysis. *Sankhyā: The Indian Journal of Statistics, Series A*, 26(4), 359–372.
- **Cleveland, W. S. (1979).** Robust locally weighted regression and smoothing scatterplots. *Journal of the American Statistical Association*, 74(368), 829–836. *(Tricube kernel, LOWESS.)*
- **Silverman, B. W. (1986).** *Density Estimation for Statistics and Data Analysis*. Chapman & Hall, London. *(Bandwidth rule of thumb.)*
- **Wand, M. P. & Jones, M. C. (1995).** *Kernel Smoothing*. Chapman & Hall. *(Unified treatment of all eight kernels.)*
- **MacKay, D. J. C. (1998).** Introduction to Gaussian Processes. *NIPS Tutorial*. *(Periodic and Rational Quadratic kernels.)*
- **Ehlers, J. F. (2000).** *Rocket Science for Traders*. John Wiley & Sons. *(Zero-lag smoothing trick.)*
- **Rasmussen, C. E. & Williams, C. K. I. (2006).** *Gaussian Processes for Machine Learning*. MIT Press. *(Locally Periodic and Rational Quadratic kernels.)*
🟦 VERSIONING & LICENSE
- **Version** — 1.0.0
- **Pine Script** — v6
- **License** — Mozilla Public License 2.0
- **Status** — Production-ready
KernelLens follows semantic versioning. Minor versions add new exports without breaking existing ones; patch versions fix bugs; major versions may change function signatures and will be announced in the changelog.
🟦 DISCLAIMER
KernelLens is a mathematical library for non-parametric regression on financial time series using the Nadaraya–Watson method. The library is provided solely for educational and research purposes and does not constitute financial, investment, or trading advice.
Kernel regression is a local smoothing technique. It estimates the mean of a source series in the neighborhood of the current bar based on historical data, but it does not predict future prices, does not generate trading signals on its own, and does not guarantee the profitability of any strategy built on top of its output.
Past performance of any model does not guarantee future results. Markets contain systemic risks that cannot be eliminated by any amount of mathematical rigor in the kernel itself. Responsibility for any trading decisions made using this library rests entirely with the user. Always apply sound capital management, conduct your own independent analysis, and never risk capital you are not prepared to lose.
The author assumes no liability for direct or indirect losses incurred through the use of KernelLens or any indicator built on top of it. Library

Library

Vantage_PickMyTrade_IntegrationVantage_PickMyTrade_Integration — Webhook integration library for Pine Script strategies routing orders through PickMyTrade.
─────────────────────────────────────────
WHAT IT DOES
Constructs and emits JSON webhook payloads in the PickMyTrade format. The library provides a strongly-typed Pine Script interface and emits the alert for you, so your strategy never has to hand-build JSON strings, remember exact field values, or track which fields are conditional.
─────────────────────────────────────────
WHAT IT PROVIDES
Strong types for every PickMyTrade enumeration — order actions (buy / sell / close), order types (market / limit / stop / stop-limit), and bracket-mode specification (price / dollar / percent). Using a typed enum catches typos at compile time.
High-level send functions covering the common order patterns — a stop entry with bracket (pre-placed at the exchange), a market or limit entry with bracket, targeted close by comment tag, a full-flatten for a symbol, and in-place SL/TP modification on an existing position. All share a single underlying builder that handles field ordering, conditional fields, and token-in-body authentication.
─────────────────────────────────────────
HOW TO USE
A complete example call is in the comment block at the top of the source file — import the library, copy the pattern, adjust to your strategy. Hover any exported type or function in the Pine Editor for per-parameter documentation. Library
