← All Articles
Every AI model failed. Then GPT-6 Astra read a math paper.
NexusTradeINFRASTRUCTURE / FIELD NOTES
Astra, continuously turning clockwise A celestial intelligence formed from dozens of fine teal and gold mathematical contours, hovering above a research paper. MATHEMATICAL OPTIMIZATION The continuous quadratic knapsack problem ∑ clamp(vᵢ − λ, 0, cᵢ) = t ∑ clamp(vᵢ − λ, 0, cᵢ) = t λ* COMINETTI · MASCARENHAS · SILVA 2014

NexusTrade · Infrastructure

Four AI models failed to make my Rust backtesting engine faster. Then GPT-6 Astra read a math paper.

GPT-6 Astra convinced me that AGI is here, and that artificial superintelligence is less than two years out. This is how it solved an optimization problem four other frontier models told me was impossible.

Austin Starks Founder, NexusTrade September 8, 2026 11 min read

Begging for Velocity 9

At the end of 2022 I gave up on my own platform.

NextTrade was the first version, written in TypeScript, and I had spent over two years on it. It was too slow to do the thing I built it for. Running a genetic optimization on my MacBook Pro could crash the entire machine, and if I kept the population small enough to survive, a hundred generations on a complex strategy took days.

So I open-sourced it. I read every Medium post and every Reddit thread I could find first. Golang was familiar from my day job, though its collector shows up in exactly the tail latencies a backtest lives in. C++ was the traditional pick and I had Jane Street daydreams. Rust won, and then I spent eighteen months hating it loudly enough to go viral about it before I came around.

ThePrimeTime read the article on stream.

Like Hunter Zolomon injecting himself with speed steroids, I wanted to be the fastest. I used AI to get there, but I have never used anything quite like this.

Zoom, masked, with blue lightning crawling over his suit
Zoom. The speed was borrowed and it cost him everything, which is roughly how the next two years went.

Where I was starting from

Let's run back in time to April. I published an article about using Claude Opus 4.7 to migrate the engine off a 200 GB per worker mmap architecture. That weekend cut my disk bill sevenfold and made warm backtests four times faster.

TypeScript against Rust · seconds
One year of SPY minute bars983.9
The same, in Rust16.6
Genetic optimization, 36 backtests1994.3
The same, in Rust9.2

Same ten-year window, same bars out of my data lake, Fly machines of the same class on both sides. The minute row measures throughput: the TypeScript side made no trades on the runner I built for it. NextTrade is still on GitHub.

Two years of my life bought that gap. When I did the Opus 4.7 migration I could not have derived the cost optimizations myself, but I understood them once they were on screen. It read Parquet instead of decoded binaries, it pruned before it decoded, and it shared one prefetched metadata read across concurrent chunk fetches.

Astra is just... different.

Four models told me no

That migration bought me a lot, and I wanted more out of it. As April turned to May and May to June, I threw every serious agentic harness at this codebase specifically to make minutely backtests on my Public Portfolio Challenge faster. I used Claude Fable 5 through Claude Code, GPT-5.6 Sol, Grok 4.6 in Cursor, and Claude Opus across a dozen sessions.

Live shared portfolio snapshot · this is the actual Public Portfolio Challenge account.

I funded a real brokerage account with $25,000 and deployed it in public, so the account, the strategies and every trade are visible while they happen. The strategies themselves are on GitHub.

These models tried their best to make it faster. What none of them did was touch the allocation solver, and eventually one of them told me why:

What Claude Opus 5 told me

"The physics just wouldn't allow it to be faster."

That reading was reasonable. My Rust backtesting engine walks minute bars in a tight event-driven loop it shares with the live trading path, so the code that replays 2019 is the code that places real orders. Every model traced the same path: the LRU cache, the columnar pruning, then an allocator with a fixed iteration budget, already tuned with a leetcode-hard binary search. It was all bounded and predictable, with no garbage collector left to blame, so the remaining cost looked structural.

WHAT IT WAS DOING

One hundred guesses to land on one number.

ORIGINAL SOLVER
commit 3d679ac6d4

Three assets want 60%, 35% and 15% of the book. No position may exceed its 50% cap, and the three must add up to a 90% deployment target. The solver looks for one offset to subtract from every proposal. It has no formula for that offset, so it guesses, checks, and halves the interval. It ran on every rebalance and every simulated minute.

