Pine Script Error Diagnosis & Solutions

Pine Script math.clamp: How to Clamp Values in v5 and v6

TradingView Pine Script v5 and v6 do not have a built-in math.clamp() function. In v5, calling math.clamp() triggers the compiler error "Could not find function or function reference 'math.clamp'". To clamp a value between a lower and upper bound in Pine Script, use the composite expression math.max(min_val, math.min(max_val, val)) or declare a custom user-defined method. The formula assumes min_val <= max_val; missing inputs propagate na.

Fix Pine Script with AI

1. The math.clamp Error in Pine Script v5 and v6

A call to math.clamp(value, min_val, max_val) fails because that built-in is absent from the Pine Script v5 and v6 reference manuals. This can appear in generated or ported code. The example below keeps the invalid call commented out so you can copy the corrected script. To reproduce the error, uncomment that line and remove the corrected assignment.

  • Typical v5 message: "Could not find function or function reference 'math.clamp'"
  • Cause: math.clamp does not exist in the Pine Script v5 or v6 standard library
  • Check generated or ported code against the reference for its declared Pine version
  • Resolution: Replace with math.max/math.min nesting or a user-defined function
Corrected v5 script with the invalid call shown in a commentpinescript
//@version=5
indicator("Replacing math.clamp", overlay=false)

raw_val = ta.rsi(close, 14)

// Uncommenting the next assignment reproduces the missing-function error:
// Could not find function or function reference 'math.clamp'.
// clamped_val = math.clamp(raw_val, 30.0, 70.0)

// Corrected assignment: use nested math.max and math.min
clamped_val = math.max(30.0, math.min(70.0, raw_val))

plot(clamped_val, "Clamped RSI", color=color.blue)

2. Implementing Clamping with math.max and math.min

Clamping restricts a numerical value to a closed interval [min_val, max_val]. In Pine Script, this is accomplished by combining math.min() and math.max(). The inner math.min(max_val, val) guarantees that any number greater than max_val is capped at max_val. The outer math.max(min_val, ...) guarantees that any number smaller than min_val is elevated to min_val. Values within ordered bounds remain unchanged. The table shows abbreviated declarations; use the complete scripts below for compilable examples.

PatternSyntax ExamplePine Script CompatibilityIdeal Use Case
Inline Expressionmath.max(low, math.min(high, val))v5 and v6Single occurrences where declaring a function is unnecessary
User-Defined Functionclamp(val, low, high) => math.max(...)v5 and v6Multiple clamp calls across indicator calculations
User-Defined Methodmethod clamp(float val, float low, float high) => math.max(...)v5 and v6Object-style chaining: series_var.clamp(low, high)
Dynamic Safe Clampsafe_clamp(val, b1, b2) => ...v5 and v6Guards against dynamic inputs where b1 may exceed b2
Comparing Inline vs Method Clampingpinescript
//@version=5
indicator("Inline vs Method Clamping", overlay=false)

// Method definition: attached directly to float series
method clamp(float val, float min_val, float max_val) =>
    math.max(min_val, math.min(max_val, val))

oscillator = (close - open) / syminfo.mintick

// Method 1: Inline evaluation
inline_clamped = math.max(-100.0, math.min(100.0, oscillator))

// Method 2: Dot-notation method call
method_clamped = oscillator.clamp(-100.0, 100.0)

plot(inline_clamped, "Inline", color=color.gray)
plot(method_clamped, "Method", color=color.teal)

3. Creating a Custom User-Defined Method in v5 and v6

Both Pine Script v5 and v6 support user-defined methods via the method keyword. By adding method in front of your function declaration, TradingView enables method call syntax on any variable matching the first parameter type. The first parameter must have an explicit type; it determines which variables can use the method.

  • Declare the first parameter as float for calculations that can contain fractions
  • Use a separate int overload when the output must remain an integer
  • Define the method before calling it; the declaration does not add a function to math.*
  • Choose inline syntax for one expression and a named function or method for repeated use
Reusable Clamp Method for Custom Indicatorspinescript
//@version=5
indicator("Custom Method Clamp Library Pattern", overlay=false)

// Declare the clamp method for float types
method clamp(float val, float min_val, float max_val) =>
    math.max(min_val, math.min(max_val, val))

// Declare an overload for int types to prevent unwanted float casting
method clamp(int val, int min_val, int max_val) =>
    math.max(min_val, math.min(max_val, val))

// Usage with float
float_signal = ta.stoch(close, high, low, 14)
clamped_stoch = float_signal.clamp(10.0, 90.0)

// Usage with int
int_length = 25
clamped_len = int_length.clamp(10, 50)

plot(clamped_stoch, "Clamped Stochastic", color=color.purple)

4. Edge Cases: na Handling, Inverted Bands, and Type Promotion

The nested expression requires ordered, defined bounds. If any argument is na, the result is na. With reversed bounds, math.max(min_val, math.min(max_val, val)) returns min_val for defined numeric inputs. The helper below deliberately sorts bounds and replaces only a missing input with its fallback. It still returns na if a bound or the selected fallback is na. Sorting is a policy choice; reject reversed settings instead if their order has meaning in your script.

Edge CaseSymptomRoot CauseDefensive Solution
Uninitialized Bar (na)Indicator fails to plot on early historical barsmath.min/math.max return na if any argument is naKeep na for unavailable data, or choose an explicit fallback before clamping
Inverted Boundaries (min > max)Output freezes at min_val regardless of inputmath.max(10, math.min(5, 7)) resolves to 10Sort boundaries with lo = math.min(a, b), hi = math.max(a, b)
Int vs Float Implicit PromotionA float argument can make the numeric result a floatFloat arguments coerce int to float across calculationsUse integer arguments or an int overload; int() truncates fractions and does not remove a series qualifier
Sorted bounds with an explicit input fallbackpinescript
//@version=5
indicator("Defensive Clamping", overlay=false)

