I learn most of my technical analysis from a YouTuber who draws harmonic patterns the way someone draws after years of doing it — fast, by feel, no hesitation. I don't have that. I've spent real time trying to spot Gartleys and Crabs on a chart the way he does, and I'm just not as good at it. There are harmonic indicators on TradingView, but none of them followed his specific rules — his ratio definitions, his tolerance bands, his sense of which patterns are reliable enough to act on. One member of his Discord built a version that did follow those rules. It's also private. I could watch it work. I couldn't open it up and learn from it, and I definitely couldn't build on top of it.
So the problem wasn't that the rules didn't exist. It was that I had a system I could see the output of, but not a way to build against it myself. That's what sent me into Pine Script trying to reverse-engineer the thing on my own.
The rulebook I could see but not run
The mentor's framework isn't vague. It's eight specific harmonic patterns — Gartley, Bat, Alt Bat, Butterfly, Deep Butterfly, Crab, Deep Crab, Shark — each with its own Fibonacci ratios at every leg, plus stated tolerance bands at 5% and 10% for how far price is allowed to drift from the "ideal" ratio before the pattern's no longer valid. It's a real rulebook, not an impression.
What I didn't have was code that actually checked a live chart against that rulebook. The public scripts on TradingView use a more generic six-pattern set and don't score against any specific tolerance system. The Discord member's script does follow the mentor's rules — but since it's closed-source, the only thing I could compare myself against was its output, not its logic.
Starting from someone else's code
I didn't start from a blank file. There's a public-domain Pine Script harmonic detector — six pattern types, decent at drawing XABCD structures, with no concept of the mentor's specific ratio framework layered on top. That was my starting point, and the work was less "write a harmonic indicator" and more "take this, and rebuild it until it actually implements the rules I'm trying to learn."
The first thing that had to change was the pattern set itself. The original script covers Gartley, Bat, Butterfly, Crab, Shark, and Cypher. The mentor's framework doesn't include Cypher, and it does include three patterns the original script never touched — Alt Bat, Deep Butterfly, Deep Crab. So before any of the harder rework started, I was already changing what the indicator could even detect.
Why a global find-and-replace wasn't enough
The original code hardcodes each pattern type into its own named array and its own branch of logic, repeated in four or five different places — once for storage, once for coloring, once for the symbol shown in a label, once for target calculation. That works fine when your pattern types are six small, contiguous numbers. The moment I dropped one type and added three with non-contiguous IDs, every one of those hardcoded branches needed new cases, by hand, in every location.
I replaced that with a single lookup — a function that maps each pattern type ID onto a dense index, and everything else (colors, names, symbols, stored arrays) reads off that index instead of switching on the raw type. Add a ninth pattern later, and it's one new line in one place, not five new branches scattered through the file.
Something similar was true of how the original script drew the lines connecting each leg of a pattern. It assumed a leg was always sitting at a fixed position in an array — leg three is always the X-A line, leg four is always the C-D line, and so on. That assumption breaks the moment pattern types start sharing drawing logic across different shapes. I rewrote it to check actual coordinates first — does this line's start and end points actually match the X-A leg's coordinates — and only fall back to positional guessing if that check fails. Slower to write, much harder to silently get wrong.
The bias I didn't expect to find
Once I started testing the rebuild against real charts, I noticed it kept favoring one harmonic shape over others when multiple patterns were plausible in the same zone. I went looking for where that preference was coded in — and it wasn't. The original script had no tie-break logic at all. When more than one pattern type matched the same price structure, whichever one happened to be checked first in a hardcoded list order won, every time. It wasn't bias from a bad rule. It was the complete absence of one.
The fix was to actually score candidates against each other — rank every matching pattern type by how closely its key ratio fits the ideal Fibonacci level, and only keep the best fit. It's a small function, but it's the difference between "this happens to be the pattern my code checks first" and "this is the pattern that actually fits the data best."
A second, related bug showed up once patterns started getting replaced by better-scoring ones: the lines and shaded fills from the discarded pattern sometimes stuck around on the chart after the pattern itself was gone. Every place that could delete a pattern needed to also clean up its drawings, and a couple of paths didn't. I routed all of it through one shared cleanup function instead of leaving each deletion path responsible for remembering to do it itself.
Why the loop looks uglier than it should
Pine Script doesn't allow recursion, and a script needs to scan for patterns at every pivot length from 3 bars up to 20. The clean way to write that is a loop. The actual way you have to write that in Pine, if you don't want every length re-evaluating and redrawing on every pass through a shared loop body, is eighteen explicit calls, each gated by its own if. It reads like something nobody bothered to clean up. It's actually the version that doesn't redraw the same pattern eighteen times a bar.
The real fix for "slow to load" wasn't the loop shape — it was adding a minimum pivot length floor so the script skips scanning lengths nobody asked for in the first place, instead of always checking the full 3-to-20 range regardless of settings.
One more simplification, smaller but worth mentioning: the original script let you configure separate profit targets for every one of its six pattern types independently — six pairs of dropdown menus, each with over a dozen options. I collapsed all of that into a single shared calculation: a Fibonacci extension measured from point D, using the same two ratios for every pattern type. It's less configurable. It's also a fraction of the code, easier to reason about, and one less place per pattern type for something to quietly drift out of sync with the rest of the script.
Proving the math instead of trusting it
I don't have the mentor's years of manually reading charts, and the Discord member's implementation is closed-source, so I couldn't check my detection logic against either of those directly. What I could check it against was the math itself.
Every detected leg gets compared against the mentor's own tolerance bands — does this ratio actually land inside the 5% or 10% window his framework defines, or is it outside the range entirely. That's not a vibe check. It's a direct comparison against stated numbers. On top of that, I ran my version side-by-side with the Discord member's script on the same chart, same time window, and compared the resulting stats tables — not to copy his numbers, but as the closest available reference point for whether the two implementations were finding equivalent zones.
Years of stats and data science coursework is what made that feel like enough. An indicator is applied statistics — the same way a calculator doesn't need to have "lived" a math problem to solve it correctly, code doesn't need a decade of chart reps to apply a stated ratio rule correctly. I didn't need his eye. I needed the math to check out, and a way to confirm it did.
What "historical outcome" actually tracks
Every completed pattern gets a profit target derived from a Fibonacci extension measured from its own low to its own high — not a fixed percentage, a ratio specific to that pattern's own geometry. The stats table tracks, for every historical instance of a given pattern type, how often price actually reached that target, and reports a weighted average return across all of them. So "this is a Gartley" isn't the end of the output — the table next to it says how often a Gartley on this exact chart, with these exact legs, has actually paid off.
What the numbers actually say
They're not a highlight reel. Across pattern types, first-target success runs somewhere in the 40s-percent range, second-target success considerably lower — and individual pattern types vary a lot. Crab patterns, in particular, have underperformed badly on the charts I've tested against. That's the honest output of comparing real detected patterns against real subsequent price action, not a cherry-picked backtest. A tool that's clearly better at some patterns than others is a more useful tool than one that implies it's equally good at all of them.
Where it stands now
The pattern-type bias, the orphaned drawing cleanup, and the gap between the original six-pattern set and the mentor's eight — all three are resolved, not pending. This wasn't an open-ended project that's still catching bugs as they surface; it was a specific, bounded problem — a rulebook I could see but not run — and the rebuild closes that gap. I still don't have his years of pattern-reading reps. But I have a way to check the math behind every pattern it draws, and that's the part that was actually missing.