0of 100 passes
before it stops
let mut low  = min(value - cap);   // -35
let mut high = max(value);         // 60
for _ in 0..100 {
    let mid = 0.5 * (low + high);
    let sum = values.iter().zip(caps)
        .map(|(v, c)| (v - mid).clamp(0.0, *c))
        .sum::<f64>();
    if sum > target { low  = mid; }
    else            { high = mid; }
}
offset guess  
low -35.00high 60.00
clamped total   target 90.00

Press play. Watch how many passes it takes before the total settles on 90.

Illustrative inputs · iteration counts, not measured runtimeThe exact answer is offset 5.00 → 50 / 30 / 10

I 100% fully believed it. I started pricing hardware.

What Astra actually did

My engine allocates capital by projecting proposed portfolio weights onto the nearest feasible set: nothing below zero, nothing above its cap, everything summing to the deployment target. Here is how it had done that since I wrote it.

Before · commit 3d679ac6d4
let mut lower = /* lowest possible offset */;
let mut upper = /* highest possible offset */;

for _ in 0..100 {
    let midpoint = 0.5 * (lower + upper);
    let sum = values
        .iter()
        .zip(caps.iter())
        .map(|(value, cap)| (value - midpoint).clamp(0.0, *cap))
        .sum::<f64>();
    if sum > feasible_target { lower = midpoint; } else { upper = midpoint; }
}

let offset = 0.5 * (lower + upper);

Guess an offset. Add up every weight. Halve the interval. Do it a hundred times, every time any strategy rebalances, on every simulated minute of every backtest.

This is what replaced it in the common case.

After · commit 31b32262fc
// If every projected weight is strictly within its bounds, every slope
// is -1. The common offset follows from sum(values) - n*offset = target.
// Verify that assumption before returning; otherwise use the full sweep.
let goal = target.min(caps.iter().sum::<f64>()).max(0.0);
let offset = (values.iter().sum::<f64>() - goal) / values.len() as f64;
if goal > f64::EPSILON
    && offset.is_finite()
    && values.iter().zip(caps).all(|(v, cap)| {
        let w = v - offset;
        w > 0.0 && w < *cap
    })
{
    projected.clear();
    projected.extend(values.iter().map(|value| value - offset));
    // verify the sum, then return
}

Sum the weights, subtract the goal, divide by how many there are. Then check that every weight landed strictly inside its bounds, and if it did, that single number is the answer.

The search only ever existed to find where weights clip at zero or at their cap. When nothing clips, every weight moves by the same amount, and that amount falls out of the arithmetic in one step. The hundred halvings were solving a case that most rebalances never reach.

A hundred scans became one division.

WATCH THE MATH

The same answer.
A very different route.

8 ASSETS
1 SHARED OFFSET

Move every proposed weight by the same offset. Keep each between zero and its cap. Make the total equal 100%.

BEFOREBINARY SEARCH
0of 100 passes
through all eight weights
λ current guess
low high

Guess, add the clamped weights, then halve the interval.

mid = (low + high) / 2
total = Σ clamp(vᵢ − mid, 0, cᵢ)
if total > target: low = mid
else:              high = mid
Clamped total
AFTER · ASTRADIRECT SOLUTION
division
then a bounds check
λ =1.86 − 1.008
0.107500
Check every weight before returning.
offset = (Σ values − target) / n
if every weight is inside its bounds:
    return the verified projection
else:
    solve the matching linear segment
Verified total
PROJECTED WEIGHTS Binary search Astra

Press Play or Step to compare the two methods.

Illustrative inputs · each cap is 25% · iteration counts, not measured runtimeOpen full demo ↗

Measured against the shipped baseline

Eight-ETF risk parity over a full year of minute bars: 352.762s to 124.343s on a first pass (64.75%) and 309.881s to 100.263s warm (67.64%). Same harness, same primary, same financial contract, only the allocation module differs. Those two figures measure this one change against the release immediately before it, so they are not the campaign totals. The whole-campaign number for the same workload, 470.161s to 51.499s warm, arrives later and folds in every change that came after this one.

The paper

The reason I could not have written those seven lines is that I did not know what my own problem was called.

Astra named it. My weight projection is a special case of the continuous quadratic knapsack problem, which has a literature going back decades, and it cited Section 2 of Cominetti, Mascarenhas and Silva, A Newton's method for the continuous quadratic knapsack problem, published in 2014.

