Library · Pine Script v6 · Library

PineToolkit

by MoDarK-MK· code credited to PINETOOLKIT

This library supplies shared pure helper functions for Pine Script indicators and strategies in the Pine Script Skill repository.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code261
Settings0inputs
LicenceMPL-2.0
Last update7 weeks ago4 Sep 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new library, select all of the template text and paste. Press Save and give it a name.
  4. 4Publish or import itA library draws nothing. Publish it from the editor, then import its functions in your own scripts.

Source Code

261 lines of Pine Script v6 from libraries/pine_toolkit/src/pine_toolkit.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

pine_toolkit.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © PINETOOLKIT

//@version=6

// Shared helpers for the indicators and strategies in this repo.
//
// WHY THIS EXISTS: Pine has no local file imports. Every helper here was
// previously copy-pasted into four separate scripts, and a comment asking
// future readers to keep the copies in sync is not a mechanism. One of those
// copies drifted; a test now holds two of them byte-identical, which works but
// does not scale. A published library is the actual fix — see
// references/decisions.md D9.
//
// SCOPE, DELIBERATELY NARROW: pure functions only. No inputs, no drawings, no
// request.*(), no `var` state. Two reasons. Pine restricts what a library may
// contain, and a pure function is the part that is unambiguously allowed. And a
// pure function is testable by inspection — a stateful one imported into four
// scripts is a shared mutable dependency, which is a worse problem than the
// duplication it would replace.
//
// WHAT IS NOT HERE: the drawing pools and the reversal scoring engine. Pools
// hold `var` state and the engine reads series data and inputs; both would drag
// this past the boundary above. references/snippets/ still carries those, and
// tests/test_shared_engine.py still holds the engine's two copies identical.
//
// NOT YET COMPILE-VERIFIED ON TRADINGVIEW. Libraries have publication
// requirements no offline tool can check. Paste it once and publish it before
// any script here depends on it.

library("PineToolkit", overlay = true)

// ————— Theme
// One palette, one place. Every dashboard in this repo was picking its own
// greys, and "roughly the same dark grey" across four scripts is what a design
// system is supposed to prevent.

// @function Primary text colour for a theme — the value column reads first.
// @param theme "Dark" or "Light". Anything else is treated as Dark.
// @returns The colour for primary text.
export textColor(string theme) =>
    theme == "Light" ? #131722 : #d1d4dc

// @function Secondary text colour, deliberately lower contrast than the value
// it labels. A label competing with its own number is the most common way a
// dashboard becomes hard to read.
// @param theme "Dark" or "Light".
// @returns The colour for secondary text.
export mutedColor(string theme) =>
    theme == "Light" ? #4a4e58 : #b2b5be

