How to Get the Current Position in TradingView Pine Script?

Understanding and managing your trading position is fundamental to strategy development in Pine Script. While it might seem straightforward to query the platform for your current position size, Pine Script’s execution model on the current bar introduces nuances that require a specific approach.

Introduction to Position Sizing in Pine Script

Position sizing determines the number of units (shares, contracts, etc.) you trade in a given strategy execution. It’s a critical component of risk management, directly impacting potential profits and losses per trade.

Why Understanding Position Sizing is Crucial

Effective position sizing is paramount because it allows you to control your exposure to market fluctuations. Without proper sizing, even highly profitable entry/exit signals can lead to catastrophic losses due to excessive risk taken on a single trade. Dynamic sizing techniques, which adjust position size based on market conditions (like volatility) or account equity, can significantly improve strategy performance and robustness.

Limitations of Direct Position Data Access in Pine Script

A common point of confusion for new Pine Script strategists is accessing the current position on the bar currently being processed. Pine Script strategies execute bar by bar. When your script is processing the data for the current bar, functions like strategy.position_size reflect the position at the close of the previous bar. Any orders placed on the current bar (via strategy.entry, strategy.exit, strategy.close) are typically processed after the script finishes its calculations for that bar. Therefore, strategy.position_size on the current bar does not immediately update to reflect orders sent on that same bar.

To know the intended position size and direction after the logic on the current bar has been evaluated but before the bar closes (and orders fill), you cannot rely solely on strategy.position_size. You must simulate and track the position state within your script’s variables.

Simulating Position Tracking in Pine Script

Since strategy.position_size lags by one bar for decisions made on the current bar, the standard and necessary practice in Pine Script strategies is to track the position state using internal variables. This simulation allows your script to make decisions based on its intended actions for the current bar.

Using strategy.entry and strategy.exit for Order Management

The foundation of position tracking lies in correctly using the strategy order functions:

  • strategy.entry: Initiates or increases a position.
  • strategy.exit: Exits part or all of a position, often linked to an entry by id.
  • strategy.close: Closes an entire open position.
  • strategy.cancel: Cancels pending orders.

Proper use of these functions is necessary, but not sufficient alone, to know your simulated state on the current bar.

Creating Variables to Track Position State (Long/Short/Flat)

You need to maintain state variables that represent your script’s understanding of the current position. Boolean variables are effective for tracking direction:

var bool inLong  = false
var bool inShort = false

These variables are updated based on the conditions that trigger your strategy.entry or strategy.close calls. For example, when your condition for a long entry is met, you set inLong = true and inShort = false before calling strategy.entry. When your exit condition for the long position is met, you set inLong = false before calling strategy.close or strategy.exit.

Simulating the position size requires a numerical variable, typically representing the number of units:

var float currentSimulatedSize = 0.0

This variable needs to be updated alongside your boolean flags based on the quantity sent in strategy.entry and the quantity exited in strategy.exit/strategy.close.

Calculating Position Size Based on Risk and Capital

Professional strategies calculate position size dynamically based on account equity, risk per trade (e.g., 1% of equity), and the stop-loss distance. The formula is typically:

Units = (Account Equity * Risk %) / (Stop Loss Distance * Value per Unit)

Example calculation (simplified, assuming fixed $ stop loss distance and $ value per point):

capital = strategy.initial_capital + strategy.net_profit
riskPercent = 0.01 // Risk 1% of equity per trade
stopLossPrice = low - 5 * syminfo.mintick // Example stop 5 ticks below entry
entryPrice = close
stopLossDistance = entryPrice - stopLossPrice // Assuming long position
valuePerUnit = syminfo.pointvalue // Value of one unit movement of 1 price tick/point

// Avoid division by zero or tiny stops
if stopLossDistance > 0
    // Calculate raw quantity
    rawQty = (capital * riskPercent) / (stopLossDistance * valuePerUnit)

    // Round or normalize quantity based on instrument requirements (e.g., lot size, shares)
    // For simplicity, let's assume integer shares
    calculatedQty = math.max(1, math.floor(rawQty)) // Ensure at least 1 unit
else
    calculatedQty = 0

// Use calculatedQty in strategy.entry
// strategy.entry("Long", strategy.long, qty = calculatedQty, when = entryCondition)

This calculatedQty is what you would use for the qty argument in strategy.entry. Your simulated position size variable (currentSimulatedSize) would then be updated by this calculatedQty when the entry condition is met.

Implementing a Simple Position Tracker

Let’s build a basic example demonstrating how to track a long/short position using variables and placing orders.

Example Code: Tracking Long and Short Entries

This snippet shows how to use boolean variables to manage state and how strategy.position_size differs from the simulated state on the current bar.

//@version=5
strategy("Simple Position Tracker", overlay=true)

// --- State Variables ---
var bool inLongEntry  = false
var bool inShortEntry = false
var float currentSimulatedSize = 0.0

// --- Parameters ---
longEntryCondition = ta.crossover(close, ta.sma(close, 20))
shortEntryCondition = ta.crossunder(close, ta.sma(close, 20))
exitCondition = ta.crossunder(close, ta.sma(close, 10)) or ta.crossover(close, ta.sma(close, 10))

// --- Position Sizing (Simple Fixed Quantity) ---
fixedQty = 100

// --- Strategy Logic and State Update ---

