feat(performance): investment performance vs Moscow Exchange index (WealthLedger/main#54) (#200)
This commit was merged in pull request #200.
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
import { uncoveredOperationIntervals } from '../../operations/domain/operations-sync-plan';
|
||||
|
||||
const ZERO_MILLIS = 0;
|
||||
const NEXT_MILLISECOND = 1;
|
||||
|
||||
export enum PerformanceUnavailableReason {
|
||||
AccountValuationDatesDiffer = 'ACCOUNT_VALUATION_DATES_DIFFER',
|
||||
AmbiguousReturn = 'AMBIGUOUS_RETURN',
|
||||
HistoryStartUnknown = 'HISTORY_START_UNKNOWN',
|
||||
IndexHistoryUnavailable = 'INDEX_HISTORY_UNAVAILABLE',
|
||||
NonRubActivity = 'NON_RUB_ACTIVITY',
|
||||
NoSolution = 'NO_SOLUTION',
|
||||
OperationsHistoryIncomplete = 'OPERATIONS_HISTORY_INCOMPLETE',
|
||||
PortfolioValuationIncomplete = 'PORTFOLIO_VALUATION_INCOMPLETE',
|
||||
UnconfirmedTransfer = 'UNCONFIRMED_TRANSFER',
|
||||
UnvaluedSecuritiesTransfer = 'UNVALUED_SECURITIES_TRANSFER',
|
||||
}
|
||||
|
||||
export const performanceUnavailableReasons = Object.values(PerformanceUnavailableReason);
|
||||
|
||||
type Coverage = { asOf: Date; from: Date; to: Date };
|
||||
|
||||
/** Coverage is half-open and must include the instant of the last valuation. */
|
||||
export function hasPerformanceCoverage(
|
||||
accountId: string,
|
||||
from: Date,
|
||||
valuationAt: Date,
|
||||
coverage: Coverage[],
|
||||
): boolean {
|
||||
if (from.valueOf() >= valuationAt.valueOf()) return false;
|
||||
const end = new Date(valuationAt.valueOf() + NEXT_MILLISECOND);
|
||||
if (!coverage.some((item) => item.asOf >= valuationAt && item.to > valuationAt)) return false;
|
||||
const confirmed = coverage.map((item) => ({ accountId, from: item.from, to: item.to }));
|
||||
return uncoveredOperationIntervals([{ accountId, from, to: end }], confirmed).length === ZERO_MILLIS;
|
||||
}
|
||||
Reference in New Issue
Block a user