Dynamic Position Sizing for TradingView Webhook Bots
Percent-of-Equity vs Fixed Quantity
Say your backtest runs with a $100,000 initial_capital, and default_qty_type is set to strategy.percent_of_equity at 10%. Your real exchange account has $2,000 in it. When the alert fires and the webhook lands on your execution server, what quantity does it actually send?
The short answer: TradingView computes that quantity as 10% of strategy.equity — and strategy.equity is a number the Pine strategy simulates entirely on TradingView's servers. It has no idea your real account holds $2,000. The quantity in the alert is sized off the backtest's internal balance, not the balance sitting at your exchange.
That single line of the strategy declaration is the thing worth getting right, and it's exactly the kind of detail an AI will pick for you silently if you don't say which one you want. So this post is short on syntax and long on two things: how to tell an AI which sizing behaviour you actually need, and how to check the code it gave you before real money is involved. There's a copy-paste prompt further down.
default_qty_type and strategy.equity work. It does not, anywhere, discuss how that relates to your real exchange balance — because there is no connection. That gap is the entire reason position sizing trips up people wiring TradingView alerts into live execution.The one setting that decides your order size
When you declare a strategy, the strategy() call takes a default_qty_type parameter with exactly three legal values, plus a default_qty_value that means something different under each one. Find that line in whatever code you've been handed — it's near the top — and read it against this table. That's the whole check.
| default_qty_type | Unit of default_qty_value | What it means |
|---|---|---|
strategy.fixed | Contracts / shares / lots | The default. A flat number of units per entry. |
strategy.cash | Account currency amount | A cash amount in strategy.account_currency. Quantity is derived as default_qty_value / close — TradingView's own docs give the example: at a $5 close price, a value of 50 yields qty = 50 / 5 = 10. |
strategy.percent_of_equity | Percentage (0–100) | A percentage of strategy.equity — the strategy's current simulated equity — used to size the entry. |
Source: Pine Script Reference Manual v6, strategy() and the three default_qty_type constants (verified July 2026).
One more detail worth knowing: if a strategy.entry() or strategy.order() call passes an explicit, non-na qty argument, that value overrides default_qty_type/default_qty_value entirely for that order — the strategy-level default only applies when no qty is given on the call itself. TradingView's own docs demonstrate this with an example where a strategy declares default_qty_type = strategy.cash but the entry call still supplies its own qty, and the default setting is simply ignored for that trade.
That override matters when you're reviewing generated code, because it means the declaration line at the top can say one thing while the order calls quietly do another. It's worth asking as a flat question: "Does any entry or order call in this script pass its own qty? List them."
Why "10% of equity" isn't 10% of your money
The official definition, verbatim, from the Pine Script Reference Manual — this is here so you recognize it, not so you memorize it:
strategy.equity = strategy.initial_capital + strategy.netprofit + strategy.openprofitnetprofit is cumulative realized profit and loss from closed trades; openprofit is unrealized profit and loss on whatever position is currently open. Both change on every bar as trades close and prices move, which makes strategy.equity a moving series — it can be a different value on almost every bar.
This is also why percent_of_equity sizing compounds by construction. A default_qty_value of 10 always means "10% of whatever strategy.equity is on this bar." After a run of profitable closed trades, equity is larger, so the same 10% now resolves to a bigger absolute quantity. After losses, the opposite happens. TradingView's own Commission Demo example strategy uses exactly this setting (default_qty_value = 2, default_qty_type = strategy.percent_of_equity) specifically to illustrate a position that scales with equity as it changes.
strategy.equity relates to the balance in your actual exchange account. Based on the definition above — initial_capital is a number you type into the strategy() declaration, and netprofit/openprofit are simulated purely on TradingView's servers — it can reasonably be inferred that strategy.equity has no connection to your real account balance. That's an inference from the official definition, not a line TradingView states directly.Which one to ask for, and what each one costs you
Neither mode is "correct." They optimize for different things, and the trade-off is worth seeing side by side rather than guessing which one a backtest happens to look better with. Read this as a menu: whichever column you want is the one you name in your prompt.
| percent_of_equity | fixed | |
|---|---|---|
| Order size scales as equity changes | ||
| Order size is predictable in absolute units ahead of time | ||
| Depends on a simulated internal balance you don't control at runtime | ||
| Needs manual resizing as your real account grows or shrinks | ||
| Backtest and live orders can diverge if simulated equity and real balance are far apart |
Read the trade-off as what each one depends on: percent_of_equity scales, but only against a number TradingView simulates internally; fixed is predictable, but never adjusts to your account on its own. That dependency is what decides whether the number in your webhook payload means what you think it means.
The prompts: asking for it, then checking it
Asking for it
The version below asks for fixed quantity and pushes the sizing decision to the execution side, which is the setup that doesn't depend on a simulated balance. If you want the opposite, swap the sizing paragraph — the point is that you say which one, and say why, rather than leaving it to be picked for you:
Write me a Pine Script v6 strategy for TradingView. It will fire a webhook into
a live exchange account.
Strategy logic: [describe your entries and exits in plain language]
Position sizing — this part is not negotiable:
- Use default_qty_type = strategy.fixed with default_qty_value = 1.
Do NOT use strategy.percent_of_equity. Reason: percent_of_equity sizes the
order off strategy.equity, which is a simulated backtest balance, and my
real exchange account is a different size. I do not want the backtest's
number reaching my exchange.
- Do not pass a qty argument on any strategy.entry() or strategy.order() call
unless I explicitly ask for one. If you do pass one anywhere, say so.
- The alert message must be one single line of valid JSON containing the
action ({{strategy.order.action}}) plus these fields and nothing else:
[paste the field list your receiver expects]
Do NOT include {{strategy.order.contracts}} — my execution server decides
the quantity, not TradingView.
Finish by telling me in one line each: what default_qty_type you used, what
default_qty_value means under that setting, and whether any order call
overrides them.The reason for spelling out the "why" in the sizing bullet isn't politeness — it stops the reply from helpfully switching you back to percent_of_equity because the backtest curve looks nicer that way.
Checking what you got back
Paste the code back with this. It's four questions, and you already know what three of the answers should be from the sections above — which is the point:
Here is my strategy. Answer these before changing anything:
1. What is default_qty_type set to, and what does default_qty_value mean
under that setting?
2. Does any strategy.entry() or strategy.order() call pass its own qty?
List them — those override the strategy-level default for that order.
3. If I run this with initial_capital = 100000 but my real exchange account
holds 2000, what number ends up in {{strategy.order.contracts}}?
4. Which fields in my alert message are derived from the simulated backtest
balance rather than from my real account?
[paste your script here]Question 3 is the one to watch. An answer that works through the quantity from initial_capital understands the setup. An answer that says the strategy will size against your $2,000 does not, and anything else in that reply is worth re-checking.
Telling the AI what to put in the alert message
These are the placeholders TradingView's official docs list for strategy order-fill events — the only place quantity data is exposed to an alert message. You're not writing these by hand; you're naming the ones you want in your prompt, and checking that what came back uses those and only those:
| Placeholder | What it resolves to |
|---|---|
{{strategy.order.contracts}} | The quantity filled on that specific order |
{{strategy.position_size}} | Current position size at the moment of trigger, signed (+long / −short) |
{{strategy.market_position_size}} | Current position size, absolute value |
{{strategy.prev_market_position_size}} | Previous position size, absolute value |
{{strategy.order.action}} | "buy" or "sell" |
{{strategy.order.price}} | Fill price |
{{strategy.order.alert_message}} | Custom text passed to the alert_message argument of that specific strategy.entry()/strategy.exit()/strategy.order() call |
Strategy order-fill event placeholders only — not usable inside alertcondition() or standalone alert() messages. Source: Pine Script user manual, Strategies / Strategy alerts (verified July 2026).
Worth flagging on {{strategy.order.alert_message}}: the official docs are explicit that this placeholder is only replaced with your custom text if the specific order-generating call actually passed an alert_message argument. If your strategy has several strategy.entry()/strategy.order() calls and only some of them set alert_message, the placeholder resolves to an empty string for the ones that didn't.
Which is a specific, checkable thing to ask for: "If you use {{strategy.order.alert_message}} anywhere in the alert message, confirm that every single order call in this script passes an alert_message argument." An empty field in a JSON payload is the kind of thing that breaks a receiver at 3am rather than at review time.
One: the
alert() call in the code. The message is assembled by the script itself, so you don't retype it in the dialog.Two: the
alert_message= argument on an order function. That text only surfaces when an order-fill event fires and the message uses {{strategy.order.alert_message}}.Three: the Message field in TradingView's Create Alert dialog. This is the only place
{{strategy.*}} placeholders work, and only when the alert was created from a strategy.The click-by-click version — chart top-right clock, Add Alert, Condition = your strategy, Notifications tab, Webhook URL — is walked through in Writing Pine Script With Claude.
The one decision no AI can make for you
Given that percent_of_equity is computed against a simulated balance, and fixed/cash don't know your account size at all, there's a real design decision in any TradingView-to-exchange automation: does TradingView decide the final order quantity, or does the execution server?
This is where the two layers of the problem meet. Everything above is about how TradingView decides what number to put in the alert. Once that number — or just a signal direction — lands on an execution server, there's a second, separate layer: how that server turns it into an actual exchange order, including how leverage interacts with margin and notional size. That second layer is covered in detail in our qty_type semantic trap article — worth reading once you've settled who computes the quantity, since it explains what happens to that number after it arrives.
TVSBot's execution side, for example, resolves quantity at order time using one of five sizing modes (fixed / usdt / percent / margin_pct / margin_usdt) rather than simply forwarding a number computed from a backtest's simulated equity. Two of those — percent and margin_pct — query your real, current exchange balance at order time and size from that. usdt and margin_usdt convert a USDT figure you specify using the live ticker price, and fixed sends the coin quantity you gave it as-is.
To see what a mode actually resolves to before real capital is at stake, dry-run mode runs the strategy against a virtual balance and shows the number that would have been sent. Per-account risk settings — max amount per trade, max percent per trade, max open positions, a daily loss limit, a max leverage cap — plus a one-click kill switch sit around whatever sizing logic feeds the order.
FAQ
Does percent_of_equity automatically account for my real exchange balance?
strategy.percent_of_equity sizes orders as a percentage of strategy.equity, which is officially defined as initial_capital + netprofit + openprofit — all three of those are simulated inside the Pine strategy, not looked up from your exchange account. TradingView's docs don't describe any mechanism for reading a real account balance.Can I just tell the AI to size positions off my real exchange balance?
strategy.equity — possibly with initial_capital set to a number that happens to match your account today, which drifts apart again as soon as the simulated equity compounds. Sizing against a live balance has to happen after the alert, on the execution side.If I set default_qty_type to strategy.fixed, will the quantity ever change on its own?
strategy.fixed uses a flat number of contracts/shares/lots defined by default_qty_value. It won't grow or shrink with account performance unless you change the input yourself.Can I pass qty directly in strategy.entry() instead of relying on default_qty_type?
na qty argument on strategy.entry() or strategy.order() takes precedence over the strategy-level default_qty_type/default_qty_value settings entirely, for that specific order.Which placeholder gives me the quantity that was actually filled?
{{strategy.order.contracts}} resolves to the quantity filled on that specific order. It's only available in strategy order-fill event alerts, not in alertcondition() or standalone alert() messages.Should quantity be decided on the TradingView side or the execution side?
initial_capital.Get started
TVSBot is a non-custodial bridge from TradingView alerts to 7 exchanges — your API keys, your funds. Percent-based sizing modes resolve against your real, live balance at order time, with dry-run testing and per-account risk limits.
Start free