🎯

pine-backtester

🎯Skill

from traderspost/pinescript-agents

VibeIndex|
What it does

pine-backtester skill from traderspost/pinescript-agents

πŸ“¦

Part of

traderspost/pinescript-agents(7 items)

pine-backtester

Installation

git cloneClone repository
git clone https://github.com/tosaha/pinescript-agents.git
pip installInstall dependencies
pip install -r requirements.txt
πŸ“– Extracted from docs: traderspost/pinescript-agents
8Installs
42
-
Last UpdatedJan 8, 2026

Skill Details

SKILL.md

Implements comprehensive backtesting capabilities for Pine Script indicators and strategies. Use when adding performance metrics, trade analysis, equity curves, win rates, drawdown tracking, or statistical validation. Triggers on "backtest", "performance", "metrics", "win rate", "drawdown", or testing requests.

Overview

# Pine Script Backtester

Specialized in adding comprehensive testing and validation capabilities to Pine Script indicators and strategies.

Core Responsibilities

Strategy Performance Metrics

  • Win rate and profit factor
  • Maximum drawdown analysis
  • Sharpe and Sortino ratios
  • Risk-adjusted returns
  • Trade distribution analysis

Indicator Accuracy Testing

  • Signal accuracy measurements
  • False positive/negative rates
  • Lag analysis
  • Divergence detection accuracy
  • Multi-timeframe validation

Statistical Analysis

  • Monte Carlo simulations
  • Walk-forward analysis
  • Confidence intervals
  • Statistical significance tests
  • Correlation analysis

Backtesting Components

1. Comprehensive Strategy Metrics Table

```pinescript

// Strategy Performance Metrics

var table metricsTable = table.new(position.bottom_right, 2, 15, bgcolor=color.new(color.black, 90))

if barstate.islastconfirmedhistory

wins = strategy.wintrades

losses = strategy.losstrades

totalTrades = wins + losses

winRate = totalTrades > 0 ? (wins / totalTrades) * 100 : 0

avgWin = strategy.grossprofit / math.max(wins, 1)

avgLoss = math.abs(strategy.grossloss) / math.max(losses, 1)

profitFactor = avgLoss > 0 ? avgWin / avgLoss : 0

// Drawdown calculation

var float maxEquity = strategy.initial_capital

var float maxDrawdown = 0.0

currentEquity = strategy.equity

if currentEquity > maxEquity

maxEquity := currentEquity

drawdown = ((maxEquity - currentEquity) / maxEquity) * 100

maxDrawdown := math.max(maxDrawdown, drawdown)

// Populate table

table.cell(metricsTable, 0, 0, "METRIC", bgcolor=color.gray, text_color=color.white)

table.cell(metricsTable, 1, 0, "VALUE", bgcolor=color.gray, text_color=color.white)

table.cell(metricsTable, 0, 1, "Total Trades", text_color=color.white)

table.cell(metricsTable, 1, 1, str.tostring(totalTrades), text_color=color.yellow)

table.cell(metricsTable, 0, 2, "Win Rate", text_color=color.white)

table.cell(metricsTable, 1, 2, str.tostring(winRate, "#.##") + "%", text_color=winRate > 50 ? color.green : color.red)

table.cell(metricsTable, 0, 3, "Profit Factor", text_color=color.white)

table.cell(metricsTable, 1, 3, str.tostring(profitFactor, "#.##"), text_color=profitFactor > 1 ? color.green : color.red)

table.cell(metricsTable, 0, 4, "Max Drawdown", text_color=color.white)

table.cell(metricsTable, 1, 4, str.tostring(maxDrawdown, "#.##") + "%", text_color=maxDrawdown < 20 ? color.green : color.red)

table.cell(metricsTable, 0, 5, "Net Profit", text_color=color.white)

netProfit = strategy.netprofit

table.cell(metricsTable, 1, 5, str.tostring(netProfit, "#,###.##"), text_color=netProfit > 0 ? color.green : color.red)

```

2. Trade Distribution Analysis

```pinescript

// Trade distribution tracking

var array tradeReturns = array.new()

var array tradeDurations = array.new()

var int tradeStartBar = 0

if strategy.position_size != strategy.position_size[1]

if strategy.position_size != 0

// Trade entry

tradeStartBar := bar_index

else

// Trade exit

tradeReturn = (strategy.equity - strategy.equity[bar_index - tradeStartBar]) / strategy.equity[bar_index - tradeStartBar] * 100

array.push(tradeReturns, tradeReturn)

array.push(tradeDurations, bar_index - tradeStartBar)

// Calculate distribution stats

if barstate.islastconfirmedhistory and array.size(tradeReturns) > 0

avgReturn = array.avg(tradeReturns)

stdReturn = array.stdev(tradeReturns)

medianReturn = array.median(tradeReturns)

maxReturn = array.max(tradeReturns)

minReturn = array.min(tradeReturns)

// Display distribution

table.cell(metricsTable, 0, 6, "Avg Return", text_color=color.white)

table.cell(metricsTable, 1, 6, str.tostring(avgReturn, "#.##") + "%", text_color=avgReturn > 0 ? color.green : color.red)

table.cell(metricsTable, 0, 7, "Std Dev", text_color=color.white)

table.cell(metricsTable, 1, 7, str.tostring(stdReturn, "#.##") + "%", text_color=color.yellow)

```

3. Sharpe Ratio Calculation

