Skip to main content

Returns Initiative

Goal: Eliminate return tracking error between Sable and BTIG, and provide configurable calculation methods for administrators.

Why This Matters

Returns are the primary performance metric for investors. When Sable and BTIG report different returns for the same fund, it creates:

  • Confusion during investor reporting
  • Manual reconciliation work each month
  • Risk of reporting incorrect performance

The Problem

Sable return calculations differ from BTIG during months with large cash inflows/outflows. The tracking error is stable otherwise but material when cash moves.

Root Cause

Different return calculation methodologies:

SystemMethodCash Flow Handling
BTIGDaily TWR + Modified DietzTime-weighted within period
Sable (current)Simple flat capitalDeferred to next month

See Modified Dietz Method for detailed methodology comparison.

Solution

Make return calculation method configurable by administrator:

  • Method 1: Simple flat capital ("AIC way") - current behavior
  • Method 2: Modified Dietz method ("BTIG way") - matches broker

Success Criteria

CriterionTargetStatus
Monthly return difference ≤ 10 bpsAll fundsPending
Admin toggle for calculation methodPer fund/orgPending
Auto-reconciliation flags discrepancies > 10 bpsAutomatedPending
Documentation for both methodsComplete

Current Problems

  1. Cash flow timing: BTIG and Sable may record cash flows on different dates
  2. Weighting differences: Exact weight calculation may vary slightly
  3. NAV computation: Sable computes NAV from P&L rollup; BTIG has their own source
  4. Missing data: Some entities/months lack complete data

Approach: Loss Function Minimization

Rather than manually debugging each discrepancy, we use an iterative optimization approach:

Loss Function

L = Σ (sable_return - btig_return)²

Sum of squared monthly return differences across all funds/months.

Workflow

# 1. Compute current loss
sable returns loss --account AV7K

# 2. Identify largest contributors
sable returns loss --account AV7K --breakdown

# 3. Hypothesize fix (e.g., adjust cash flow timing)
# 4. Implement fix in sable-cli or dbt model
# 5. Re-run loss function
# 6. Repeat until L converges to acceptable threshold

Target

  • L < 0.0001 (less than 1 bp² average per month)
  • No individual month > 10 bps difference

This treats returns reconciliation as a convergence problem rather than a debugging exercise. Each iteration of sable-cli improvements should reduce L.

Current Status

As of January 2026:

  • Modified Dietz implemented in gold.v_dietz_daily
  • Returns comparison API available at /api/returns/comparison
  • Loss function tooling: not yet built
  • Admin configuration UI: not yet built

Implementation Roadmap

Epic 1: sable-cli Returns Loss Function

The foundation for the iterative convergence approach. All CLI commands live in sable-cli.

TicketDescriptionPriority
sable returns lossCompute L = Σ(sable - btig)² for account/fundHigh
sable returns loss --breakdownShow top contributors to loss by month/entityHigh
sable returns compareSide-by-side comparison table (Sable vs BTIG)High
Integration testsTest loss function with real BTIG dataMedium

CLI Usage:

# Compute total loss for an account
sable returns loss --account AV7K
# Output: L = 0.000342 (3.42 bp² total)

# Break down by month to find worst offenders
sable returns loss --account AV7K --breakdown
# Output:
# Month | Sable | BTIG | Diff | Contribution
# 2025-03 | 2.34% | 2.12% | 22 bps | 48.4%
# 2025-07 | -1.21% | -1.08% | 13 bps | 16.9%
# ...

# Compare returns side-by-side
sable returns compare --account AV7K --year 2025

Epic 2: Returns Method Configuration

Admin toggle for calculation method per fund/org.

TicketDescriptionPriority
Database schemaorg_settings.return_method enum (simple_flat, modified_dietz)High
Admin UISettings page to toggle method per fund/orgMedium
Apply method in calculationsUse selected method in P&L/returns viewsHigh
Migration pathHandle existing data when method changesMedium

Schema:

-- org_settings table
ALTER TABLE sable.org ADD COLUMN return_method TEXT
DEFAULT 'simple_flat'
CHECK (return_method IN ('simple_flat', 'modified_dietz'));

-- Or per-entity if needed
ALTER TABLE sable.entity ADD COLUMN return_method TEXT;

Epic 3: Automated Reconciliation

Scheduled flagging of discrepancies for review.

TicketDescriptionPriority
Scheduled comparison jobDaily/weekly cron to compare Sable vs BTIGMedium
Discrepancy flaggingFlag months with diff > 10 bpsHigh
Dashboard widgetShow flagged items requiring reviewMedium
Alert notificationsEmail/Slack when new discrepancies detectedLow

Workflow:

Daily job runs → Compares all funds →
≤ 10 bps: Auto-approve ✓
> 10 bps: Create review ticket → Notify admin

Backlog (Existing)

TicketTypeDescription
Validate 10 bps thresholdSpikeConfirm 10 bps is the right acceptance threshold
2025 YTD comparison reportTaskGenerate full year comparison for all funds

Key Metrics

Returns within:

  • ≤ 10 bps → Auto-approve (match)
  • 10-50 bps → Review required
  • > 50 bps → Investigate

Documentation

  • BTIG Integration - Data pipeline from BTIG
  • Initiative ID: c11848bc-ac6b-4a15-afa7-f6cc89cf5553