@accounter/server
Version:
Accounter GraphQL server
42 lines (41 loc) • 1.93 kB
TypeScript
import type { TimelessDateString } from '../../../shared/types/index.js';
export type PositionExecution = {
trade_date: Date;
trade_type: string;
nv: string | null;
net_value_trade_currency: string | null;
trade_currency: string | null;
};
export type SecurityPositionProto = {
/** Units held, derived from the ingested executions alone. */
quantity: number;
/** Weighted average price paid per unit bought, in the trade currency. Null with no buys. */
averageCost: number | null;
totalBought: number;
totalSold: number;
/** The currency the amounts above are in — the trade currency the executions report. */
currency: string | null;
/**
* The earliest ingested execution. The position is only as complete as history from this
* day on, which is what the UI has to say out loud: holdings are not ingested, so anything
* bought before the first scraped execution is invisible here.
*/
historyStartDate: TimelessDateString | null;
lastExecutionDate: TimelessDateString | null;
};
/**
* Whether anything is still held.
*
* `Math.abs` on purpose: a negative quantity means the ingested history starts mid-life — units
* were sold that were never seen bought — and that is a data-quality signal worth surfacing,
* not a closed position to filter away.
*/
export declare const isOpenPosition: (position: Pick<SecurityPositionProto, "quantity">) => boolean;
/**
* The holding a security's ingested executions add up to, plus what was paid for it.
*
* Derived, not reported: the bank's own balances are not ingested. Corporate actions that
* change the unit count without an execution row (a split, say) are therefore invisible, and a
* history that starts mid-life starts from zero — hence `historyStartDate`.
*/
export declare function calculateSecurityPosition(executions: readonly PositionExecution[]): SecurityPositionProto;