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,41 @@
|
||||
import { formatDecimal } from '#src/common/decimal';
|
||||
|
||||
import { candidateTransfers, readPerformanceOperations, sumFlows } from './performance-flows';
|
||||
|
||||
const at = (date: string) => new Date(date);
|
||||
const op = (accountId: string, type: string, date: string, units: string, currency = 'rub') => ({
|
||||
accountId, occurredAt: at(date), instrumentUid: null,
|
||||
payload: { type, payment: { units, nano: 0, currency } },
|
||||
});
|
||||
|
||||
describe('performance cash flows', () => {
|
||||
it('includes only external cash and preserves dividends within the portfolio', () => {
|
||||
const operations = [
|
||||
op('A', 'OPERATION_TYPE_INPUT', '2025-01-01T15:00:00Z', '100000'),
|
||||
op('A', 'OPERATION_TYPE_INPUT_ACQUIRING', '2025-02-01T15:00:00Z', '50000'),
|
||||
op('A', 'OPERATION_TYPE_OUTPUT', '2025-03-01T15:00:00Z', '-20000'),
|
||||
op('A', 'OPERATION_TYPE_DIVIDEND', '2025-04-01T15:00:00Z', '3000'),
|
||||
];
|
||||
const result = readPerformanceOperations(operations);
|
||||
expect(formatDecimal(sumFlows(result.flows))).toBe('130000');
|
||||
expect(result.flows).toHaveLength(3);
|
||||
});
|
||||
|
||||
it('treats equal opposite cash movements as unconfirmed transfer candidates, not a proven pair', () => {
|
||||
const result = readPerformanceOperations([
|
||||
op('A', 'OPERATION_TYPE_OUTPUT', '2025-03-01T15:00:00Z', '-50000'),
|
||||
op('B', 'OPERATION_TYPE_INPUT', '2025-03-01T15:01:00Z', '50000'),
|
||||
]);
|
||||
expect(candidateTransfers(result)).toEqual([{ accountIds: ['A', 'B'], type: 'cash' }]);
|
||||
expect(result.flows).toHaveLength(2);
|
||||
});
|
||||
|
||||
it('detects non-RUB operations and unvalued securities transfers', () => {
|
||||
const result = readPerformanceOperations([
|
||||
op('A', 'OPERATION_TYPE_INPUT', '2025-01-01T15:00:00Z', '10', 'usd'),
|
||||
op('B', 'OPERATION_TYPE_INPUT_SECURITIES', '2025-01-01T15:00:00Z', '0'),
|
||||
]);
|
||||
expect([...result.nonRubAccounts]).toEqual(['A']);
|
||||
expect([...result.unvaluedAccounts]).toEqual(['B']);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user