Steven Imrich

HomeTrading platforms → Why does ChatGPT write ThinkScript that doesn't compile?

Why does ChatGPT write ThinkScript that doesn't compile?

Updated August 27, 2026

Short answer

thinkScript is a small, unusual language with almost no public code compared to Pine Script or Python, and the model has no compiler in the loop to tell it when it's wrong. So it produces something that looks like thinkScript, borrows syntax from Pine, invents functions and plot names that don't exist, and confidently gives you menu paths that aren't there. It's still useful for scaffolding. It is not useful for anything you paste in without reading.

The short version of why

thinkScript is a small proprietary language used by one broker. Pine Script has an enormous public corpus, MQL has decades of forum code, Python has all of GitHub. thinkScript has a documentation site, one very good forum, and not much else.

On top of that, the model never sees your error. It writes code, you paste it into the thinkScript Editor, the editor rejects it, and unless you tell it what happened, it has no idea.

The result isn’t random garbage. It’s the specific failure of something that learned the shape of a language without the details, which is worse, because it looks right.

Invented functions and invented plot names

The most reported one, and the hardest to spot if you’re new, because a made-up function name looks exactly like a real one. A useThinkScript administrator working through a broken AI script put it bluntly: chatGPT invented plots that don’t exist. Not the functions, the plots. It called MACD().signal when the real plot is .Avg. It called .line, .result, .output, none of which are things.

The fix they recommend is the Inspector, which will show you the actual plot names available on a built-in study so you can click the real ones instead of guessing. Put your cursor on the function that’s erroring, or type the function name in, and it lists what’s really there.

Pine Script bleeding through

Second most common, and once you know the tells you spot it in two seconds. thinkScript comments start with #. If you’re seeing //, that’s Pine. If you see study( or indicator( or strategy.entry( at the top, that’s Pine. If you see ta.sma(close, 20), that’s Pine. If you see := for reassignment, that’s Pine. If you see plot(close, color=color.red) with the arguments inside the parentheses rather than plot X = close; followed by X.SetDefaultColor(Color.RED);, that’s Pine.

MQL leaks in too, usually as C-style braces and for loops. Which leads to the next one.

Loops written as if this were a procedural language

thinkScript has no for and no standalone while. It has fold, and the syntax is nothing like a normal loop:

input n = 10;
plot factorial = fold index = 1 to n + 1 with p = 1 do p * index;

while only exists as an optional clause inside a fold, as a termination condition. So when a model writes you a for (i = 0; i < 20; i++) block, it isn’t a typo, it’s the model assuming this language works like the languages it knows.

Related: variables don’t get reassigned the way you’d expect. You can’t declare def x = 0; and then write x = x + 1; later. Assignment inside if/else blocks is the mechanism, and it has its own rules.

Aggregation, which it gets wrong constantly

Ask for a multi-timeframe indicator and you’ll get one. Ask for a multi-timeframe scan and you’ll get one that cannot work, because thinkorswim’s own Stock Hacker documentation says secondary aggregation is not allowed in scan filters, and the model doesn’t know that.

You’ll also get scripts referencing a smaller aggregation than the chart, which is refused on charts too. That whole family of failures has its own page, and it’s worth reading before you next ask an AI for anything involving two timeframes, because you’ll be able to reject the answer without pasting it.

Circular references

More than one person has described getting circular dependency code repeatedly, and the model not understanding its own error when told. thinkScript lets a variable reference its own previous bar (def x = if cond then x[1] + 1 else 0; is legal and useful) but not its own current bar. Models write chains where A depends on B and B depends on A, which reads fine as prose and is impossible as a data series.

A cousin of this: if you paste recursive code into a study alert you’ll hit rec usage is not allowed in this context and the OK button greys out. rec is the older keyword for exactly that self-referencing pattern. The alert dialog rejects it outright.

def, plot, rec, and where each one is allowed

A lot of AI thinkScript uses plot for everything, including intermediate values nobody wants to see. That’s not a compile error, it just makes a chart with fourteen lines on it. It becomes a real error the moment you move the script to a scan filter or a study alert, since both require exactly one plot.

The habit worth adopting: def for anything intermediate, plot only for what you actually want drawn or, in a scan, for the single boolean that is the answer.

Confidently wrong menu instructions

This has nothing to do with code and wastes the most time. Ask where a setting lives and you’ll get a clean numbered path with plausible submenu names, and it will be wrong in small ways. There’s a 2025 useThinkScript thread where someone posts a tidy AI-generated procedure for enabling real-time futures data on schwab.com, complete with a “Market Data Subscriptions” section and a Quote Speed setting under Application Settings > General. The person who tried it replied with a screenshot showing none of it existed on their account, and Quote Speed is actually under System, not General.

Neither the model nor the person posting it was being dishonest. It just generated the interface Schwab probably should have.

A workflow that actually works

Ask for one small piece. “Write me a scanner for consolidation breakouts with volume confirmation across three timeframes” produces a mess you can’t debug. “Write a thinkScript def that’s true when volume is more than twice its 20 bar average” produces something you can check by eye.

Read the first error, not the last one. The editor shows the last error and you have to scroll up to find the first. Everything below the first error is usually just fallout from it.

Paste the actual error text back. Not “it doesn’t work”. The literal string, plus the line. The model can’t see your screen and it does genuinely fix things when you give it the message.

Check every function name against the official reference at toslc.thinkorswim.com. Thirty seconds each. If it isn’t there, the model made it up, and no amount of re-prompting will conjure it into existence.

Keep the working version. Save each one that compiles before asking for the next change, because these scripts have a way of drifting into unrecoverable states.

One last thing, said plainly

This page was written by a person checking a machine. I researched the failure modes against forum threads and the official reference, checked the function names, and cut the bits I couldn’t verify, including one confident-sounding error-rate statistic that I couldn’t trace to any actual study.

That’s the same job you have to do with an AI-written script. Not “is it plausible”, but “can I confirm this line”. The tool is genuinely useful for a skeleton and for explaining code you’ve been handed. It is not a substitute for knowing whether HighestAll() belongs in a watchlist column, and it will tell you it does.

Related questions