finance-calculator-pro 1.1.0 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@
11
11
  ![finance-calculator-pro banner](https://raw.githubusercontent.com/boffincoders/finance-calculator/refs/heads/master/.github/assets/finance-calculator-pro.png)
12
12
 
13
13
  > **Zero-dependency financial analysis engine for JavaScript and TypeScript.**
14
- > Calculate 30+ fundamental analysis metrics — valuation ratios, profitability metrics, liquidity ratios, solvency indicators, efficiency metrics, earnings quality signals, and bankruptcy risk scores — from raw financial data. No API calls. No heavy dependencies. Works in Node.js, browsers, and edge runtimes.
14
+ > Calculate 70+ financial metrics — valuation ratios, profitability, liquidity, solvency, efficiency, intrinsic value, composite scoring, TTM aggregation, historical analysis, and bankruptcy risk scores — from raw financial data. No API calls. No runtime dependencies. Works in Node.js, browsers, and edge runtimes.
15
15
 
16
16
  ---
17
17
 
@@ -50,7 +50,7 @@ Building a stock screener, neo-bank, or internal financial analysis tool? [Let's
50
50
 
51
51
  ---
52
52
 
53
- ## Metrics Reference — 30+ Fundamental Analysis Metrics
53
+ ## Metrics Reference — 70+ Functions Across 11 Categories
54
54
 
55
55
  ### Valuation Ratios
56
56
  | Metric | Function | Formula |
@@ -67,6 +67,7 @@ Building a stock screener, neo-bank, or internal financial analysis tool? [Let's
67
67
  | Dividend Yield | `dividendYield()` | `Annual Dividend / Price` |
68
68
  | Discounted Cash Flow (DCF) | `calculateDCF()` | Terminal value + discounted FCF streams |
69
69
  | Graham Number | `grahamNumber()` | `√(22.5 × EPS × Book Value)` |
70
+ | Market Cap to Total Capital | `marketCapToDebtCap()` | `Market Cap / (Market Cap + Total Debt)` |
70
71
 
71
72
  ### Profitability Metrics
72
73
  | Metric | Function | Formula |
@@ -101,6 +102,9 @@ Building a stock screener, neo-bank, or internal financial analysis tool? [Let's
101
102
  | Inventory Turnover | `inventoryTurnover()` | `COGS / Average Inventory` |
102
103
  | Receivables Turnover | `receivablesTurnover()` | `Revenue / Trade Receivables` |
103
104
  | Days Sales Outstanding (DSO) | `daysSalesOutstanding()` | `365 / Receivables Turnover` |
105
+ | Payable Days (DPO) | `payableDays()` | `(Trade Payables / COGS) × 365` |
106
+ | Working Capital Days | `workingCapitalDays()` | `(Working Capital / Revenue) × 365` |
107
+ | Cash Conversion Cycle | `cashConversionCycle()` | `DSO + DIO − DPO` |
104
108
 
105
109
  ### Earnings Quality Metrics
106
110
  | Metric | Function | Formula |
@@ -116,11 +120,37 @@ Building a stock screener, neo-bank, or internal financial analysis tool? [Let's
116
120
  | Sharpe Ratio | `sharpe()` | Risk-adjusted return vs risk-free rate |
117
121
  | Target Upside | `targetUpside()` | % gap to analyst target price |
118
122
 
123
+ ### Intrinsic Valuation & Scoring
124
+ | Metric | Function | Notes |
125
+ |---|---|---|
126
+ | Graham Number | `grahamNumber()` | Benjamin Graham's defensive value ceiling |
127
+ | Net Current Value Per Share | `computeNCVPS()` | (Current Assets − Total Liabilities) / Shares |
128
+ | Intrinsic Value Estimate | `computeIntrinsicValue()` | Simple 5-yr EPS projection with margin of safety |
129
+ | G-Factor (Composite) | `computeGFactor()` | Quality×40% + Growth×35% + Momentum×25% |
130
+ | Quality Score | `computeQualityScore()` | Piotroski + ROE vs sector + margins + pledge + promoter |
131
+ | Growth Score | `computeGrowthScore()` | Revenue growth + profit growth + EPS growth + CFO |
132
+ | Value Score | `computeValueScore()` | P/E vs avg + P/B vs sector + PEG + historical percentile |
133
+ | Momentum Score | `computeMomentumScore()` | SMA200 + RSI + ADX + volume ratio + ROC-125 |
134
+
119
135
  ### Growth & Timeseries Analysis
120
- - **YoY Growth** Year-over-year revenue, net income, EPS growth rates
121
- - **QoQ Growth** — Quarter-over-quarter sequential growth
122
- - **CAGR** Compound Annual Growth Rate over any period
123
- - **Fundamental Trends** — Multi-period margin trends, FCF conversion tracking
136
+ | Function | Description |
137
+ |---|---|
138
+ | `calculateGrowthRate()` | Single-period % growth rate |
139
+ | `yoyGrowth()` | Year-over-year growth rates for a series |
140
+ | `qoqGrowth()` | Quarter-over-quarter growth rates |
141
+ | `cagr()` | Compound Annual Growth Rate |
142
+ | `medianGrowth()` | Median YoY growth rate (outlier-resistant) |
143
+
144
+ ### TTM & Historical Aggregation
145
+ | Function | Description |
146
+ |---|---|
147
+ | `computeTTM()` | Trailing Twelve Months sum (last 4 quarters) |
148
+ | `computeTTMAvg()` | Trailing Twelve Months average |
149
+ | `computeNYearAverage()` | Rolling N-year average of quarterly data |
150
+ | `computeNYearSum()` | Rolling N-year sum of quarterly data |
151
+ | `computeHistoricalPoint()` | Value at exactly N quarters back |
152
+
153
+
124
154
 
125
155
  ---
126
156
 
@@ -247,14 +277,46 @@ Import any function directly for lightweight single-metric use. Every function r
247
277
 
248
278
  ```typescript
249
279
  import {
280
+ // Valuation
250
281
  pe, pb, ps, peg, evEbitda, evRevenue, evFcf,
251
282
  priceToCashFlow, earningsYield, grahamNumber, calculateDCF,
252
- roa, roe, roic, grossMargin, operatingMargin, netProfitMargin,
283
+ marketCapToDebtCap,
284
+
285
+ // Profitability
286
+ roa, roe, roic, grossMargin, operatingMargin, netProfitMargin, fcfMargin,
287
+
288
+ // Liquidity
253
289
  currentRatio, quickRatio, debtToEquity, interestCoverage,
290
+
291
+ // Solvency
254
292
  netDebt, netDebtToEbitda, debtToAssets,
255
- assetTurnover, receivablesTurnover, daysSalesOutstanding,
293
+
294
+ // Efficiency
295
+ assetTurnover, inventoryTurnover, receivablesTurnover, daysSalesOutstanding,
296
+ payableDays, workingCapitalDays, cashConversionCycle,
297
+
298
+ // Quality
256
299
  payoutRatio, cashConversionRatio,
300
+
301
+ // Risk
257
302
  altmanZScore, piotroski, sharpe, targetUpside,
303
+
304
+ // Intrinsic Valuation
305
+ computeNCVPS, computeGFactor, computeIntrinsicValue,
306
+
307
+ // Composite Scoring
308
+ computeQualityScore, computeGrowthScore, computeValueScore, computeMomentumScore,
309
+
310
+ // Growth
311
+ calculateGrowthRate, yoyGrowth, qoqGrowth, cagr, medianGrowth,
312
+
313
+ // TTM
314
+ computeTTM, computeTTMAvg,
315
+
316
+ // Historical
317
+ computeNYearAverage, computeNYearSum, computeHistoricalPoint,
318
+
319
+ // Insights Engine
258
320
  evaluate,
259
321
  } from 'finance-calculator-pro';
260
322
 
@@ -262,7 +324,8 @@ import {
262
324
  pe(150, 5); // → 30
263
325
  priceToCashFlow(150_000, 7_000); // → 21.43
264
326
  earningsYield(5, 150); // → 0.0333 (3.33%)
265
- grahamNumber(5, 20); // → 47.43 (null if EPS or book ≤ 0)
327
+ grahamNumber(5, 20); // → 47.43
328
+ marketCapToDebtCap(150_000, 20_000); // → 0.882 (88.2% equity financed)
266
329
 
267
330
  // Solvency
268
331
  netDebtToEbitda(20_000, 5_000, 10_000); // → 1.5
@@ -270,9 +333,8 @@ debtToAssets(20_000, 100_000); // → 0.20
270
333
 
271
334
  // Efficiency
272
335
  daysSalesOutstanding(50_000, 6_250); // → 45.6 days
273
-
274
- // Earnings Quality
275
- cashConversionRatio(7_000, 5_000); // → 1.4
336
+ payableDays(30_000, 200_000); // → 54.75 days
337
+ cashConversionCycle(45, 60, 55); // 50 days
276
338
 
277
339
  // Risk
278
340
  altmanZScore(15_000, 20_000, 7_500, 250_000, 50_000, 100_000, 60_000); // → 3.71
@@ -286,6 +348,36 @@ const result = piotroski({
286
348
  result.score; // → 4
287
349
  result.maxScore; // → 5
288
350
 
351
+ // Intrinsic Valuation
352
+ computeNCVPS(500_000, 300_000, 100_000); // → 2.00 (net current value per share)
353
+ computeIntrinsicValue(10, 0.15, 0.25); // → 5-yr EPS projection with 25% safety margin
354
+ computeGFactor(82, 78, 67); // → composite G-Factor score
355
+
356
+ // Composite Scoring
357
+ computeQualityScore({ piotroskiScore: 7, roeVsSector: 1.1,
358
+ marginsImproving: true, pledgeFree: true, promoterStable: true }); // → 82
359
+ computeGrowthScore({ revenueGrowthVsSector: 1.3, profitGrowthRate: 0.20,
360
+ epsGrowthRate: 0.18, cfoPositive: true, revenueAccelerating: true }); // → 78
361
+ computeValueScore({ peVs3yrAvg: 0.8, pbVsSector: 0.75, peg: 0.9,
362
+ historicalPePercentile: 30 }); // → 72
363
+ computeMomentumScore({ priceVsSma200: 1.08, rsi: 58, adx: 28,
364
+ volumeRatio: 1.2, roc125: 0.18 }); // → 67
365
+
366
+ // TTM Aggregation
367
+ const quarters = [2200, 2400, 2600, 2800]; // Q1–Q4 revenue
368
+ computeTTM(quarters); // → 10000 (annualised TTM)
369
+ computeTTMAvg(quarters); // → 2500 (average quarterly)
370
+
371
+ // Historical Analysis
372
+ const qData = [2000, 2200, 2400, 2600, 2800, 3000, 3200, 3400];
373
+ computeNYearAverage(qData, 2); // → 2700 (2-year average)
374
+ computeNYearSum(qData, 1); // → 12400 (last 4 quarters sum)
375
+ computeHistoricalPoint(qData, 4); // → 2600 (same quarter last year)
376
+
377
+ // Growth
378
+ cagr(1000, 2000, 5); // → 0.1487 (14.87%)
379
+ medianGrowth([800, 900, 1100, 1050, 1300]); // → 0.176 (17.6%)
380
+
289
381
  // Pair raw math with the Insights Engine
290
382
  const ratio = pe(150, 5); // → 30
291
383
  evaluate.pe(ratio);
@@ -372,7 +464,7 @@ interface CompanySnapshotInput {
372
464
  | `analyzeProfitability(data, insights?)` | Profitability | ROA, ROE, ROIC, all margins |
373
465
  | `analyzeLiquidity(data, insights?)` | Liquidity | Current, Quick, D/E, Interest Coverage |
374
466
  | `analyzeSolvency(data, insights?)` | Solvency | Net Debt, Net Debt/EBITDA, Debt/Assets |
375
- | `analyzeEfficiency(data, insights?)` | Efficiency | Asset Turnover, Inventory, Receivables, DSO |
467
+ | `analyzeEfficiency(data, insights?)` | Efficiency | Asset Turnover, Inventory, Receivables, DSO, Payable Days, WC Days, CCC |
376
468
  | `analyzeRisk(data, insights?)` | Risk | Altman Z-Score, Sharpe, Piotroski F-Score |
377
469
  | `analyzeQuality(data, insights?)` | Quality | Payout Ratio, Cash Conversion Ratio |
378
470
  | `analyzeBatch(dataArray, insights?)` | Batch | Array of snapshots → array of analyses |
@@ -385,7 +477,7 @@ interface CompanySnapshotInput {
385
477
  | Feature | finance-calculator-pro |
386
478
  |---|---|
387
479
  | Dependencies | **Zero** |
388
- | Bundle size | **< 20 KB** (tree-shakeable) |
480
+ | Bundle size | **< 50 KB** (tree-shakeable) |
389
481
  | TypeScript | **Full types included** |
390
482
  | Return type | `number \| null` (never throws) |
391
483
  | Insights engine | **Built-in** (value + status + insight) |
package/dist/index.d.mts CHANGED
@@ -711,6 +711,18 @@ declare const evRevenue: (enterpriseValue: number, totalRevenue: number) => numb
711
711
  */
712
712
  declare const evFcf: (enterpriseValue: number, freeCashFlow: number) => number | null;
713
713
 
714
+ /**
715
+ * Market Cap to Total Capitalization Ratio (Market Cap / (Market Cap + Debt))
716
+ * Also known as the equity-to-total-capital ratio.
717
+ * Formula: Market Cap / (Market Cap + Total Debt)
718
+ * Interpretation:
719
+ * - Ranges from 0 to 1.
720
+ * - Higher ratio → company is predominantly equity-financed (lower financial risk).
721
+ * - Lower ratio → company is more debt-heavy relative to its total capital.
722
+ * - Useful for comparing capital structure across companies.
723
+ */
724
+ declare const marketCapToDebtCap: (marketCap: number, totalDebt: number) => number | null;
725
+
714
726
  /**
715
727
  * Return on Equity (ROE)
716
728
  * Formula: Net Income / Equity
@@ -870,6 +882,38 @@ declare const receivablesTurnover: (totalRevenue: number, tradeReceivables: numb
870
882
  */
871
883
  declare const daysSalesOutstanding: (totalRevenue: number, tradeReceivables: number) => number | null;
872
884
 
885
+ /**
886
+ * Payable Days (Days Payable Outstanding — DPO)
887
+ * Formula: (Trade Payables / COGS) × 365
888
+ * Interpretation:
889
+ * - How many days on average it takes the company to pay its suppliers.
890
+ * - Higher DPO can indicate strong bargaining power, but excessively high values
891
+ * may signal liquidity stress or strained supplier relationships.
892
+ */
893
+ declare const payableDays: (tradePayables: number, cogs: number) => number | null;
894
+
895
+ /**
896
+ * Working Capital Days
897
+ * Formula: (Working Capital / Revenue) × 365
898
+ * Where Working Capital = Current Assets - Current Liabilities
899
+ * Interpretation:
900
+ * - Measures how many days of revenue are tied up in working capital.
901
+ * - Lower is generally better (capital is not locked in operations).
902
+ * - Negative values indicate current liabilities exceed current assets.
903
+ */
904
+ declare const workingCapitalDays: (workingCapital: number, revenue: number) => number | null;
905
+
906
+ /**
907
+ * Cash Conversion Cycle (CCC)
908
+ * Formula: Debtor Days + Inventory Days - Payable Days
909
+ * Interpretation:
910
+ * - Measures the number of days it takes to convert inventory/payables into cash.
911
+ * - Lower (or negative) is better — negative CCC means the company collects cash
912
+ * before it pays its suppliers (e.g. e-commerce, supermarkets).
913
+ * - High positive CCC indicates capital is tied up in operations for longer.
914
+ */
915
+ declare const cashConversionCycle: (debtorDays: number, inventoryDays: number, payableDays: number) => number;
916
+
873
917
  /**
874
918
  * Dividend Payout Ratio
875
919
  * The proportion of earnings paid to shareholders as dividends.
@@ -930,6 +974,56 @@ declare const altmanZScore: (workingCapital: number, retainedEarnings: number, e
930
974
  */
931
975
  declare const grahamNumber: (eps: number, book: number) => number | null;
932
976
 
977
+ /**
978
+ * Net Current Value Per Share (NCVPS)
979
+ * Formula: (Current Assets - Total Liabilities) / Shares Outstanding
980
+ * Interpretation:
981
+ * - A conservative "liquidation value" per share, inspired by Benjamin Graham's
982
+ * net-net working capital criterion.
983
+ * - If NCVPS > market price, the stock may be trading below liquidation value —
984
+ * a deep value signal (but also common in distressed or declining businesses).
985
+ * - Positive NCVPS means current assets alone cover all liabilities.
986
+ */
987
+ declare const computeNCVPS: (currentAssets: number, totalLiabilities: number, sharesOutstanding: number) => number | null;
988
+
989
+ /**
990
+ * G-Factor (Composite Fundamental Score)
991
+ * Formula: (Quality × 0.40) + (Growth × 0.35) + (Momentum × 0.25)
992
+ * Inputs should be scores in the range [0, 100].
993
+ * Output is a weighted composite in the range [0, 100].
994
+ *
995
+ * Interpretation:
996
+ * - G-Factor > 70 → Strong composite fundamentals
997
+ * - G-Factor 40–70 → Average
998
+ * - G-Factor < 40 → Weak
999
+ *
1000
+ * Weights are based on typical quantitative equity-factor research priorities:
1001
+ * Quality is the most predictive of long-term returns; Growth drives near-term
1002
+ * re-rating; Momentum captures market confirmation of the thesis.
1003
+ */
1004
+ declare const computeGFactor: (qualityScore: number, growthScore: number, momentumScore: number) => number;
1005
+
1006
+ /**
1007
+ * Simplified Intrinsic Value Estimate
1008
+ * Formula: EPS × (1 + growthRate) ^ years / (1 + discountRate) ^ years
1009
+ * applied over a default 5-year horizon, then divided by (1 - safetyMargin)
1010
+ *
1011
+ * A lightweight DCF approximation for quick screening:
1012
+ * intrinsicValue = (EPS × (1 + growthRate)^5) / (1 - safetyMargin)
1013
+ *
1014
+ * Parameters:
1015
+ * @param eps Earnings Per Share (current or TTM)
1016
+ * @param growthRate Expected annual EPS growth rate as a decimal (e.g. 0.15 for 15%)
1017
+ * @param safetyMargin Margin of safety as a decimal (e.g. 0.25 for 25% discount)
1018
+ *
1019
+ * Interpretation:
1020
+ * - If market price < intrinsicValue → potential undervaluation
1021
+ * - safetyMargin of 0.25–0.35 is conventional for conservative investing
1022
+ *
1023
+ * Returns null for non-positive EPS or invalid inputs.
1024
+ */
1025
+ declare const computeIntrinsicValue: (eps: number, growthRate: number, safetyMargin: number) => number | null;
1026
+
933
1027
  /**
934
1028
  * Calculate basic growth rate given current and previous values.
935
1029
  * Useful for building out mapping functions natively in the analyzer.
@@ -950,6 +1044,16 @@ declare const qoqGrowth: (dataPoints: number[]) => number[];
950
1044
  * Formula: (Ending Value / Beginning Value) ^ (1 / Years) - 1
951
1045
  */
952
1046
  declare const cagr: (beginningValue: number, endingValue: number, periods: number) => number | null;
1047
+ /**
1048
+ * Median Growth Rate
1049
+ * Calculates the YoY growth rates for a series of annual values (oldest first),
1050
+ * then returns the median of those rates.
1051
+ * Interpretation:
1052
+ * - More robust than mean growth because it is not skewed by outlier years.
1053
+ * - Useful for evaluating the "typical" annual growth of earnings, revenue, etc.
1054
+ * Returns null if fewer than 2 data points are provided.
1055
+ */
1056
+ declare const medianGrowth: (annualValues: number[]) => number | null;
953
1057
 
954
1058
  /**
955
1059
  * Analyst Target Upside / Downside
@@ -960,4 +1064,192 @@ declare const cagr: (beginningValue: number, endingValue: number, periods: numbe
960
1064
  */
961
1065
  declare const targetUpside: (currentPrice: number, targetPrice: number) => number | null;
962
1066
 
963
- export { type CompanySnapshotInput, type EvaluatedMetric, type FundamentalTimeseriesInput, type MetricStatus, type PiotroskiInput, type PiotroskiResult, type PiotroskiSignals, altmanZScore, analyzeBatch, analyzeCompany, analyzeEfficiency, analyzeFundamentalTrends, analyzeLiquidity, analyzeProfitability, analyzeQuality, analyzeRisk, analyzeSolvency, analyzeValuation, assetTurnover, cagr, calculateDCF, calculateEnterpriseValue, calculateGrowthRate, cashConversionRatio, currentRatio, daysSalesOutstanding, debtToAssets, debtToEquity, dividendYield, earningsYield, evEbitda, evFcf, evRevenue, evaluate, fcfMargin, grahamNumber, grossMargin, impliedSharePrice, interestCoverage, inventoryTurnover, netDebt, netDebtToEbitda, netProfitMargin, operatingMargin, payoutRatio, pb, pbFromMarketCap, pe, peg, piotroski, priceToCashFlow, priceToCashFlowPerShare, ps, psFromMarketCap, qoqGrowth, quickRatio, receivablesTurnover, roa, roe, roic, safeDivide, sharpe, targetUpside, yoyGrowth };
1067
+ /**
1068
+ * Trailing Twelve Months (TTM) Utilities
1069
+ *
1070
+ * TTM aggregates the most recent four quarters of data to produce
1071
+ * an annualised figure without waiting for a full fiscal year.
1072
+ */
1073
+ /**
1074
+ * Trailing Twelve Months Sum
1075
+ * Returns the sum of the last 4 quarterly values (or fewer if < 4 available).
1076
+ * Expects values in chronological order: oldest first, most recent last.
1077
+ * e.g. [Q1, Q2, Q3, Q4, Q1_next, Q2_next] → sums last 4
1078
+ */
1079
+ declare const computeTTM: (quarterlyValues: number[]) => number | null;
1080
+ /**
1081
+ * Trailing Twelve Months Average
1082
+ * Returns the average of the last 4 quarterly values (or fewer if < 4 available).
1083
+ * Handles arrays shorter than 4 gracefully by averaging whatever is available.
1084
+ * Expects chronological order: oldest first, most recent last.
1085
+ */
1086
+ declare const computeTTMAvg: (quarterlyValues: number[]) => number | null;
1087
+
1088
+ /**
1089
+ * Historical Aggregation Utilities
1090
+ *
1091
+ * Functions for computing averages, sums, and point lookups over
1092
+ * rolling windows of quarterly (or annual) data.
1093
+ * All functions expect chronological order: oldest first, most recent last.
1094
+ */
1095
+ /**
1096
+ * N-Year Average
1097
+ * Returns the average of the last (years × 4) quarterly values.
1098
+ * e.g. computeNYearAverage(data, 3) → average of last 12 quarters.
1099
+ * If fewer values are available than requested, averages all available values.
1100
+ */
1101
+ declare const computeNYearAverage: (quarterlyValues: number[], years: number) => number | null;
1102
+ /**
1103
+ * N-Year Sum
1104
+ * Returns the sum of the last (years × 4) quarterly values.
1105
+ * If fewer values are available, sums all available values.
1106
+ */
1107
+ declare const computeNYearSum: (quarterlyValues: number[], years: number) => number | null;
1108
+ /**
1109
+ * Historical Point Lookup
1110
+ * Returns the value at exactly `quartersBack` quarters from the most recent value.
1111
+ * quartersBack = 0 → most recent value
1112
+ * quartersBack = 4 → value from 1 year ago (same quarter last year)
1113
+ * Returns null if the index is out of bounds.
1114
+ */
1115
+ declare const computeHistoricalPoint: (quarterlyValues: number[], quartersBack: number) => number | null;
1116
+
1117
+ /**
1118
+ * Composite Scoring Engine
1119
+ *
1120
+ * Four domain scores — Quality, Growth, Value, Momentum — each in range [0, 100].
1121
+ * Each score is a weighted sum of normalised sub-signals (also 0-100 or boolean).
1122
+ *
1123
+ * These scores feed into computeGFactor for the overall composite.
1124
+ */
1125
+ interface QualityScoreInput {
1126
+ /** Piotroski F-Score (0–9) */
1127
+ piotroskiScore: number;
1128
+ /**
1129
+ * ROE vs. sector median — percentage of sector ROE this company achieves.
1130
+ * e.g. if company ROE is 18% and sector median is 15%, pass 18/15 = 1.2.
1131
+ * Capped at 1.0 (100 points if >= sector median).
1132
+ */
1133
+ roeVsSector: number;
1134
+ /** Whether operating margins are improving YoY (boolean) */
1135
+ marginsImproving: boolean;
1136
+ /** Promoter pledge percentage is 0 or negligible (boolean) */
1137
+ pledgeFree: boolean;
1138
+ /** Promoter holding is stable or increasing YoY (boolean) */
1139
+ promoterStable: boolean;
1140
+ }
1141
+ /**
1142
+ * Quality Score (0–100)
1143
+ * Weights:
1144
+ * Piotroski (0–9 → 0–100): 30 %
1145
+ * ROE vs Sector (capped at 1.0 multiplier): 20 %
1146
+ * Margins improving: 20 %
1147
+ * Pledge-free: 15 %
1148
+ * Promoter stable: 15 %
1149
+ */
1150
+ declare const computeQualityScore: (input: QualityScoreInput) => number;
1151
+ interface GrowthScoreInput {
1152
+ /**
1153
+ * Revenue growth rate relative to sector.
1154
+ * e.g. if company revenue grew 20% and sector average is 12%, pass 20/12 = 1.67.
1155
+ * Capped at 1.0 (100 points if >= sector growth).
1156
+ */
1157
+ revenueGrowthVsSector: number;
1158
+ /**
1159
+ * Profit (net income) growth rate as decimal (e.g. 0.20 for 20% growth).
1160
+ * Capped at 30% for full score (0.30 → 100).
1161
+ */
1162
+ profitGrowthRate: number;
1163
+ /**
1164
+ * EPS growth rate as decimal. Capped at 25% for full score (0.25 → 100).
1165
+ */
1166
+ epsGrowthRate: number;
1167
+ /** Operating cash flow is positive this period (boolean) */
1168
+ cfoPositive: boolean;
1169
+ /** Revenue acceleration: current year growth > prior year growth (boolean) */
1170
+ revenueAccelerating: boolean;
1171
+ }
1172
+ /**
1173
+ * Growth Score (0–100)
1174
+ * Weights:
1175
+ * Revenue growth vs sector: 25 %
1176
+ * Profit growth rate: 25 %
1177
+ * EPS growth rate: 20 %
1178
+ * CFO positive: 15 %
1179
+ * Revenue accelerating: 15 %
1180
+ */
1181
+ declare const computeGrowthScore: (input: GrowthScoreInput) => number;
1182
+ interface ValueScoreInput {
1183
+ /**
1184
+ * Current P/E divided by the stock's own 3-year average P/E.
1185
+ * e.g. currentPE = 15, avgPE = 20 → ratio = 15/20 = 0.75 (trading below avg → higher score).
1186
+ * Score is higher when ratio < 1 (currently cheaper than historical average).
1187
+ */
1188
+ peVs3yrAvg: number;
1189
+ /**
1190
+ * Current P/B vs sector median P/B. Score is higher when < 1.
1191
+ * e.g. company PB = 2, sector median PB = 3 → ratio = 2/3 ≈ 0.67
1192
+ */
1193
+ pbVsSector: number;
1194
+ /**
1195
+ * PEG ratio (P/E ÷ Growth Rate). Lower is better; 1.0 = fair, < 1 = undervalued.
1196
+ * Capped at 0 for negative PEG; capped at full score for PEG ≤ 0.5.
1197
+ */
1198
+ peg: number;
1199
+ /**
1200
+ * Current P/E percentile over the stock's own 5-year history (0–100).
1201
+ * Lower percentile = cheaper vs history = higher score.
1202
+ * Pass 0–100 directly.
1203
+ */
1204
+ historicalPePercentile: number;
1205
+ }
1206
+ /**
1207
+ * Value Score (0–100)
1208
+ * Weights:
1209
+ * P/E vs 3yr avg: 30 %
1210
+ * P/B vs sector: 25 %
1211
+ * PEG: 25 %
1212
+ * Historical P/E percentile: 20 %
1213
+ */
1214
+ declare const computeValueScore: (input: ValueScoreInput) => number;
1215
+ interface MomentumScoreInput {
1216
+ /**
1217
+ * Current price vs its 200-day SMA ratio.
1218
+ * e.g. price = 105, SMA200 = 100 → ratio = 1.05 (above SMA → bullish).
1219
+ * Score peaks at ratio ≥ 1.10 (10% above SMA).
1220
+ */
1221
+ priceVsSma200: number;
1222
+ /**
1223
+ * RSI (14-period). Range 0–100.
1224
+ * Score peaks at RSI 50–65 (trending without being overbought).
1225
+ */
1226
+ rsi: number;
1227
+ /**
1228
+ * ADX (Average Directional Index). Range 0–100.
1229
+ * ADX > 25 indicates a strong trend; ADX < 20 is trendless.
1230
+ * Score peaks at ADX ≥ 30.
1231
+ */
1232
+ adx: number;
1233
+ /**
1234
+ * Volume ratio: current 20-day avg volume / 90-day avg volume.
1235
+ * > 1.0 = rising volume (confirming move). Score caps at 1.5x.
1236
+ */
1237
+ volumeRatio: number;
1238
+ /**
1239
+ * Rate of Change over 125 trading days (6 months), as a decimal.
1240
+ * e.g. 0.20 = 20% return over 6 months. Capped at 40% for full score.
1241
+ */
1242
+ roc125: number;
1243
+ }
1244
+ /**
1245
+ * Momentum Score (0–100)
1246
+ * Weights:
1247
+ * Price vs SMA200: 25 %
1248
+ * RSI: 20 %
1249
+ * ADX: 20 %
1250
+ * Volume ratio: 20 %
1251
+ * ROC-125: 15 %
1252
+ */
1253
+ declare const computeMomentumScore: (input: MomentumScoreInput) => number;
1254
+
1255
+ export { type CompanySnapshotInput, type EvaluatedMetric, type FundamentalTimeseriesInput, type GrowthScoreInput, type MetricStatus, type MomentumScoreInput, type PiotroskiInput, type PiotroskiResult, type PiotroskiSignals, type QualityScoreInput, type ValueScoreInput, altmanZScore, analyzeBatch, analyzeCompany, analyzeEfficiency, analyzeFundamentalTrends, analyzeLiquidity, analyzeProfitability, analyzeQuality, analyzeRisk, analyzeSolvency, analyzeValuation, assetTurnover, cagr, calculateDCF, calculateEnterpriseValue, calculateGrowthRate, cashConversionCycle, cashConversionRatio, computeGFactor, computeGrowthScore, computeHistoricalPoint, computeIntrinsicValue, computeMomentumScore, computeNCVPS, computeNYearAverage, computeNYearSum, computeQualityScore, computeTTM, computeTTMAvg, computeValueScore, currentRatio, daysSalesOutstanding, debtToAssets, debtToEquity, dividendYield, earningsYield, evEbitda, evFcf, evRevenue, evaluate, fcfMargin, grahamNumber, grossMargin, impliedSharePrice, interestCoverage, inventoryTurnover, marketCapToDebtCap, medianGrowth, netDebt, netDebtToEbitda, netProfitMargin, operatingMargin, payableDays, payoutRatio, pb, pbFromMarketCap, pe, peg, piotroski, priceToCashFlow, priceToCashFlowPerShare, ps, psFromMarketCap, qoqGrowth, quickRatio, receivablesTurnover, roa, roe, roic, safeDivide, sharpe, targetUpside, workingCapitalDays, yoyGrowth };
package/dist/index.d.ts CHANGED
@@ -711,6 +711,18 @@ declare const evRevenue: (enterpriseValue: number, totalRevenue: number) => numb
711
711
  */
712
712
  declare const evFcf: (enterpriseValue: number, freeCashFlow: number) => number | null;
713
713
 
714
+ /**
715
+ * Market Cap to Total Capitalization Ratio (Market Cap / (Market Cap + Debt))
716
+ * Also known as the equity-to-total-capital ratio.
717
+ * Formula: Market Cap / (Market Cap + Total Debt)
718
+ * Interpretation:
719
+ * - Ranges from 0 to 1.
720
+ * - Higher ratio → company is predominantly equity-financed (lower financial risk).
721
+ * - Lower ratio → company is more debt-heavy relative to its total capital.
722
+ * - Useful for comparing capital structure across companies.
723
+ */
724
+ declare const marketCapToDebtCap: (marketCap: number, totalDebt: number) => number | null;
725
+
714
726
  /**
715
727
  * Return on Equity (ROE)
716
728
  * Formula: Net Income / Equity
@@ -870,6 +882,38 @@ declare const receivablesTurnover: (totalRevenue: number, tradeReceivables: numb
870
882
  */
871
883
  declare const daysSalesOutstanding: (totalRevenue: number, tradeReceivables: number) => number | null;
872
884
 
885
+ /**
886
+ * Payable Days (Days Payable Outstanding — DPO)
887
+ * Formula: (Trade Payables / COGS) × 365
888
+ * Interpretation:
889
+ * - How many days on average it takes the company to pay its suppliers.
890
+ * - Higher DPO can indicate strong bargaining power, but excessively high values
891
+ * may signal liquidity stress or strained supplier relationships.
892
+ */
893
+ declare const payableDays: (tradePayables: number, cogs: number) => number | null;
894
+
895
+ /**
896
+ * Working Capital Days
897
+ * Formula: (Working Capital / Revenue) × 365
898
+ * Where Working Capital = Current Assets - Current Liabilities
899
+ * Interpretation:
900
+ * - Measures how many days of revenue are tied up in working capital.
901
+ * - Lower is generally better (capital is not locked in operations).
902
+ * - Negative values indicate current liabilities exceed current assets.
903
+ */
904
+ declare const workingCapitalDays: (workingCapital: number, revenue: number) => number | null;
905
+
906
+ /**
907
+ * Cash Conversion Cycle (CCC)
908
+ * Formula: Debtor Days + Inventory Days - Payable Days
909
+ * Interpretation:
910
+ * - Measures the number of days it takes to convert inventory/payables into cash.
911
+ * - Lower (or negative) is better — negative CCC means the company collects cash
912
+ * before it pays its suppliers (e.g. e-commerce, supermarkets).
913
+ * - High positive CCC indicates capital is tied up in operations for longer.
914
+ */
915
+ declare const cashConversionCycle: (debtorDays: number, inventoryDays: number, payableDays: number) => number;
916
+
873
917
  /**
874
918
  * Dividend Payout Ratio
875
919
  * The proportion of earnings paid to shareholders as dividends.
@@ -930,6 +974,56 @@ declare const altmanZScore: (workingCapital: number, retainedEarnings: number, e
930
974
  */
931
975
  declare const grahamNumber: (eps: number, book: number) => number | null;
932
976
 
977
+ /**
978
+ * Net Current Value Per Share (NCVPS)
979
+ * Formula: (Current Assets - Total Liabilities) / Shares Outstanding
980
+ * Interpretation:
981
+ * - A conservative "liquidation value" per share, inspired by Benjamin Graham's
982
+ * net-net working capital criterion.
983
+ * - If NCVPS > market price, the stock may be trading below liquidation value —
984
+ * a deep value signal (but also common in distressed or declining businesses).
985
+ * - Positive NCVPS means current assets alone cover all liabilities.
986
+ */
987
+ declare const computeNCVPS: (currentAssets: number, totalLiabilities: number, sharesOutstanding: number) => number | null;
988
+
989
+ /**
990
+ * G-Factor (Composite Fundamental Score)
991
+ * Formula: (Quality × 0.40) + (Growth × 0.35) + (Momentum × 0.25)
992
+ * Inputs should be scores in the range [0, 100].
993
+ * Output is a weighted composite in the range [0, 100].
994
+ *
995
+ * Interpretation:
996
+ * - G-Factor > 70 → Strong composite fundamentals
997
+ * - G-Factor 40–70 → Average
998
+ * - G-Factor < 40 → Weak
999
+ *
1000
+ * Weights are based on typical quantitative equity-factor research priorities:
1001
+ * Quality is the most predictive of long-term returns; Growth drives near-term
1002
+ * re-rating; Momentum captures market confirmation of the thesis.
1003
+ */
1004
+ declare const computeGFactor: (qualityScore: number, growthScore: number, momentumScore: number) => number;
1005
+
1006
+ /**
1007
+ * Simplified Intrinsic Value Estimate
1008
+ * Formula: EPS × (1 + growthRate) ^ years / (1 + discountRate) ^ years
1009
+ * applied over a default 5-year horizon, then divided by (1 - safetyMargin)
1010
+ *
1011
+ * A lightweight DCF approximation for quick screening:
1012
+ * intrinsicValue = (EPS × (1 + growthRate)^5) / (1 - safetyMargin)
1013
+ *
1014
+ * Parameters:
1015
+ * @param eps Earnings Per Share (current or TTM)
1016
+ * @param growthRate Expected annual EPS growth rate as a decimal (e.g. 0.15 for 15%)
1017
+ * @param safetyMargin Margin of safety as a decimal (e.g. 0.25 for 25% discount)
1018
+ *
1019
+ * Interpretation:
1020
+ * - If market price < intrinsicValue → potential undervaluation
1021
+ * - safetyMargin of 0.25–0.35 is conventional for conservative investing
1022
+ *
1023
+ * Returns null for non-positive EPS or invalid inputs.
1024
+ */
1025
+ declare const computeIntrinsicValue: (eps: number, growthRate: number, safetyMargin: number) => number | null;
1026
+
933
1027
  /**
934
1028
  * Calculate basic growth rate given current and previous values.
935
1029
  * Useful for building out mapping functions natively in the analyzer.
@@ -950,6 +1044,16 @@ declare const qoqGrowth: (dataPoints: number[]) => number[];
950
1044
  * Formula: (Ending Value / Beginning Value) ^ (1 / Years) - 1
951
1045
  */
952
1046
  declare const cagr: (beginningValue: number, endingValue: number, periods: number) => number | null;
1047
+ /**
1048
+ * Median Growth Rate
1049
+ * Calculates the YoY growth rates for a series of annual values (oldest first),
1050
+ * then returns the median of those rates.
1051
+ * Interpretation:
1052
+ * - More robust than mean growth because it is not skewed by outlier years.
1053
+ * - Useful for evaluating the "typical" annual growth of earnings, revenue, etc.
1054
+ * Returns null if fewer than 2 data points are provided.
1055
+ */
1056
+ declare const medianGrowth: (annualValues: number[]) => number | null;
953
1057
 
954
1058
  /**
955
1059
  * Analyst Target Upside / Downside
@@ -960,4 +1064,192 @@ declare const cagr: (beginningValue: number, endingValue: number, periods: numbe
960
1064
  */
961
1065
  declare const targetUpside: (currentPrice: number, targetPrice: number) => number | null;
962
1066
 
963
- export { type CompanySnapshotInput, type EvaluatedMetric, type FundamentalTimeseriesInput, type MetricStatus, type PiotroskiInput, type PiotroskiResult, type PiotroskiSignals, altmanZScore, analyzeBatch, analyzeCompany, analyzeEfficiency, analyzeFundamentalTrends, analyzeLiquidity, analyzeProfitability, analyzeQuality, analyzeRisk, analyzeSolvency, analyzeValuation, assetTurnover, cagr, calculateDCF, calculateEnterpriseValue, calculateGrowthRate, cashConversionRatio, currentRatio, daysSalesOutstanding, debtToAssets, debtToEquity, dividendYield, earningsYield, evEbitda, evFcf, evRevenue, evaluate, fcfMargin, grahamNumber, grossMargin, impliedSharePrice, interestCoverage, inventoryTurnover, netDebt, netDebtToEbitda, netProfitMargin, operatingMargin, payoutRatio, pb, pbFromMarketCap, pe, peg, piotroski, priceToCashFlow, priceToCashFlowPerShare, ps, psFromMarketCap, qoqGrowth, quickRatio, receivablesTurnover, roa, roe, roic, safeDivide, sharpe, targetUpside, yoyGrowth };
1067
+ /**
1068
+ * Trailing Twelve Months (TTM) Utilities
1069
+ *
1070
+ * TTM aggregates the most recent four quarters of data to produce
1071
+ * an annualised figure without waiting for a full fiscal year.
1072
+ */
1073
+ /**
1074
+ * Trailing Twelve Months Sum
1075
+ * Returns the sum of the last 4 quarterly values (or fewer if < 4 available).
1076
+ * Expects values in chronological order: oldest first, most recent last.
1077
+ * e.g. [Q1, Q2, Q3, Q4, Q1_next, Q2_next] → sums last 4
1078
+ */
1079
+ declare const computeTTM: (quarterlyValues: number[]) => number | null;
1080
+ /**
1081
+ * Trailing Twelve Months Average
1082
+ * Returns the average of the last 4 quarterly values (or fewer if < 4 available).
1083
+ * Handles arrays shorter than 4 gracefully by averaging whatever is available.
1084
+ * Expects chronological order: oldest first, most recent last.
1085
+ */
1086
+ declare const computeTTMAvg: (quarterlyValues: number[]) => number | null;
1087
+
1088
+ /**
1089
+ * Historical Aggregation Utilities
1090
+ *
1091
+ * Functions for computing averages, sums, and point lookups over
1092
+ * rolling windows of quarterly (or annual) data.
1093
+ * All functions expect chronological order: oldest first, most recent last.
1094
+ */
1095
+ /**
1096
+ * N-Year Average
1097
+ * Returns the average of the last (years × 4) quarterly values.
1098
+ * e.g. computeNYearAverage(data, 3) → average of last 12 quarters.
1099
+ * If fewer values are available than requested, averages all available values.
1100
+ */
1101
+ declare const computeNYearAverage: (quarterlyValues: number[], years: number) => number | null;
1102
+ /**
1103
+ * N-Year Sum
1104
+ * Returns the sum of the last (years × 4) quarterly values.
1105
+ * If fewer values are available, sums all available values.
1106
+ */
1107
+ declare const computeNYearSum: (quarterlyValues: number[], years: number) => number | null;
1108
+ /**
1109
+ * Historical Point Lookup
1110
+ * Returns the value at exactly `quartersBack` quarters from the most recent value.
1111
+ * quartersBack = 0 → most recent value
1112
+ * quartersBack = 4 → value from 1 year ago (same quarter last year)
1113
+ * Returns null if the index is out of bounds.
1114
+ */
1115
+ declare const computeHistoricalPoint: (quarterlyValues: number[], quartersBack: number) => number | null;
1116
+
1117
+ /**
1118
+ * Composite Scoring Engine
1119
+ *
1120
+ * Four domain scores — Quality, Growth, Value, Momentum — each in range [0, 100].
1121
+ * Each score is a weighted sum of normalised sub-signals (also 0-100 or boolean).
1122
+ *
1123
+ * These scores feed into computeGFactor for the overall composite.
1124
+ */
1125
+ interface QualityScoreInput {
1126
+ /** Piotroski F-Score (0–9) */
1127
+ piotroskiScore: number;
1128
+ /**
1129
+ * ROE vs. sector median — percentage of sector ROE this company achieves.
1130
+ * e.g. if company ROE is 18% and sector median is 15%, pass 18/15 = 1.2.
1131
+ * Capped at 1.0 (100 points if >= sector median).
1132
+ */
1133
+ roeVsSector: number;
1134
+ /** Whether operating margins are improving YoY (boolean) */
1135
+ marginsImproving: boolean;
1136
+ /** Promoter pledge percentage is 0 or negligible (boolean) */
1137
+ pledgeFree: boolean;
1138
+ /** Promoter holding is stable or increasing YoY (boolean) */
1139
+ promoterStable: boolean;
1140
+ }
1141
+ /**
1142
+ * Quality Score (0–100)
1143
+ * Weights:
1144
+ * Piotroski (0–9 → 0–100): 30 %
1145
+ * ROE vs Sector (capped at 1.0 multiplier): 20 %
1146
+ * Margins improving: 20 %
1147
+ * Pledge-free: 15 %
1148
+ * Promoter stable: 15 %
1149
+ */
1150
+ declare const computeQualityScore: (input: QualityScoreInput) => number;
1151
+ interface GrowthScoreInput {
1152
+ /**
1153
+ * Revenue growth rate relative to sector.
1154
+ * e.g. if company revenue grew 20% and sector average is 12%, pass 20/12 = 1.67.
1155
+ * Capped at 1.0 (100 points if >= sector growth).
1156
+ */
1157
+ revenueGrowthVsSector: number;
1158
+ /**
1159
+ * Profit (net income) growth rate as decimal (e.g. 0.20 for 20% growth).
1160
+ * Capped at 30% for full score (0.30 → 100).
1161
+ */
1162
+ profitGrowthRate: number;
1163
+ /**
1164
+ * EPS growth rate as decimal. Capped at 25% for full score (0.25 → 100).
1165
+ */
1166
+ epsGrowthRate: number;
1167
+ /** Operating cash flow is positive this period (boolean) */
1168
+ cfoPositive: boolean;
1169
+ /** Revenue acceleration: current year growth > prior year growth (boolean) */
1170
+ revenueAccelerating: boolean;
1171
+ }
1172
+ /**
1173
+ * Growth Score (0–100)
1174
+ * Weights:
1175
+ * Revenue growth vs sector: 25 %
1176
+ * Profit growth rate: 25 %
1177
+ * EPS growth rate: 20 %
1178
+ * CFO positive: 15 %
1179
+ * Revenue accelerating: 15 %
1180
+ */
1181
+ declare const computeGrowthScore: (input: GrowthScoreInput) => number;
1182
+ interface ValueScoreInput {
1183
+ /**
1184
+ * Current P/E divided by the stock's own 3-year average P/E.
1185
+ * e.g. currentPE = 15, avgPE = 20 → ratio = 15/20 = 0.75 (trading below avg → higher score).
1186
+ * Score is higher when ratio < 1 (currently cheaper than historical average).
1187
+ */
1188
+ peVs3yrAvg: number;
1189
+ /**
1190
+ * Current P/B vs sector median P/B. Score is higher when < 1.
1191
+ * e.g. company PB = 2, sector median PB = 3 → ratio = 2/3 ≈ 0.67
1192
+ */
1193
+ pbVsSector: number;
1194
+ /**
1195
+ * PEG ratio (P/E ÷ Growth Rate). Lower is better; 1.0 = fair, < 1 = undervalued.
1196
+ * Capped at 0 for negative PEG; capped at full score for PEG ≤ 0.5.
1197
+ */
1198
+ peg: number;
1199
+ /**
1200
+ * Current P/E percentile over the stock's own 5-year history (0–100).
1201
+ * Lower percentile = cheaper vs history = higher score.
1202
+ * Pass 0–100 directly.
1203
+ */
1204
+ historicalPePercentile: number;
1205
+ }
1206
+ /**
1207
+ * Value Score (0–100)
1208
+ * Weights:
1209
+ * P/E vs 3yr avg: 30 %
1210
+ * P/B vs sector: 25 %
1211
+ * PEG: 25 %
1212
+ * Historical P/E percentile: 20 %
1213
+ */
1214
+ declare const computeValueScore: (input: ValueScoreInput) => number;
1215
+ interface MomentumScoreInput {
1216
+ /**
1217
+ * Current price vs its 200-day SMA ratio.
1218
+ * e.g. price = 105, SMA200 = 100 → ratio = 1.05 (above SMA → bullish).
1219
+ * Score peaks at ratio ≥ 1.10 (10% above SMA).
1220
+ */
1221
+ priceVsSma200: number;
1222
+ /**
1223
+ * RSI (14-period). Range 0–100.
1224
+ * Score peaks at RSI 50–65 (trending without being overbought).
1225
+ */
1226
+ rsi: number;
1227
+ /**
1228
+ * ADX (Average Directional Index). Range 0–100.
1229
+ * ADX > 25 indicates a strong trend; ADX < 20 is trendless.
1230
+ * Score peaks at ADX ≥ 30.
1231
+ */
1232
+ adx: number;
1233
+ /**
1234
+ * Volume ratio: current 20-day avg volume / 90-day avg volume.
1235
+ * > 1.0 = rising volume (confirming move). Score caps at 1.5x.
1236
+ */
1237
+ volumeRatio: number;
1238
+ /**
1239
+ * Rate of Change over 125 trading days (6 months), as a decimal.
1240
+ * e.g. 0.20 = 20% return over 6 months. Capped at 40% for full score.
1241
+ */
1242
+ roc125: number;
1243
+ }
1244
+ /**
1245
+ * Momentum Score (0–100)
1246
+ * Weights:
1247
+ * Price vs SMA200: 25 %
1248
+ * RSI: 20 %
1249
+ * ADX: 20 %
1250
+ * Volume ratio: 20 %
1251
+ * ROC-125: 15 %
1252
+ */
1253
+ declare const computeMomentumScore: (input: MomentumScoreInput) => number;
1254
+
1255
+ export { type CompanySnapshotInput, type EvaluatedMetric, type FundamentalTimeseriesInput, type GrowthScoreInput, type MetricStatus, type MomentumScoreInput, type PiotroskiInput, type PiotroskiResult, type PiotroskiSignals, type QualityScoreInput, type ValueScoreInput, altmanZScore, analyzeBatch, analyzeCompany, analyzeEfficiency, analyzeFundamentalTrends, analyzeLiquidity, analyzeProfitability, analyzeQuality, analyzeRisk, analyzeSolvency, analyzeValuation, assetTurnover, cagr, calculateDCF, calculateEnterpriseValue, calculateGrowthRate, cashConversionCycle, cashConversionRatio, computeGFactor, computeGrowthScore, computeHistoricalPoint, computeIntrinsicValue, computeMomentumScore, computeNCVPS, computeNYearAverage, computeNYearSum, computeQualityScore, computeTTM, computeTTMAvg, computeValueScore, currentRatio, daysSalesOutstanding, debtToAssets, debtToEquity, dividendYield, earningsYield, evEbitda, evFcf, evRevenue, evaluate, fcfMargin, grahamNumber, grossMargin, impliedSharePrice, interestCoverage, inventoryTurnover, marketCapToDebtCap, medianGrowth, netDebt, netDebtToEbitda, netProfitMargin, operatingMargin, payableDays, payoutRatio, pb, pbFromMarketCap, pe, peg, piotroski, priceToCashFlow, priceToCashFlowPerShare, ps, psFromMarketCap, qoqGrowth, quickRatio, receivablesTurnover, roa, roe, roic, safeDivide, sharpe, targetUpside, workingCapitalDays, yoyGrowth };
package/dist/index.js CHANGED
@@ -35,7 +35,20 @@ __export(index_exports, {
35
35
  calculateDCF: () => calculateDCF,
36
36
  calculateEnterpriseValue: () => calculateEnterpriseValue,
37
37
  calculateGrowthRate: () => calculateGrowthRate,
38
+ cashConversionCycle: () => cashConversionCycle,
38
39
  cashConversionRatio: () => cashConversionRatio,
40
+ computeGFactor: () => computeGFactor,
41
+ computeGrowthScore: () => computeGrowthScore,
42
+ computeHistoricalPoint: () => computeHistoricalPoint,
43
+ computeIntrinsicValue: () => computeIntrinsicValue,
44
+ computeMomentumScore: () => computeMomentumScore,
45
+ computeNCVPS: () => computeNCVPS,
46
+ computeNYearAverage: () => computeNYearAverage,
47
+ computeNYearSum: () => computeNYearSum,
48
+ computeQualityScore: () => computeQualityScore,
49
+ computeTTM: () => computeTTM,
50
+ computeTTMAvg: () => computeTTMAvg,
51
+ computeValueScore: () => computeValueScore,
39
52
  currentRatio: () => currentRatio,
40
53
  daysSalesOutstanding: () => daysSalesOutstanding,
41
54
  debtToAssets: () => debtToAssets,
@@ -52,10 +65,13 @@ __export(index_exports, {
52
65
  impliedSharePrice: () => impliedSharePrice,
53
66
  interestCoverage: () => interestCoverage,
54
67
  inventoryTurnover: () => inventoryTurnover,
68
+ marketCapToDebtCap: () => marketCapToDebtCap,
69
+ medianGrowth: () => medianGrowth,
55
70
  netDebt: () => netDebt,
56
71
  netDebtToEbitda: () => netDebtToEbitda,
57
72
  netProfitMargin: () => netProfitMargin,
58
73
  operatingMargin: () => operatingMargin,
74
+ payableDays: () => payableDays,
59
75
  payoutRatio: () => payoutRatio,
60
76
  pb: () => pb,
61
77
  pbFromMarketCap: () => pbFromMarketCap,
@@ -75,6 +91,7 @@ __export(index_exports, {
75
91
  safeDivide: () => safeDivide,
76
92
  sharpe: () => sharpe,
77
93
  targetUpside: () => targetUpside,
94
+ workingCapitalDays: () => workingCapitalDays,
78
95
  yoyGrowth: () => yoyGrowth
79
96
  });
80
97
  module.exports = __toCommonJS(index_exports);
@@ -740,6 +757,14 @@ var cagr = (beginningValue, endingValue, periods) => {
740
757
  if (periods <= 0 || beginningValue <= 0 || endingValue < 0) return null;
741
758
  return Math.pow(endingValue / beginningValue, 1 / periods) - 1;
742
759
  };
760
+ var medianGrowth = (annualValues) => {
761
+ if (!annualValues || annualValues.length < 2) return null;
762
+ const rates = yoyGrowth(annualValues).filter((r) => isFinite(r));
763
+ if (rates.length === 0) return null;
764
+ const sorted = [...rates].sort((a, b) => a - b);
765
+ const mid = Math.floor(sorted.length / 2);
766
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
767
+ };
743
768
 
744
769
  // src/analyzer/analyzeFundamentalTrends.ts
745
770
  function analyzeFundamentalTrends(data, periodType = "annual") {
@@ -811,6 +836,100 @@ var impliedSharePrice = (enterpriseValue, totalDebt, cashEquivalents, sharesOuts
811
836
  const equityValue = enterpriseValue - totalDebt + cashEquivalents;
812
837
  return equityValue / sharesOutstanding;
813
838
  };
839
+
840
+ // src/valuation/marketCapToDebtCap.ts
841
+ var marketCapToDebtCap = (marketCap, totalDebt) => safeDivide(marketCap, marketCap + totalDebt);
842
+
843
+ // src/efficiency/payableDays.ts
844
+ var payableDays = (tradePayables, cogs) => safeDivide(tradePayables * 365, cogs);
845
+
846
+ // src/efficiency/workingCapitalDays.ts
847
+ var workingCapitalDays = (workingCapital, revenue) => safeDivide(workingCapital * 365, revenue);
848
+
849
+ // src/efficiency/cashConversionCycle.ts
850
+ var cashConversionCycle = (debtorDays, inventoryDays, payableDays2) => debtorDays + inventoryDays - payableDays2;
851
+
852
+ // src/intrinsic/ncvps.ts
853
+ var computeNCVPS = (currentAssets, totalLiabilities, sharesOutstanding) => safeDivide(currentAssets - totalLiabilities, sharesOutstanding);
854
+
855
+ // src/intrinsic/gfactor.ts
856
+ var computeGFactor = (qualityScore, growthScore, momentumScore) => qualityScore * 0.4 + growthScore * 0.35 + momentumScore * 0.25;
857
+
858
+ // src/intrinsic/intrinsicValue.ts
859
+ var computeIntrinsicValue = (eps, growthRate, safetyMargin) => {
860
+ if (eps == null || eps <= 0) return null;
861
+ if (growthRate < -1) return null;
862
+ if (safetyMargin < 0 || safetyMargin >= 1) return null;
863
+ const futureEps = eps * Math.pow(1 + growthRate, 5);
864
+ return futureEps / (1 - safetyMargin);
865
+ };
866
+
867
+ // src/ttm/index.ts
868
+ var computeTTM = (quarterlyValues) => {
869
+ if (!quarterlyValues || quarterlyValues.length === 0) return null;
870
+ const last4 = quarterlyValues.slice(-4);
871
+ return last4.reduce((sum, v) => sum + v, 0);
872
+ };
873
+ var computeTTMAvg = (quarterlyValues) => {
874
+ if (!quarterlyValues || quarterlyValues.length === 0) return null;
875
+ const last4 = quarterlyValues.slice(-4);
876
+ return last4.reduce((sum, v) => sum + v, 0) / last4.length;
877
+ };
878
+
879
+ // src/historical/index.ts
880
+ var computeNYearAverage = (quarterlyValues, years) => {
881
+ if (!quarterlyValues || quarterlyValues.length === 0 || years <= 0) return null;
882
+ const window = quarterlyValues.slice(-(years * 4));
883
+ return window.reduce((sum, v) => sum + v, 0) / window.length;
884
+ };
885
+ var computeNYearSum = (quarterlyValues, years) => {
886
+ if (!quarterlyValues || quarterlyValues.length === 0 || years <= 0) return null;
887
+ const window = quarterlyValues.slice(-(years * 4));
888
+ return window.reduce((sum, v) => sum + v, 0);
889
+ };
890
+ var computeHistoricalPoint = (quarterlyValues, quartersBack) => {
891
+ if (!quarterlyValues || quarterlyValues.length === 0 || quartersBack < 0) return null;
892
+ const idx = quarterlyValues.length - 1 - quartersBack;
893
+ if (idx < 0) return null;
894
+ return quarterlyValues[idx];
895
+ };
896
+
897
+ // src/scoring/index.ts
898
+ var computeQualityScore = (input) => {
899
+ const { piotroskiScore, roeVsSector, marginsImproving, pledgeFree, promoterStable } = input;
900
+ const piotroskiNorm = Math.min(piotroskiScore / 9, 1) * 100;
901
+ const roeNorm = Math.min(roeVsSector, 1) * 100;
902
+ const marginsScore = marginsImproving ? 100 : 0;
903
+ const pledgeScore = pledgeFree ? 100 : 0;
904
+ const promoterScore = promoterStable ? 100 : 0;
905
+ return piotroskiNorm * 0.3 + roeNorm * 0.2 + marginsScore * 0.2 + pledgeScore * 0.15 + promoterScore * 0.15;
906
+ };
907
+ var computeGrowthScore = (input) => {
908
+ const { revenueGrowthVsSector, profitGrowthRate, epsGrowthRate, cfoPositive, revenueAccelerating } = input;
909
+ const revVsSectorNorm = Math.min(Math.max(revenueGrowthVsSector, 0), 1) * 100;
910
+ const profitNorm = Math.min(Math.max(profitGrowthRate / 0.3, 0), 1) * 100;
911
+ const epsNorm = Math.min(Math.max(epsGrowthRate / 0.25, 0), 1) * 100;
912
+ const cfoScore = cfoPositive ? 100 : 0;
913
+ const accelScore = revenueAccelerating ? 100 : 0;
914
+ return revVsSectorNorm * 0.25 + profitNorm * 0.25 + epsNorm * 0.2 + cfoScore * 0.15 + accelScore * 0.15;
915
+ };
916
+ var computeValueScore = (input) => {
917
+ const { peVs3yrAvg, pbVsSector, peg: peg2, historicalPePercentile } = input;
918
+ const peAvgScore = Math.min(Math.max((1 - peVs3yrAvg + 1) * 50, 0), 100);
919
+ const pbScore = Math.min(Math.max((1 - pbVsSector + 1) * 50, 0), 100);
920
+ const pegScore = peg2 <= 0 ? 0 : Math.min(Math.max((2 - peg2) / 1.5 * 100, 0), 100);
921
+ const histScore = Math.max(0, 100 - historicalPePercentile);
922
+ return peAvgScore * 0.3 + pbScore * 0.25 + pegScore * 0.25 + histScore * 0.2;
923
+ };
924
+ var computeMomentumScore = (input) => {
925
+ const { priceVsSma200, rsi, adx, volumeRatio, roc125 } = input;
926
+ const smaScore = Math.min(Math.max((priceVsSma200 - 0.9) / 0.2 * 100, 0), 100);
927
+ const rsiScore = rsi <= 0 || rsi >= 100 ? 0 : Math.max(0, 100 - Math.abs(rsi - 57.5) * 2.5);
928
+ const adxScore = Math.min(Math.max(adx / 30 * 100, 0), 100);
929
+ const volScore = Math.min(Math.max((volumeRatio - 0.5) / 1 * 100, 0), 100);
930
+ const rocScore = Math.min(Math.max(roc125 / 0.4 * 100, 0), 100);
931
+ return smaScore * 0.25 + rsiScore * 0.2 + adxScore * 0.2 + volScore * 0.2 + rocScore * 0.15;
932
+ };
814
933
  // Annotate the CommonJS export names for ESM import in node:
815
934
  0 && (module.exports = {
816
935
  altmanZScore,
@@ -829,7 +948,20 @@ var impliedSharePrice = (enterpriseValue, totalDebt, cashEquivalents, sharesOuts
829
948
  calculateDCF,
830
949
  calculateEnterpriseValue,
831
950
  calculateGrowthRate,
951
+ cashConversionCycle,
832
952
  cashConversionRatio,
953
+ computeGFactor,
954
+ computeGrowthScore,
955
+ computeHistoricalPoint,
956
+ computeIntrinsicValue,
957
+ computeMomentumScore,
958
+ computeNCVPS,
959
+ computeNYearAverage,
960
+ computeNYearSum,
961
+ computeQualityScore,
962
+ computeTTM,
963
+ computeTTMAvg,
964
+ computeValueScore,
833
965
  currentRatio,
834
966
  daysSalesOutstanding,
835
967
  debtToAssets,
@@ -846,10 +978,13 @@ var impliedSharePrice = (enterpriseValue, totalDebt, cashEquivalents, sharesOuts
846
978
  impliedSharePrice,
847
979
  interestCoverage,
848
980
  inventoryTurnover,
981
+ marketCapToDebtCap,
982
+ medianGrowth,
849
983
  netDebt,
850
984
  netDebtToEbitda,
851
985
  netProfitMargin,
852
986
  operatingMargin,
987
+ payableDays,
853
988
  payoutRatio,
854
989
  pb,
855
990
  pbFromMarketCap,
@@ -869,5 +1004,6 @@ var impliedSharePrice = (enterpriseValue, totalDebt, cashEquivalents, sharesOuts
869
1004
  safeDivide,
870
1005
  sharpe,
871
1006
  targetUpside,
1007
+ workingCapitalDays,
872
1008
  yoyGrowth
873
1009
  });
package/dist/index.mjs CHANGED
@@ -659,6 +659,14 @@ var cagr = (beginningValue, endingValue, periods) => {
659
659
  if (periods <= 0 || beginningValue <= 0 || endingValue < 0) return null;
660
660
  return Math.pow(endingValue / beginningValue, 1 / periods) - 1;
661
661
  };
662
+ var medianGrowth = (annualValues) => {
663
+ if (!annualValues || annualValues.length < 2) return null;
664
+ const rates = yoyGrowth(annualValues).filter((r) => isFinite(r));
665
+ if (rates.length === 0) return null;
666
+ const sorted = [...rates].sort((a, b) => a - b);
667
+ const mid = Math.floor(sorted.length / 2);
668
+ return sorted.length % 2 === 0 ? (sorted[mid - 1] + sorted[mid]) / 2 : sorted[mid];
669
+ };
662
670
 
663
671
  // src/analyzer/analyzeFundamentalTrends.ts
664
672
  function analyzeFundamentalTrends(data, periodType = "annual") {
@@ -730,6 +738,100 @@ var impliedSharePrice = (enterpriseValue, totalDebt, cashEquivalents, sharesOuts
730
738
  const equityValue = enterpriseValue - totalDebt + cashEquivalents;
731
739
  return equityValue / sharesOutstanding;
732
740
  };
741
+
742
+ // src/valuation/marketCapToDebtCap.ts
743
+ var marketCapToDebtCap = (marketCap, totalDebt) => safeDivide(marketCap, marketCap + totalDebt);
744
+
745
+ // src/efficiency/payableDays.ts
746
+ var payableDays = (tradePayables, cogs) => safeDivide(tradePayables * 365, cogs);
747
+
748
+ // src/efficiency/workingCapitalDays.ts
749
+ var workingCapitalDays = (workingCapital, revenue) => safeDivide(workingCapital * 365, revenue);
750
+
751
+ // src/efficiency/cashConversionCycle.ts
752
+ var cashConversionCycle = (debtorDays, inventoryDays, payableDays2) => debtorDays + inventoryDays - payableDays2;
753
+
754
+ // src/intrinsic/ncvps.ts
755
+ var computeNCVPS = (currentAssets, totalLiabilities, sharesOutstanding) => safeDivide(currentAssets - totalLiabilities, sharesOutstanding);
756
+
757
+ // src/intrinsic/gfactor.ts
758
+ var computeGFactor = (qualityScore, growthScore, momentumScore) => qualityScore * 0.4 + growthScore * 0.35 + momentumScore * 0.25;
759
+
760
+ // src/intrinsic/intrinsicValue.ts
761
+ var computeIntrinsicValue = (eps, growthRate, safetyMargin) => {
762
+ if (eps == null || eps <= 0) return null;
763
+ if (growthRate < -1) return null;
764
+ if (safetyMargin < 0 || safetyMargin >= 1) return null;
765
+ const futureEps = eps * Math.pow(1 + growthRate, 5);
766
+ return futureEps / (1 - safetyMargin);
767
+ };
768
+
769
+ // src/ttm/index.ts
770
+ var computeTTM = (quarterlyValues) => {
771
+ if (!quarterlyValues || quarterlyValues.length === 0) return null;
772
+ const last4 = quarterlyValues.slice(-4);
773
+ return last4.reduce((sum, v) => sum + v, 0);
774
+ };
775
+ var computeTTMAvg = (quarterlyValues) => {
776
+ if (!quarterlyValues || quarterlyValues.length === 0) return null;
777
+ const last4 = quarterlyValues.slice(-4);
778
+ return last4.reduce((sum, v) => sum + v, 0) / last4.length;
779
+ };
780
+
781
+ // src/historical/index.ts
782
+ var computeNYearAverage = (quarterlyValues, years) => {
783
+ if (!quarterlyValues || quarterlyValues.length === 0 || years <= 0) return null;
784
+ const window = quarterlyValues.slice(-(years * 4));
785
+ return window.reduce((sum, v) => sum + v, 0) / window.length;
786
+ };
787
+ var computeNYearSum = (quarterlyValues, years) => {
788
+ if (!quarterlyValues || quarterlyValues.length === 0 || years <= 0) return null;
789
+ const window = quarterlyValues.slice(-(years * 4));
790
+ return window.reduce((sum, v) => sum + v, 0);
791
+ };
792
+ var computeHistoricalPoint = (quarterlyValues, quartersBack) => {
793
+ if (!quarterlyValues || quarterlyValues.length === 0 || quartersBack < 0) return null;
794
+ const idx = quarterlyValues.length - 1 - quartersBack;
795
+ if (idx < 0) return null;
796
+ return quarterlyValues[idx];
797
+ };
798
+
799
+ // src/scoring/index.ts
800
+ var computeQualityScore = (input) => {
801
+ const { piotroskiScore, roeVsSector, marginsImproving, pledgeFree, promoterStable } = input;
802
+ const piotroskiNorm = Math.min(piotroskiScore / 9, 1) * 100;
803
+ const roeNorm = Math.min(roeVsSector, 1) * 100;
804
+ const marginsScore = marginsImproving ? 100 : 0;
805
+ const pledgeScore = pledgeFree ? 100 : 0;
806
+ const promoterScore = promoterStable ? 100 : 0;
807
+ return piotroskiNorm * 0.3 + roeNorm * 0.2 + marginsScore * 0.2 + pledgeScore * 0.15 + promoterScore * 0.15;
808
+ };
809
+ var computeGrowthScore = (input) => {
810
+ const { revenueGrowthVsSector, profitGrowthRate, epsGrowthRate, cfoPositive, revenueAccelerating } = input;
811
+ const revVsSectorNorm = Math.min(Math.max(revenueGrowthVsSector, 0), 1) * 100;
812
+ const profitNorm = Math.min(Math.max(profitGrowthRate / 0.3, 0), 1) * 100;
813
+ const epsNorm = Math.min(Math.max(epsGrowthRate / 0.25, 0), 1) * 100;
814
+ const cfoScore = cfoPositive ? 100 : 0;
815
+ const accelScore = revenueAccelerating ? 100 : 0;
816
+ return revVsSectorNorm * 0.25 + profitNorm * 0.25 + epsNorm * 0.2 + cfoScore * 0.15 + accelScore * 0.15;
817
+ };
818
+ var computeValueScore = (input) => {
819
+ const { peVs3yrAvg, pbVsSector, peg: peg2, historicalPePercentile } = input;
820
+ const peAvgScore = Math.min(Math.max((1 - peVs3yrAvg + 1) * 50, 0), 100);
821
+ const pbScore = Math.min(Math.max((1 - pbVsSector + 1) * 50, 0), 100);
822
+ const pegScore = peg2 <= 0 ? 0 : Math.min(Math.max((2 - peg2) / 1.5 * 100, 0), 100);
823
+ const histScore = Math.max(0, 100 - historicalPePercentile);
824
+ return peAvgScore * 0.3 + pbScore * 0.25 + pegScore * 0.25 + histScore * 0.2;
825
+ };
826
+ var computeMomentumScore = (input) => {
827
+ const { priceVsSma200, rsi, adx, volumeRatio, roc125 } = input;
828
+ const smaScore = Math.min(Math.max((priceVsSma200 - 0.9) / 0.2 * 100, 0), 100);
829
+ const rsiScore = rsi <= 0 || rsi >= 100 ? 0 : Math.max(0, 100 - Math.abs(rsi - 57.5) * 2.5);
830
+ const adxScore = Math.min(Math.max(adx / 30 * 100, 0), 100);
831
+ const volScore = Math.min(Math.max((volumeRatio - 0.5) / 1 * 100, 0), 100);
832
+ const rocScore = Math.min(Math.max(roc125 / 0.4 * 100, 0), 100);
833
+ return smaScore * 0.25 + rsiScore * 0.2 + adxScore * 0.2 + volScore * 0.2 + rocScore * 0.15;
834
+ };
733
835
  export {
734
836
  altmanZScore,
735
837
  analyzeBatch,
@@ -747,7 +849,20 @@ export {
747
849
  calculateDCF,
748
850
  calculateEnterpriseValue,
749
851
  calculateGrowthRate,
852
+ cashConversionCycle,
750
853
  cashConversionRatio,
854
+ computeGFactor,
855
+ computeGrowthScore,
856
+ computeHistoricalPoint,
857
+ computeIntrinsicValue,
858
+ computeMomentumScore,
859
+ computeNCVPS,
860
+ computeNYearAverage,
861
+ computeNYearSum,
862
+ computeQualityScore,
863
+ computeTTM,
864
+ computeTTMAvg,
865
+ computeValueScore,
751
866
  currentRatio,
752
867
  daysSalesOutstanding,
753
868
  debtToAssets,
@@ -764,10 +879,13 @@ export {
764
879
  impliedSharePrice,
765
880
  interestCoverage,
766
881
  inventoryTurnover,
882
+ marketCapToDebtCap,
883
+ medianGrowth,
767
884
  netDebt,
768
885
  netDebtToEbitda,
769
886
  netProfitMargin,
770
887
  operatingMargin,
888
+ payableDays,
771
889
  payoutRatio,
772
890
  pb,
773
891
  pbFromMarketCap,
@@ -787,5 +905,6 @@ export {
787
905
  safeDivide,
788
906
  sharpe,
789
907
  targetUpside,
908
+ workingCapitalDays,
790
909
  yoyGrowth
791
910
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "finance-calculator-pro",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "author": "boffincoders",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,7 +10,7 @@
10
10
  "url": "https://github.com/boffincoders/finance-calculator/issues"
11
11
  },
12
12
  "homepage": "https://boffincoders.github.io/finance-calculator/",
13
- "description": "Zero-dependency financial analysis engine for JavaScript/TypeScript. Calculates 30+ metrics: P/E, P/B, EV/EBITDA, ROE, Altman Z-Score, Piotroski F-Score, DCF, Graham Number, Sharpe Ratio and more. Works with yahoo-finance2 and any data source.",
13
+ "description": "Zero-dependency financial analysis engine for JavaScript/TypeScript. Calculates 60+ metrics: P/E, P/B, EV/EBITDA, ROE, Altman Z-Score, Piotroski F-Score, DCF, Graham Number, Sharpe Ratio, RSI, MACD, Bollinger Bands, ATR, VWAP, Beta, Cash Conversion Cycle, TTM aggregation, composite scoring engine, and more. Works with any data source.",
14
14
  "keywords": [
15
15
  "finance",
16
16
  "financial-ratios",
@@ -45,7 +45,25 @@
45
45
  "solvency",
46
46
  "portfolio-analysis",
47
47
  "typescript",
48
- "zero-dependency"
48
+ "zero-dependency",
49
+ "technical-analysis",
50
+ "rsi",
51
+ "macd",
52
+ "bollinger-bands",
53
+ "moving-average",
54
+ "ema",
55
+ "sma",
56
+ "atr",
57
+ "vwap",
58
+ "beta",
59
+ "pivot-points",
60
+ "cash-conversion-cycle",
61
+ "ttm",
62
+ "trailing-twelve-months",
63
+ "intrinsic-value",
64
+ "composite-scoring",
65
+ "f-score",
66
+ "quant-finance"
49
67
  ],
50
68
  "main": "dist/index.js",
51
69
  "module": "dist/index.mjs",