The full record of how Webull’s Vega assistant was tested. Chapter 10 and Appendix E carry the summary: Vega was evaluated and not kept in the framework’s toolkit.
Webull ships its own AI assistant inside the trading platform, called Vega. Vega is not a competitor to Claude in the framework’s strategic intelligence workload. It is a different category of tool entirely—in-platform rather than external, code-focused rather than strategic on the desktop product, and a market-context chatbot rather than a script editor on the mobile product. A Webull user meets Vega whether or not they go looking for it, so this page records what it was tested on and what it is and is not good at.
Two tests were run on desktop Vega. Both are documented below, with the actual outputs reproduced or described faithfully. The first test demonstrates a failure mode that is genuinely instructive. The second demonstrates a capability that Vega is, in fact, very good at. Both results matter.
The first test asked Vega to build an Expected Move indicator that plots upper and lower limits of the day’s move. The phrasing “upper and lower limits of the day’s move” is technically ambiguous. It could describe at least two completely different indicators. It could describe a static envelope derived from the option chain’s implied volatility at market open and held constant across the session, which is what the framework’s EM is. Or it could describe a dynamic envelope derived from price action, an ATR-based Keltner-style band that expands and contracts intraday.
Vega selected the second interpretation. It produced a TypeScript class implementing an ATR-derived envelope with configurable period and multiplier, plotting upper as price plus ATR times multiplier and lower as price minus ATR times multiplier. The code Vega produced was correct as a Keltner-style indicator. The chart it would draw is a valid technical indicator that real traders use. As a translation of “upper and lower limits of the day’s move,” it is defensible: the more common technical-analysis interpretation of that phrase is exactly what Vega built.
It is also structurally wrong for the framework. The framework’s EM is two horizontal lines, EM+ and EM−, placed at fixed prices derived from the implied-volatility-derived expected move at market open. The lines do not move during the session. They are reference levels, not adaptive bands. An ATR envelope is the wrong instrument.
The failure mode is not Vega’s competence. Vega’s competence as a code generator is not in question. It produced functional, idiomatic TypeScript for the indicator it built. The failure mode is that Vega did not have the framework context required to disambiguate the prompt. Claude, with the framework loaded, would have asked which kind of EM was wanted before writing any code, because the framework rules make the distinction explicit. Vega had no framework rules. Vega selected the more common interpretation of the natural-language phrase, which was the wrong one. The intelligence gap is in the context, not in the code generation.
This is the load-bearing point for understanding what Vega is and is not. Vega is a capable code generator. Vega is not a strategic intelligence layer. The two are different tools, and the difference matters when the prompt is written in natural language without explicit framework constraints. Claude with framework context produces correct work because the context disambiguates. Vega without framework context produces a defensible interpretation of an ambiguous prompt, which is sometimes correct and sometimes not. For framework work specifically, the difference is the difference between a tool that fits and a tool that does not.
The second test asked Vega to translate the framework’s GEX Levels indicator from WebullScript into TypeScript. This is a different kind of task. It is not a natural-language design problem. It is a translation problem, and a strict one—the output had to preserve every static price value as a hardcoded literal, every level name verbatim, line types and widths matching the source, the source-to-color mapping intact, total line count equal to the source, and a single-class structure with all levels in one CustomIndicator, exported as the default. Seven fidelity criteria. All required.
Vega’s output, reproduced as it ran. It predates two later naming changes in the framework: the flip level then labeled GT is now GF, and the GB line has been retired.
import { CustomIndicator, Bar, Color, HlineType, CustomIndicatorOptions } from 'metrix';
class StaticHLines extends CustomIndicator {
constructor(options: CustomIndicatorOptions) {
super(options);
this.defineIndicator('Static HLines', 'SHL', true);
// GT & GB & Pin
this.defineHline('GT', 7154, { color: Color.White, lineType: HlineType.Solid, lineWidth: 2 });
this.defineHline('GB', 7154, { color: Color.White, lineType: HlineType.Dashed, lineWidth: 1 });
this.defineHline('PN', 7175, { color: Color.Yellow, lineType: HlineType.Solid, lineWidth: 2 });
// Resistance Zone
this.defineHline('RB', 7185, { color: Color.Red, lineType: HlineType.Solid, lineWidth: 1 });
this.defineHline('RT', 7220, { color: Color.Red, lineType: HlineType.Solid, lineWidth: 1 });
// Support Zone
this.defineHline('ST', 7160, { color: Color.Green, lineType: HlineType.Solid, lineWidth: 1 });
this.defineHline('SB', 7150, { color: Color.Green, lineType: HlineType.Solid, lineWidth: 1 });
// Danger Zone
this.defineHline('DT', 7220, { color: Color.Orange, lineType: HlineType.Solid, lineWidth: 1 });
this.defineHline('DB', 7125, { color: Color.Orange, lineType: HlineType.Solid, lineWidth: 1 });
// Walls
this.defineHline('PW', 7125, { color: Color.Lime, lineType: HlineType.Dashed, lineWidth: 2 });
this.defineHline('CW', 7200, { color: Color.Maroon, lineType: HlineType.Dashed, lineWidth: 2 });
}
onBar(_bar: Bar): void {
// No logic needed as hlines are static and defined in the constructor.
// The onBar method must still be present, but can be empty.
}
}
export default StaticHLines;
All seven criteria preserved. Every price and every name carried over, line types and widths correct, colors correct, the eleven hlines in the source mapped to eleven defineHline() calls in the output, single class with all levels in the constructor, exported as default. Worth flagging: Vega used the defineHline() primitive, the correct primitive for static horizontal lines, exactly matching the source’s intent. It did not reach for that primitive when building EM from natural language in Test 1 but reached for it correctly here. The translation path is reliable. The natural-language path is not.
One small honest detail. The output includes an onBar() method with two comment lines explaining that the method must be present but can be empty. This is technically accurate. The TypeScript class structure requires the method to exist even when there is no per-bar logic to run. It is also a small illustration of the workflow argument that comes next. The framework’s WebullScript GEX Levels block has no equivalent of an empty onBar() method, because WebullScript does not require one. The class machinery in TypeScript carries overhead that the static-hline pattern does not need. Vega’s translation is correct. The structure it has to translate into is heavier than the work the indicator actually does.
At the time of the evaluation, a mid-session update was a hand edit to the level script. Test 2 demonstrates that Vega’s translation is structurally faithful. A user who pasted the GEX Levels WebullScript into Vega and added the resulting TypeScript indicator to chart would see the correct level lines, with the correct names, in the correct colors, at the correct widths. The output is functionally equivalent to the source. That is the fidelity argument, and it lands cleanly.
There is a separate argument, though, that does not land the same way. The fidelity argument and the workflow argument are different. Both can be true. Both have to be said.
Mid-session, a fresh GEX print surfaces a structural shift that requires an immediate hand edit to the level script. A GF zero-crossing migration. A wall repositioning after volume prints in an unexpected node. The window for the edit is measured in seconds, not minutes. The script has to come up, the value has to change, the script has to save, and the chart has to refresh—fast.
In WebullScript, the level block is a flat list of hline() calls. Open the script, scan to the line, change the number, save. The flat list is exactly the structure the eye can scan fastest because there is no scaffolding between the level name and the price value. The source code of the indicator is, structurally, the data of the indicator. They are the same thing.
In TypeScript, the same edit lives inside a class declaration, inside a constructor, inside a defineHline() call, inside an options object, with the price value as the second positional argument. The edit is the same edit, change one number, but the eye has more structure to navigate to get to the number. Under time pressure, that structural overhead matters. The seconds are real.
This was the case for staying on WebullScript rather than moving to Vega’s TypeScript. It is not that Vega’s translation is wrong. The translation is correct. It is that the framework’s three indicators (GEX Levels, Expected Move, Intraday HOD/LOD) were all static-hline indicators that benefit from a flat-list structure specifically because they get edited mid-session under time pressure. The class-based machinery in TypeScript is not doing useful work for this pattern. For calculated indicators that genuinely need bar-by-bar logic (Bollinger Bands, MACD, custom oscillators), the class structure earns its keep. For static lines that change only when the trader types a new number, the flat list wins on the dimension that matters most: how fast the eye gets from the level name to the value, and how fast the value gets changed. The framework has since moved its chart layer to Pine Script on TradingView, for the reasons in Chapter 12, and the move had to pass the same test. It does. Each level in the Suite is one input line with the name beside the value, and a mid-session update is a paste and a save. The WebullScript version is updated the same way, by pasting the full block (Appendix B).
Webull’s mobile app includes a product called Vega that shares the name with the desktop scripting assistant but is a different tool: a generative AI chat assistant. It is watchlist-aware, it has access to real-time market data, and it accepts custom prompts. It does not write code and has no script editor.
It was tested for three jobs, all for the moments when the phone is the only screen: end-of-day market summaries, news scans across watchlist symbols, and ad-hoc market-context queries during the day. The end-of-day test used a short prompt:
“Use current market data to concisely summarize today’s performance of major indexes and the key drivers behind the move.”
It returned a usable summary in under a minute. That summary is not the framework’s EOD post-mortem: the post-mortem covers what happened inside the framework’s own session, and the Vega summary covers the wider market.
A premarket read was tried the same way. Vega summarized overnight conditions and named observable drivers (a futures move, a macro print already released, an overnight headline), and when prompted carefully it warned that it could not forecast the session, which is the correct behavior. A read like that is background only; the Premarket Setup prompt, run with the GEX data and the macro calendar, is what produces the session plan.
Why it was not kept. Claude covers the same queries with web search and the framework’s context loaded, from its own mobile app on the phone. A second assistant for the same three jobs adds a tool without adding a capability, and without the framework’s context Vega answers the question as asked, which is not always the question meant. These are tool-fit findings, not framework rules (Appendix E).