```pinescript

// Sharpe Ratio calculation

var array returns = array.new()

var float previousEquity = strategy.initial_capital

if bar_index > 0

currentReturn = (strategy.equity - previousEquity) / previousEquity

array.push(returns, currentReturn)

if array.size(returns) > 252 // Keep 1 year of daily returns

array.shift(returns)

previousEquity := strategy.equity

if barstate.islastconfirmedhistory and array.size(returns) > 30

avgReturn = array.avg(returns) * 252 // Annualized

stdReturn = array.stdev(returns) * math.sqrt(252) // Annualized

riskFreeRate = 0.02 // 2% risk-free rate

sharpeRatio = stdReturn > 0 ? (avgReturn - riskFreeRate) / stdReturn : 0

table.cell(metricsTable, 0, 8, "Sharpe Ratio", text_color=color.white)

table.cell(metricsTable, 1, 8, str.tostring(sharpeRatio, "#.##"), text_color=sharpeRatio > 1 ? color.green : sharpeRatio > 0 ? color.yellow : color.red)

```

4. Indicator Accuracy Testing

```pinescript

// For indicators: Track signal accuracy

var int truePositives = 0

var int falsePositives = 0

var int trueNegatives = 0

var int falseNegatives = 0

// Define what constitutes a successful signal (example: price moves 1% in signal direction)

targetMove = input.float(1.0, "Target Move %", group="Backtest Settings")

lookforward = input.int(10, "Bars to Confirm", group="Backtest Settings")

if barstate.isconfirmed and bar_index > lookforward

// Check if past signal was correct

if buySignal[lookforward]

priceChange = (close - close[lookforward]) / close[lookforward] * 100

if priceChange >= targetMove

truePositives += 1

else

falsePositives += 1

else if sellSignal[lookforward]

priceChange = (close[lookforward] - close) / close[lookforward] * 100

if priceChange >= targetMove

trueNegatives += 1

else

falseNegatives += 1

// Display accuracy metrics

if barstate.islastconfirmedhistory

accuracy = (truePositives + trueNegatives) / math.max(truePositives + trueNegatives + falsePositives + falseNegatives, 1) * 100

precision = truePositives / math.max(truePositives + falsePositives, 1) * 100

recall = truePositives / math.max(truePositives + falseNegatives, 1) * 100

table.cell(metricsTable, 0, 9, "Signal Accuracy", text_color=color.white)

table.cell(metricsTable, 1, 9, str.tostring(accuracy, "#.##") + "%", text_color=accuracy > 60 ? color.green : color.red)

```

5. Equity Curve Visualization

```pinescript

// Plot equity curve (for strategies)

plot(strategy.equity, "Equity Curve", color=color.blue, linewidth=2)

// Add drawdown visualization

equityMA = ta.sma(strategy.equity, 20)

plot(equityMA, "Equity MA", color=color.orange, linewidth=1)

// Underwater equity (drawdown visualization)

var float peakEquity = strategy.initial_capital

peakEquity := math.max(peakEquity, strategy.equity)

drawdownValue = (peakEquity - strategy.equity) / peakEquity * 100

// Plot drawdown as histogram

plot(drawdownValue, "Drawdown %", color=color.red, style=plot.style_histogram, histbase=0)

```

6. Multi-Timeframe Validation

```pinescript

// Test indicator on multiple timeframes

htf1_signal = request.security(syminfo.tickerid, "60", buySignal)

htf2_signal = request.security(syminfo.tickerid, "240", buySignal)

htf3_signal = request.security(syminfo.tickerid, "D", buySignal)

// Confluence scoring

confluenceScore = 0

confluenceScore += buySignal ? 1 : 0

confluenceScore += htf1_signal ? 1 : 0

confluenceScore += htf2_signal ? 1 : 0

confluenceScore += htf3_signal ? 1 : 0

// Track confluence performance

var array confluenceReturns = array.new()

if confluenceScore >= 3 and barstate.isconfirmed

// Track returns when high confluence

futureReturn = (close[10] - close) / close * 100 // 10-bar forward return

array.push(confluenceReturns, futureReturn)

```

7. Walk-Forward Analysis

```pinescript

// Simple walk-forward testing

lookbackPeriod = input.int(100, "Training Period", group="Walk-Forward")

forwardPeriod = input.int(20, "Testing Period", group="Walk-Forward")

// Optimize parameters on lookback period

var float optimalParam = na

if bar_index % (lookbackPeriod + forwardPeriod) == 0

// Re-optimize parameters based on past performance

// This is simplified - real implementation would test multiple values

optimalParam := ta.sma(close, lookbackPeriod) > close ? 20 : 50

// Use optimized parameters

maLength = int(optimalParam)

ma = ta.sma(close, maLength)

```

Testing Checklist

  • [ ] Net profit/loss calculation
  • [ ] Win rate and trade count
  • [ ] Maximum drawdown tracking
  • [ ] Risk-adjusted returns (Sharpe/Sortino)
  • [ ] Trade distribution analysis
  • [ ] Equity curve visualization
  • [ ] Signal accuracy for indicators
  • [ ] Multi-timeframe validation
  • [ ] Statistical significance tests
  • [ ] Forward testing results

Output Format

Always provide:

  1. Performance metrics table
  2. Equity curve visualization
  3. Drawdown analysis
  4. Trade distribution stats
  5. Risk metrics
  6. Recommendations for improvement

Backtesting in Pine Script has limitations. Past performance doesn't guarantee future results. Always include appropriate disclaimers.