Skip to main content

Math Expressions

Two fields — stopLossExpression and takeProfitExpression — let you compute SL/TP prices server-side from arithmetic over the entry price. They're the bridge between TradingView's Pine values and TVH's absolute-price SL/TP handling.

TL;DR
  • Expressions are evaluated server-side after Pine substitutes placeholders. Allowed operators: + - * / and parentheses.
  • Triggers only when the corresponding type field is "absolute": stopLossType="absolute" for SL, targetType="absolute" for TP.
  • TVH auto-flips operator signs based on orderType so the same template works for longs and shorts.
  • Errors are silently swallowed. If the expression throws, stopLoss or targets[0].price stays at its previous value (often 0 = no order placed). Test before going live.
  • takeProfitExpression updates only targets[0].price. Multi-target ladders need explicit prices on targets[1..n].

Quick reference table

PropertyTypeRequiredDefaultDescription
stopLossExpressionstringno""Arithmetic expression. Resolves to absolute SL price when stopLossType="absolute". Sign-flipped by orderType.
takeProfitExpressionstringno""Arithmetic expression. Resolves to absolute price for targets[0] when targetType="absolute". Sign-flipped by orderType.

Both fields are categorised on the Stop Loss and Take Profit detail pages as well — the expressions live in two homes in the schema because they touch both subsystems.

When expressions evaluate

The server runs its auto-mapping step after parsing your JSON. The math step fires only when all three of these are true:

  1. stopLossType="absolute" (for SL) or targetType="absolute" (for TP).
  2. The expression field (stopLossExpression / takeProfitExpression) is non-empty.
  3. The expression contains at least one of * + - /.

If any of those is missing, the expression is ignored and the regular fields (stopLoss, stopLossPercent, targets[].price) are used as-is.

Supported syntax

OperatorExampleResult
Addition100 + 5105
Subtraction100 - 595
Multiplication100 * 0.022
Division100 / 425
Parentheses(100 + 5) * 0.552.5
Decimal literals0.02 * 650001300

Not supported:

  • Exponentiation (^ or **). Use repeated multiplication.
  • Functions (sqrt, abs, min, max).
  • Comparisons or boolean logic.
  • Identifiers other than substituted Pine placeholders.

Anything else fails to evaluate, and the result is silently discarded.

Pine placeholders inside expressions

The expression is a string, not Pine code. Pine substitutes the placeholders before sending the webhook; by the time TVH evaluates the expression, the curly-brace tokens are gone.

1. Pine source string (what you write in the template):

"{{strategy.order.price}}-0.02*{{strategy.order.price}}"

2. After TradingView substitutes (entry price was 65000):

"65000-0.02*65000"

3. After TVH evaluates the expression:

63700

Common placeholders used in expressions:

PlaceholderResolves to
{{strategy.order.price}}The exact entry price of the order Pine just submitted.
{{close}}Latest bar close. Useful for indicator alerts (no strategy context).
{{high}} / {{low}}Bar high / low. Stop placement based on recent extremes.
{{open}}Bar open.

You can mix them. {{strategy.order.price}} is the most common because it lines up exactly with the entry's actual fill.

Smart sign-flipping

The same expression should work for longs and shorts. TVH ensures that by flipping operator signs based on orderType, after placeholder substitution.

Stop loss

orderTypeOperatorAuto-flipped toRationale
"sell"-+SL on a short sits above entry. entry - 0.02*entry would put it below — wrong side. Flip to + to push it above.
"buy"+-SL on a long sits below entry. Same logic mirrored.

Take profit

The flip is inverted for TP:

orderTypeOperatorAuto-flipped toRationale
"sell"+-TP on a short sits below entry.
"buy"-+TP on a long sits above entry.

One template, both directions

Write the expression as if for a long, and let TVH flip on sells:

stopLossExpression = "{{strategy.order.price}}-0.02*{{strategy.order.price}}"
takeProfitExpression = "{{strategy.order.price}}+0.04*{{strategy.order.price}}"

On a buy: SL = entry × 0.98, TP = entry × 1.04. Risk-reward 1:2.

On a sell: signs auto-flip. SL = entry × 1.02, TP = entry × 0.96. Same 1:2 R:R, mirrored.

Caveat: the flip is a literal string replace of -/+. If your expression has both operators in different roles (e.g. entry - 0.02*entry + 100), the flip replaces both occurrences, which may not be what you want. Keep expressions simple — one risk multiplier per expression.

Common patterns

Fixed % from entry