// Reset state at the start of a potential reversal or exit
// This logic assumes only one position direction at a time
if (exitCondition)
    if inLongEntry
        strategy.close("Long")
        inLongEntry := false
        currentSimulatedSize := 0.0
    if inShortEntry
        strategy.close("Short")
        inShortEntry := false
        currentSimulatedSize := 0.0

// Entry logic - only if currently flat
if not inLongEntry and not inShortEntry
    if longEntryCondition
        strategy.entry("Long", strategy.long, qty = fixedQty)
        inLongEntry := true
        currentSimulatedSize := fixedQty
    else if shortEntryCondition
        strategy.entry("Short", strategy.short, qty = fixedQty)
        inShortEntry := true
        currentSimulatedSize := fixedQty

// --- Display Status (Optional) ---
plotchar(inLongEntry, title="In Long (Simulated)", char='L', color=color.green, location=location.top)
plotchar(inShortEntry, title="In Short (Simulated)", char='S', color=color.red, location=location.top)

// Note: strategy.position_size here reflects the position *before* orders on this bar fill
// plotchar(strategy.position_size > 0, title="In Long (Actual)", char='L', color=color.lime, location=location.bottom)
// plotchar(strategy.position_size < 0, title="In Short (Actual)", char='S', color=color.orange, location=location.bottom)

In this code, inLongEntry and inShortEntry tell you the script’s intention or simulated state on the current bar. currentSimulatedSize tracks the quantity based on the fixedQty used in the entry. strategy.position_size, if plotted, would show the position state at the start of the bar’s calculation.

Displaying Position Status on the Chart

Using plotchar or plotshape based on your state variables (inLongEntry, inShortEntry) is an excellent way to visualize your simulated position on the chart. This helps in debugging and understanding exactly when your script believes it is in a position.

// Inside the previous example code, after the logic:
plotchar(inLongEntry, title="Simulated Long", char='▲', color=color.green, location=location.belowbar, size=size.small)
plotchar(inShortEntry, title="Simulated Short", char='▼', color=color.red, location=location.abovebar, size=size.small)
plot(currentSimulatedSize, title="Simulated Size", display=display.data_window) // Show size in data window

These plots provide immediate visual confirmation of your script’s internal state tracking.

Handling Position Flips and Reversals

Special care is needed when your strategy allows flipping from a long position directly into a short position (or vice versa) on the same bar. The simple example above includes logic to strategy.close the current position before potentially entering a new one. This ensures that the state variables are correctly reset (currentSimulatedSize = 0.0) before being updated with the size of the new opposing entry.

Without correctly handling flips, your simulated size and direction variables can become out of sync with the actual orders placed, leading to unpredictable behavior and incorrect backtest results.

Advanced Position Management Techniques

Beyond fixed position sizing, advanced strategies employ dynamic methods.

Scaling In and Out of Positions

Scaling involves adding to (scaling in) or partially reducing (scaling out) an existing position. This is managed by calling strategy.entry multiple times with the same id (for scaling in) or strategy.exit with a specific qty (for scaling out) while tracking the total position size in your simulated variables.

If you have a long position and your scaling-in condition is met, you would calculate the additional quantity, call strategy.entry("Long", strategy.long, qty = additionalQty), and then add additionalQty to your currentSimulatedSize variable.

Dynamic Position Sizing Based on Volatility (ATR)

Using indicators like Average True Range (ATR) allows you to size positions based on market volatility. Higher volatility implies a larger stop-loss distance, thus requiring a smaller position size for the same risk percentage. Conversely, lower volatility allows for larger positions.

The calculation shown earlier Units = (Account Equity * Risk %) / (Stop Loss Distance * Value per Unit) is the standard approach. You would calculate stopLossDistance based on current price and a multiple of ATR (e.g., close - 2 * ta.atr(14) for a long stop) and use this in the formula to derive calculatedQty for each trade.

Combining Multiple Indicators for Position Decisions

Complex strategies often use multiple indicators to build conviction before entering or scaling a position. Your state tracking variables (inLongEntry, inShortEntry) and size calculation logic become conditional on combinations of indicator signals. Ensure your state update logic correctly reflects the outcome of these combined signals and the orders placed as a result.

Limitations and Considerations

While simulating position tracking in Pine Script is essential, it’s not without limitations.

Backtesting vs. Real-World Trading: Slippage and Commissions

The simulated position size and state in your script assume perfect order fills at the exact price and quantity requested. In real-world trading, slippage and partial fills are common. strategy.position_size does reflect the actual filled position in the backtest results, but remember its lag for decisions on the current bar.

Therefore, your simulated state is an ideal state based on your strategy’s logic, while strategy.position_size reflects the actual state resulting from the backtester’s (or broker’s) fill engine. Significant discrepancies between the two in backtests might indicate issues with order type assumptions or realistic fill modeling.

Importance of Accurate Backtesting Data

The accuracy of your backtest, including the simulated position size, depends heavily on the quality and resolution of the historical data. Use high-resolution data where available and ensure you understand how Pine Script backtests handle specific order types (market, limit, stop) on historical bars.

The Risk of Over-Optimization

When implementing complex position sizing or scaling logic, be wary of over-optimization. Tuning parameters (like ATR lookback or risk percentage) too tightly to historical data can lead to strategies that perform poorly on unseen data. Robust position sizing principles, rather than hyper-optimized parameters, usually yield more reliable results.

In conclusion, while Pine Script doesn’t offer a simple getPosition() function for the current bar’s logic, effectively tracking your position through diligent variable management based on your order placement conditions is the standard and powerful way to build sophisticated and risk-aware trading strategies.


Leave a Reply