npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

dromanis.finora.common

v3.3.10

Published

Common utilities and functions for Dromanis Finora projects

Readme

Dromanis Finora Common

npm version License: MIT TypeScript Build Status Coverage

A comprehensive TypeScript utility library for financial calculations and portfolio analytics. This library provides robust, well-tested components for investment portfolio management, trading analytics, risk assessment, and financial data processing.

🌟 Features

  • 🧮 Financial Calculators: Portfolio analytics, trade calculations, cash flow analysis
  • 📊 Distribution Analysis: Risk, sector, industry, and instrument type distributions
  • 💱 Currency Support: Multi-currency portfolio support with FX rate conversions
  • 📈 Performance Analytics: P&L calculations, return percentages, daily change tracking
  • 🔧 Utility Functions: Date handling, formatting, string manipulation, number operations
  • 📋 Logging: Configurable logging with multiple levels and contexts
  • 🧪 Fully Tested: 100% test coverage with 507+ comprehensive tests
  • 🔄 Async Support: Modern async/await patterns with dependency injection
  • 📦 Dual Packaging: Both CommonJS and ES Module builds included

📦 Installation

npm install dromanis.finora.common

🚀 Quick Start

import { 
  PortfolioCalculator, 
  RiskProfileCalculator,
  TradeCalculator,
  Formatter,
  formatCurrency,
  parseDate
} from 'dromanis.finora.common';

// Calculate investment summary
const portfolioCalculator = new PortfolioCalculator();
const investmentSummary = await portfolioCalculator.calculateInvestmentSummary(
  asOfDateTime,
  userProfile,
  instruments,
  portfolios,
  transactions,
  cashTransactions,
  pricePoints,
  fxRatePoints,
  pricePointCalculator
);

// Analyze risk distribution
const riskCalculator = new RiskProfileCalculator();
const riskDistribution = riskCalculator.calculateRiskProfile(
  instruments,
  portfolioBreakdowns,
  instrumentRiskProfiles,
  userInstruments
);

// Format financial data
const formatter = new Formatter();
const formattedAmount = formatter.formatCurrency(1234.56, 'USD'); // "$1,234.56"
const formattedPercent = formatter.formatPercentage(12.345); // "12.35%"

📚 API Documentation

🧮 Financial Calculators

PortfolioCalculator

Core calculator for comprehensive investment portfolio analytics.

class PortfolioCalculator {
  async calculateInvestmentSummary(
    asOfDateTime: string,
    userProfile: UserProfile,
    instruments: Instrument[],
    portfolios: Portfolio[],
    transactions: Transaction[],
    cashTransactions: CashTransaction[],
    pricePoints: PricePoint[],
    fxRatePoints: FxRatePoint[],
    pricePointCalculator: IPricePointCalculator
  ): Promise<InvestmentSummary>
}

Features:

  • Multi-portfolio aggregation with currency conversion
  • Real-time P&L calculations with daily change tracking
  • Cash balance integration
  • Instrument-level breakdown analysis
  • Asynchronous price point resolution

Returns: InvestmentSummary containing:

  • totalAnalytics: Aggregated portfolio performance metrics
  • totalCashBalance: Combined cash positions across portfolios
  • portfoliosAnalytics: Individual portfolio breakdowns
  • portfoliosCashBalance: Per-portfolio cash balances

TradeCalculator

Calculates individual trades from transaction history with FIFO lot matching.

class TradeCalculator {
  async calculateTrades({
    asOfDateTime,
    instruments,
    portfolios,
    pricePoints,
    fxRatePoints,
    transactions,
    pricePointCalculator
  }: TradeCalculatorParams): Promise<Trade[]>
}

Features:

  • FIFO (First-In-First-Out) lot matching algorithm
  • Cross-currency position tracking
  • Real-time market value calculations
  • Previous day value and daily change percentage
  • Comprehensive analytics per trade

CashCalculator

Processes cash transactions and calculates balances.

class CashCalculator {
  calculateCashBalance(
    asOfDateTime: string,
    portfolio: Portfolio,
    cashTransactions: CashTransaction[],
    trades: Trade[],
    fxRatePoints: FxRatePoint[]
  ): CashBalance
}

FxRateCalculator

Handles currency conversions with interpolation and cross-currency support.

