Optimising Portfolio Initialisation: Achieving ~99.96% Reduction in Processing Time

Alexander Talei

Alexander Talei

Founder at Obermind

Optimising Portfolio Initialisation: Achieving ~99.96% Reduction in Time

$ ./portfolio-init --mode=bulk --users=164,284

[2024-01-15 06:08:19.123456] ObermindStream - Starting portfolio initialisation...

[2024-01-15 06:08:19.143902] Loading user data... ✓

[2024-01-15 06:08:19.167210] Initialising strategies...

Progress:
164,284/164,284 (100%)

✓ Successfully initialised 164284 portfolios

Performance gain: 99.96%

Database calls optimised: Millions → 1

Scalability: Linear performance scaling

The Challenge

In financial technology, performance isn't just about user experience — it's about operational efficiency at scale. Our trading platform serves over 150,000+ active portfolios globally, and during system startup we need to initialise portfolio strategies for all users to ensure they're ready for market operations. That includes running valuations and risk metrics, loading orders, constructing positions, handling instrument and market data subscriptions, and more.

What started as a minor inconvenience with a few hundred users had grown into a significant operational bottleneck. Our initialisation process was taking over ~5.06 seconds on average per portfolio, and we knew this would scale poorly as our user base continued to grow.

The Problem: Death by a Million Database Calls

Our original initialisation approach seemed logical at first glance:

For each user portfolio:
1. Simulate login authentication
2. Initialise portfolio strategy
3. Set up market data subscriptions
4. Simulate logout

However, this approach had a fatal flaw hidden in the authentication step. Each simulated login was performing multiple database queries:

  • Credential verification — database query to validate user credentials
  • User data retrieval — database query to fetch user account information
  • Account validation — additional queries for account status checks

On a development server with only 484 portfolios, this resulted in 1,500+ individual database calls during startup. On our globally distributed production infrastructure — with databases across numerous datacenter locations — network latency amplified this into an unacceptable initialisation time.

The Investigation

Performance profiling revealed the bottleneck wasn't in the portfolio logic itself (which we'd spent years fine-tuning for ultra low-latency operations), but in the authentication layer that was silently creating unnecessary database calls. Each user initialisation was waiting for database roundtrips that were completely unnecessary — we already knew these were valid users since we'd just queried them from the database.

The authentication calls were happening because we were simulating the full login/logout cycle to trigger the portfolio initialisation code paths. While this ensured consistency with the normal user flow, it created a massive performance penalty during bulk initialisation.

The Solution: Direct Portfolio Initialisation

We implemented a direct initialisation approach that bypasses unnecessary authentication while maintaining all the critical portfolio setup logic.

Before (slow path):

Single DB query: Get all users
For each user:
├── Simulate login → Database credential check
├── Simulate login → Database user data fetch
├── Initialise portfolio strategy ✓
├── Setup market subscriptions ✓
└── Simulate logout → Database cleanup

After (fast path):

Single DB query: Get all users
For each user:
├── Create portfolio context directly
├── Initialise portfolio strategy ✓
├── Setup market subscriptions ✓
└── Clean up resources

The key insight was that portfolio initialisation and user authentication are orthogonal concerns. During startup, we don't need to verify credentials — we need to ensure portfolios are ready for trading and operations involving their assets.

Implementation Strategy

  • Preserved original logic — we kept the existing initialisation method intact for individual user scenarios
  • Added direct path — created a new initialisation method specifically for bulk operations
  • Maintained consistency — all the same portfolio setup, market data subscriptions, and business logic still execute
  • Zero behavioural changes — the end result is identical; only the path to get there is optimised

The Results

The performance improvement was dramatic:

| Metric | Before | After | | --- | --- | --- | | Time per portfolio | ~5.06 seconds | ~1.73 milliseconds | | Improvement | — | ~99.96% reduction | | Database calls (production) | Hundreds of thousands | 1 | | Scalability | Exponential degradation | Linear scaling |

Optimising Portfolio Initialisation: Achieving ~99.96% Reduction in Time

$ ./portfolio-init --mode=bulk --users=164,284

For our production environment serving 150,000+ portfolios, this optimisation means:

  • Startup time reduced dramatically
  • Significantly reduced database load during deployments
  • Faster disaster recovery and system restarts
  • Improved operational efficiency

Key Lessons Learned

  1. Profile before optimising — the bottleneck wasn't where we initially suspected. Performance profiling revealed that business logic was fast; it was the authentication layer causing delays.

  2. Question every database call — each database query should serve a purpose. During bulk operations, many individual queries can often be replaced with a single batch operation.

  3. Separate concerns — authentication and initialisation are different concerns. During startup, we don't need to verify what we already know to be true.

  4. Preserve existing behaviour — optimisation shouldn't change functionality. We maintained the original code path for individual operations while adding an optimised path for bulk operations.

  5. Think about scale early — what works for 100 users might not work for 100,000. Consider how your initialisation patterns will scale with growth.

Technical Implementation Notes

The solution involved:

  • Smart batching — single query to fetch all user data upfront
  • Direct object creation — bypassing authentication layers during bulk initialisation
  • Resource management — proper cleanup of temporary objects
  • Progress monitoring — added progress indicators for operational visibility
  • Graceful degradation — fallback to original method when needed

Conclusion

This optimisation demonstrates that significant performance gains often come from questioning fundamental assumptions about how systems should work. By separating authentication concerns from portfolio initialisation, we achieved a nearly 3000× performance improvement.

The lesson extends beyond our specific use case: when building systems at scale, always consider whether your initialisation patterns will grow linearly or exponentially with your user base. Sometimes the best optimisation is not doing unnecessary work at all.

Alipay
Stripe
Eurex
AWS
Azure
Google Cloud
Currenex
Velocity Trade
Bitcoin
CME
Interactive Brokers
Kraken
FIX API
XTX
Bloomberg
Binance

Lancez votre plateforme.

Commencer.