Why ChatGPT / Claude can't properly convert Pine Script to Python — and why it matters
If you’ve ever pasted a Pine Script into ChatGPT or Claude and asked for Python, you probably got something that looked right. Clean code, proper syntax, maybe even ran without errors.
But did you compare the actual output values to TradingView? Most people don’t.
I did. Multiple times, across different indicators. And the numbers almost never match. Here’s why.
Pine Script thinks in time. Python libraries think in columns.
This is the core issue, and everything else follows from it.
Pine Script runs sequentially, bar by bar. Each bar executes the entire script once, and state evolves over time — like a simulation stepping forward. Most Python trading libraries (TA-Lib, pandas-ta, numpy-based solutions) work vectorized — they operate on the entire dataset as column transformations.
For simple cases like SMA or EMA, both approaches can produce the same results. But once you need anything with branching logic, event-based state, or cross-timeframe data, the vectorized model breaks down:
Stateful functions have no natural equivalent.
Functions like ta.barssince(close > open) or ta.valuewhen(condition, price, 0) depend on past events, not just past values. They track when something happened and recall what the state was at that moment.
Try implementing barssince in pandas without a loop. You can, technically — but you end up reconstructing state across columns, adding intermediate variables, and the result is fragile, hard to reason about, and easy to get wrong. You trade one line of Pine for five columns of pandas gymnastics, and debugging becomes guessing.
The AI doesn’t even attempt this. It either drops the statefulness entirely or produces something that looks plausible but computes different values.
Errors become data in Pine. In Python, they crash your script.
Pine Script is fault-tolerant by design. If volume happens to be zero and you divide by it, you don’t get an exception — you get na. That na propagates cleanly: na + 5 is na, ta.sma(na, 14) handles it gracefully. No value? No crash. Just “this doesn’t have a result yet.”
In Python, you’re on your own. Plain Python throws ZeroDivisionError. NumPy gives you inf and a warning. Pandas sometimes returns NaN, sometimes raises, sometimes silently does something else — depending on the operation and the library version. There’s no unified model, so you end up writing defensive code everywhere. if denom != 0, try/except, .fillna(), .replace(np.inf, np.nan) — none of this is trading logic. It’s just “please don’t die.”
When the AI converts Pine to Python, it doesn’t add any of this. Why would it? The original Pine code didn’t need it.
Warming behavior is silently different.
This is the one nobody talks about. How does an SMA behave when it only has 3 bars but needs 14? How does RSI initialize? Every library handles this differently — different defaults, different edge cases, different NaN handling.
TradingView has a well-defined and consistent warming behavior. Other libraries differ — sometimes subtly, sometimes significantly. When ChatGPT picks a random Python library for the conversion, the warming behavior will diverge, and your values will be off from the very first bars. Depending on your strategy logic, that can cascade.
Multi-timeframe? Good luck.
request.security() is one of the most used Pine Script features, and it’s also one of the hardest to replicate correctly. Timeframe alignment, partial bars, data availability — all of this has specific, well-defined behavior in Pine Script. There is simply no Python equivalent that handles this correctly out of the box. The AI will typically produce something that fetches higher-timeframe data and merges it with a join or reindex — which silently introduces alignment errors (e.g. forward-filled values or misaligned closes).
Look-ahead bias: the guardrail disappears.
Pine Script’s execution model naturally prevents look-ahead bias — your script simply doesn’t have access to future data on each bar. When AI converts to Python using vectorized operations on the full dataframe, that protection is gone. It doesn’t always introduce look-ahead bias, but subtle bugs become very easy to miss — a shift(-1) in the wrong direction, an implicit forward fill, and suddenly your backtest looks amazing for the wrong reasons.
(Yes, Pine Script has its own ways to introduce look-ahead bias — request.security() with lookahead=barmerge.lookahead_on, for example. But the default execution model protects you. The converted Python code doesn’t.)
Why does the AI get it wrong?
The AI doesn’t have a correct execution model to target. Its training data is full of vectorized TA implementations, so that’s what it produces. There’s no widely-used Python framework that replicates Pine Script’s sequential, stateful execution — so the AI has nothing to learn from.
To be fair: vectorized isn’t wrong.
Vectorized libraries exist for a reason. They can be extremely fast because they’re backed by highly optimized C/Fortran code under the hood. If raw computation speed is your primary concern and you know exactly what you’re doing, a hand-tuned vectorized implementation can outperform a sequential one.
But that’s the key — hand-tuned. Getting a vectorized implementation to produce correct, Pine-compatible results takes deep understanding of both models. The AI can give you a starting point, but not a finished result. And if you’re not verifying every value against a reference, you won’t know where it went wrong.
What I did about it
I got frustrated enough by this that I built PyneCore — an open-source (Apache 2.0) Python framework that replicates Pine Script’s bar-by-bar execution model, including series handling, persistent state, and warming behavior.
It’s not a wrapper around pandas or TA-Lib. It’s a runtime that executes scripts the same way Pine Script does. The values match TradingView’s output — I continuously validate this against real TradingView data.
There’s also a compiler service (PyneComp) that automatically converts Pine Script to PyneCore — so you don’t have to rewrite anything by hand. The compiled code is readable Python, not a black box.
If you’ve been trying to use Pine indicators in Python and kept getting different numbers, this might be why.