class FxRateCalculator {
  convert(
    amount: number,
    fromCurrency: string,
    toCurrency: string,
    asOfDateTime: string,
    fxRatePoints: FxRatePoint[]
  ): number | null
}

Features:

  • Direct and reverse currency pair lookup
  • Time-based rate interpolation
  • Cross-currency conversion via intermediate currencies
  • Automatic rate sorting and caching

PricePointCalculator

Calculates instrument prices with time-based interpolation.

class PricePointCalculator implements IPricePointCalculator {
  async calculatePricePoint(
    instrumentId: string,
    asOfDateTime: string,
    allPricePoints: PricePoint[]
  ): Promise<PricePoint | null>
}

📊 Distribution Analyzers

RiskProfileCalculator

Analyzes portfolio risk distribution across high/medium/low risk categories.

class RiskProfileCalculator {
  calculateRiskProfile(
    instruments: Instrument[],
    portfolioInstrumentBreakdowns: PortfolioInstrumentBreakdown[],
    instrumentRiskProfiles: InstrumentRiskProfile[],
    userInstruments: UserInstrument[]
  ): RiskDistribution
}

Returns: RiskDistribution with:

  • Risk percentage breakdowns (high/medium/low/unknown)
  • Absolute values per risk category
  • Instrument lists per risk level
  • Fallback to UserInstrument risk levels when profiles unavailable

SectorDistributionCalculator

Calculates portfolio distribution by market sectors.

class SectorDistributionCalculator {
  calculateSectorDistribution(
    instruments: Instrument[],
    portfolioInstrumentBreakdowns: PortfolioInstrumentBreakdown[]
  ): SectorDistribution
}

Features:

  • Sector-based portfolio allocation analysis
  • Top 3 sector concentration metrics
  • Herfindahl-Hirschman Index (HHI) diversification scoring
  • Instrument lists per sector

IndustryDistributionCalculator

Analyzes portfolio distribution by industries.

class IndustryDistributionCalculator {
  calculateIndustryDistribution(
    instruments: Instrument[],
    portfolioInstrumentBreakdowns: PortfolioInstrumentBreakdown[]
  ): IndustryDistribution
}

InstrumentDistributionCalculator

Provides granular instrument-level portfolio analysis.

class InstrumentDistributionCalculator {
  calculateInstrumentDistribution(
    instruments: Instrument[],
    portfolioInstrumentBreakdowns: PortfolioInstrumentBreakdown[]
  ): InstrumentDistribution
}

Features:

  • Individual instrument allocation percentages
  • Top 5 and Top 10 holdings analysis
  • Small holdings concentration (under 1%)
  • Diversification scoring

InstrumentTypeDistributionCalculator

Calculates distribution by asset classes (stocks, ETFs, bonds, etc.).

class InstrumentTypeDistributionCalculator {
  calculateInstrumentTypeDistribution(
    instruments: Instrument[],
    portfolioInstrumentBreakdowns: PortfolioInstrumentBreakdown[]
  ): InstrumentTypeDistribution
}

🔧 Utility Functions

Date Utilities

Comprehensive UTC-based date handling functions:

// Date parsing and validation
parseDate(dateString: string): moment.Moment | null
parseDateTime(dateTimeString: string): moment.Moment | null

// Date generation
getTodayDate(): string // YYYY-MM-DD format
getTodayDateTime(): string // YYYY-MM-DD HH:mm:ss format

// Date comparison
isAfter(date1: string, date2: string): boolean
isBefore(date1: string, date2: string): boolean
isSame(date1: string, date2: string): boolean
isSameOrAfter(date1: string, date2: string): boolean
isSameOrBefore(date1: string, date2: string): boolean

// Date arithmetic
addHours(dateTime: string, hours: number): string
addMinutes(dateTime: string, minutes: number): string
addDays(dateTime: string, days: number): string
addMonths(dateTime: string, months: number): string
addYears(dateTime: string, years: number): string

// Utility functions
toEndOfDayDateTime(dateOrDateTime: string): string
isExchangeOpen(dateTime: string, exchange: string): boolean

Formatting Utilities

Professional formatting for financial data:

class Formatter {
  formatCurrency(amount: number, currency: string): string
  formatPercentage(percentage: number): string
  formatQuantity(quantity: number): string
  formatEnum(enumValue: string): string
}

// Standalone formatting functions
formatCurrency(amount: number, currency?: string, locale?: string): string
round(value: number, decimals?: number): number
percentage(value: number, total: number, decimals?: number): number