// @function Panel background for a theme.
// @param theme "Dark" or "Light".
// @param transp Transparency 0-100. Keep it low: above roughly 80 the candles
// behind the panel win and the numbers stop being readable.
// @returns The panel background colour.
export panelColor(string theme, int transp) =>
    color.new(theme == "Light" ? #ffffff : #131722, math.max(0, math.min(100, transp)))

// @function The repo's standard bullish colour.
// @returns TradingView's own green, so scripts sit next to the platform's UI.
export bullColor() =>
    #089981

// @function The repo's standard bearish colour.
// @returns TradingView's own red.
export bearColor() =>
    #f23645

// @function The repo's standard accent, used for points of control and for
// anything flagged as at-a-limit.
// @returns An amber that reads on both themes.
export accentColor() =>
    #d98b1f

// ————— Formatting

// @function Compact human-readable volume: 1.24M, 345.6K, 12.3.
// @param v The value. na and negative values are handled.
// @returns A short string suitable for a table cell or a label.
export formatVolume(float v) =>
    float av = math.abs(nz(v))
    switch
        av >= 1000000000 => str.tostring(v / 1000000000, "#.##") + "B"
        av >= 1000000    => str.tostring(v / 1000000, "#.##") + "M"
        av >= 1000       => str.tostring(v / 1000, "#.#") + "K"
        => str.tostring(nz(v), "#.#")

// @function Formats a ratio as a percentage string.
// @param value The numerator.
// @param total The denominator. Zero and na return "--" rather than a
// misleading 0%.
// @param digits Decimal places, 0-4.
// @returns e.g. "62.4%" or "--".
export formatPercent(float value, float total, int digits) =>
    string out = na(total) or total == 0 or na(value) ? "--" :
         str.tostring(value / total * 100, "#." + str.repeat("#", math.max(0, math.min(4, digits)))) + "%"
    out

// @function Repeats an on/off glyph pair into a filled/empty meter.
// @param score How many positions are filled.
// @param maxScore Total positions.
// @param onGlyph The filled glyph, e.g. "★".
// @param offGlyph The empty glyph, e.g. "☆".
// @returns The meter as one string.
export glyphMeter(int score, int maxScore, string onGlyph, string offGlyph) =>
    int filled = math.max(0, math.min(maxScore, score))
    str.repeat(onGlyph, filled) + str.repeat(offGlyph, math.max(0, maxScore - filled))

// ————— Maths

// @function Clamps a value into a range.
// @param value The value.
// @param lo Lower bound.
// @param hi Upper bound.
// @returns The clamped value.
export clamp(float value, float lo, float hi) =>
    math.max(lo, math.min(hi, value))

// @function Division that returns a fallback instead of na or infinity.
// @param numerator The numerator.
// @param denominator The denominator.
// @param fallback Returned when the denominator is zero or na.
// @returns The quotient, or the fallback.
export safeDiv(float numerator, float denominator, float fallback) =>
    na(denominator) or denominator == 0 ? fallback : numerator / denominator

// @function Where a value sits between two bounds, as a percentage.
// Used for "price is 62% of the way from the swing low to the swing high".
// @param value The value.
// @param lo The 0% bound.
// @param hi The 100% bound.
// @returns 0-100, or na when the bounds are unusable.
export positionBetween(float value, float lo, float hi) =>
    float span = hi - lo
    float out = na(span) or span <= 0 ? na : math.max(0.0, math.min(100.0, (value - lo) / span * 100))
    out

// @function The share of a bar's volume attributable to buying, estimated from
// where the bar closed inside its own range.
//
// STATED PLAINLY: Pine exposes no bid/ask, so no script can know which side was
// the aggressor. A bar closing at its high counts fully as buying, at its low
// fully as selling, in the middle 50/50. This is the standard approximation and
// it is wrong on bars that reverse hard intrabar — exactly where you would most
// want it to be right. See references/decisions.md D2.
// @param barOpen Unused by the range model; accepted so a caller can switch
// models without changing its call sites.
// @param barHigh The bar's high.
// @param barLow The bar's low.
// @param barClose The bar's close.
// @returns 0.0-1.0. A zero-range bar returns 0.5 rather than na.
export buyShare(float barOpen, float barHigh, float barLow, float barClose) =>
    float span = barHigh - barLow
    float share = span > 0 ? (barClose - barLow) / span : 0.5
    math.max(0.0, math.min(1.0, share))

// ————— Mapping helpers
// These exist because every script was writing the same switch, and a typo in
// one of them fails at runtime rather than at compile time.

// @function Maps a style name to a line.style_* constant.
// @param name "Solid", "Dashed" or "Dotted". Anything else gives solid.
// @returns The matching line.style_* constant.
export lineStyleFrom(string name) =>
    switch name
        "Dashed" => line.style_dashed
        "Dotted" => line.style_dotted
        => line.style_solid

// @function Maps a size name to a size.* constant, capped at size.normal.
// The cap is the design system's, not Pine's: size.large and size.huge dwarf
// TradingView's own chart text and make a script look like an intrusion.
// @param name "Tiny", "Small" or "Normal".
// @returns The matching size.* constant.
export sizeFrom(string name) =>
    switch name
        "Tiny"  => size.tiny
        "Small" => size.small
        => size.normal

// ————— Volume & Key Level Helpers

// @function Calculates Effort vs Result (VSA ratio) for a candle.
// @param spread Current candle high - low.
// @param vol Current candle volume.
// @param avgSpread Average candle range (e.g. ATR).
// @param avgVol Average candle volume (e.g. SMA of volume).
// @returns The ratio (> 2.0 indicates high effort with little price progress / absorption).
export effortResultRatio(float spread, float vol, float avgSpread, float avgVol) =>
    float sRatio = avgSpread > 0 ? math.max(0.05, spread / avgSpread) : 1.0
    float vRatio = avgVol > 0 ? vol / avgVol : 1.0
    vRatio / sRatio

// @function Detects if a bar's volume qualifies as a volume climax / capitulation surge.
// @param vol Bar volume.
// @param avgVol Benchmark average volume.
// @param multiplier Multiplier threshold (e.g. 2.5 or 3.0).
// @returns True if volume exceeds threshold.
export isVolumeClimax(float vol, float avgVol, float multiplier) =>
    avgVol > 0 and vol >= (avgVol * multiplier)

// @function Detects if a pullback bar represents a low-volume supply/demand test.
// @param vol Bar volume.
// @param avgVol Benchmark average volume.
// @param ratio Ratio threshold (e.g. 0.5 for volume under 50% average).
// @returns True if volume is dry.
export isLowVolumeTest(float vol, float avgVol, float ratio) =>
    avgVol > 0 and vol <= (avgVol * ratio)

// @function Checks if a price is within the Value Area (VAH to VAL).
// @param price The price to check.
// @param vah Value Area High.
// @param val Value Area Low.
// @returns True if price is inside or at the edges of the Value Area.
export inValueArea(float price, float vah, float val) =>
    not na(price) and not na(vah) and not na(val) and price >= val and price <= vah

// @function Calculates an institutional confluence score for a Key Level (0 - 100).
// @param touches Number of previous price rejections/touches at this level.
// @param isHtf Whether this level is rooted in a higher timeframe (e.g. Daily/Weekly).
// @param isVpoc Whether this level aligns with a Virgin POC.
// @param isUnmitigated Whether the level is still fresh (untested / unmitigated).
// @returns Confluence score integer between 0 and 100.
export scoreKeyLevel(int touches, bool isHtf, bool isVpoc, bool isUnmitigated) =>
    int score = 0
    score := score + (isHtf ? 35 : 15)
    score := score + (isVpoc ? 25 : 0)
    score := score + (isUnmitigated ? 20 : 5)
    score := score + math.min(20, touches * 5)
    math.min(100, score)

// @function Analyzes two swing points for regular delta divergence.
// @param priceCurr Price at the current swing point.
// @param pricePrev Price at the previous swing point.
// @param cvdCurr Cumulative Delta at current swing point.
// @param cvdPrev Cumulative Delta at previous swing point.
// @param isBullish True to check bullish divergence (lower low in price, higher low in CVD).
// @returns True if delta divergence is present.
export detectDeltaDivergence(float priceCurr, float pricePrev, float cvdCurr, float cvdPrev, bool isBullish) =>
    bool div = false
    if isBullish
        div := priceCurr < pricePrev and cvdCurr > cvdPrev
    else
        div := priceCurr > pricePrev and cvdCurr < cvdPrev
    div

// ————— Library self-check
// A library cannot be unit-tested offline, so it plots its own invariants. Load
// it on a chart once: every one of these must read 1.

plot(formatVolume(1240000) == "1.24M" ? 1 : 0, "selfcheck: formatVolume", display = display.data_window)
plot(glyphMeter(3, 5, "*", "-") == "***--" ? 1 : 0, "selfcheck: glyphMeter", display = display.data_window)
plot(safeDiv(1, 0, -1) == -1 ? 1 : 0, "selfcheck: safeDiv", display = display.data_window)
plot(clamp(7, 0, 5) == 5 ? 1 : 0, "selfcheck: clamp", display = display.data_window)
plot(positionBetween(5, 0, 10) == 50 ? 1 : 0, "selfcheck: positionBetween", display = display.data_window)
plot(buyShare(1, 2, 1, 2) == 1.0 ? 1 : 0, "selfcheck: buyShare", display = display.data_window)
plot(na(positionBetween(5, 10, 10)) ? 1 : 0, "selfcheck: positionBetween na", display = display.data_window)
plot(inValueArea(100.0, 110.0, 90.0) ? 1 : 0, "selfcheck: inValueArea", display = display.data_window)
plot(isVolumeClimax(300.0, 100.0, 2.5) ? 1 : 0, "selfcheck: isVolumeClimax", display = display.data_window)
plot(scoreKeyLevel(3, true, true, true) == 95 ? 1 : 0, "selfcheck: scoreKeyLevel", display = display.data_window)

Overview

PineToolkit exports theme-aware color functions that return primary text, muted text, and panel background colors based on selected dark or light theme. Additional helpers include standard bullish and bearish colors along with an accent color, plus a compact volume formatting function that shortens large numbers for table display. These functions promote design system consistency and readability without state or drawings.

Details

Published by

MoDarK-MK on GitHub

Code credit

PINETOOLKIT, as written in the script's header

Type

Library, Pine Script v6

Draws

Library (no plots)

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Topics

ci-cdindicatorslinterpine-scriptpythonstrategiestradingview

Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

FunctionLinearRegression

by ricardosantos79
261 stars

This Pine Script v5 library provides functions to calculate and plot linear regression channels using sample point arrays. It evaluates paired X and Y arrays to calculate the regression slope, intercept, fitted values, maximum deviation, minimum deviation, and

Library v5 Trend
Updated 4 years ago · None stated GitHub repository of FunctionLinearRegression

PositionSizing

by iamrichardD
57 stars

This Pine Script v6 library calculates trade position sizes and provides risk management functions for external scripts. It computes position sizes from account equity, percentage risk, and stop-loss distance, and offers dynamic sizing adjustments based on vol

Library v6
Updated 1 year ago · Apache-2.0 GitHub repository of PositionSizing

Chart Patterns

by deepentropy
13 stars

Chart Patterns is a Pine Script v6 library designed to scan for and render technical chart patterns directly on the price chart. It defines custom user-defined types to configure scanning parameters, such as Zigzag pivot offsets, error ratios, flat ratios, and

Library v6 Repaints
Updated 6 months ago · MIT GitHub repository of Chart Patterns

AuthLib

by alboogycOdR
6 stars

AuthLib is a Pine Script utility library providing access control and state management structures for technical indicators. It checks callers against a hardcoded array of authorized TradingView usernames before executing operations. The library exports user-de

Library v5 SMC / ICT / price actionSessions & time
Updated 7 months ago · None stated GitHub repository of AuthLib

WebhookMessageLibrary

by TradersPost
6 stars

WebhookMessageLibrary is a helper library designed to construct structured JSON payload messages for automated trading integrations like TradersPost. It defines custom exported types and constants for trade actions, market sentiments, quantities, limit prices,

Library v5
Updated 1 year ago · None stated GitHub repository of WebhookMessageLibrary

PineDraw

by 345-strategies
5 stars

PineDraw is a Pine Script v6 library that provides object primitives for drawing and updating price levels on the chart. It enables indicators and strategies to maintain lines, boxes, and labels in place by updating existing objects instead of deleting and rec

Library v6 Support & resistance
Updated 2 days ago · MPL-2.0 GitHub repository of PineDraw

More libraries

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers