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 +106 -14
- package/dist/index.d.mts +293 -1
- package/dist/index.d.ts +293 -1
- package/dist/index.js +136 -0
- package/dist/index.mjs +119 -0
- package/package.json +21 -3
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|

|
|
12
12
|
|
|
13
13
|
> **Zero-dependency financial analysis engine for JavaScript and TypeScript.**
|
|
14
|
-
> Calculate
|
|
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 —
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
//
|
|
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 | **<
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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",
|