String Utilities

Text processing and manipulation:

// Case conversions
capitalize(str: string): string
toCamelCase(str: string): string
toKebabCase(str: string): string

// Text processing
truncate(str: string, length: number, suffix?: string): string
normalizeWhitespace(str: string): string
randomString(length: number, charset?: string): string

Number Utilities

Mathematical operations and validations:

// Range operations
isInRange(value: number, min: number, max: number): boolean
clamp(value: number, min: number, max: number): number

// Validation
isEven(value: number): boolean
isOdd(value: number): boolean
isNegative(value: number): boolean

// Generation
randomNumber(min: number, max: number): number

Logging

Configurable logging system with multiple levels:

interface Logger {
  debug(message: string, context?: string, data?: any): void
  info(message: string, context?: string, data?: any): void
  warn(message: string, context?: string, data?: any): void
  error(message: string, context?: string, data?: any): void
  child(context: string): Logger
}

// Usage
import { logger, createLogger } from 'dromanis.finora.common';

logger.info('Portfolio calculation completed', 'PortfolioService', { portfolioId: 'P123' });
const childLogger = logger.child('TradeCalculator');

Configuration via Environment Variables:

  • LOG_LEVEL: DEBUG, INFO, WARN, ERROR (default: DEBUG)
  • LOG_TIMESTAMP: true/false (default: true)

ID Generation

Unique identifier generation using UUID v4 (GUID):

class IdGenerator {
  generateId(prefix?: string): string
}

// Global instance
import { idGenerator } from 'dromanis.finora.common';
const id = idGenerator.generateId('TXN'); // TXN-xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
const pureUuid = idGenerator.generateId(); // xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx

Features:

  • Generates RFC 4122 compliant UUID v4 (random-based)
  • Optional prefix support with hyphen separator
  • Uses crypto.randomUUID() when available for better performance
  • Fallback implementation for older environments
  • Guaranteed global uniqueness

Trade Utilities

Helper functions for trade and portfolio analysis:

class TradeUtil {
  getNumber(obj: any, key: string, fallback: number): number
  inferPortfolioCurrency(portfolioId: string, portfolios: Portfolio[], userProfile: UserProfile): string
  inferInstrumentDisplay(instrumentId: string, instruments: Instrument[]): { symbol: string; name: string }
  getAverageBuyingPrice(breakdown: PortfolioInstrumentBreakdown): number
  getAverageCurrentPrice(breakdown: PortfolioInstrumentBreakdown): number
  getTotalProfit(breakdown: PortfolioInstrumentBreakdown): number
  getTotalProfitPercentage(breakdown: PortfolioInstrumentBreakdown): number
  calculateProfitLoss(transaction: Transaction, trades: Trade[], fxRatePoints: FxRatePoint[]): number
}

🏗️ Type Interfaces

IPricePointCalculator

Interface for price point calculation services:

interface IPricePointCalculator {
  calculatePricePoint(
    instrumentId: string,
    asOfDateTime: string,
    allPricePoints: PricePoint[]
  ): Promise<PricePoint | null>
}

Distribution Result Types

interface RiskDistribution {
  highRiskPercentage: number
  mediumRiskPercentage: number
  lowRiskPercentage: number
  totalInvestmentValue: number
  breakdown: {
    highRisk: { value: number; percentage: number; instruments: string[] }
    mediumRisk: { value: number; percentage: number; instruments: string[] }
    lowRisk: { value: number; percentage: number; instruments: string[] }
    unknown: { value: number; percentage: number; instruments: string[] }
  }
}

interface SectorDistribution {
  sectors: Record<string, { percentage: number; value: number; instruments: string[] }>
  totalInvestmentValue: number
  diversificationScore: number
  topThreeConcentration: number
}

interface IndustryDistribution {
  industries: Record<string, { percentage: number; value: number; instruments: string[] }>
  totalInvestmentValue: number
  diversificationScore: number
}

interface InstrumentDistribution {
  instruments: Record<string, { percentage: number; value: number }>
  totalInvestmentValue: number
  diversificationScore: number
  topFiveConcentration: number
  topTenConcentration: number
  smallHoldingsConcentration: number
  smallHoldingsCount: number
}

