dromanis.finora.common
v3.3.10
Published
Common utilities and functions for Dromanis Finora projects
Maintainers
Readme
Dromanis Finora Common
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 metricstotalCashBalance: Combined cash positions across portfoliosportfoliosAnalytics: Individual portfolio breakdownsportfoliosCashBalance: 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): booleanFormatting 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): numberString 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): stringNumber 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): numberLogging
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-xxxxxxxxxxxxFeatures:
- 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 buildAvailable 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 hooksProject 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 suiteBuild 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 configurationtsconfig.cjs.json- CommonJS configurationtsconfig.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:coverageTest 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
- dromanis.finora.types
^3.0.1- Core type definitions - moment
^2.30.1- Date manipulation and parsing - string
^3.3.3- Advanced string operations
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:
- Async Method Calls: Update to async/await pattern
- Additional Parameters: Provide required dependencies
- 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
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit changes (
git commit -m 'Add amazing feature') - Write comprehensive tests
- Push to branch (
git push origin feature/amazing-feature) - 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
- Documentation: This README and inline code documentation
- Issues: GitHub Issues
- Discussions: GitHub Discussions
🔗 Related Packages
- dromanis.finora.types - Core type definitions
- dromanis.finora.api - API client library
- dromanis.finora.ui - React component library
Made with ❤️ for the financial technology community
