| name | typescript-financial-data-modeling |
| description | Type-safe data modeling patterns for financial and economic data visualization applications Use when this capability is needed. |
| metadata | {"author":"C00ldudeNoonan"} |
TypeScript Financial Data Modeling
Branded Types for Domain Safety
type Brand<T, B extends string> = T & { readonly __brand: B };
type USD = Brand<number, 'USD'>;
type EUR = Brand<number, 'EUR'>;
export function usd(value: number): USD { return value as USD; }
export function eur(value: number): EUR { return value as EUR; }
export function addUSD(a: USD, b: USD): USD { return (a + b) as USD; }
type Percentage = Brand<number, 'Percentage'>;
type Ratio = Brand<number, 'Ratio'>;
type BasisPoints = Brand<number, 'BasisPoints'>;
export function percentage(value: number): Percentage {
if (value < 0 || value > 100) throw new Error(`Invalid percentage: ${value}`);
return value as Percentage;
}
export function percentageToRatio(pct: Percentage): Ratio {
return (pct / 100) as Ratio;
}
Time Series Data Structures
export interface TimeSeriesPoint<T = number> {
readonly timestamp: Date;
readonly value: T;
}
export interface TimeSeries<T = number> {
readonly id: string;
readonly name: string;
readonly unit: string;
readonly frequency: 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly';
readonly data: readonly TimeSeriesPoint<T>[];
readonly metadata?: {
readonly source: string;
readonly lastUpdated: Date;
readonly seasonallyAdjusted?: boolean;
};
}
export interface OHLCPoint {
readonly timestamp: Date;
readonly open: number;
readonly : ;
: ;
: ;
?: ;
}
{
: ;
: ;
: | | ;
: | | | ;
: [];
}
Economic Indicators with Discriminated Unions
interface BaseEconomicIndicator {
readonly id: string;
readonly country: string;
readonly releaseDate: Date;
readonly period: string;
}
export interface GDPIndicator extends BaseEconomicIndicator {
readonly type: 'gdp';
readonly value: number;
readonly growthRate: number;
readonly unit: 'billions_usd' | 'trillions_usd';
readonly seasonallyAdjusted: boolean;
}
export interface InflationIndicator extends BaseEconomicIndicator {
readonly type: 'inflation';
readonly rate: number;
readonly monthOverMonth: number;
readonly yearOverYear: number;
}
export interface {
: ;
: ;
: ;
}
= | | ;
(): i is {
i. === ;
}
(): {
(indicator.) {
: ;
: ;
: ;
}
}
Zod Runtime Validation
import { z } from 'zod';
export const OHLCSchema = z.object({
timestamp: z.coerce.date(),
open: z.number().positive(),
high: z.number().positive(),
low: z.number().positive(),
close: z.number().positive(),
volume: z.number().int().nonnegative().optional(),
}).refine(
(data) => data.high >= data.low && data.high >= data.open && data.low <= data.close,
{ message: 'Invalid OHLC: high >= all, low <= all' }
);
export const TimeSeriesSchema = z.object({
id: z.string().min(1),
name: z.string().min(1),
frequency: z.enum([, , , , ]),
: z.(z.({
: z..(),
: z.(),
})),
});
= z.({
: z.({
: z.(),
: z.().(),
: z.().(),
: z.().( (s.(, ))),
}),
}).( ({
: data[][],
: data[][],
: data[][],
: data[][],
}));
Nivo Integration Types
import type { Serie, Datum } from '@nivo/line';
export interface FinancialDatum extends Datum {
x: Date | string | number;
y: number | null;
metadata?: { volume?: number; change?: number };
}
export interface FinancialSerie extends Omit<Serie, 'data'> {
id: string;
data: readonly FinancialDatum[];
color?: string;
}
export function toNivoSeries(timeSeries: TimeSeries[]): FinancialSerie[] {
return timeSeries.map((series) => ({
id: series.id,
data: series.data.map((point) => ({ x: point., : point. })),
}));
}
Data Transformation Utilities
export function calculateMovingAverage(
data: readonly TimeSeriesPoint<number>[],
windowSize: number
): readonly TimeSeriesPoint<number>[] {
return data.map((point, index) => {
const start = Math.max(0, index - windowSize + 1);
const window = data.slice(start, index + 1);
const avg = window.reduce((sum, p) => sum + p.value, 0) / window.length;
return { timestamp: point.timestamp, value: avg };
});
}
export interface ChangeResult {
readonly absolute: number;
readonly percentage: number;
readonly direction: 'up' | 'down' | 'unchanged';
}
(): {
absolute = current - previous;
percentage = previous !== ? (absolute / previous) * : ;
{
absolute,
percentage,
: absolute > ? : absolute < ? : ,
};
}
API Response Types
export type ApiResponse<T> =
| { status: 'success'; data: T; timestamp: Date }
| { status: 'error'; error: { code: string; message: string } }
| { status: 'loading' };
export interface PaginatedResponse<T> {
data: readonly T[];
pagination: {
page: number;
pageSize: number;
totalItems: number;
hasNext: boolean;
};
}
Testing Utilities
type DataFactory<T> = (overrides?: Partial<T>) => T;
export const createMockOHLC: DataFactory<OHLCPoint> = (overrides = {}) => ({
timestamp: new Date(),
open: 100,
high: 105,
low: 98,
close: 102,
volume: 1000000,
...overrides,
});
export function generatePriceData(startPrice: number, days: number, volatility = 0.02): OHLCPoint[] {
let price = startPrice;
return Array.from({ length: days }, (_, i) => {
const change = (Math.random() - 0.5) * volatility * price;
const open = price;
const close = price + change;
const result = {
timestamp: new Date(2024, , i + ),
open, close,
: .(open, close) * ,
: .(open, close) * ,
: .(.() * ),
};
price = close;
result;
});
}
Source: C00ldudeNoonan/economic-data-project — distributed by TomeVault.