stopLossExpression: "{{strategy.order.price}}-0.02*{{strategy.order.price}}"

2% from entry. Equivalent to stopLossType="percent", stopLossPercent: 2.0 — but stored as an absolute on submission, which is what some adapters need for native conditional orders.

Risk-reward TP from a known SL

stopLossExpression: "{{strategy.order.price}}-0.01*{{strategy.order.price}}"
takeProfitExpression: "{{strategy.order.price}}+0.02*{{strategy.order.price}}"

SL at 1% below, TP at 2% above. 1:2 R:R.

ATR-based SL (Pine pre-computes ATR)

You can't reference atr(14) inside the expression — TVH doesn't know what that is. Instead, compute the ATR in Pine and pass the concrete number:

//@version=5
strategy("ATR SL example", overlay=true)
atr = ta.atr(14)
slDistance = atr * 1.5
slPrice = strategy.position_avg_price - slDistance

alert_message = '{"exchange":"binance-futures","pair":"' + syminfo.ticker + '","isBuy":true,"stopLossType":"absolute","stopLoss":' + str.tostring(slPrice) + ',"alertTimestamp":"' + syminfo.ticker + '-' + str.tostring(time) + '","token":"<token>"}'

if longCondition
strategy.entry("L", strategy.long, alert_message=alert_message)

Here Pine produces an already-computed stopLoss number. The expression machinery isn't used — you've moved the math to Pine. That's the right pattern when the math depends on indicator values.

Asymmetric SL/TP

stopLossExpression: "{{strategy.order.price}}-150"
takeProfitExpression: "{{strategy.order.price}}+450"

Fixed 150 below entry, 450 above. Works for any price level — the dollar offsets are absolute.

Error handling

The rule is simple: if the expression can't be evaluated, the error is swallowed silently. Invalid syntax, divide-by-zero, an unsupported operator — any of these means stopLoss keeps whatever value it had (usually 0), and the order is submitted with no stop loss.

There is no log of the parse failure on the user's side. The Activity Log shows the trade with stopLoss: 0, which looks like "stop loss not configured" — not "stop loss expression failed to parse".

Test before going live

Three good practices:

  1. Test on a demo account first. Send the exact payload from your Pine alert template to a demo account and verify the SL/TP arrived at the expected price. See Demo Accounts for the per-exchange setup.
  2. Echo the resolved expression in strategyComment. TradingView substitutes placeholders in any string field. Putting "sl_expr":"{{strategy.order.price}}-0.02*{{strategy.order.price}}" in the comment gives you a logged trace of the post-substitution string.
  3. Start with simple expressions. Two-operand expressions like entry - 0.02*entry are nearly impossible to mistype. Save complex ladder math for when you need it.

takeProfitExpression updates only targets[0]

For multi-target ladders, the expression updates only the first slot. Targets [1..n] keep whatever price value you sent.

If you want all targets computed from the entry price, set them explicitly in Pine:

tp1 = entryPrice + 0.005 * entryPrice
tp2 = entryPrice + 0.010 * entryPrice
tp3 = entryPrice + 0.020 * entryPrice

Then build the targets array in the JSON template directly. The expression field is a single-slot convenience, not a multi-target engine.

Detail per property

stopLossExpression

AttributeValue
Typestring
Requiredno
Default""
TV placeholder compatibleyes
Auto-mappedyes — sign-flipped, evaluated server-side, writes to stopLoss

Arithmetic expression. Only evaluated when stopLossType="absolute" and the string contains + - * /.

takeProfitExpression

AttributeValue
Typestring
Requiredno
Default""
TV placeholder compatibleyes
Auto-mappedyes — sign-flipped, evaluated server-side, writes to targets[0].price

Arithmetic expression. Only evaluated when targetType="absolute" and at least one entry exists in targets.

Common mistakes

  • stopLossExpression with stopLossType="percent". Ignored. Switch to "absolute".
  • Using ^ for exponentiation. Fails to evaluate — silently swallowed. Use x*x for squares.
  • Expression with both + and - in different roles. The sign-flip replaces all occurrences. entry - 100 + 50 on a sell becomes entry + 100 - 50. Keep expressions to a single risk operator.
  • takeProfitExpression on a payload with 3 targets. Only targets[0] is updated. The other two keep their original price values.
  • Forgetting that the expression must produce a price, not a percent. 0.02 * 65000 = 1300 (a number of dollars), not a price. Combine with the entry: 65000 - 0.02 * 65000.

Next

Examples — 12 complete Pine + JSON pairs, including math-expression patterns from this page.