Getting started
Set up PineBag once, then prepare your first test in a few minutes.
You need three things
- Google Chrome 116 or newer.
- A signed-in TradingView account with access to the symbols you want to test.
- A Pine Script file that declares
strategy(), not onlyindicator().
Install and open PineBag
-
Install the extension.
Use the PineBag install button. Pin the extension if you want quick access. -
Open a TradingView chart.
Sign in first, then open any supported market and timeframe. -
Reload the chart tab.
Do this after installing or updating PineBag so the chart can connect. -
Open PineBag.
Select the PineBag icon. The connection indicator turns green when the chart is ready.
The side panel, control by control
Numbers on the real interface match the explanations. Nothing in this image is a mock-up.
1
2
3
4
5
6
7
8
9
10
11
- 1Strategy
The loaded strategy. Click the card to open it in the editor; the bin in the section header removes it.
- 2Run summary
Timeframe, capital, order size and commission that will be used.
- 3Search
Opens TradingView symbol search so you can add an exchange-qualified ticker.
- 4Copy bag
Copies every ticker, one
EXCHANGE:SYMBOLper line. - 5Paste bag
Accepts lines, commas, semicolons or spaces and ignores duplicates.
- 6Clear
Asks for a second click, copies the tickers, then clears the list, so Paste tickers can bring it back.
- 7Ticker tags
Shows the current bag. Use × to remove one symbol; add up to 500.
- 8Run backtest
Validates the setup and starts the sequential portfolio run.
- 9Reports
Save the latest 50 reports locally and export JSON or CSV.
- 10Days remaining
Active days: 05— Days remaining. - 11Support
Support is available for technical, billing, licensing and privacy requests.
Load a strategy
- Choose the source.
Drop a.pinefile into Strategy, or open Editor and paste the code. - Fix any validation message.
The script must containstrategy(). PineBag shows a clear error if it cannot be used. - Check the summary.
Confirm the script name, timeframe, capital and order size shown above Run.
indicator(), convert it to a strategy before running PineBag.Strategy template
Every field in the TradingView Properties tab maps to a strategy() argument. Keep the values as named constants at the top of the script: with Script priority, every ticker runs with the same assumptions.
TIMEFRAMETimeframe
INITIAL_CAPITAL · CURRENCYInitial capital
ORDER_SIZE · ORDER_SIZE_TYPEDefault order size
PYRAMIDINGPyramiding
BAR_MAGNIFIERBar detalization
CALC_EVERY_TICK · CALC_ON_FILLSScript execution
COMMISSION · COMMISSION_TYPECommission
MARGIN_LONG · MARGIN_SHORTLong and short leverage
SLIPPAGESlippage
LIMIT_FILL_TICKSLimit order execution
FILL_ON_BAR_CLOSEOrder execution delay
runtime.error()Stops the script on any other timeframe.
//@version=6
// ============================================================================
// Trend breakout · ATR risk — PineBag strategy template
// ============================================================================
// ----------------------------------------------------------------------------
// STRATEGY PROPERTIES (TradingView: Settings → Properties)
// ----------------------------------------------------------------------------
// TIMEFRAME takes a standard TradingView interval. Paste one of these, by the
// lowest TradingView plan that has it (tradingview.com/pricing, Charts):
// Basic days "1D" "1W" "1M" "3M" "6M" "12M"
// Essential minutes "1" "3" "5" "15" "30" "45"
// hours "60" "120" "180" "240"
// ranges "1R" "10R" "100R" "1000R"
// Premium seconds "1S" "5S" "10S" "15S" "30S" "45S"
// Ultimate ticks "1T" "10T" "100T" "1000T"
// Other intervals are custom and not used: a week is "1W", not "7D".
const string TIMEFRAME = "1D" // Chart timeframe
const float INITIAL_CAPITAL = 100000 // Initial capital
const string CURRENCY = currency.USD // Initial capital currency
const float ORDER_SIZE = 100 // Default order size
const string ORDER_SIZE_TYPE = strategy.percent_of_equity // Order size: % of equity
const int PYRAMIDING = 1 // Pyramiding
const bool BAR_MAGNIFIER = false // Bar detalization: Default (4 ticks per bar)
const bool CALC_EVERY_TICK = false // Script execution: On bar close
const bool CALC_ON_FILLS = false // Script execution: no recalculation after fills
const float COMMISSION = 0 // Commission
const string COMMISSION_TYPE = strategy.commission.percent // Commission: Percent
const float MARGIN_LONG = 100 // Long leverage 1x (leverage = 100 / margin)
const float MARGIN_SHORT = 100 // Short leverage 1x
const int SLIPPAGE = 0 // Slippage, ticks
const int LIMIT_FILL_TICKS = 0 // Limit order execution: Requested price
const bool FILL_ON_BAR_CLOSE = false // Order execution delay: One tick
strategy("Trend breakout · ATR risk", overlay = true,
initial_capital = INITIAL_CAPITAL,
currency = CURRENCY,
default_qty_type = ORDER_SIZE_TYPE,
default_qty_value = ORDER_SIZE,
pyramiding = PYRAMIDING,
use_bar_magnifier = BAR_MAGNIFIER,
calc_on_every_tick = CALC_EVERY_TICK,
calc_on_order_fills = CALC_ON_FILLS,
commission_type = COMMISSION_TYPE,
commission_value = COMMISSION,
margin_long = MARGIN_LONG,
margin_short = MARGIN_SHORT,
slippage = SLIPPAGE,
backtest_fill_limits_assumption = LIMIT_FILL_TICKS,
process_orders_on_close = FILL_ON_BAR_CLOSE)
// Stops with a clear message on any other timeframe; PineBag reads TIMEFRAME
// and selects it for the run.
if timeframe.period != TIMEFRAME
runtime.error("Switch the chart to the " + TIMEFRAME + " timeframe.")
// ----------------------------------------------------------------------------
// INPUT SETTINGS (TradingView: Settings → Inputs)
// ----------------------------------------------------------------------------
fastLength = input.int(20, "Fast EMA", minval = 1)
slowLength = input.int(50, "Slow EMA", minval = 2)
breakoutLength = input.int(20, "Breakout lookback", minval = 2)
atrLength = input.int(14, "ATR length", minval = 1)
atrStop = input.float(2.0, "ATR stop multiplier", minval = 0.1, step = 0.1)
// ----------------------------------------------------------------------------
// CALCULATIONS
// ----------------------------------------------------------------------------
fast = ta.ema(close, fastLength)
slow = ta.ema(close, slowLength)
atr = ta.atr(atrLength)
highestBefore = ta.highest(high, breakoutLength)[1]
// ----------------------------------------------------------------------------
// ENTRIES AND EXITS
// ----------------------------------------------------------------------------
longSignal = fast > slow and close > highestBefore
if longSignal and strategy.position_size == 0
strategy.entry("Long", strategy.long)
stopPrice = strategy.position_avg_price - atr * atrStop
strategy.exit("ATR stop", "Long", stop = stopPrice)
// ----------------------------------------------------------------------------
// PLOTS
// ----------------------------------------------------------------------------
plot(fast, "Fast EMA", color = color.rgb(0, 153, 255))
plot(slow, "Slow EMA", color = color.rgb(123, 97, 255))
TIMEFRAME values
Write one of TradingView's standard intervals in quotes. Which of them load depends on your TradingView plan, as listed on tradingview.com/pricing.
Days, weeks and months.
"1D" "1W" "1M" "3M" "6M" "12M"
Minutes, hours and range bars. Minutes have no letter; one hour is 60.
"1" "3" "5" "15" "30" "45""60" "120" "180" "240""1R" "10R" "100R" "1000R"
Second-based intervals.
"1S" "5S" "10S" "15S" "30S" "45S"
Tick-based intervals.
"1T" "10T" "100T" "1000T"
const string TIMEFRAME = "1D" // 1 day
// const string TIMEFRAME = "1W" // 1 week
// const string TIMEFRAME = "240" // 4 hours
// const string TIMEFRAME = "15" // 15 minutes
// const string TIMEFRAME = "30S" // 30 seconds, Premium and higher
Order size: percent, cash or quantity
ORDER_SIZE holds the number and ORDER_SIZE_TYPE says what it means. Together they fill the Order size field of the TradingView Properties tab.
strategy.percent_of_equity
A percent of current equity. 10 means 10% of equity per trade.
strategy.cash
An amount in the strategy currency. 1000 means 1,000 USD per trade.
strategy.fixed
A number of contracts, shares or coins. 0.5 means 0.5 BTC per trade.
qty = …
The default size applies only to orders without their own qty. An entry with qty = … uses that value instead.
// 10% of equity per trade
const float ORDER_SIZE = 10
const string ORDER_SIZE_TYPE = strategy.percent_of_equity
// 1,000 USD per trade (CURRENCY = currency.USD)
// const float ORDER_SIZE = 1000
// const string ORDER_SIZE_TYPE = strategy.cash
// 0.5 contracts, shares or coins per trade
// const float ORDER_SIZE = 0.5
// const string ORDER_SIZE_TYPE = strategy.fixed
Your own variables
Keep the settings of your own strategy logic in a separate INPUT SETTINGS block. Each input.int(), input.float() or input.bool() call becomes a field in the TradingView Inputs tab, so you can tune it without editing the code.
// ----------------------------------------------------------------------------
// INPUT SETTINGS (TradingView: Settings → Inputs)
// ----------------------------------------------------------------------------
fastLength = input.int(20, "Fast EMA", minval = 1)
slowLength = input.int(50, "Slow EMA", minval = 2)
breakoutLength = input.int(20, "Breakout lookback", minval = 2)
atrLength = input.int(14, "ATR length", minval = 1)
atrStop = input.float(2.0, "ATR stop multiplier", minval = 0.1, step = 0.1)