When to convert Pine Script to Python (and when it's a waste of a weekend)
Thinking of converting Pine Script to Python? Most traders don't need to. Here's when the rewrite is worth it, when it isn't, and what to do instead.
11 min read
In this article ▾
- Why do people want to convert Pine Script to Python in the first place
- Pine Script and Python are not the same kind of tool
- You lose the chart, and this matters more than people admit
- When converting Pine Script to Python is the right call
- When people think they need to convert, but don’t
- Pine Script to Python conversion: the actual work involved
- Skip the rewrite: how FillEdge does it instead
- When you’ll regret converting six months later
- FAQ
Someone wrote a working Pine Script strategy, hit a wall, googled “convert Pine Script to Python,” and is now three tabs deep in backtesting.py documentation. If that’s you, close two of those tabs.
Most people who start down this road don’t need to finish it. The rewrite is real work, a weekend minimum, plus $0 in “saved” bridge fees that turn into 20+ hours of maintenance a year. A few cases genuinely do warrant converting. This post sorts one from the other.
Why do people want to convert Pine Script to Python in the first place
The decision to convert Pine Script to Python has a dozen different underlying problems. The most common ones:
- You need data that TradingView doesn’t have — tick data, full order book, alternative data for signals.
- You want to layer ML on top of a strategy, and Pine Script doesn’t do that.
- Your broker isn’t in TradingView’s native integration list, and you want to execute directly.
- You looked at webhook bridges, saw they cost money, and were told, “Just do it in Python for free.”
- You want to backtest on something more granular than what Pine offers.
- Someone told you Pine Script is “limited,” and you assumed Python was the adult version.
Only two or three of those are actually solved by converting. The rest have cheaper answers.
Pine Script and Python are not the same kind of tool
Pine Script isn’t a general programming language that happens to live inside TradingView. It’s a domain-specific language built around one execution model: bar-by-bar, event-driven, tied to a chart. Every calculation runs in the context of a specific bar, with a specific series of past bars behind it.
Variables carry forward. Indicators update as new bars close. The whole engine is designed around that one way of thinking.
Python doesn’t work like that by default. Most Python trading code is vectorized: you load a DataFrame of OHLCV data, calculate an indicator across the whole column at once, and generate signals as another column. Backtesters like vectorbt and backtesting.py wrap this in different abstractions, but none of them exactly match Pine’s event-driven model.
So when you “convert” a Pine Script, you’re not translating syntax. You’re rebuilding the strategy on a fundamentally different engine, plus the data layer Pine gave you for free, plus the plotting layer Pine gave you for free, plus some execution layer because TradingView doesn’t hand you one.
Here’s what “the same strategy” looks like in both.
Pine Script:
//@version=5
strategy("SMA cross", overlay=true)
fast = ta.sma(close, 20)
slow = ta.sma(close, 50)
longCondition = ta.crossover(fast, slow)
shortCondition = ta.crossunder(fast, slow)
if longCondition
strategy.entry("Long", strategy.long)
if shortCondition
strategy.close("Long")
plot(fast, color=color.blue)
plot(slow, color=color.orange)Nine lines. It runs, backtests, and draws itself on the chart.
Python equivalent, using backtesting.py:
import pandas as pd
from backtesting import Backtest, Strategy
from backtesting.lib import crossover
class SmaCross(Strategy):
n1 = 20
n2 = 50
def init(self):
self.sma1 = self.I(lambda x: pd.Series(x).rolling(self.n1).mean(), self.data.Close)
self.sma2 = self.I(lambda x: pd.Series(x).rolling(self.n2).mean(), self.data.Close)
def next(self):
if crossover(self.sma1, self.sma2):
self.buy()
elif crossover(self.sma2, self.sma1):
self.position.close()
df = pd.read_csv("ohlcv.csv", parse_dates=["Date"], index_col="Date")
bt = Backtest(df, SmaCross, cash=10_000, commission=.002)
bt.run()
bt.plot()That’s just the backtest. Before any of it runs, you need OHLCV data in a CSV from somewhere. TradingView doesn’t export it unless you’re on a paid plan with export enabled, so you’re probably now writing another script to pull from ccxt, Yahoo, or a broker API.
For live trading, you need an entirely separate block of code that connects to your broker, handles reconnections, manages order state, and reconciles fills. None of that is strategy logic. All of it is work.
You lose the chart, and this matters more than people admit
Pine Script draws on the chart. Your SMAs plot themselves. Your signal markers appear on the bars where they fired. Your bands, your pivots, your custom indicators, all visible, all aligned with price, all debuggable by eye.
When a strategy misbehaves, you open the chart, and you see it. A signal fired one bar too late. An indicator diverged. The stop landed on the wrong side of a gap. Ten seconds of eyeballing and you know where the bug lives.
In Python, you’re back to printing DataFrames, dumping signal arrays to CSV, and reconstructing behavior from columns of numbers. You can plot in matplotlib or Plotly, but now you’re maintaining plotting code next to strategy code, and every time you want to inspect a new feature, you’re writing more plotting code. On TradingView, when indicators are not working as expected, you open the chart, and the cause is obvious within a minute. In Python, you’re writing a debugger.
For a strategy that’s finished, tested, and won’t change, that trade-off is fine. For a strategy you’ll actually use, it’s brutal.
Markets shift regime. Strategies that worked in 2024 volatility underperform in 2026 compression. Every strategy needs retuning eventually, and retuning blind is a tax you pay every time. Some traders deal with this by pushing against Pine Script limitations rather than leaving the visual environment, which tells you something about which constraint is actually worse.
When converting Pine Script to Python is the right call
Four situations where the rewrite genuinely earns its cost.
You need data that Pine Script can’t access. Tick data. Full Level 2 order book. On-chain metrics for crypto strategies. Options chains. Macro indicators at release time. Satellite or alternative data.
TradingView’s data feed is broad, but it’s OHLCV-first and bar-based. If your edge requires anything else, Pine can’t help you, and Python is where you go.
You’re doing ML or statistics that Pine can’t express. Training a gradient-boosted classifier on feature vectors across multiple symbols. Running a Kalman filter. Fitting a hidden Markov model to regime-label your bars.
These aren’t things you awkwardly port to Pine. They’re things Pine wasn’t designed for. Python, specifically pandas, scikit-learn, and PyTorch, is where this work lives.
You’re running at a frequency Pine can’t keep up with. Pine runs on TradingView’s servers, on TradingView’s bar cadence. If you’re trading tick-by-tick or need sub-second reactions to market data, the bar-based model is the bottleneck, not your code.
You’re building infrastructure where the strategy is one piece. A multi-strategy portfolio with dynamic position sizing across strategies. A system that ingests fundamentals, runs a filter, and passes a universe to a technical strategy.
Anything where the strategy is a component inside something bigger. Pine Script is designed to be a whole thing; Python is designed to be a part of things. Different tools, different shapes of problem.
Notice what’s common across all four: the goal isn’t “run the same strategy in a new language.” It’s “do something Pine Script fundamentally can’t do.” If that’s not your situation, keep reading.
When people think they need to convert, but don’t
Four common reasons for converting that don’t hold up under pressure.
“I want to execute on my broker, and Python lets me do that via the broker’s API.” Technically true. Your broker probably has a Python SDK. You can absolutely write a script that takes a signal and opens a position.
But the strategy isn’t the hard part. The hard part is everything around execution: reliable signal transport from TradingView to your Python process, reconnection logic when the websocket drops at 3 am, order state synchronization when your script restarts, fill confirmation, slippage-tolerant stop placement, and reversal sequencing. Whether you want to trade directly on TradingView through a native broker or route signals out to a Python script, the same pile of execution problems is waiting. You’re not avoiding a problem; you’re volunteering for it.
“Bridges cost money, Python is free.” Python is free. Your weekends aren’t.
A bridge runs $30-60 a month. A rebuild is a weekend minimum, plus a year of maintenance when brokers change APIs, when your VPS hangs, when your Python process dies silently at 2 am, and you don’t notice until Monday. And if your target is MetaTrader specifically, connecting it to TradingView from a custom Python process includes every reliability quirk of the MT5 terminal on top of everything else. Price your time at $50/hour and do the math.
“Python is more serious. Real traders use Python.” Some real traders use Python. Some real traders use C++. Some real traders still use Excel and a phone.
The language doesn’t make your edge bigger. Whatever gets your strategy running reliably with the least friction is the right tool. If your strategy is a Pine Script and it works, converting it to Python for aesthetic reasons is cargo-cult trading.
“I need custom indicators Pine can’t do.” Maybe. But Pine Script is much more capable than most people who have just written their first script realize. request.security() pulls data from other symbols and timeframes. varip gives you the intra-bar state. Arrays and matrices handle complex data structures.
User-defined types and methods let you build real abstractions. If you haven’t tried converting a Pine Script indicator into a strategy within Pine first, or pushed the language to its edges, you might not actually be at the limit you think you’re at.
That said, there’s one genuine wall. Pine Script cannot make HTTP requests, so if your indicator needs to call an external API in real time, Pine can’t do it. Everything else, check before you assume.
Pine Script to Python conversion: the actual work involved
If you’ve read this far and you’re still in the minority who should convert, here’s what the Pine Script-to-Python conversion actually involves. Not the fantasy version.
Data layer. Pine gave you OHLCV for every symbol on every exchange, free, clean, adjusted. Python doesn’t. You’ll use ccxt for crypto, yfinance or a paid data vendor for stocks, and a broker API for forex.
Each has its own quirks: different date formats, different time zones, different handling of gaps and splits. Budget a day just to get the data into a DataFrame that matches what your Pine Script was seeing.
Indicators. Most Pine indicators have Python equivalents, but not 1:1. ta.sma(close, 20) is a rolling mean, easy. ta.rsi has at least three common implementations in Python (pandas-ta, ta, talib), and they yield slightly different results due to how they handle initialization and smoothing.
Pine’s internal implementations are specific. Matching them exactly requires carefully reading Pine’s docs, or accepting that your backtest results will differ.
Three ways to get RSI in Python, all slightly different from Pine’s:
import pandas_ta as ta_lib1
df['rsi1'] = ta_lib1.rsi(df['close'], length=14)
from ta.momentum import RSIIndicator
df['rsi2'] = RSIIndicator(close=df['close'], window=14).rsi()
import talib
df['rsi3'] = talib.RSI(df['close'], timeperiod=14)Pick one library and stick with it, because mixing them means debugging differences that have nothing to do with your strategy.
Backtester. Pine Script has a backtester built in. Python doesn’t, so you pick one. Backtesting.py is simple and readable. Vectorbt is fast and good for parameter optimization but has a steeper learning curve.
Bt is strategy-framework-style. Zipline-reloaded is more institutional but finicky. Each has different assumptions about bar closing, fills, commission, and slippage, and none will match Pine’s assumptions exactly. Expect your backtest numbers to shift when you change engines.
Execution layer. This is where most people underestimate the work. Pine’s alerts can fire webhooks that hit any endpoint. In Python, if you’re trading direct-to-broker, you’re writing the reliability layer yourself: order placement, confirmation, retry on rejection, position reconciliation, stop-loss management, handling partial fills, reacting to disconnects.
This is 70% of the work in any serious Python trading system. Strategy logic is maybe 20%. Data pipeline is 10%.
Plotting and debugging. Already covered above. Add matplotlib or Plotly to your stack. Add logging. Add a way to replay your signals against historical data when something breaks. You’ll need all of it.
Realistic first-time build: a weekend for the basic conversion, another weekend for execution plumbing, then two or three iterations as you discover edge cases in production. If you’re someone who’s just finished writing their first Pine Script, double those estimates.
Skip the rewrite: how FillEdge does it instead
If your reason to convert Pine Script to Python was “I need my strategy to execute reliably on my broker,” you don’t need to convert anything. A webhook bridge does that, and FillEdge is built specifically to solve the execution problems people discover after they’ve already committed to rewriting in Python.
FillEdge connects TradingView strategies to external execution venues. Your Pine Script stays where it is. TradingView’s alert fires, FillEdge receives it, and the order reaches your broker with the fill, stop, and ordering behavior your strategy actually intended, not an approximation.
Specifically: signals only fire when fills are confirmed, so the phantom positions that would otherwise appear when orders don’t fill never get sent. Reversals arrive in the correct order. Close the long, open the short. Never backwards. Stop losses land where your strategy logic intended. You choose per strategy: exact price for structure-based stops, or distance from entry for volatility-scaled stops. Multiple strategies on the same account run isolated, so a signal from one never closes a position belonging to another.
Every signal carries a reconciliation badge: ✓MATCHED means TradingView and your broker agree on the trade, 🎯LOCKED means your stop landed at the exact strategy price despite entry slippage, 👻CAUGHT means a phantom signal was blocked before it reached the broker. That’s the debugging layer you’d otherwise be building in Python with logging, SQLite, and matplotlib. It’s already done.
FillEdge also monitors the pipeline continuously. Synthetic test signals travel the full path on a regular cadence, without opening a trade. If any leg fails, you get an email or Telegram alert within minutes. Your Python process dying at 2 am on a Saturday is exactly the failure mode this replaces.
That’s the execution layer you’d otherwise be writing in Python, running behind the scenes, priced lower than a single hour of your time per month. The same infrastructure applies whether you’re on MetaTrader, a crypto exchange, or any other venue FillEdge supports.
**Keep your Pine Script, skip the rewrite. → **Get early access
When you’ll regret converting six months later
Here’s the scenario nobody writes about when they’re mid-conversion.
It’s six months from now. You finished the Python rewrite in March. Ran it clean through April and May. Markets shifted in June — volatility collapsed, your SMA crossover stopped catching moves, you’re breakeven on a strategy that was making money. You need to retune.
In Pine Script you’d open the chart, look at the last fifty signals, and see instantly what’s wrong. The bands are too wide for the compressed range. The crossover is firing on noise. You tweak the parameters, visually confirm the new signals fire at the right places, and ship.
In Python you’re reading logs. You’re pulling signal timestamps from a SQLite file. You’re writing matplotlib code to plot the last three months of signals over candles. You’re comparing two DataFrames side by side to figure out why the strategy you converted in March doesn’t match what your backtester says it should be doing. Half a day of tooling work before you even get to the tuning.
The conversion was for a strategy you thought was static. No strategy is static. The same logic applies to converting Pine Script into MQL5: any move out of Pine is a decision to debug without the chart, indefinitely.
If you’re still in Pine Script when the regime shifts, you’re an hour away from an adjustment. If you’re in Python, you’re a day away, and that’s if you built the debugging tools carefully the first time. Worth keeping in mind before you decide the rewrite is worth it.
FAQ
Can I automatically convert Pine Script to Python with a tool or script?
No reliable converter exists, and the reason is structural: Pine Script runs bar-by-bar inside TradingView’s engine while most Python code is vectorized across a DataFrame, so there’s no one-to-one mapping between the two. A few GitHub projects claim partial conversion, but they handle trivial cases only and break on anything with request.security(), varip, custom types, or strategy-level features. In practice, every serious Pine-to-Python port is a manual rewrite.
Can I run Pine Script outside of TradingView?
No. Pine Script is a proprietary language that only executes on TradingView’s servers. There’s no offline runtime, no open-source interpreter, and no export path to another platform. If you want your logic to run elsewhere, you either rewrite it in that platform’s language (MQL5 for MetaTrader, Python for custom systems) or keep the Pine Script on TradingView and use a bridge to route its signals outward.
How long does it take to convert a Pine Script strategy to Python?
For a simple strategy, plan on a weekend for the basic conversion itself, plus another weekend to build the execution and data-loading layers that Pine gave you for free. Expect two or three more rounds of debugging once you run it on live data, because indicator libraries and backtesters handle edge cases differently from Pine. First-time converters should roughly double these estimates.
More from FillEdge