// Sort bounds; replace missing input only. Missing bounds still return na.
safe_clamp(float val, float bound_a, float bound_b, float fallback = 0.0) =>
    clean_val = na(val) ? fallback : val
    lo = math.min(bound_a, bound_b)
    hi = math.max(bound_a, bound_b)
    math.max(lo, math.min(hi, clean_val))

// Test with inverted boundaries (bound_a = 100, bound_b = -100)
test_val = safe_clamp(close - close[1], 100.0, -100.0)
plot(test_val, "Defensive Clamped Value", color=color.orange)

5. Clip Percentage Momentum Without Changing Its Units

This example clips percentage price change to two chosen limits. It does not statistically normalize the series: every value beyond a limit becomes that limit, so the size of larger moves is lost. The calculation uses the current close and can change while the realtime bar is open. Clamping does not prevent repainting or establish useful trading thresholds.

  • The default -4% and +4% limits are illustrative user settings, not statistical or trading recommendations
  • Sorted limits are used consistently for the calculation, horizontal lines, and colors
  • Missing lookback prices and a zero denominator produce na instead of a substitute signal
  • For bar-close alerts, separately require confirmed bars in the alert condition
Clipped percentage momentum with ordered display limitspinescript
//@version=5
indicator("Bounded Momentum Oscillator [Pineify]", overlay=false)

// Inputs
len       = input.int(14, "Momentum Lookback", minval=1)
limit_min = input.float(-4.0, "Lower Bound (%)")
limit_max = input.float(4.0, "Upper Bound (%)")

// User-defined clamp method
method clamp(float val, float min_val, float max_val) =>
    math.max(math.min(min_val, max_val), math.min(math.max(min_val, max_val), val))

// Use the same sorted bounds for calculation and display
lo = math.min(limit_min, limit_max)
hi = math.max(limit_min, limit_max)

// Preserve missing history and guard a zero denominator
base = close[len]
raw_mom = not na(base) and base != 0.0 ? ((close - base) / base) * 100.0 : na

// Apply clamp method
clamped_mom = raw_mom.clamp(lo, hi)

// Visual guidelines
hline(0.0, "Baseline", color=color.gray, linestyle=hline.style_dotted)
hline(hi, "Upper clipping limit", color=color.red, linestyle=hline.style_dashed)
hline(lo, "Lower clipping limit", color=color.green, linestyle=hline.style_dashed)

// Dynamic bar color based on boundary saturation
mom_color = clamped_mom >= hi ? color.red : clamped_mom <= lo ? color.green : color.teal
plot(clamped_mom, "Bounded Momentum", color=mom_color, linewidth=2)

6. Check the Boundaries with Fixed Inputs

For bounds 0 and 100, inputs -10, 0, 25, 100, and 120 should return 0, 0, 25, 100, and 100. Equal bounds should return that boundary for any defined input. The v6 script below encodes those expectations, checks na propagation, and checks reversed bounds after sorting. Add it to a chart to execute the assertions: a mismatch raises a runtime error. These are reproducible checks, not a reported chart execution or trading backtest.

InputBoundsExpected result
-100, 1000
00, 1000
250, 10025
1000, 100100
1200, 100100
2510, 1010
na0, 100na
25na, 100na
25100, 0100 with the basic formula; 25 after sorting
Pine v6 boundary assertions to run on a chartpinescript
//@version=6
indicator("Clamp boundary checks", overlay=false)

clamp(float val, float lo, float hi) =>
    math.max(lo, math.min(hi, val))

sorted_clamp(float val, float a, float b) =>
    clamp(val, math.min(a, b), math.max(a, b))

if barstate.isfirst
    values = array.from(-10.0, 0.0, 25.0, 100.0, 120.0)
    expected = array.from(0.0, 0.0, 25.0, 100.0, 100.0)
    for i = 0 to array.size(values) - 1
        actual = clamp(array.get(values, i), 0.0, 100.0)
        if na(actual) or actual != array.get(expected, i)
            runtime.error("Numeric clamp assertion failed")
    if clamp(25.0, 10.0, 10.0) != 10.0
        runtime.error("Equal bounds assertion failed")
    if not na(clamp(float(na), 0.0, 100.0)) or not na(clamp(25.0, float(na), 100.0))
        runtime.error("Missing value assertion failed")
    if clamp(25.0, 100.0, 0.0) != 100.0 or sorted_clamp(25.0, 100.0, 0.0) != 25.0
        runtime.error("Reversed bounds assertion failed")

plot(clamp(25.0, 0.0, 100.0), "Expected 25")
Where Pineify fits

Pine Script AI Coding Agent

Give the Pine Script AI Coding Agent your complete script, Pine version, and compiler message to request a correction. Review the replacement calculation and compile the returned script in TradingView before using it.

Also useful: Visual Pine Script Editor. Build indicators and conditions with the Visual Pine Script Editor if you prefer a visual workflow. Use the code examples on this page when you need a specific clamp implementation.

Fix Pine Script with AI

Frequently asked questions

Programming examples only, not investment advice or a trading strategy. Clipping limits change displayed values and do not indicate profitable entries or exits. Syntax validation does not verify trading behavior.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.