Skip to main content
POST
Get Variant History

Overview

Returns time-series portfolio history for all trading variants, aggregated across all models using each variant. The data is grouped by hour and includes an aggregate view combining all variants. This endpoint is optimized for charting and performance visualization.

Request

Input Schema

enum
default:"7d"
Time window for historical data retrieval

Example Request

Response

Output Schema

array
required
Array of variant history entries, one per variant
array
required
Combined portfolio history averaging all variants

Example Response

Data Aggregation

Hourly Bucketing

Raw portfolio snapshots are aggregated into hourly buckets:
  1. Query all portfolioSize records within the time window for each variant’s models
  2. Group timestamps by hour (truncate to YYYY-MM-DDTHH:00:00.000Z)
  3. Average all netPortfolio values within each hour bucket
  4. Sort by timestamp ascending

Multi-Model Aggregation

For variants with multiple models:
  • All models using the variant are identified via models.variant = ?
  • Portfolio values are averaged across models at each timestamp
  • This provides a representative “average model” view per variant

Aggregate Calculation

The aggregate array combines all variants:
  1. Collect all unique timestamps across all variants
  2. For each timestamp, average the values from all variants that have data
  3. This creates an “index” representing the overall platform performance

Empty History Handling

If a variant has no models or no portfolio data:
  • The variant is included in the response
  • history is an empty array []
  • This allows UI to display “No data” states per variant

Usage

Performance Optimization

Database Queries

Optimizations:
  • Index on ("createdAt", "modelId") for fast filtering
  • Parallel execution via Promise.all()
  • Early filtering at database level (not in-memory)

Time Window Performance

Caching Strategy

Recommendations:
  • Cache 30d data for longer (historical data rarely changes)
  • Shorter staleTime for 24h window (more recent = more volatile)
  • Use SSE to invalidate cache on new portfolio snapshots

Data Interpretation

Source: portfolioSize.netPortfolio from databaseCalculation:
Snapshot frequency: Varies by activity
  • During active trading: Every minute
  • Idle periods: Hourly scheduled snapshots
Hourly averaging: Multiple snapshots within an hour are averaged to smooth volatility
Purpose: Platform-wide performance benchmarkCalculation: Average of all variant values at each timestampUse cases:
  • Compare individual variants against overall performance
  • Identify outperforming/underperforming strategies
  • Visualize strategy diversification benefit
Note: Not weighted by model count or capital allocation
Causes:
  • Variant has no active models
  • Models were created after the time window start
  • Data retention policy deleted old records
Handling:
  • Empty history arrays for variants with no data
  • Aggregate only includes timestamps with at least one variant’s data
  • UI should gracefully handle gaps in time series

Get Variants

List all available variants and their configurations

Get Variant Stats

View aggregated performance statistics per variant

Best Practices

Charting Performance: For smooth charts with large datasets (30d window), consider:
  • Downsampling on the client side for display
  • Using canvas-based charting libraries (e.g., uPlot) instead of SVG
  • Virtualizing the time axis for very long time ranges
Data Consistency: Portfolio history is eventually consistent due to:
  • Asynchronous portfolio snapshot scheduling
  • Hourly bucketing and averaging
  • Multi-model aggregation
For real-time portfolio values, use the portfolio.getPortfolio endpoint instead.
Time Zones: All timestamps are in UTC (ISO 8601 format). Convert to local time zones in the UI:

Monitoring

The endpoint is tracked via Sentry:
Key metrics:
  • Span duration (target: < 500ms for 7d window)
  • Database query count (should equal 2 × number of variants)
  • Response payload size (monitor for > 1MB responses)