Debug the Impact Model
Reported by candidates from Millennium's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The Millennium OA reported in September 2026 looks like a finance problem, but it's a one-line bug fix wrapped in a lot of prose. You get a buggy quote loop and have to repair the recurrence without touching the signature. It's a simulation over a stream with one running state variable. If you read the spec slowly, the whole job is moving a multiplication. And if the wording rattles you mid-assessment, StealthCoder can run invisibly as a safety net while you finish.
The problem
A market-making desk quotes an ordered stream of client requests for one asset. Each completed request leaves a temporary signed market impact that biases later quotes and then decays. The supplied implementation produces the expected first quote, but its state drifts across a multi-request stream. Repair the recurrence without changing the method signature.
Buggy implementation to repair
The source's request objects are represented here by the portable parallel-array interface. This implementation intentionally retains the reported decay-placement defect:
public double[] quoteImpactStream(double reference, double[] impactParams, double liquidityScore, String[] sides, double[] quantities) {
double k = impactParams[0];
double decay = impactParams[1];
double halfSpread = impactParams[2];
double accumulatedImpact = 0.0;
double[] quotes = new double[sides.length];
boolean first = true;
for (int i = 0; i < sides.length; i++) {
double direction = sides[i].equals("BUY") ? 1.0 : -1.0;
double signedSpread = direction * halfSpread;
if (first) {
quotes[i] = reference + signedSpread;
first = false;
} else {
quotes[i] = reference + signedSpread + accumulatedImpact;
}
double currentSizeImpact = direction * k * quantities[i] * (1.0 - liquidityScore);
accumulatedImpact = accumulatedImpact * decay + currentSizeImpact;
}
return quotes;
}
Correct quote and state rules
Let impactParams = [k, decay, halfSpread]. The accumulated impact starts at 0.
For the current request, use direction +1 for BUY and -1 for SELL.
Emit reference + direction * halfSpread + accumulatedImpact. The current request must not affect its own quote.
Compute the current size impact as direction * k * quantity * (1 - liquidityScore).
After emitting the quote, update the state to (accumulatedImpact + currentSizeImpact) * decay. The resulting value biases the next request.
Return one quote per request in the original order.
Function
quoteImpactStream(reference: double, impactParams: double[], liquidityScore: double, sides: String[], quantities: double[]) → double[]
Examples
Example 1
reference = 100
impactParams = [0.01,0.5,0.1]
liquidityScore = 0.8
sides = ["BUY","BUY","SELL"]
quantities = [10,20,5]
return = [100.1,100.11,99.925]
The first quote has no prior impact. Its accepted BUY contributes 0.02 before decay, so the next offset is 0.01. The second BUY leaves an offset of 0.025 for the SELL quote.
Example 2
reference = 50
impactParams = [0.2,0.7,0.05]
liquidityScore = 1
sides = ["SELL","BUY"]
quantities = [100,250]
return = [49.95,50.05]
Perfect liquidity makes every size-impact contribution zero, so only the side-specific half spread changes each quote.
Example 3
reference = 10
impactParams = [0.1,0,0.2]
liquidityScore = 0
sides = ["BUY","BUY"]
quantities = [3,4]
return = [10.2,10.2]
A decay of zero clears the updated state after every request, so the second request also sees zero prior impact.
Constraints
1 <= sides.length = quantities.length <= 500.
impactParams.length = 3, representing nonnegative k, decay in [0, 1], and nonnegative halfSpread.
reference > 0 and every quantity is positive.
0 <= liquidityScore <= 1.
Every side is exactly BUY or SELL.
Every input and intermediate result fits in a finite double.Reported by candidates. Source: FastPrep
Pattern and pitfall
What it really reduces to: a single running accumulator updated in order. The buggy code applies decay only to the old accumulated value, then adds the new size impact. The spec says decay the sum. So the fix is accumulatedImpact = (accumulatedImpact + currentSizeImpact) * decay. That's it. The first-quote special case is redundant because accumulated impact starts at 0, so you can drop the boolean or leave it alone. Check example 1: the first BUY gives 0.02 impact, times 0.5 is 0.01, which matches the second quote of 100.11. The pitfall is overthinking it or changing the order. Quote first, then update state. Don't let the current request touch its own quote. Also watch the SELL sign on both the spread and the impact. Decay of 0 must clear state fully. If you blank on the sign handling live, StealthCoder is the hedge, but you probably won't need it.
StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.
You can drill Debug the Impact Model cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. If you're reading this with an OA window open, you're who this was built for.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Millennium's OA.
Millennium reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Debug the Impact Model FAQ
What's the actual bug in the Millennium impact model problem?+
Decay is applied in the wrong place. The buggy line multiplies only the old accumulated impact by decay, then adds the new size impact undecayed. The correct rule decays the sum: (accumulatedImpact + currentSizeImpact) * decay. Everything else in the loop is already right.
How hard is this OA question really?+
Easy on algorithm, tricky only on reading. It's one pass, O(n), with n up to 500. The risk is misreading the state update or the sign for SELL. Trace example 1 by hand and you'll confirm the fix in under two minutes.
Do I need to rewrite the whole function?+
No. Keep the signature and the loop. Change the state update line. You can also remove the first flag since accumulated impact starts at 0 and gives the same first quote. Minimal edits lower the chance of introducing new bugs.
Which edge cases should I test?+
Decay of 0, which should clear state after every request, as in example 3. Liquidity score of 1, which zeroes all size impact, as in example 2. Also a single request, and mixed BUY and SELL streams where the signed impacts partially cancel.
How do I prepare for this in 48 hours?+
Practice stateful stream simulations: read the spec, write the recurrence on paper, then code it. Verify against the given examples by hand. For this style, the skill is reading precisely and checking order of operations, not memorizing algorithms.