The Day My Three Positions Were Really One
Suneet Malhotra
May 07, 2026
For most of the last year, my position-count cap has been 10 open trades. I have rarely come close. In practice the engine has hovered between three and six concurrent positions on any given day, and I have read that as a comfortable, well-diversified book. Last week I checked whether it was, and the answer was uncomfortable.
The check was straightforward. For each day in the last 90 sessions where I had three or more open options positions, I pulled the underlying tickers, computed the rolling 30-day return correlation between every pair, and asked the simple question: how many independent bets did I actually have on?
What I found
Across 47 multi-position days, the average pairwise correlation between my open underlyings was 0.71. The median was 0.74. The minimum on any single day was 0.42, and the maximum was 0.93.
For portfolio variance purposes, two assets with a 0.7 correlation behave like roughly one and a half assets, not two. Using the effective-N approximation N_eff = 1 / sum(w_i * w_j * rho_ij), my five-position days were running at roughly N_eff of 1.6 to 1.9. Five-position days were two-position days. Three-position days were closer to N_eff 1.2.
That is not diversification. That is one trade with a wider order ticket.
Why it happened
The engine's universe is biased toward high-liquidity tech: SPY, QQQ, AAPL, MSFT, NVDA, AMZN, META, GOOGL, AMD, AVGO. The bias score gate selects for clean directional setups, which on any given trending day tend to fire across most of the index leaders simultaneously. When the engine says "go long four names," those four names are usually different ways of being long the same factor.
I had spent a lot of time tuning per-trade risk. $100 max loss preferred. $200 max loss with conviction. $1,000 daily loss cap. 10 concurrent positions maximum. None of those parameters knew that three NVDA-correlated entries on the same day were ninety percent the same trade.
Where it cost me
I went back to the days where I had four or more open positions and the day went red on the dominant factor. There were 11 such days in the 90-session window. Average daily loss on those days was $187. That is a reasonable absolute number, but it is not a four-position outcome. It is a one-and-a-half-position outcome with the arithmetic of four. The daily loss cap was never breached because the per-trade risk caps were doing their job. The exposure that bled was the correlated exposure I was not measuring.
I do not know what those days would have looked like if I had taken one of the four positions instead of all four. A clean simulation would need to compare against the trades the bias score scored second-highest, not the trades the gate rejected, and I have not built that yet. The directional answer is bounded above by "less bad than what happened" and below by "exactly the same loss on a smaller dollar base."
What I am changing
Three things, in order of how likely they are to actually move the number.
1. A correlation-effective-N gate. Before opening a new position, the engine now estimates the rolling 30-day correlation of the candidate underlying against every currently held underlying. If the resulting effective N would not increase by at least 0.25, the trade is not taken. This is conservative. It will miss some good entries. It is the right shape for a system whose dominant sizing failure mode has been "more positions, same trade."
2. A factor-bucket cap. The 19-ticker universe is now sliced into three buckets: index proxies (SPY, QQQ), mega-cap tech (AAPL, MSFT, NVDA, AMZN, META, GOOGL, AMD, AVGO), and crypto-adjacent (COIN, MSTR, HOOD). Maximum two positions per bucket. The 10-position cap was implicitly assuming 10 independent bets. The bucket cap forces the engine to be honest about which bets are which.
3. Logging of effective-N alongside position count. The Telegram daily update used to say "5 open." It now says "5 open / N_eff 2.1." The framing matters. I had been reading position count as a proxy for diversification for so long that my intuition was wrong by a factor of two.
The general lesson
A portfolio of correlated positions does not feel like a concentrated bet on the way in. Each entry passes its own filters, looks like its own thesis, has its own stop. The concentration is emergent and only visible if you measure it. The number that would have shown me sooner was effective N, and I was not computing it.
This is the same shape as the slippage audit I ran two weeks ago. The cost was real, the metric existed, the chart was missing. A system that makes most of its decisions by passing per-trade filters does not automatically obey portfolio-level constraints. It will only obey the ones you have written down.
For the next 60 sessions I will track the new gates' effect on entry count and on those red factor days. If the bucket cap is too tight I will know within a few weeks, because the engine's trade rate will collapse below where it was. If the effective-N gate is doing its job, the variance on the worst factor days should compress visibly. Either way, the chart I should have been keeping is the chart I will be keeping now.
Share this post
You Might Also Like
The Check That Passes Until the Day It Does Not
Every day my engine reconciles its own record of open positions against the broker's. Almost every day the two lists match. I do not run the check for those days.
OpenClaw TutorialsThe Three-Percent Daily Stop That Freezes at $3,000
My engine has two daily loss limits: three percent of equity and a flat $3,000. They are the same number on exactly one day, the day the account opened. After that they quietly diverge.
AI & AutomationThe One Step I Never Hand to a Subagent
My content routine dispatches a fleet of subagents to gather, then hands none of them the draft. A fleet parallelizes retrieval. It cannot parallelize a voice.
Quantitative TradingThe Ninety Minutes My Engine Sits Out
My stock engine refuses to open any new position after 2:30 PM ET. It surrenders the most active hour of the day on purpose. Here is the arithmetic behind the refusal.
Latest Blog Posts
The One Step I Never Hand to a Subagent
My content routine dispatches a fleet of subagents to gather, then hands none of them the draft. A fleet parallelizes retrieval. It cannot parallelize a voice.
The Ninety Minutes My Engine Sits Out
My stock engine refuses to open any new position after 2:30 PM ET. It surrenders the most active hour of the day on purpose. Here is the arithmetic behind the refusal.
The Numbers I Used to Ask You to Trust
My April posts reported measured numbers you had to take on faith. My recent ones derive every figure from public config. The change was not discipline. It was topology.
Related Tools & Demos
Multi-Model LLM Harness
One interface to call any AI model — capability routing, fallback chains, budgets, circuit breakers, and a quality feedback loop. A practical architecture pattern write-up.
Automated Trading System
Multi-engine trading platform with real-time risk management, regime-based strategy selection, and automated order execution.
View Source Code →Personal Health Analytics
Multi-modal health data platform integrating wearables, lab results, and lifestyle tracking with predictive habit modeling.
View Source Code →
Stay in the Loop
Get weekly insights on AI-driven QA, engineering leadership, and automation strategies.
No spam, ever. Unsubscribe anytime.