Conversation
APY is now calculated using active days (time with capital deployed) rather than calendar days from first entry. Idle gaps after full liquidation no longer dilute APY. start_date removed from fund config since it's redundant with first entry date. - Make start_date optional in SubFundConfig (deprecated) - Engine derives start date from first trade/cashflow entry - Server fund-metrics tracks cycle boundaries for active days - FundDetail.tsx uses active days for all APY calculations - Remove start_date from create/edit forms and import flows - Fix E2E test helper computeStartInput to handle accumulate mode
Replace snapshot-based denominator fallback chain with time-weighted average position (TWAP) so multi-cycle funds reflect actual average capital deployed over time rather than cumulative or current values.
isTestPlatform() used endsWith('test') which only matched platforms
named exactly 'test' or ending in 'test'. Changed to startsWith('test')
to match global-setup/teardown cleanup logic, fixing orphaned test
funds and platforms after E2E runs.
There was a problem hiding this comment.
Pull request overview
This PR updates fund performance metrics to use time-weighted denominators (TWAP/TWAB) and “active days” (time with capital deployed), removes reliance on start_date in fund config by deriving start dates from entries, and aligns test-platform detection with E2E cleanup behavior.
Changes:
- Replace snapshot-based trading-fund APY denominator with TWAP and update APY day-counting to use active days.
- Deprecate/make optional
start_dateacross engine/server/web, updating UI and import flows to derive from first entry/transaction. - Fix test-platform detection logic and update E2E helpers/specs accordingly; bump version to 0.38.2.
Reviewed changes
Copilot reviewed 34 out of 35 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/generate-m1test.cjs | Removes start_date from generated test config. |
| pages/src/engine/backtest.ts | Stops setting start_date in backtest scenario config. |
| packages/web/src/pages/FundDetail.tsx | Implements active-days APY + TWAP denominator and removes config start_date dependency. |
| packages/web/src/components/FundCharts.tsx | Derives chart start date from first entry instead of config. |
| packages/web/src/components/EditFundPanel.tsx | Removes start_date from edit form/state and submission payload. |
| packages/web/src/components/EditFundConfigModal.tsx | Removes start_date from config modal form/state and submission payload. |
| packages/web/src/components/CreateFundModal.tsx | Removes start_date from create form defaults and submission payload. |
| packages/web/src/components/CoinbaseImportButton.tsx | Makes fundStartDate optional and only renders when present. |
| packages/web/src/api/funds.ts | Makes FundConfig.start_date optional in the web API types. |
| packages/server/src/utils/test-data-generator.ts | Removes start_date usage from generated server-side test fund configs. |
| packages/server/src/utils/fund-metrics.ts | Adds active-days tracking + TWAP denominator to server-computed final metrics. |
| packages/server/src/services/dashboard-cache.ts | Aligns test-platform predicate to startsWith('test'). |
| packages/server/src/routes/platforms.ts | Removes start_date from cash-tracking enablement flow config. |
| packages/server/src/routes/import.ts | Derives Coinbase scrape/apply dates from earliest entries/transactions instead of config start date. |
| packages/server/src/routes/funds.ts | Aligns test-platform predicate to startsWith('test'); derives history start date from first entry. |
| packages/engine/test/recommendation.test.ts | Removes start_date from test config. |
| packages/engine/test/invariants.test.ts | Removes start_date from test config. |
| packages/engine/test/expected-equity.test.ts | Keeps start_date in one test (now optional) and adjusts formatting. |
| packages/engine/test/config-behaviors.test.ts | Removes start_date from test config. |
| packages/engine/test/aggregate.test.ts | Removes start_date from test config. |
| packages/engine/src/types.ts | Deprecates start_date and makes it optional for backward compatibility. |
| packages/engine/src/index.ts | Exports getFundStartDate from the engine public API. |
| packages/engine/src/expected-equity.ts | Uses config start_date if present, otherwise derives from first event for cash-interest accrual. |
| packages/engine/src/aggregate.ts | Derives start date from first trade/cashflow entry and computes TWFS accordingly. |
| package.json | Bumps version to 0.38.2. |
| package-lock.json | Bumps lockfile package version to 0.38.2. |
| e2e/yearly-simulation.spec.ts | Removes start_date usage and fixes expected start-input helper call for accumulate mode. |
| e2e/test-utils.ts | Makes start_date optional and fixes computeStartInput liquidation logic for accumulate mode. |
| e2e/integrity-tests.spec.ts | Removes start_date from generated configs and adjusts entry data for share-based expectations. |
| e2e/high-priority-features.spec.ts | Removes start_date from test configs. |
| e2e/fund-configurations.spec.ts | Removes start_date from test configs. |
| e2e/derivatives-funds.spec.ts | Removes start_date from derivatives test config generator. |
| e2e/cash-funds.spec.ts | Removes start_date from cash fund test config generator. |
| PLAN.md | Documents completion of TWAP + active-days changes and start_date removal. |
| .changelogs/v0.37.x.md | Adds a changelog entry describing TWAP denominator and related removals. |
Comments suppressed due to low confidence (1)
packages/server/src/utils/fund-metrics.ts:72
computeFundFinalMetricsusesentries[0]/entries[entries.length-1]and iteratesentriesassuming chronological order, but it never sorts. Because the API accepts out-of-order entries, this can yield negative/incorrect day deltas (TWAB/TWAP), wrong cycle boundaries, and an incorrectdaysActive/TWAP denominator. Sort a copy offund.entriesby date at the start of this function (and use that everywhere).
const startDate = entries.length > 0 ? entries[0]!.date : new Date().toISOString().slice(0, 10)
const endDate = lastState.date
const daysActive = Math.max(1, Math.floor(
(new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24)
))
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Fix platforms.ts isTestPlatform to use startsWith('test') matching
funds.ts and dashboard-cache.ts
- Sort entries chronologically in computeFundFinalMetrics to handle
out-of-order API entries
- Fix readFund call in import.ts to pass file path instead of fund ID
- Use min/max date derivation instead of assuming entries[0] is earliest
in funds.ts history endpoint and FundDetail.tsx
- Make getFundStartDate defensively find earliest date via linear scan
- Remove always-true daysActive > 0 guard and redundant ternaries in
fund-metrics APY calculation
- Move changelog entries from v0.37.x to v0.38.x to match actual version
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 34 out of 35 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- computeFundMetrics derives startDate from earliest of trades, cashFlows, and config.start_date; clamps daysActive to at least 1 - Pass entriesToCashFlows to computeFundMetrics for cash funds in both aggregate endpoints so TWFS and daysActive are computed correctly - Clarify activeDays logic in FundDetail.tsx with explicit boolean vars - Fix TWAP same-day inflation: use Math.max(0, ...) instead of Math.max(1, ...) for daysBetween in both client and server TWAP accumulation so same-date entries contribute 0 elapsed days
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 34 out of 35 changed files in this pull request and generated 5 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Use fractional days consistently for TWAP, TWAB, and activeDays calculations on both server and client (removes Math.floor from server day deltas to match client precision) - Fix computeCashInterest fallback to use asOfDate instead of new Date() which could produce negative periods in backtests - Update PR description to reflect current version (0.38.3)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 34 out of 35 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
packages/server/src/utils/fund-metrics.ts:73
- In the derivatives-fund branch,
daysActiveis still computed usingMath.floor(...), which drops fractional days. Elsewhere in this PR you switched to fractional-day precision (no flooring) to align client/server metrics. Consider using the same fractional-day calculation here (and the same clamping strategy) so derivatives APY/day counts are consistent with the rest of the system and with the client-sideFundDetailcalculations.
const startDate = entries.length > 0 ? entries[0]!.date : new Date().toISOString().slice(0, 10)
const endDate = lastState.date
const daysActive = Math.max(1, Math.floor(
(new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 60 * 60 * 24)
))
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
start_dateremoved from fund config as it's redundant with first entry dateisTestPlatform()changed fromendsWith('test')tostartsWith('test')to match cleanup logic, fixing orphaned test funds after E2E runsChanges
Engine (
packages/engine/)aggregate.tsstart_dateoptional inSubFundConfig(deprecated)getFundStartDatedefensively scans for minimum datecomputeCashInterestfallback to useasOfDateinstead ofnew Date()Server (
packages/server/)fund-metrics.tscomputeFundFinalMetricscomputeFundMetricsfor correct cash fund TWFSreadFundcall in import.ts to use file pathstart_datefrom import flowsWeb (
packages/web/)FundDetail.tsxstart_datefrom create/edit forms and import flowsTests & Infrastructure
v0.38.xfileTest Plan
npm run test- 222 tests)