Once the problem has a name the structure is visible. Every weight is clamp(proposal[i] - offset, 0, cap[i]), so each coordinate changes behavior at exactly two offsets: the one where it pins to its cap, and the one where it falls to zero. Between those breakpoints the total is linear in the offset. Eight assets give you at most sixteen breakpoints. Sort them, sweep once, solve the segment holding your target.

The clamp equation
wi = clamp(vi − λ, 0, ci)
vi · proposed weightλ · shared offsetci · weight cap
How the clamped weight changes as the offset increases The weight stays at its cap until the offset reaches proposal minus cap, then decreases linearly until the offset reaches the proposal, then stays at zero. Light moves from left to right through those three regions. AT THE CAP FREE TO MOVE AT ZERO cᵢ 0 λ = vᵢ − cᵢ λ = vᵢ offset increases →

Two breakpoints. A straight line between them. Increase the offset and the weight moves from its cap toward zero.

That alone replaced a hundred scans with a sort and one pass. The guarded interior shortcut then removed the sort too, because when nothing is pinned every slope is exactly −1 and the answer is arithmetic.

I have written this allocator, profiled it, and optimized it twice. I never thought to ask whether somebody had already solved it in 2014.

Everything else in the same release

The projection was one of five changes Astra shipped in a single release, plus a repair to its own regression. Three of the five are things Rust lets you say out loud: borrow instead of clone, reuse a buffer instead of allocating, and settle at compile time which of two sweep directions a basket gets.

Shipped as source 307932169a on September 6, across all five backtesting machines. Click any row for the code and the numbers.
ChangeWhat it doesclick

That release is one of twenty-one accepted changes across the campaign. The broad stress workload, 5,655 names of minute options data, came down like this.

Broad cold series · seconds
Select a row to explore the change ↗

Phases reset between measurements. These are not additive percentages.

Across all of it, I have exactly one matched comparison between the engine before any of this and the engine after, on the same saved one-year minute options request with eighteen recorded observations.

Untouched engine 3d679ac6d4 against the optimized release. Medians are taken across predeclared samples. Click a row for what that cache state means.
Cache stateBeforeAfterLess timeSpeedupclick

So the Rust backtesting engine is 77.8% faster warm and 73.4% faster from a fresh process on a populated disk. The true number depends on cache state. On the workload the solver actually touches, eight-ETF risk parity, warm execution went from 470.161 seconds to 51.499 seconds. That is 89% less, or 9.1 times.

What it cost me to ship it

There were two real costs.

It cost storage, and it cost a lot of complexity. The sparse stock layout keeps a second representation of the same daily data beside the canonical one so a reader can take only the rows a strategy actually touches. Active companion data and indexes come to 69.375 GiB, and the whole sparse prefix including retained canaries is 77.044 GiB. At $0.02 per GiB-month that is about $1.54 a month.

The dollar figure was never the problem. The cost is that there are now two layouts, a publisher that has to keep them in step, a reader that falls back to canonical when a companion is missing or stale, and a whole class of bug where a backtest quietly reads the wrong representation. That complexity is permanent and I carry it on every change I make from here.

It is worth it at my volume, and it gets better with scale. Once I am running enough load that a machine has to be always on, a gigabyte and a half a month amortizes into nothing against the compute it saves.

The first version was slower where it counted. On baskets of 2,048 and 8,192 assets the sweep ran nearly twice as slow as the bisection it replaced, because cancellation while subtracting from a large capped total drove it into its own fallback after it had already paid for the sort. The repair sweeps downward from zero invested above 128 assets. At 8,192 the final version is 1.17 to 2.20 times faster, and it fell back in 0 of 72 calls where the first fell back in 72 of 72.

Who found the regression

The regression only showed on input shapes the first benchmark never covered, and I did not catch it. Astra did. It profiled the engine, found the bottleneck, read the code, wrote the fix, benchmarked it, noticed its own 8,192-asset regression, diagnosed the cancellation causing it, repaired it, ran the regression suite, deployed once I approved, and then asked whether I wanted to keep going. I barely asked a follow-up question.

Five minutes

Five minutes is roughly where a person stops waiting and goes to do something else. That was the target. On September 4 my own notes read: the cold five-minute goal remains unmet.

Broad 5,655-name stress

9m42s → ~4m

581.7s to 218–245s

Year request, app path

5m49s → 1m52s

post-first-fixes baseline

Saved options year, warm

37s