interface InstrumentTypeDistribution {
  instrumentTypes: Record<string, { percentage: number; value: number; instruments: string[] }>
  totalInvestmentValue: number
  diversificationScore: number
  topThreeConcentration: number
}

🛠️ Development

Prerequisites

  • Node.js 16+
  • npm or yarn
  • TypeScript 5.0+

Setup

# Clone the repository
git clone <repository-url>
cd dromanis.finora.common

# Install dependencies
npm install

# Build the project
npm run build

Available Scripts

# Development
npm run build          # Build both ESM and CommonJS
npm run build:esm      # Build ES modules only
npm run build:cjs      # Build CommonJS only
npm run clean          # Remove build artifacts

# Testing
npm test               # Run all tests
npm run test:watch     # Run tests in watch mode
npm run test:coverage  # Generate coverage report

# Code Quality
npm run prepare        # Setup husky hooks

Project Structure

src/
├── domain/           # Financial calculation classes
│   ├── calculators/  # Core financial calculators
│   └── analyzers/    # Distribution analysis tools
├── utils/            # Utility functions
│   ├── date.ts       # Date handling utilities
│   ├── formatter.ts  # Data formatting
│   ├── string.ts     # String manipulation
│   ├── number.ts     # Mathematical operations
│   └── logger.ts     # Logging system
└── __tests__/        # Comprehensive test suite

Build System

The library uses TypeScript with dual-module compilation:

  • ESM Build (dist-esm/): Modern ES modules for bundlers
  • CommonJS Build (dist-cjs/): Legacy CommonJS for Node.js

Build configurations:

  • tsconfig.esm.json - ES modules configuration
  • tsconfig.cjs.json - CommonJS configuration
  • tsconfig.test.json - Test environment configuration

🧪 Testing

The library maintains 100% test coverage with comprehensive test suites:

  • 507+ Test Cases across 17 test suites
  • Numerical Validation for all financial calculations
  • Edge Case Coverage including error scenarios
  • Integration Tests for complex workflows
  • Performance Tests for large datasets
# Run specific test suites
npm test -- --testPathPattern=portfolioCalculator
npm test -- --testPathPattern=riskProfile
npm test -- --testPathPattern=utils

# Generate detailed coverage report
npm run test:coverage

Test Categories

  • Unit Tests: Individual function and class testing
  • Integration Tests: Multi-component workflow testing
  • Numerical Validation: Mathematical accuracy verification
  • Edge Case Testing: Boundary condition and error handling
  • Performance Testing: Large dataset handling verification

📋 Dependencies

Runtime Dependencies

Development Dependencies

  • TypeScript ^5.0.0 - Type-safe JavaScript development
  • Jest ^29.7.0 - Testing framework with TypeScript support
  • Husky ^8.0.0 - Git hooks for code quality

🔄 Version History

Latest: v3.0.1

Major Features:

  • ✨ UserInstrument fallback support in RiskProfileCalculator
  • 🔄 Asynchronous patterns with dependency injection
  • 📊 Enhanced daily change percentage calculations
  • 🧮 Comprehensive distribution analyzers
  • 🛡️ Improved error handling and edge case coverage

Breaking Changes:

  • Method signatures updated to support async/await patterns
  • Additional required parameters for enhanced functionality

Migration Guide

Updating from v2.x to v3.x requires:

  1. Async Method Calls: Update to async/await pattern
  2. Additional Parameters: Provide required dependencies
  3. Type Updates: Update imports for new distribution types
// v2.x (legacy)
const summary = portfolioCalculator.calculateInvestmentSummary(/*...*/);

// v3.x (current)
const summary = await portfolioCalculator.calculateInvestmentSummary(
  /*...existing params...*/, 
  pricePointCalculator
);

🤝 Contributing

We welcome contributions! Please follow these guidelines:

Code Standards

  • TypeScript: Use strict type checking
  • Testing: Maintain 100% test coverage
  • Documentation: Update README for new features
  • Formatting: Follow existing code style

Pull Request Process

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit changes (git commit -m 'Add amazing feature')
  4. Write comprehensive tests
  5. Push to branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

Issue Reporting

When reporting issues, please include:

  • Environment: Node.js version, OS, package version
  • Expected vs Actual: Clear description of the problem
  • Reproduction: Minimal code example
  • Error Messages: Full stack traces if applicable

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support

🔗 Related Packages


Made with ❤️ for the financial technology community