current source, September 7

I wanted five minutes. I got thirty-seven seconds warm, one minute fifty-two on the request my users actually submit, and under four minutes on the heaviest thing I run.

I did not buy anything. My notes from that week say do not buy larger machines yet, with the 160 GiB and 256 GiB resize ideas rejected. The fleet is the same five 128 GB machines it was in August. The bare metal I was pricing is still unbought.

These are the workloads I measured. They do not establish a five-minute ceiling for arbitrary histories, universes, strategies or concurrent load, and I have never claimed they do.

So is this AGI

AGI is here.

Every model I have used, including ones I have written glowing articles about, is excellent at work I can describe. Make this faster. Remove this allocation. Read four columns instead of twelve. I supply direction, the model supplies competence, and the ceiling on the result is my own imagination.

I could not have asked for this one. Asking required knowing that my allocator was an instance of a named problem, and I did not know it had a name. Astra crossed from a Rust file into a 2014 optimization paper, came back, and left seven lines that took 65% off a workload four other frontier models had looked at and left alone. One of them told me physics forbade it.

It knew something I did not, about my own code.

My codebase is not where it started doing this. Astra scores 97.6% on FrontierMath Tier 4, against 83.0% for the model before it. It pushed the bound on short prime gaps from 240 down to 186, and OpenAI published the conditional Lean 4 formalization and the numerical certificate alongside the paper. In a separate result it improved a term in a large prime gap bound that had not moved in more than eighty years. A model that produces new mathematics and then applies a decade-old paper to a Rust file it had never seen is doing the thing the word was invented for.

I wanted my platform to be the fastest retail trading platform there is. And now, it is.

Zolomon's speed was borrowed and it made him the fastest. Mine was borrowed too, out of a paper I never read, in seven lines I did not write. I will take that trade.

There are still theoretical improvements sitting in my run log, and I do not need a single one of them. The engine is far more than fast enough for my needs on even my most complex books, and it is faster than I ever imagined it would get.

Rust is now by far the best language to build in. It was always the fastest and the strictest; what changed is that the cost of satisfying it moved off me. The model writes the code, the compiler refuses the whole category of mistakes I used to review for, and a model at Astra's level makes even that review a formality. The tax I spent eighteen months complaining about is the exact thing that makes AI-written systems code safe to ship.

AGI stands for artificial general intelligence, and the load-bearing word is general. It means one system that is smarter than the average person across the whole spread of what people know.

Ask someone to explain the citric acid cycle, prototype a GPU from scratch, and interpret the result of a quantum mechanics experiment. We have experts in each of those three. I would wager that well under one percent of the people alive can do all three fluently. Astra does all three, and it also went and found a 2014 optimization paper for a Rust file it had never seen.

Superintelligence is the part that has become a hardware question. On August 6 AMD announced it is acquiring Taalas, a Toronto startup that etches model weights directly into the silicon rather than paging them out of high-bandwidth memory, keeping the KV cache and fine-tuning adapters in SRAM beside them. Its first chip served Llama 3.1 8B at 16,960 tokens a second. Take generality this broad, delete the trip from memory, and you end up with a model that processes about as fast as you can think.

That generality is already showing up a long way from code. Astra drives Blender directly, writing the Python, running it headless, looking at the render and revising it. Two days after launch the AI researcher Peter Gostev posted a clip of it rebuilding Craig Federighi as a 3D character, roughly 900 frames rendered and stitched into 19 seconds, and it cleared 2.5 million views by the next morning.

Astra rebuilding Craig Federighi in Blender. Posted by Peter Gostev, September 5, 2026.

The paper is the smallest part of it. The same model profiled my engine, found the bottleneck, wrote the fix, measured it, caught its own regression, repaired that, deployed, and asked whether I wanted to go again. Put that loop inside the system that builds worlds in Blender at 10,000 tokens per second, and general stops being the right word for what these things are doing.

ASI is coming.

Run a backtest and watch the clock

Describe a trading strategy in plain English. The Rust backtesting engine behind it is the one this article is about.

Open the agent
ENGINE NOTES

seconds · chart phase

RUST · CONDENSED

Source & measurement note

View the source change ↗

Build the strategy this article describes

Create a free account to backtest ideas against market history, inspect the risk, and deploy to paper or live markets when you're ready.

or

Free to browse. No credit card required.

Discussion

Sign in or create a free account to join the discussion.

No comments yet.