@lacspace/market 1.1.0 → 1.1.3

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
@@ -132,4 +132,14 @@ This package is **free** under the **[Lacspace Free Licence](https://lacspace.co
132
132
 
133
133
  Not every Lacspace package is free. We also offer **Commercial** (paid), **Client-specific**, and **Private** (proprietary) packages under separate terms. See the full **[Lacspace Licence Centre](https://lacspace.com/licenses)**.
134
134
 
135
+ ---
136
+
137
+ <div align="center">
138
+
139
+ **Part of the Lacspace ecosystem — 35 zero-dependency, isomorphic TypeScript packages.**
140
+
141
+ [All packages ↗](https://lacspace.com/packages) · [npm org ↗](https://www.npmjs.com/org/lacspace) · [Licence Centre ↗](https://lacspace.com/licenses) · [GitHub ↗](https://github.com/lacspace/npm-packages)
142
+
143
+ </div>
144
+
135
145
  <div align="center"><sub>Built with care by <a href="https://lacspace.com">Lacspace</a> · powers <a href="https://stockyatra.com">StockYatra</a> · Lacspace Free Licence · <a href="https://github.com/lacspace/npm-packages">source</a></sub></div>
package/dist/index.cjs CHANGED
@@ -51,7 +51,7 @@ function xirr(flows, guess = 0.1) {
51
51
  if (Math.abs(next - r) < 1e-10) return next;
52
52
  r = next;
53
53
  }
54
- return r;
54
+ return NaN;
55
55
  }
56
56
  function averagePrice(trades) {
57
57
  let qty = 0;
@@ -190,6 +190,26 @@ function blackScholes(o) {
190
190
  const { type, spot: S, strike: K, timeYears: t, rate: r } = o;
191
191
  const q = o.dividendYield ?? 0;
192
192
  const sigma = o.volatility;
193
+ if (t <= 0 || sigma <= 0) {
194
+ if (type === "call") {
195
+ return {
196
+ price: Math.max(0, S - K),
197
+ delta: S > K ? 1 : 0,
198
+ gamma: 0,
199
+ theta: 0,
200
+ vega: 0,
201
+ rho: 0
202
+ };
203
+ }
204
+ return {
205
+ price: Math.max(0, K - S),
206
+ delta: S < K ? -1 : 0,
207
+ gamma: 0,
208
+ theta: 0,
209
+ vega: 0,
210
+ rho: 0
211
+ };
212
+ }
193
213
  const sqrtT = Math.sqrt(t);
194
214
  const d1 = (Math.log(S / K) + (r - q + sigma * sigma / 2) * t) / (sigma * sqrtT);
195
215
  const d2 = d1 - sigma * sqrtT;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["r"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @lacspace/market\n * The money & mechanics toolkit every stock-market app re-implements.\n *\n * P&L, returns, CAGR, XIRR, tick-size rounding, circuit limits, position sizing\n * — plus a real Indian brokerage & charges calculator (STT, GST, SEBI, stamp,\n * exchange txn) with discount-broker presets.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\n/* ------------------------------------------------------------------ *\n * Formatting\n * ------------------------------------------------------------------ */\n\nexport interface FormatMoneyOptions {\n symbol?: string;\n decimals?: number;\n}\n\n/**\n * Format a number in the Indian numbering system (lakh / crore grouping).\n * @example formatINR(1234567.5) // \"₹12,34,567.50\"\n */\nexport function formatINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\", decimals = 2 } = opts;\n const neg = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart = \"0\", frac = \"\"] = fixed.split(\".\");\n const last3 = intPart.slice(-3);\n const rest = intPart.slice(0, -3);\n const grouped = rest\n ? rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3\n : last3;\n return `${neg ? \"-\" : \"\"}${symbol}${grouped}${decimals > 0 ? \".\" + frac : \"\"}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Returns & P&L\n * ------------------------------------------------------------------ */\n\n/** Absolute profit/loss for a round-trip. */\nexport function pnl(o: { buy: number; sell: number; qty: number }): number {\n return (o.sell - o.buy) * o.qty;\n}\n\n/** Percentage change from `reference` to `current` (e.g. LTP vs prev close). */\nexport function changePercent(current: number, reference: number): number {\n if (reference === 0) return 0;\n return ((current - reference) / reference) * 100;\n}\n\n/** Profit/loss as a percentage of the buy price. */\nexport function pnlPercent(o: { buy: number; sell: number }): number {\n return changePercent(o.sell, o.buy);\n}\n\n/** Compound Annual Growth Rate as a fraction (0.15 = 15%). */\nexport function cagr(begin: number, end: number, years: number): number {\n if (begin <= 0 || years <= 0) return NaN;\n return Math.pow(end / begin, 1 / years) - 1;\n}\n\nexport interface CashFlow {\n /** Negative = money out (investment), positive = money in (redemption). */\n amount: number;\n date: Date | string | number;\n}\n\nfunction toMillis(d: Date | string | number): number {\n if (d instanceof Date) return d.getTime();\n if (typeof d === \"number\") return d;\n return new Date(d).getTime();\n}\n\n/**\n * Extended Internal Rate of Return for irregularly-spaced cash flows.\n * Returns an annualised rate as a fraction. Uses Newton–Raphson.\n * @example xirr([{amount:-10000, date:\"2024-01-01\"}, {amount:12000, date:\"2025-01-01\"}]) // ~0.20\n */\nexport function xirr(flows: CashFlow[], guess = 0.1): number {\n if (flows.length < 2) return NaN;\n const cf = flows\n .map((f) => ({ amount: f.amount, t: toMillis(f.date) }))\n .sort((a, b) => a.t - b.t);\n const t0 = cf[0]!.t;\n const yearFrac = (t: number) => (t - t0) / (365 * 24 * 3600 * 1000);\n const npv = (r: number) =>\n cf.reduce((s, c) => s + c.amount / Math.pow(1 + r, yearFrac(c.t)), 0);\n const dnpv = (r: number) =>\n cf.reduce((s, c) => {\n const y = yearFrac(c.t);\n return s - (y * c.amount) / Math.pow(1 + r, y + 1);\n }, 0);\n\n let r = guess;\n for (let i = 0; i < 100; i++) {\n const f = npv(r);\n if (Math.abs(f) < 1e-7) return r;\n const d = dnpv(r);\n if (d === 0) break;\n const next = r - f / d;\n if (!isFinite(next)) break;\n if (Math.abs(next - r) < 1e-10) return next;\n r = next;\n }\n return r;\n}\n\n/* ------------------------------------------------------------------ *\n * Position mechanics\n * ------------------------------------------------------------------ */\n\n/** Volume-weighted average price across a set of trades. */\nexport function averagePrice(trades: { price: number; qty: number }[]): number {\n let qty = 0;\n let value = 0;\n for (const t of trades) {\n qty += t.qty;\n value += t.price * t.qty;\n }\n return qty === 0 ? 0 : value / qty;\n}\n\n/**\n * Risk-based position sizing. Returns the whole-share quantity so that a stop-out\n * costs at most `riskPercent` of capital.\n * @example positionSize({ capital: 100000, riskPercent: 1, entry: 500, stop: 480 }) // 50\n */\nexport function positionSize(o: {\n capital: number;\n riskPercent: number;\n entry: number;\n stop: number;\n}): number {\n const riskAmount = o.capital * (o.riskPercent / 100);\n const perShareRisk = Math.abs(o.entry - o.stop);\n if (perShareRisk === 0) return 0;\n return Math.floor(riskAmount / perShareRisk);\n}\n\n/** Round a price to the nearest exchange tick (default ₹0.05 for NSE equity). */\nexport function roundToTick(price: number, tick = 0.05): number {\n if (tick <= 0) return price;\n return Number((Math.round(price / tick) * tick).toFixed(4));\n}\n\n/** Upper & lower circuit price for a given previous close and band percent. */\nexport function circuitLimits(\n prevClose: number,\n percent: number,\n): { upper: number; lower: number } {\n const delta = prevClose * (percent / 100);\n return {\n upper: roundToTick(prevClose + delta),\n lower: roundToTick(prevClose - delta),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Brokerage & statutory charges (India)\n * ------------------------------------------------------------------ */\n\nexport type Segment = \"delivery\" | \"intraday\" | \"futures\" | \"options\";\n\nexport interface SegmentRates {\n /** Brokerage as a fraction of turnover per side (0.0003 = 0.03%). */\n brokeragePct: number;\n /** Per-order brokerage cap (₹). */\n brokerageCap: number;\n /** Flat per-order brokerage (₹) — overrides the pct/cap model when set. */\n brokerageFlat?: number;\n sttBuy: number;\n sttSell: number;\n exchangeTxn: number;\n stampBuy: number;\n /** Depository (DP) charge per scrip on the sell leg (₹). */\n dpPerScrip: number;\n}\n\nexport interface ChargeConfig {\n segments: Record<Segment, SegmentRates>;\n sebi: number;\n gst: number;\n}\n\n/**\n * Default rates approximating an Indian discount broker (Zerodha-style) as of\n * FY2024–25. Statutory rates change — override any field via the `config`\n * argument of {@link charges} and always verify against the live rate card.\n */\nexport const IN_DISCOUNT_BROKER: ChargeConfig = {\n segments: {\n delivery: {\n brokeragePct: 0,\n brokerageCap: 0,\n sttBuy: 0.001,\n sttSell: 0.001,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00015,\n dpPerScrip: 13.5,\n },\n intraday: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.00025,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n futures: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.0002,\n exchangeTxn: 0.0000173,\n stampBuy: 0.00002,\n dpPerScrip: 0,\n },\n options: {\n brokeragePct: 0,\n brokerageCap: 20,\n brokerageFlat: 20,\n sttBuy: 0,\n sttSell: 0.001,\n exchangeTxn: 0.0003503,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n },\n sebi: 0.000001, // ₹10 per crore\n gst: 0.18,\n};\n\nexport interface ChargeInput {\n segment: Segment;\n /** Buy price per unit. Omit / 0 for a sell-only leg. */\n buy: number;\n /** Sell price per unit. Omit / 0 for a buy-only leg. */\n sell: number;\n qty: number;\n}\n\nexport interface ChargeBreakdown {\n turnover: number;\n brokerage: number;\n stt: number;\n exchangeTxn: number;\n sebi: number;\n stamp: number;\n gst: number;\n dp: number;\n totalCharges: number;\n grossPnl: number;\n netPnl: number;\n /** Per-share price move needed just to break even on charges. */\n breakeven: number;\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction legBrokerage(turnover: number, r: SegmentRates): number {\n if (turnover <= 0) return 0;\n if (r.brokerageFlat !== undefined) return r.brokerageFlat;\n if (r.brokeragePct === 0) return 0;\n return Math.min(turnover * r.brokeragePct, r.brokerageCap);\n}\n\n/**\n * Full brokerage + statutory charges breakdown for a trade, Indian market.\n * @example\n * charges({ segment: \"intraday\", buy: 100, sell: 102, qty: 500 });\n * // { brokerage, stt, gst, sebi, stamp, exchangeTxn, totalCharges, netPnl, breakeven, ... }\n */\nexport function charges(\n input: ChargeInput,\n config: ChargeConfig = IN_DISCOUNT_BROKER,\n): ChargeBreakdown {\n const r = config.segments[input.segment];\n const buyVal = (input.buy || 0) * input.qty;\n const sellVal = (input.sell || 0) * input.qty;\n const turnover = buyVal + sellVal;\n\n const brokerage = legBrokerage(buyVal, r) + legBrokerage(sellVal, r);\n const stt = buyVal * r.sttBuy + sellVal * r.sttSell;\n const exchangeTxn = turnover * r.exchangeTxn;\n const sebi = turnover * config.sebi;\n const stamp = buyVal * r.stampBuy;\n const gst = (brokerage + exchangeTxn + sebi) * config.gst;\n const dp = sellVal > 0 ? r.dpPerScrip : 0;\n\n const totalCharges = brokerage + stt + exchangeTxn + sebi + stamp + gst + dp;\n const grossPnl = sellVal - buyVal;\n\n return {\n turnover: round2(turnover),\n brokerage: round2(brokerage),\n stt: round2(stt),\n exchangeTxn: round2(exchangeTxn),\n sebi: round2(sebi),\n stamp: round2(stamp),\n gst: round2(gst),\n dp: round2(dp),\n totalCharges: round2(totalCharges),\n grossPnl: round2(grossPnl),\n netPnl: round2(grossPnl - totalCharges),\n breakeven: input.qty === 0 ? 0 : round2(totalCharges / input.qty),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Compact formatting\n * ------------------------------------------------------------------ */\n\nfunction trimTo2(n: number): string {\n return Number(n.toFixed(2)).toString();\n}\n\n/** Compact INR: `formatCompactINR(12345678)` → `\"₹1.23 Cr\"`. */\nexport function formatCompactINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\" } = opts;\n const neg = amount < 0;\n const a = Math.abs(amount);\n const units: [number, string][] = [\n [1e7, \"Cr\"],\n [1e5, \"L\"],\n [1e3, \"K\"],\n ];\n const u = units.find(([size]) => a >= size);\n const out = u ? `${trimTo2(a / u[0])} ${u[1]}` : trimTo2(a);\n return `${neg ? \"-\" : \"\"}${symbol}${out}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Options — Black-Scholes greeks\n * ------------------------------------------------------------------ */\n\nfunction normPdf(x: number): number {\n return Math.exp((-x * x) / 2) / Math.sqrt(2 * Math.PI);\n}\n\n/** Standard normal CDF (Abramowitz & Stegun 7.1.26 approximation). */\nfunction normCdf(x: number): number {\n const t = 1 / (1 + 0.2316419 * Math.abs(x));\n const d = 0.3989422804014327 * Math.exp((-x * x) / 2);\n const p = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n return x > 0 ? 1 - p : p;\n}\n\nexport interface OptionInput {\n type: \"call\" | \"put\";\n /** Spot price of the underlying. */\n spot: number;\n strike: number;\n /** Time to expiry in years (e.g. 30 days ≈ 30/365). */\n timeYears: number;\n /** Risk-free rate (annual, decimal — e.g. 0.07). */\n rate: number;\n /** Volatility (annual, decimal — e.g. 0.25). */\n volatility: number;\n /** Continuous dividend yield (annual, decimal). Default 0. */\n dividendYield?: number;\n}\n\nexport interface Greeks {\n price: number;\n delta: number;\n gamma: number;\n /** Per-year theta (divide by 365 for per-day). */\n theta: number;\n /** Per 1.00 change in volatility (divide by 100 for per 1%). */\n vega: number;\n /** Per 1.00 change in rate (divide by 100 for per 1%). */\n rho: number;\n}\n\n/** Black-Scholes price + greeks for a European option. */\nexport function blackScholes(o: OptionInput): Greeks {\n const { type, spot: S, strike: K, timeYears: t, rate: r } = o;\n const q = o.dividendYield ?? 0;\n const sigma = o.volatility;\n const sqrtT = Math.sqrt(t);\n const d1 = (Math.log(S / K) + (r - q + (sigma * sigma) / 2) * t) / (sigma * sqrtT);\n const d2 = d1 - sigma * sqrtT;\n const disc = Math.exp(-r * t);\n const dq = Math.exp(-q * t);\n const nd1 = normPdf(d1);\n const gamma = (dq * nd1) / (S * sigma * sqrtT);\n const vega = S * dq * nd1 * sqrtT;\n if (type === \"call\") {\n const Nd1 = normCdf(d1);\n const Nd2 = normCdf(d2);\n return {\n price: S * dq * Nd1 - K * disc * Nd2,\n delta: dq * Nd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) - r * K * disc * Nd2 + q * S * dq * Nd1,\n vega,\n rho: K * t * disc * Nd2,\n };\n }\n const Nnd1 = normCdf(-d1);\n const Nnd2 = normCdf(-d2);\n return {\n price: K * disc * Nnd2 - S * dq * Nnd1,\n delta: -dq * Nnd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) + r * K * disc * Nnd2 - q * S * dq * Nnd1,\n vega,\n rho: -K * t * disc * Nnd2,\n };\n}\n\n/** Solve implied volatility from an observed option price (bisection). */\nexport function impliedVolatility(\n marketPrice: number,\n o: Omit<OptionInput, \"volatility\">,\n opts: { tolerance?: number; maxIterations?: number } = {},\n): number | null {\n const tol = opts.tolerance ?? 1e-6;\n const maxIter = opts.maxIterations ?? 100;\n let lo = 1e-4;\n let hi = 5;\n for (let i = 0; i < maxIter; i++) {\n const mid = (lo + hi) / 2;\n const price = blackScholes({ ...o, volatility: mid }).price;\n const diff = price - marketPrice;\n if (Math.abs(diff) < tol) return mid;\n if (diff > 0) hi = mid;\n else lo = mid;\n }\n return null;\n}\n\n/* ------------------------------------------------------------------ *\n * Portfolio analytics\n * ------------------------------------------------------------------ */\n\n/** Period-over-period simple returns from a price/equity series. */\nexport function simpleReturns(series: number[]): number[] {\n const out: number[] = [];\n for (let i = 1; i < series.length; i++) {\n const prev = series[i - 1]!;\n if (prev !== 0) out.push((series[i]! - prev) / prev);\n }\n return out;\n}\n\nfunction mean(xs: number[]): number {\n return xs.length ? xs.reduce((s, x) => s + x, 0) / xs.length : 0;\n}\n\nfunction stdev(xs: number[]): number {\n if (xs.length < 2) return 0;\n const m = mean(xs);\n return Math.sqrt(xs.reduce((s, x) => s + (x - m) ** 2, 0) / (xs.length - 1));\n}\n\n/** Volatility (stdev of returns); annualized by default. */\nexport function volatility(returns: number[], opts: { annualize?: boolean; periodsPerYear?: number } = {}): number {\n const sd = stdev(returns);\n return opts.annualize === false ? sd : sd * Math.sqrt(opts.periodsPerYear ?? 252);\n}\n\n/** Annualized Sharpe ratio from a return series. */\nexport function sharpe(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const sd = stdev(excess);\n if (sd === 0) return 0;\n return (mean(excess) / sd) * Math.sqrt(ppy);\n}\n\n/** Annualized Sortino ratio (downside-deviation only). */\nexport function sortino(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const downside = excess.filter((r) => r < 0);\n if (!downside.length) return 0;\n const dd = Math.sqrt(downside.reduce((s, r) => s + r * r, 0) / downside.length);\n if (dd === 0) return 0;\n return (mean(excess) / dd) * Math.sqrt(ppy);\n}\n\n/** Maximum drawdown of an equity curve, as a positive fraction (0.2 = −20%). */\nexport function maxDrawdown(equity: number[]): { maxDrawdown: number; peakIndex: number; troughIndex: number } {\n let peak = equity[0] ?? 0;\n let peakIdx = 0;\n let maxDd = 0;\n let ddPeak = 0;\n let ddTrough = 0;\n for (let i = 0; i < equity.length; i++) {\n const v = equity[i]!;\n if (v > peak) {\n peak = v;\n peakIdx = i;\n }\n const dd = peak > 0 ? (peak - v) / peak : 0;\n if (dd > maxDd) {\n maxDd = dd;\n ddPeak = peakIdx;\n ddTrough = i;\n }\n }\n return { maxDrawdown: maxDd, peakIndex: ddPeak, troughIndex: ddTrough };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["r"],"mappings":";;;AAwBO,SAAS,SAAA,CAAU,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AAC/E,EAAA,MAAM,EAAE,MAAA,GAAS,QAAA,EAAK,QAAA,GAAW,GAAE,GAAI,IAAA;AACvC,EAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,QAAQ,QAAQ,CAAA;AAC/C,EAAA,MAAM,CAAC,UAAU,GAAA,EAAK,IAAA,GAAO,EAAE,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,EAAE,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAChC,EAAA,MAAM,OAAA,GAAU,OACZ,IAAA,CAAK,OAAA,CAAQ,yBAAyB,GAAG,CAAA,GAAI,MAAM,KAAA,GACnD,KAAA;AACJ,EAAA,OAAO,CAAA,EAAG,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,EAAG,QAAA,GAAW,CAAA,GAAI,GAAA,GAAM,OAAO,EAAE,CAAA,CAAA;AAC9E;AAOO,SAAS,IAAI,CAAA,EAAuD;AACzE,EAAA,OAAA,CAAQ,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,GAAA,IAAO,CAAA,CAAE,GAAA;AAC9B;AAGO,SAAS,aAAA,CAAc,SAAiB,SAAA,EAA2B;AACxE,EAAA,IAAI,SAAA,KAAc,GAAG,OAAO,CAAA;AAC5B,EAAA,OAAA,CAAS,OAAA,GAAU,aAAa,SAAA,GAAa,GAAA;AAC/C;AAGO,SAAS,WAAW,CAAA,EAA0C;AACnE,EAAA,OAAO,aAAA,CAAc,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,GAAG,CAAA;AACpC;AAGO,SAAS,IAAA,CAAK,KAAA,EAAe,GAAA,EAAa,KAAA,EAAuB;AACtE,EAAA,IAAI,KAAA,IAAS,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG,OAAO,GAAA;AACrC,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,GAAM,KAAA,EAAO,CAAA,GAAI,KAAK,CAAA,GAAI,CAAA;AAC5C;AAQA,SAAS,SAAS,CAAA,EAAmC;AACnD,EAAA,IAAI,CAAA,YAAa,IAAA,EAAM,OAAO,CAAA,CAAE,OAAA,EAAQ;AACxC,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,CAAA;AAClC,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,CAAA,CAAE,OAAA,EAAQ;AAC7B;AAWO,SAAS,IAAA,CAAK,KAAA,EAAmB,KAAA,GAAQ,GAAA,EAAa;AAC3D,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,GAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,MACR,GAAA,CAAI,CAAC,OAAO,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA,EAAG,QAAA,CAAS,EAAE,IAAI,CAAA,EAAE,CAAE,CAAA,CACtD,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,CAAC,CAAA,CAAG,CAAA;AAClB,EAAA,MAAM,WAAW,CAAC,CAAA,KAAA,CAAe,IAAI,EAAA,KAAO,GAAA,GAAM,KAAK,IAAA,GAAO,GAAA,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,CAACA,EAAAA,KACX,EAAA,CAAG,OAAO,CAAC,CAAA,EAAG,MAAM,CAAA,GAAI,CAAA,CAAE,SAAS,IAAA,CAAK,GAAA,CAAI,IAAIA,EAAAA,EAAG,QAAA,CAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;AACtE,EAAA,MAAM,OAAO,CAACA,EAAAA,KACZ,GAAG,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM;AAClB,IAAA,MAAM,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,CAAC,CAAA;AACtB,IAAA,OAAO,CAAA,GAAK,IAAI,CAAA,CAAE,MAAA,GAAU,KAAK,GAAA,CAAI,CAAA,GAAIA,EAAAA,EAAG,CAAA,GAAI,CAAC,CAAA;AAAA,EACnD,GAAG,CAAC,CAAA;AAEN,EAAA,IAAI,CAAA,GAAI,KAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,IAAA,MAAM,CAAA,GAAI,IAAI,CAAC,CAAA;AACf,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,MAAM,OAAO,CAAA;AAC/B,IAAA,MAAM,CAAA,GAAI,KAAK,CAAC,CAAA;AAChB,IAAA,IAAI,MAAM,CAAA,EAAG;AACb,IAAA,MAAM,IAAA,GAAO,IAAI,CAAA,GAAI,CAAA;AACrB,IAAA,IAAI,CAAC,QAAA,CAAS,IAAI,CAAA,EAAG;AACrB,IAAA,IAAI,KAAK,GAAA,CAAI,IAAA,GAAO,CAAC,CAAA,GAAI,OAAO,OAAO,IAAA;AACvC,IAAA,CAAA,GAAI,IAAA;AAAA,EACN;AAEA,EAAA,OAAO,GAAA;AACT;AAOO,SAAS,aAAa,MAAA,EAAkD;AAC7E,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,GAAA,IAAO,CAAA,CAAE,GAAA;AACT,IAAA,KAAA,IAAS,CAAA,CAAE,QAAQ,CAAA,CAAE,GAAA;AAAA,EACvB;AACA,EAAA,OAAO,GAAA,KAAQ,CAAA,GAAI,CAAA,GAAI,KAAA,GAAQ,GAAA;AACjC;AAOO,SAAS,aAAa,CAAA,EAKlB;AACT,EAAA,MAAM,UAAA,GAAa,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,WAAA,GAAc,GAAA,CAAA;AAChD,EAAA,MAAM,eAAe,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,IAAI,CAAA;AAC9C,EAAA,IAAI,YAAA,KAAiB,GAAG,OAAO,CAAA;AAC/B,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,YAAY,CAAA;AAC7C;AAGO,SAAS,WAAA,CAAY,KAAA,EAAe,IAAA,GAAO,IAAA,EAAc;AAC9D,EAAA,IAAI,IAAA,IAAQ,GAAG,OAAO,KAAA;AACtB,EAAA,OAAO,MAAA,CAAA,CAAQ,KAAK,KAAA,CAAM,KAAA,GAAQ,IAAI,CAAA,GAAI,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA;AAC5D;AAGO,SAAS,aAAA,CACd,WACA,OAAA,EACkC;AAClC,EAAA,MAAM,KAAA,GAAQ,aAAa,OAAA,GAAU,GAAA,CAAA;AACrC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,WAAA,CAAY,SAAA,GAAY,KAAK,CAAA;AAAA,IACpC,KAAA,EAAO,WAAA,CAAY,SAAA,GAAY,KAAK;AAAA,GACtC;AACF;AAkCO,IAAM,kBAAA,GAAmC;AAAA,EAC9C,QAAA,EAAU;AAAA,IACR,QAAA,EAAU;AAAA,MACR,YAAA,EAAc,CAAA;AAAA,MACd,YAAA,EAAc,CAAA;AAAA,MACd,MAAA,EAAQ,IAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,KAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,QAAA,EAAU;AAAA,MACR,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,KAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,OAAA,EAAS;AAAA,MACP,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,OAAA,EAAS;AAAA,MACP,YAAA,EAAc,CAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,aAAA,EAAe,EAAA;AAAA,MACf,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,OAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA;AACd,GACF;AAAA,EACA,IAAA,EAAM,IAAA;AAAA;AAAA,EACN,GAAA,EAAK;AACP;AA2BA,SAAS,OAAO,CAAA,EAAmB;AACjC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAC/B;AAEA,SAAS,YAAA,CAAa,UAAkB,CAAA,EAAyB;AAC/D,EAAA,IAAI,QAAA,IAAY,GAAG,OAAO,CAAA;AAC1B,EAAA,IAAI,CAAA,CAAE,aAAA,KAAkB,MAAA,EAAW,OAAO,CAAA,CAAE,aAAA;AAC5C,EAAA,IAAI,CAAA,CAAE,YAAA,KAAiB,CAAA,EAAG,OAAO,CAAA;AACjC,EAAA,OAAO,KAAK,GAAA,CAAI,QAAA,GAAW,CAAA,CAAE,YAAA,EAAc,EAAE,YAAY,CAAA;AAC3D;AAQO,SAAS,OAAA,CACd,KAAA,EACA,MAAA,GAAuB,kBAAA,EACN;AACjB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA;AACvC,EAAA,MAAM,MAAA,GAAA,CAAU,KAAA,CAAM,GAAA,IAAO,CAAA,IAAK,KAAA,CAAM,GAAA;AACxC,EAAA,MAAM,OAAA,GAAA,CAAW,KAAA,CAAM,IAAA,IAAQ,CAAA,IAAK,KAAA,CAAM,GAAA;AAC1C,EAAA,MAAM,WAAW,MAAA,GAAS,OAAA;AAE1B,EAAA,MAAM,YAAY,YAAA,CAAa,MAAA,EAAQ,CAAC,CAAA,GAAI,YAAA,CAAa,SAAS,CAAC,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,MAAA,GAAS,CAAA,CAAE,MAAA,GAAS,UAAU,CAAA,CAAE,OAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,WAAW,CAAA,CAAE,WAAA;AACjC,EAAA,MAAM,IAAA,GAAO,WAAW,MAAA,CAAO,IAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,CAAA,CAAE,QAAA;AACzB,EAAA,MAAM,GAAA,GAAA,CAAO,SAAA,GAAY,WAAA,GAAc,IAAA,IAAQ,MAAA,CAAO,GAAA;AACtD,EAAA,MAAM,EAAA,GAAK,OAAA,GAAU,CAAA,GAAI,CAAA,CAAE,UAAA,GAAa,CAAA;AAExC,EAAA,MAAM,eAAe,SAAA,GAAY,GAAA,GAAM,WAAA,GAAc,IAAA,GAAO,QAAQ,GAAA,GAAM,EAAA;AAC1E,EAAA,MAAM,WAAW,OAAA,GAAU,MAAA;AAE3B,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,OAAO,QAAQ,CAAA;AAAA,IACzB,SAAA,EAAW,OAAO,SAAS,CAAA;AAAA,IAC3B,GAAA,EAAK,OAAO,GAAG,CAAA;AAAA,IACf,WAAA,EAAa,OAAO,WAAW,CAAA;AAAA,IAC/B,IAAA,EAAM,OAAO,IAAI,CAAA;AAAA,IACjB,KAAA,EAAO,OAAO,KAAK,CAAA;AAAA,IACnB,GAAA,EAAK,OAAO,GAAG,CAAA;AAAA,IACf,EAAA,EAAI,OAAO,EAAE,CAAA;AAAA,IACb,YAAA,EAAc,OAAO,YAAY,CAAA;AAAA,IACjC,QAAA,EAAU,OAAO,QAAQ,CAAA;AAAA,IACzB,MAAA,EAAQ,MAAA,CAAO,QAAA,GAAW,YAAY,CAAA;AAAA,IACtC,SAAA,EAAW,MAAM,GAAA,KAAQ,CAAA,GAAI,IAAI,MAAA,CAAO,YAAA,GAAe,MAAM,GAAG;AAAA,GAClE;AACF;AAMA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,OAAO,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,EAAE,QAAA,EAAS;AACvC;AAGO,SAAS,gBAAA,CAAiB,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AACtF,EAAA,MAAM,EAAE,MAAA,GAAS,QAAA,EAAI,GAAI,IAAA;AACzB,EAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AACzB,EAAA,MAAM,KAAA,GAA4B;AAAA,IAChC,CAAC,KAAK,IAAI,CAAA;AAAA,IACV,CAAC,KAAK,GAAG,CAAA;AAAA,IACT,CAAC,KAAK,GAAG;AAAA,GACX;AACA,EAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,CAAC,CAAC,IAAI,CAAA,KAAM,KAAK,IAAI,CAAA;AAC1C,EAAA,MAAM,GAAA,GAAM,CAAA,GAAI,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAC,CAAC,CAAC,IAAI,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA,GAAK,QAAQ,CAAC,CAAA;AAC1D,EAAA,OAAO,GAAG,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,EAAG,MAAM,GAAG,GAAG,CAAA,CAAA;AACzC;AAMA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,OAAO,IAAA,CAAK,GAAA,CAAK,CAAC,CAAA,GAAI,CAAA,GAAK,CAAC,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AACvD;AAGA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,MAAM,IAAI,CAAA,IAAK,CAAA,GAAI,SAAA,GAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AACzC,EAAA,MAAM,IAAI,kBAAA,GAAqB,IAAA,CAAK,IAAK,CAAC,CAAA,GAAI,IAAK,CAAC,CAAA;AACpD,EAAA,MAAM,CAAA,GAAI,CAAA,GAAI,CAAA,IAAK,SAAA,GAAY,CAAA,IAAK,aAAa,CAAA,IAAK,WAAA,GAAc,CAAA,IAAK,YAAA,GAAe,CAAA,GAAI,WAAA,CAAA,CAAA,CAAA,CAAA;AAC5F,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA;AACzB;AA8BO,SAAS,aAAa,CAAA,EAAwB;AACnD,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,MAAA,EAAQ,GAAG,SAAA,EAAW,CAAA,EAAG,IAAA,EAAM,CAAA,EAAE,GAAI,CAAA;AAC5D,EAAA,MAAM,CAAA,GAAI,EAAE,aAAA,IAAiB,CAAA;AAC7B,EAAA,MAAM,QAAQ,CAAA,CAAE,UAAA;AAIhB,EAAA,IAAI,CAAA,IAAK,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG;AACxB,IAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,MAAA,OAAO;AAAA,QACL,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,QACxB,KAAA,EAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA;AAAA,QACnB,KAAA,EAAO,CAAA;AAAA,QACP,KAAA,EAAO,CAAA;AAAA,QACP,IAAA,EAAM,CAAA;AAAA,QACN,GAAA,EAAK;AAAA,OACP;AAAA,IACF;AACA,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,MACxB,KAAA,EAAO,CAAA,GAAI,CAAA,GAAI,EAAA,GAAK,CAAA;AAAA,MACpB,KAAA,EAAO,CAAA;AAAA,MACP,KAAA,EAAO,CAAA;AAAA,MACP,IAAA,EAAM,CAAA;AAAA,MACN,GAAA,EAAK;AAAA,KACP;AAAA,EACF;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA;AACzB,EAAA,MAAM,EAAA,GAAA,CAAM,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,GAAA,CAAK,CAAA,GAAI,CAAA,GAAK,KAAA,GAAQ,KAAA,GAAS,CAAA,IAAK,CAAA,KAAM,KAAA,GAAQ,KAAA,CAAA;AAC5E,EAAA,MAAM,EAAA,GAAK,KAAK,KAAA,GAAQ,KAAA;AACxB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAC,CAAA;AAC5B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAC,CAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,EAAA,MAAM,KAAA,GAAS,EAAA,GAAK,GAAA,IAAQ,CAAA,GAAI,KAAA,GAAQ,KAAA,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,CAAA,GAAI,EAAA,GAAK,GAAA,GAAM,KAAA;AAC5B,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,IAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,CAAA,GAAI,EAAA,GAAK,GAAA,GAAM,IAAI,IAAA,GAAO,GAAA;AAAA,MACjC,OAAO,EAAA,GAAK,GAAA;AAAA,MACZ,KAAA;AAAA,MACA,KAAA,EAAO,EAAE,CAAA,GAAI,EAAA,GAAK,MAAM,KAAA,CAAA,IAAU,CAAA,GAAI,KAAA,CAAA,GAAS,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO,GAAA,GAAM,CAAA,GAAI,IAAI,EAAA,GAAK,GAAA;AAAA,MACjF,IAAA;AAAA,MACA,GAAA,EAAK,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO;AAAA,KACtB;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,EAAE,CAAA;AACxB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,EAAE,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,IAAI,EAAA,GAAK,IAAA;AAAA,IAClC,KAAA,EAAO,CAAC,EAAA,GAAK,IAAA;AAAA,IACb,KAAA;AAAA,IACA,KAAA,EAAO,EAAE,CAAA,GAAI,EAAA,GAAK,MAAM,KAAA,CAAA,IAAU,CAAA,GAAI,KAAA,CAAA,GAAS,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,IAAA;AAAA,IAClF,IAAA;AAAA,IACA,GAAA,EAAK,CAAC,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO;AAAA,GACvB;AACF;AAGO,SAAS,iBAAA,CACd,WAAA,EACA,CAAA,EACA,IAAA,GAAuD,EAAC,EACzC;AACf,EAAA,MAAM,GAAA,GAAM,KAAK,SAAA,IAAa,IAAA;AAC9B,EAAA,MAAM,OAAA,GAAU,KAAK,aAAA,IAAiB,GAAA;AACtC,EAAA,IAAI,EAAA,GAAK,IAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAChC,IAAA,MAAM,GAAA,GAAA,CAAO,KAAK,EAAA,IAAM,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,aAAa,EAAE,GAAG,GAAG,UAAA,EAAY,GAAA,EAAK,CAAA,CAAE,KAAA;AACtD,IAAA,MAAM,OAAO,KAAA,GAAQ,WAAA;AACrB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,GAAI,KAAK,OAAO,GAAA;AACjC,IAAA,IAAI,IAAA,GAAO,GAAG,EAAA,GAAK,GAAA;AAAA,SACd,EAAA,GAAK,GAAA;AAAA,EACZ;AACA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,cAAc,MAAA,EAA4B;AACxD,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AACzB,IAAA,IAAI,IAAA,KAAS,GAAG,GAAA,CAAI,IAAA,CAAA,CAAM,OAAO,CAAC,CAAA,GAAK,QAAQ,IAAI,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,KAAK,EAAA,EAAsB;AAClC,EAAA,OAAO,EAAA,CAAG,MAAA,GAAS,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,EAAA,CAAG,MAAA,GAAS,CAAA;AACjE;AAEA,SAAS,MAAM,EAAA,EAAsB;AACnC,EAAA,IAAI,EAAA,CAAG,MAAA,GAAS,CAAA,EAAG,OAAO,CAAA;AAC1B,EAAA,MAAM,CAAA,GAAI,KAAK,EAAE,CAAA;AACjB,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAA,CAAK,CAAA,GAAI,MAAM,CAAA,EAAG,CAAC,CAAA,IAAK,EAAA,CAAG,SAAS,CAAA,CAAE,CAAA;AAC7E;AAGO,SAAS,UAAA,CAAW,OAAA,EAAmB,IAAA,GAAyD,EAAC,EAAW;AACjH,EAAA,MAAM,EAAA,GAAK,MAAM,OAAO,CAAA;AACxB,EAAA,OAAO,IAAA,CAAK,cAAc,KAAA,GAAQ,EAAA,GAAK,KAAK,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,cAAA,IAAkB,GAAG,CAAA;AAClF;AAGO,SAAS,MAAA,CAAO,OAAA,EAAmB,IAAA,GAAuD,EAAC,EAAW;AAC3G,EAAA,MAAM,GAAA,GAAM,KAAK,cAAA,IAAkB,GAAA;AACnC,EAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,QAAA,IAAY,CAAA,IAAK,GAAA;AAC3C,EAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,WAAW,CAAA;AACjD,EAAA,MAAM,EAAA,GAAK,MAAM,MAAM,CAAA;AACvB,EAAA,IAAI,EAAA,KAAO,GAAG,OAAO,CAAA;AACrB,EAAA,OAAQ,KAAK,MAAM,CAAA,GAAI,EAAA,GAAM,IAAA,CAAK,KAAK,GAAG,CAAA;AAC5C;AAGO,SAAS,OAAA,CAAQ,OAAA,EAAmB,IAAA,GAAuD,EAAC,EAAW;AAC5G,EAAA,MAAM,GAAA,GAAM,KAAK,cAAA,IAAkB,GAAA;AACnC,EAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,QAAA,IAAY,CAAA,IAAK,GAAA;AAC3C,EAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,WAAW,CAAA;AACjD,EAAA,MAAM,WAAW,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,IAAI,CAAC,CAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAQ,OAAO,CAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,OAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,SAAS,MAAM,CAAA;AAC9E,EAAA,IAAI,EAAA,KAAO,GAAG,OAAO,CAAA;AACrB,EAAA,OAAQ,KAAK,MAAM,CAAA,GAAI,EAAA,GAAM,IAAA,CAAK,KAAK,GAAG,CAAA;AAC5C;AAGO,SAAS,YAAY,MAAA,EAAmF;AAC7G,EAAA,IAAI,IAAA,GAAO,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA;AACxB,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,IAAI,IAAI,IAAA,EAAM;AACZ,MAAA,IAAA,GAAO,CAAA;AACP,MAAA,OAAA,GAAU,CAAA;AAAA,IACZ;AACA,IAAA,MAAM,EAAA,GAAK,IAAA,GAAO,CAAA,GAAA,CAAK,IAAA,GAAO,KAAK,IAAA,GAAO,CAAA;AAC1C,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,KAAA,GAAQ,EAAA;AACR,MAAA,MAAA,GAAS,OAAA;AACT,MAAA,QAAA,GAAW,CAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,EAAE,WAAA,EAAa,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,aAAa,QAAA,EAAS;AACxE","file":"index.cjs","sourcesContent":["/**\n * @lacspace/market\n * The money & mechanics toolkit every stock-market app re-implements.\n *\n * P&L, returns, CAGR, XIRR, tick-size rounding, circuit limits, position sizing\n * — plus a real Indian brokerage & charges calculator (STT, GST, SEBI, stamp,\n * exchange txn) with discount-broker presets.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\n/* ------------------------------------------------------------------ *\n * Formatting\n * ------------------------------------------------------------------ */\n\nexport interface FormatMoneyOptions {\n symbol?: string;\n decimals?: number;\n}\n\n/**\n * Format a number in the Indian numbering system (lakh / crore grouping).\n * @example formatINR(1234567.5) // \"₹12,34,567.50\"\n */\nexport function formatINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\", decimals = 2 } = opts;\n const neg = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart = \"0\", frac = \"\"] = fixed.split(\".\");\n const last3 = intPart.slice(-3);\n const rest = intPart.slice(0, -3);\n const grouped = rest\n ? rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3\n : last3;\n return `${neg ? \"-\" : \"\"}${symbol}${grouped}${decimals > 0 ? \".\" + frac : \"\"}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Returns & P&L\n * ------------------------------------------------------------------ */\n\n/** Absolute profit/loss for a round-trip. */\nexport function pnl(o: { buy: number; sell: number; qty: number }): number {\n return (o.sell - o.buy) * o.qty;\n}\n\n/** Percentage change from `reference` to `current` (e.g. LTP vs prev close). */\nexport function changePercent(current: number, reference: number): number {\n if (reference === 0) return 0;\n return ((current - reference) / reference) * 100;\n}\n\n/** Profit/loss as a percentage of the buy price. */\nexport function pnlPercent(o: { buy: number; sell: number }): number {\n return changePercent(o.sell, o.buy);\n}\n\n/** Compound Annual Growth Rate as a fraction (0.15 = 15%). */\nexport function cagr(begin: number, end: number, years: number): number {\n if (begin <= 0 || years <= 0) return NaN;\n return Math.pow(end / begin, 1 / years) - 1;\n}\n\nexport interface CashFlow {\n /** Negative = money out (investment), positive = money in (redemption). */\n amount: number;\n date: Date | string | number;\n}\n\nfunction toMillis(d: Date | string | number): number {\n if (d instanceof Date) return d.getTime();\n if (typeof d === \"number\") return d;\n return new Date(d).getTime();\n}\n\n/**\n * Extended Internal Rate of Return for irregularly-spaced cash flows.\n * Returns an annualised rate as a fraction. Uses Newton–Raphson.\n *\n * Returns `NaN` when there are fewer than two flows OR when the solver fails to\n * converge within its iteration budget (e.g. no sign change in the flows, or a\n * diverging/oscillating series) — check with `Number.isNaN(result)` before use.\n * @example xirr([{amount:-10000, date:\"2024-01-01\"}, {amount:12000, date:\"2025-01-01\"}]) // ~0.20\n */\nexport function xirr(flows: CashFlow[], guess = 0.1): number {\n if (flows.length < 2) return NaN;\n const cf = flows\n .map((f) => ({ amount: f.amount, t: toMillis(f.date) }))\n .sort((a, b) => a.t - b.t);\n const t0 = cf[0]!.t;\n const yearFrac = (t: number) => (t - t0) / (365 * 24 * 3600 * 1000);\n const npv = (r: number) =>\n cf.reduce((s, c) => s + c.amount / Math.pow(1 + r, yearFrac(c.t)), 0);\n const dnpv = (r: number) =>\n cf.reduce((s, c) => {\n const y = yearFrac(c.t);\n return s - (y * c.amount) / Math.pow(1 + r, y + 1);\n }, 0);\n\n let r = guess;\n for (let i = 0; i < 100; i++) {\n const f = npv(r);\n if (Math.abs(f) < 1e-7) return r;\n const d = dnpv(r);\n if (d === 0) break;\n const next = r - f / d;\n if (!isFinite(next)) break;\n if (Math.abs(next - r) < 1e-10) return next;\n r = next;\n }\n // Exhausted the iteration budget without meeting the tolerance: did not converge.\n return NaN;\n}\n\n/* ------------------------------------------------------------------ *\n * Position mechanics\n * ------------------------------------------------------------------ */\n\n/** Volume-weighted average price across a set of trades. */\nexport function averagePrice(trades: { price: number; qty: number }[]): number {\n let qty = 0;\n let value = 0;\n for (const t of trades) {\n qty += t.qty;\n value += t.price * t.qty;\n }\n return qty === 0 ? 0 : value / qty;\n}\n\n/**\n * Risk-based position sizing. Returns the whole-share quantity so that a stop-out\n * costs at most `riskPercent` of capital.\n * @example positionSize({ capital: 100000, riskPercent: 1, entry: 500, stop: 480 }) // 50\n */\nexport function positionSize(o: {\n capital: number;\n riskPercent: number;\n entry: number;\n stop: number;\n}): number {\n const riskAmount = o.capital * (o.riskPercent / 100);\n const perShareRisk = Math.abs(o.entry - o.stop);\n if (perShareRisk === 0) return 0;\n return Math.floor(riskAmount / perShareRisk);\n}\n\n/** Round a price to the nearest exchange tick (default ₹0.05 for NSE equity). */\nexport function roundToTick(price: number, tick = 0.05): number {\n if (tick <= 0) return price;\n return Number((Math.round(price / tick) * tick).toFixed(4));\n}\n\n/** Upper & lower circuit price for a given previous close and band percent. */\nexport function circuitLimits(\n prevClose: number,\n percent: number,\n): { upper: number; lower: number } {\n const delta = prevClose * (percent / 100);\n return {\n upper: roundToTick(prevClose + delta),\n lower: roundToTick(prevClose - delta),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Brokerage & statutory charges (India)\n * ------------------------------------------------------------------ */\n\nexport type Segment = \"delivery\" | \"intraday\" | \"futures\" | \"options\";\n\nexport interface SegmentRates {\n /** Brokerage as a fraction of turnover per side (0.0003 = 0.03%). */\n brokeragePct: number;\n /** Per-order brokerage cap (₹). */\n brokerageCap: number;\n /** Flat per-order brokerage (₹) — overrides the pct/cap model when set. */\n brokerageFlat?: number;\n sttBuy: number;\n sttSell: number;\n exchangeTxn: number;\n stampBuy: number;\n /** Depository (DP) charge per scrip on the sell leg (₹). */\n dpPerScrip: number;\n}\n\nexport interface ChargeConfig {\n segments: Record<Segment, SegmentRates>;\n sebi: number;\n gst: number;\n}\n\n/**\n * Default rates approximating an Indian discount broker (Zerodha-style) as of\n * FY2024–25. Statutory rates change — override any field via the `config`\n * argument of {@link charges} and always verify against the live rate card.\n */\nexport const IN_DISCOUNT_BROKER: ChargeConfig = {\n segments: {\n delivery: {\n brokeragePct: 0,\n brokerageCap: 0,\n sttBuy: 0.001,\n sttSell: 0.001,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00015,\n dpPerScrip: 13.5,\n },\n intraday: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.00025,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n futures: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.0002,\n exchangeTxn: 0.0000173,\n stampBuy: 0.00002,\n dpPerScrip: 0,\n },\n options: {\n brokeragePct: 0,\n brokerageCap: 20,\n brokerageFlat: 20,\n sttBuy: 0,\n sttSell: 0.001,\n exchangeTxn: 0.0003503,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n },\n sebi: 0.000001, // ₹10 per crore\n gst: 0.18,\n};\n\nexport interface ChargeInput {\n segment: Segment;\n /** Buy price per unit. Omit / 0 for a sell-only leg. */\n buy: number;\n /** Sell price per unit. Omit / 0 for a buy-only leg. */\n sell: number;\n qty: number;\n}\n\nexport interface ChargeBreakdown {\n turnover: number;\n brokerage: number;\n stt: number;\n exchangeTxn: number;\n sebi: number;\n stamp: number;\n gst: number;\n dp: number;\n totalCharges: number;\n grossPnl: number;\n netPnl: number;\n /** Per-share price move needed just to break even on charges. */\n breakeven: number;\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction legBrokerage(turnover: number, r: SegmentRates): number {\n if (turnover <= 0) return 0;\n if (r.brokerageFlat !== undefined) return r.brokerageFlat;\n if (r.brokeragePct === 0) return 0;\n return Math.min(turnover * r.brokeragePct, r.brokerageCap);\n}\n\n/**\n * Full brokerage + statutory charges breakdown for a trade, Indian market.\n * @example\n * charges({ segment: \"intraday\", buy: 100, sell: 102, qty: 500 });\n * // { brokerage, stt, gst, sebi, stamp, exchangeTxn, totalCharges, netPnl, breakeven, ... }\n */\nexport function charges(\n input: ChargeInput,\n config: ChargeConfig = IN_DISCOUNT_BROKER,\n): ChargeBreakdown {\n const r = config.segments[input.segment];\n const buyVal = (input.buy || 0) * input.qty;\n const sellVal = (input.sell || 0) * input.qty;\n const turnover = buyVal + sellVal;\n\n const brokerage = legBrokerage(buyVal, r) + legBrokerage(sellVal, r);\n const stt = buyVal * r.sttBuy + sellVal * r.sttSell;\n const exchangeTxn = turnover * r.exchangeTxn;\n const sebi = turnover * config.sebi;\n const stamp = buyVal * r.stampBuy;\n const gst = (brokerage + exchangeTxn + sebi) * config.gst;\n const dp = sellVal > 0 ? r.dpPerScrip : 0;\n\n const totalCharges = brokerage + stt + exchangeTxn + sebi + stamp + gst + dp;\n const grossPnl = sellVal - buyVal;\n\n return {\n turnover: round2(turnover),\n brokerage: round2(brokerage),\n stt: round2(stt),\n exchangeTxn: round2(exchangeTxn),\n sebi: round2(sebi),\n stamp: round2(stamp),\n gst: round2(gst),\n dp: round2(dp),\n totalCharges: round2(totalCharges),\n grossPnl: round2(grossPnl),\n netPnl: round2(grossPnl - totalCharges),\n breakeven: input.qty === 0 ? 0 : round2(totalCharges / input.qty),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Compact formatting\n * ------------------------------------------------------------------ */\n\nfunction trimTo2(n: number): string {\n return Number(n.toFixed(2)).toString();\n}\n\n/** Compact INR: `formatCompactINR(12345678)` → `\"₹1.23 Cr\"`. */\nexport function formatCompactINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\" } = opts;\n const neg = amount < 0;\n const a = Math.abs(amount);\n const units: [number, string][] = [\n [1e7, \"Cr\"],\n [1e5, \"L\"],\n [1e3, \"K\"],\n ];\n const u = units.find(([size]) => a >= size);\n const out = u ? `${trimTo2(a / u[0])} ${u[1]}` : trimTo2(a);\n return `${neg ? \"-\" : \"\"}${symbol}${out}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Options — Black-Scholes greeks\n * ------------------------------------------------------------------ */\n\nfunction normPdf(x: number): number {\n return Math.exp((-x * x) / 2) / Math.sqrt(2 * Math.PI);\n}\n\n/** Standard normal CDF (Abramowitz & Stegun 7.1.26 approximation). */\nfunction normCdf(x: number): number {\n const t = 1 / (1 + 0.2316419 * Math.abs(x));\n const d = 0.3989422804014327 * Math.exp((-x * x) / 2);\n const p = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n return x > 0 ? 1 - p : p;\n}\n\nexport interface OptionInput {\n type: \"call\" | \"put\";\n /** Spot price of the underlying. */\n spot: number;\n strike: number;\n /** Time to expiry in years (e.g. 30 days ≈ 30/365). */\n timeYears: number;\n /** Risk-free rate (annual, decimal — e.g. 0.07). */\n rate: number;\n /** Volatility (annual, decimal — e.g. 0.25). */\n volatility: number;\n /** Continuous dividend yield (annual, decimal). Default 0. */\n dividendYield?: number;\n}\n\nexport interface Greeks {\n price: number;\n delta: number;\n gamma: number;\n /** Per-year theta (divide by 365 for per-day). */\n theta: number;\n /** Per 1.00 change in volatility (divide by 100 for per 1%). */\n vega: number;\n /** Per 1.00 change in rate (divide by 100 for per 1%). */\n rho: number;\n}\n\n/** Black-Scholes price + greeks for a European option. */\nexport function blackScholes(o: OptionInput): Greeks {\n const { type, spot: S, strike: K, timeYears: t, rate: r } = o;\n const q = o.dividendYield ?? 0;\n const sigma = o.volatility;\n\n // Degenerate inputs (expired option or zero vol) would divide by zero and\n // produce NaN/Infinity — fall back to the intrinsic value instead.\n if (t <= 0 || sigma <= 0) {\n if (type === \"call\") {\n return {\n price: Math.max(0, S - K),\n delta: S > K ? 1 : 0,\n gamma: 0,\n theta: 0,\n vega: 0,\n rho: 0,\n };\n }\n return {\n price: Math.max(0, K - S),\n delta: S < K ? -1 : 0,\n gamma: 0,\n theta: 0,\n vega: 0,\n rho: 0,\n };\n }\n\n const sqrtT = Math.sqrt(t);\n const d1 = (Math.log(S / K) + (r - q + (sigma * sigma) / 2) * t) / (sigma * sqrtT);\n const d2 = d1 - sigma * sqrtT;\n const disc = Math.exp(-r * t);\n const dq = Math.exp(-q * t);\n const nd1 = normPdf(d1);\n const gamma = (dq * nd1) / (S * sigma * sqrtT);\n const vega = S * dq * nd1 * sqrtT;\n if (type === \"call\") {\n const Nd1 = normCdf(d1);\n const Nd2 = normCdf(d2);\n return {\n price: S * dq * Nd1 - K * disc * Nd2,\n delta: dq * Nd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) - r * K * disc * Nd2 + q * S * dq * Nd1,\n vega,\n rho: K * t * disc * Nd2,\n };\n }\n const Nnd1 = normCdf(-d1);\n const Nnd2 = normCdf(-d2);\n return {\n price: K * disc * Nnd2 - S * dq * Nnd1,\n delta: -dq * Nnd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) + r * K * disc * Nnd2 - q * S * dq * Nnd1,\n vega,\n rho: -K * t * disc * Nnd2,\n };\n}\n\n/** Solve implied volatility from an observed option price (bisection). */\nexport function impliedVolatility(\n marketPrice: number,\n o: Omit<OptionInput, \"volatility\">,\n opts: { tolerance?: number; maxIterations?: number } = {},\n): number | null {\n const tol = opts.tolerance ?? 1e-6;\n const maxIter = opts.maxIterations ?? 100;\n let lo = 1e-4;\n let hi = 5;\n for (let i = 0; i < maxIter; i++) {\n const mid = (lo + hi) / 2;\n const price = blackScholes({ ...o, volatility: mid }).price;\n const diff = price - marketPrice;\n if (Math.abs(diff) < tol) return mid;\n if (diff > 0) hi = mid;\n else lo = mid;\n }\n return null;\n}\n\n/* ------------------------------------------------------------------ *\n * Portfolio analytics\n * ------------------------------------------------------------------ */\n\n/** Period-over-period simple returns from a price/equity series. */\nexport function simpleReturns(series: number[]): number[] {\n const out: number[] = [];\n for (let i = 1; i < series.length; i++) {\n const prev = series[i - 1]!;\n if (prev !== 0) out.push((series[i]! - prev) / prev);\n }\n return out;\n}\n\nfunction mean(xs: number[]): number {\n return xs.length ? xs.reduce((s, x) => s + x, 0) / xs.length : 0;\n}\n\nfunction stdev(xs: number[]): number {\n if (xs.length < 2) return 0;\n const m = mean(xs);\n return Math.sqrt(xs.reduce((s, x) => s + (x - m) ** 2, 0) / (xs.length - 1));\n}\n\n/** Volatility (stdev of returns); annualized by default. */\nexport function volatility(returns: number[], opts: { annualize?: boolean; periodsPerYear?: number } = {}): number {\n const sd = stdev(returns);\n return opts.annualize === false ? sd : sd * Math.sqrt(opts.periodsPerYear ?? 252);\n}\n\n/** Annualized Sharpe ratio from a return series. */\nexport function sharpe(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const sd = stdev(excess);\n if (sd === 0) return 0;\n return (mean(excess) / sd) * Math.sqrt(ppy);\n}\n\n/** Annualized Sortino ratio (downside-deviation only). */\nexport function sortino(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const downside = excess.filter((r) => r < 0);\n if (!downside.length) return 0;\n const dd = Math.sqrt(downside.reduce((s, r) => s + r * r, 0) / downside.length);\n if (dd === 0) return 0;\n return (mean(excess) / dd) * Math.sqrt(ppy);\n}\n\n/** Maximum drawdown of an equity curve, as a positive fraction (0.2 = −20%). */\nexport function maxDrawdown(equity: number[]): { maxDrawdown: number; peakIndex: number; troughIndex: number } {\n let peak = equity[0] ?? 0;\n let peakIdx = 0;\n let maxDd = 0;\n let ddPeak = 0;\n let ddTrough = 0;\n for (let i = 0; i < equity.length; i++) {\n const v = equity[i]!;\n if (v > peak) {\n peak = v;\n peakIdx = i;\n }\n const dd = peak > 0 ? (peak - v) / peak : 0;\n if (dd > maxDd) {\n maxDd = dd;\n ddPeak = peakIdx;\n ddTrough = i;\n }\n }\n return { maxDrawdown: maxDd, peakIndex: ddPeak, troughIndex: ddTrough };\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -40,6 +40,10 @@ interface CashFlow {
40
40
  /**
41
41
  * Extended Internal Rate of Return for irregularly-spaced cash flows.
42
42
  * Returns an annualised rate as a fraction. Uses Newton–Raphson.
43
+ *
44
+ * Returns `NaN` when there are fewer than two flows OR when the solver fails to
45
+ * converge within its iteration budget (e.g. no sign change in the flows, or a
46
+ * diverging/oscillating series) — check with `Number.isNaN(result)` before use.
43
47
  * @example xirr([{amount:-10000, date:"2024-01-01"}, {amount:12000, date:"2025-01-01"}]) // ~0.20
44
48
  */
45
49
  declare function xirr(flows: CashFlow[], guess?: number): number;
package/dist/index.d.ts CHANGED
@@ -40,6 +40,10 @@ interface CashFlow {
40
40
  /**
41
41
  * Extended Internal Rate of Return for irregularly-spaced cash flows.
42
42
  * Returns an annualised rate as a fraction. Uses Newton–Raphson.
43
+ *
44
+ * Returns `NaN` when there are fewer than two flows OR when the solver fails to
45
+ * converge within its iteration budget (e.g. no sign change in the flows, or a
46
+ * diverging/oscillating series) — check with `Number.isNaN(result)` before use.
43
47
  * @example xirr([{amount:-10000, date:"2024-01-01"}, {amount:12000, date:"2025-01-01"}]) // ~0.20
44
48
  */
45
49
  declare function xirr(flows: CashFlow[], guess?: number): number;
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ function xirr(flows, guess = 0.1) {
49
49
  if (Math.abs(next - r) < 1e-10) return next;
50
50
  r = next;
51
51
  }
52
- return r;
52
+ return NaN;
53
53
  }
54
54
  function averagePrice(trades) {
55
55
  let qty = 0;
@@ -188,6 +188,26 @@ function blackScholes(o) {
188
188
  const { type, spot: S, strike: K, timeYears: t, rate: r } = o;
189
189
  const q = o.dividendYield ?? 0;
190
190
  const sigma = o.volatility;
191
+ if (t <= 0 || sigma <= 0) {
192
+ if (type === "call") {
193
+ return {
194
+ price: Math.max(0, S - K),
195
+ delta: S > K ? 1 : 0,
196
+ gamma: 0,
197
+ theta: 0,
198
+ vega: 0,
199
+ rho: 0
200
+ };
201
+ }
202
+ return {
203
+ price: Math.max(0, K - S),
204
+ delta: S < K ? -1 : 0,
205
+ gamma: 0,
206
+ theta: 0,
207
+ vega: 0,
208
+ rho: 0
209
+ };
210
+ }
191
211
  const sqrtT = Math.sqrt(t);
192
212
  const d1 = (Math.log(S / K) + (r - q + sigma * sigma / 2) * t) / (sigma * sqrtT);
193
213
  const d2 = d1 - sigma * sqrtT;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"names":["r"],"mappings":";AAwBO,SAAS,SAAA,CAAU,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AAC/E,EAAA,MAAM,EAAE,MAAA,GAAS,QAAA,EAAK,QAAA,GAAW,GAAE,GAAI,IAAA;AACvC,EAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA,CAAE,QAAQ,QAAQ,CAAA;AAC/C,EAAA,MAAM,CAAC,UAAU,GAAA,EAAK,IAAA,GAAO,EAAE,CAAA,GAAI,KAAA,CAAM,MAAM,GAAG,CAAA;AAClD,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,EAAE,CAAA;AAC9B,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA;AAChC,EAAA,MAAM,OAAA,GAAU,OACZ,IAAA,CAAK,OAAA,CAAQ,yBAAyB,GAAG,CAAA,GAAI,MAAM,KAAA,GACnD,KAAA;AACJ,EAAA,OAAO,CAAA,EAAG,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,EAAG,MAAM,CAAA,EAAG,OAAO,CAAA,EAAG,QAAA,GAAW,CAAA,GAAI,GAAA,GAAM,OAAO,EAAE,CAAA,CAAA;AAC9E;AAOO,SAAS,IAAI,CAAA,EAAuD;AACzE,EAAA,OAAA,CAAQ,CAAA,CAAE,IAAA,GAAO,CAAA,CAAE,GAAA,IAAO,CAAA,CAAE,GAAA;AAC9B;AAGO,SAAS,aAAA,CAAc,SAAiB,SAAA,EAA2B;AACxE,EAAA,IAAI,SAAA,KAAc,GAAG,OAAO,CAAA;AAC5B,EAAA,OAAA,CAAS,OAAA,GAAU,aAAa,SAAA,GAAa,GAAA;AAC/C;AAGO,SAAS,WAAW,CAAA,EAA0C;AACnE,EAAA,OAAO,aAAA,CAAc,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,GAAG,CAAA;AACpC;AAGO,SAAS,IAAA,CAAK,KAAA,EAAe,GAAA,EAAa,KAAA,EAAuB;AACtE,EAAA,IAAI,KAAA,IAAS,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG,OAAO,GAAA;AACrC,EAAA,OAAO,KAAK,GAAA,CAAI,GAAA,GAAM,KAAA,EAAO,CAAA,GAAI,KAAK,CAAA,GAAI,CAAA;AAC5C;AAQA,SAAS,SAAS,CAAA,EAAmC;AACnD,EAAA,IAAI,CAAA,YAAa,IAAA,EAAM,OAAO,CAAA,CAAE,OAAA,EAAQ;AACxC,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,CAAA;AAClC,EAAA,OAAO,IAAI,IAAA,CAAK,CAAC,CAAA,CAAE,OAAA,EAAQ;AAC7B;AAOO,SAAS,IAAA,CAAK,KAAA,EAAmB,KAAA,GAAQ,GAAA,EAAa;AAC3D,EAAA,IAAI,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG,OAAO,GAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,MACR,GAAA,CAAI,CAAC,OAAO,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA,EAAG,QAAA,CAAS,EAAE,IAAI,CAAA,EAAE,CAAE,CAAA,CACtD,IAAA,CAAK,CAAC,GAAG,CAAA,KAAM,CAAA,CAAE,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA;AAC3B,EAAA,MAAM,EAAA,GAAK,EAAA,CAAG,CAAC,CAAA,CAAG,CAAA;AAClB,EAAA,MAAM,WAAW,CAAC,CAAA,KAAA,CAAe,IAAI,EAAA,KAAO,GAAA,GAAM,KAAK,IAAA,GAAO,GAAA,CAAA;AAC9D,EAAA,MAAM,GAAA,GAAM,CAACA,EAAAA,KACX,EAAA,CAAG,OAAO,CAAC,CAAA,EAAG,MAAM,CAAA,GAAI,CAAA,CAAE,SAAS,IAAA,CAAK,GAAA,CAAI,IAAIA,EAAAA,EAAG,QAAA,CAAS,EAAE,CAAC,CAAC,GAAG,CAAC,CAAA;AACtE,EAAA,MAAM,OAAO,CAACA,EAAAA,KACZ,GAAG,MAAA,CAAO,CAAC,GAAG,CAAA,KAAM;AAClB,IAAA,MAAM,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,CAAC,CAAA;AACtB,IAAA,OAAO,CAAA,GAAK,IAAI,CAAA,CAAE,MAAA,GAAU,KAAK,GAAA,CAAI,CAAA,GAAIA,EAAAA,EAAG,CAAA,GAAI,CAAC,CAAA;AAAA,EACnD,GAAG,CAAC,CAAA;AAEN,EAAA,IAAI,CAAA,GAAI,KAAA;AACR,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,GAAA,EAAK,CAAA,EAAA,EAAK;AAC5B,IAAA,MAAM,CAAA,GAAI,IAAI,CAAC,CAAA;AACf,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAI,MAAM,OAAO,CAAA;AAC/B,IAAA,MAAM,CAAA,GAAI,KAAK,CAAC,CAAA;AAChB,IAAA,IAAI,MAAM,CAAA,EAAG;AACb,IAAA,MAAM,IAAA,GAAO,IAAI,CAAA,GAAI,CAAA;AACrB,IAAA,IAAI,CAAC,QAAA,CAAS,IAAI,CAAA,EAAG;AACrB,IAAA,IAAI,KAAK,GAAA,CAAI,IAAA,GAAO,CAAC,CAAA,GAAI,OAAO,OAAO,IAAA;AACvC,IAAA,CAAA,GAAI,IAAA;AAAA,EACN;AACA,EAAA,OAAO,CAAA;AACT;AAOO,SAAS,aAAa,MAAA,EAAkD;AAC7E,EAAA,IAAI,GAAA,GAAM,CAAA;AACV,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,GAAA,IAAO,CAAA,CAAE,GAAA;AACT,IAAA,KAAA,IAAS,CAAA,CAAE,QAAQ,CAAA,CAAE,GAAA;AAAA,EACvB;AACA,EAAA,OAAO,GAAA,KAAQ,CAAA,GAAI,CAAA,GAAI,KAAA,GAAQ,GAAA;AACjC;AAOO,SAAS,aAAa,CAAA,EAKlB;AACT,EAAA,MAAM,UAAA,GAAa,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,WAAA,GAAc,GAAA,CAAA;AAChD,EAAA,MAAM,eAAe,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,GAAQ,EAAE,IAAI,CAAA;AAC9C,EAAA,IAAI,YAAA,KAAiB,GAAG,OAAO,CAAA;AAC/B,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,UAAA,GAAa,YAAY,CAAA;AAC7C;AAGO,SAAS,WAAA,CAAY,KAAA,EAAe,IAAA,GAAO,IAAA,EAAc;AAC9D,EAAA,IAAI,IAAA,IAAQ,GAAG,OAAO,KAAA;AACtB,EAAA,OAAO,MAAA,CAAA,CAAQ,KAAK,KAAA,CAAM,KAAA,GAAQ,IAAI,CAAA,GAAI,IAAA,EAAM,OAAA,CAAQ,CAAC,CAAC,CAAA;AAC5D;AAGO,SAAS,aAAA,CACd,WACA,OAAA,EACkC;AAClC,EAAA,MAAM,KAAA,GAAQ,aAAa,OAAA,GAAU,GAAA,CAAA;AACrC,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,WAAA,CAAY,SAAA,GAAY,KAAK,CAAA;AAAA,IACpC,KAAA,EAAO,WAAA,CAAY,SAAA,GAAY,KAAK;AAAA,GACtC;AACF;AAkCO,IAAM,kBAAA,GAAmC;AAAA,EAC9C,QAAA,EAAU;AAAA,IACR,QAAA,EAAU;AAAA,MACR,YAAA,EAAc,CAAA;AAAA,MACd,YAAA,EAAc,CAAA;AAAA,MACd,MAAA,EAAQ,IAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,KAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,QAAA,EAAU;AAAA,MACR,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,KAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,OAAA,EAAS;AAAA,MACP,YAAA,EAAc,IAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,MAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA,KACd;AAAA,IACA,OAAA,EAAS;AAAA,MACP,YAAA,EAAc,CAAA;AAAA,MACd,YAAA,EAAc,EAAA;AAAA,MACd,aAAA,EAAe,EAAA;AAAA,MACf,MAAA,EAAQ,CAAA;AAAA,MACR,OAAA,EAAS,IAAA;AAAA,MACT,WAAA,EAAa,OAAA;AAAA,MACb,QAAA,EAAU,IAAA;AAAA,MACV,UAAA,EAAY;AAAA;AACd,GACF;AAAA,EACA,IAAA,EAAM,IAAA;AAAA;AAAA,EACN,GAAA,EAAK;AACP;AA2BA,SAAS,OAAO,CAAA,EAAmB;AACjC,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,GAAI,GAAG,CAAA,GAAI,GAAA;AAC/B;AAEA,SAAS,YAAA,CAAa,UAAkB,CAAA,EAAyB;AAC/D,EAAA,IAAI,QAAA,IAAY,GAAG,OAAO,CAAA;AAC1B,EAAA,IAAI,CAAA,CAAE,aAAA,KAAkB,MAAA,EAAW,OAAO,CAAA,CAAE,aAAA;AAC5C,EAAA,IAAI,CAAA,CAAE,YAAA,KAAiB,CAAA,EAAG,OAAO,CAAA;AACjC,EAAA,OAAO,KAAK,GAAA,CAAI,QAAA,GAAW,CAAA,CAAE,YAAA,EAAc,EAAE,YAAY,CAAA;AAC3D;AAQO,SAAS,OAAA,CACd,KAAA,EACA,MAAA,GAAuB,kBAAA,EACN;AACjB,EAAA,MAAM,CAAA,GAAI,MAAA,CAAO,QAAA,CAAS,KAAA,CAAM,OAAO,CAAA;AACvC,EAAA,MAAM,MAAA,GAAA,CAAU,KAAA,CAAM,GAAA,IAAO,CAAA,IAAK,KAAA,CAAM,GAAA;AACxC,EAAA,MAAM,OAAA,GAAA,CAAW,KAAA,CAAM,IAAA,IAAQ,CAAA,IAAK,KAAA,CAAM,GAAA;AAC1C,EAAA,MAAM,WAAW,MAAA,GAAS,OAAA;AAE1B,EAAA,MAAM,YAAY,YAAA,CAAa,MAAA,EAAQ,CAAC,CAAA,GAAI,YAAA,CAAa,SAAS,CAAC,CAAA;AACnE,EAAA,MAAM,GAAA,GAAM,MAAA,GAAS,CAAA,CAAE,MAAA,GAAS,UAAU,CAAA,CAAE,OAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,WAAW,CAAA,CAAE,WAAA;AACjC,EAAA,MAAM,IAAA,GAAO,WAAW,MAAA,CAAO,IAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,SAAS,CAAA,CAAE,QAAA;AACzB,EAAA,MAAM,GAAA,GAAA,CAAO,SAAA,GAAY,WAAA,GAAc,IAAA,IAAQ,MAAA,CAAO,GAAA;AACtD,EAAA,MAAM,EAAA,GAAK,OAAA,GAAU,CAAA,GAAI,CAAA,CAAE,UAAA,GAAa,CAAA;AAExC,EAAA,MAAM,eAAe,SAAA,GAAY,GAAA,GAAM,WAAA,GAAc,IAAA,GAAO,QAAQ,GAAA,GAAM,EAAA;AAC1E,EAAA,MAAM,WAAW,OAAA,GAAU,MAAA;AAE3B,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,OAAO,QAAQ,CAAA;AAAA,IACzB,SAAA,EAAW,OAAO,SAAS,CAAA;AAAA,IAC3B,GAAA,EAAK,OAAO,GAAG,CAAA;AAAA,IACf,WAAA,EAAa,OAAO,WAAW,CAAA;AAAA,IAC/B,IAAA,EAAM,OAAO,IAAI,CAAA;AAAA,IACjB,KAAA,EAAO,OAAO,KAAK,CAAA;AAAA,IACnB,GAAA,EAAK,OAAO,GAAG,CAAA;AAAA,IACf,EAAA,EAAI,OAAO,EAAE,CAAA;AAAA,IACb,YAAA,EAAc,OAAO,YAAY,CAAA;AAAA,IACjC,QAAA,EAAU,OAAO,QAAQ,CAAA;AAAA,IACzB,MAAA,EAAQ,MAAA,CAAO,QAAA,GAAW,YAAY,CAAA;AAAA,IACtC,SAAA,EAAW,MAAM,GAAA,KAAQ,CAAA,GAAI,IAAI,MAAA,CAAO,YAAA,GAAe,MAAM,GAAG;AAAA,GAClE;AACF;AAMA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,OAAO,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,EAAE,QAAA,EAAS;AACvC;AAGO,SAAS,gBAAA,CAAiB,MAAA,EAAgB,IAAA,GAA2B,EAAC,EAAW;AACtF,EAAA,MAAM,EAAE,MAAA,GAAS,QAAA,EAAI,GAAI,IAAA;AACzB,EAAA,MAAM,MAAM,MAAA,GAAS,CAAA;AACrB,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AACzB,EAAA,MAAM,KAAA,GAA4B;AAAA,IAChC,CAAC,KAAK,IAAI,CAAA;AAAA,IACV,CAAC,KAAK,GAAG,CAAA;AAAA,IACT,CAAC,KAAK,GAAG;AAAA,GACX;AACA,EAAA,MAAM,CAAA,GAAI,MAAM,IAAA,CAAK,CAAC,CAAC,IAAI,CAAA,KAAM,KAAK,IAAI,CAAA;AAC1C,EAAA,MAAM,GAAA,GAAM,CAAA,GAAI,CAAA,EAAG,OAAA,CAAQ,IAAI,CAAA,CAAE,CAAC,CAAC,CAAC,IAAI,CAAA,CAAE,CAAC,CAAC,CAAA,CAAA,GAAK,QAAQ,CAAC,CAAA;AAC1D,EAAA,OAAO,GAAG,GAAA,GAAM,GAAA,GAAM,EAAE,CAAA,EAAG,MAAM,GAAG,GAAG,CAAA,CAAA;AACzC;AAMA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,OAAO,IAAA,CAAK,GAAA,CAAK,CAAC,CAAA,GAAI,CAAA,GAAK,CAAC,CAAA,GAAI,IAAA,CAAK,IAAA,CAAK,CAAA,GAAI,IAAA,CAAK,EAAE,CAAA;AACvD;AAGA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,MAAM,IAAI,CAAA,IAAK,CAAA,GAAI,SAAA,GAAY,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AACzC,EAAA,MAAM,IAAI,kBAAA,GAAqB,IAAA,CAAK,IAAK,CAAC,CAAA,GAAI,IAAK,CAAC,CAAA;AACpD,EAAA,MAAM,CAAA,GAAI,CAAA,GAAI,CAAA,IAAK,SAAA,GAAY,CAAA,IAAK,aAAa,CAAA,IAAK,WAAA,GAAc,CAAA,IAAK,YAAA,GAAe,CAAA,GAAI,WAAA,CAAA,CAAA,CAAA,CAAA;AAC5F,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA,GAAI,CAAA;AACzB;AA8BO,SAAS,aAAa,CAAA,EAAwB;AACnD,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,MAAA,EAAQ,GAAG,SAAA,EAAW,CAAA,EAAG,IAAA,EAAM,CAAA,EAAE,GAAI,CAAA;AAC5D,EAAA,MAAM,CAAA,GAAI,EAAE,aAAA,IAAiB,CAAA;AAC7B,EAAA,MAAM,QAAQ,CAAA,CAAE,UAAA;AAChB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA;AACzB,EAAA,MAAM,EAAA,GAAA,CAAM,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAC,CAAA,GAAA,CAAK,CAAA,GAAI,CAAA,GAAK,KAAA,GAAQ,KAAA,GAAS,CAAA,IAAK,CAAA,KAAM,KAAA,GAAQ,KAAA,CAAA;AAC5E,EAAA,MAAM,EAAA,GAAK,KAAK,KAAA,GAAQ,KAAA;AACxB,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAC,CAAA;AAC5B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAC,IAAI,CAAC,CAAA;AAC1B,EAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,EAAA,MAAM,KAAA,GAAS,EAAA,GAAK,GAAA,IAAQ,CAAA,GAAI,KAAA,GAAQ,KAAA,CAAA;AACxC,EAAA,MAAM,IAAA,GAAO,CAAA,GAAI,EAAA,GAAK,GAAA,GAAM,KAAA;AAC5B,EAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,IAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,IAAA,MAAM,GAAA,GAAM,QAAQ,EAAE,CAAA;AACtB,IAAA,OAAO;AAAA,MACL,KAAA,EAAO,CAAA,GAAI,EAAA,GAAK,GAAA,GAAM,IAAI,IAAA,GAAO,GAAA;AAAA,MACjC,OAAO,EAAA,GAAK,GAAA;AAAA,MACZ,KAAA;AAAA,MACA,KAAA,EAAO,EAAE,CAAA,GAAI,EAAA,GAAK,MAAM,KAAA,CAAA,IAAU,CAAA,GAAI,KAAA,CAAA,GAAS,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO,GAAA,GAAM,CAAA,GAAI,IAAI,EAAA,GAAK,GAAA;AAAA,MACjF,IAAA;AAAA,MACA,GAAA,EAAK,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO;AAAA,KACtB;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,EAAE,CAAA;AACxB,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,CAAC,EAAE,CAAA;AACxB,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,IAAI,EAAA,GAAK,IAAA;AAAA,IAClC,KAAA,EAAO,CAAC,EAAA,GAAK,IAAA;AAAA,IACb,KAAA;AAAA,IACA,KAAA,EAAO,EAAE,CAAA,GAAI,EAAA,GAAK,MAAM,KAAA,CAAA,IAAU,CAAA,GAAI,KAAA,CAAA,GAAS,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,CAAA,GAAI,IAAI,EAAA,GAAK,IAAA;AAAA,IAClF,IAAA;AAAA,IACA,GAAA,EAAK,CAAC,CAAA,GAAI,CAAA,GAAI,IAAA,GAAO;AAAA,GACvB;AACF;AAGO,SAAS,iBAAA,CACd,WAAA,EACA,CAAA,EACA,IAAA,GAAuD,EAAC,EACzC;AACf,EAAA,MAAM,GAAA,GAAM,KAAK,SAAA,IAAa,IAAA;AAC9B,EAAA,MAAM,OAAA,GAAU,KAAK,aAAA,IAAiB,GAAA;AACtC,EAAA,IAAI,EAAA,GAAK,IAAA;AACT,EAAA,IAAI,EAAA,GAAK,CAAA;AACT,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,OAAA,EAAS,CAAA,EAAA,EAAK;AAChC,IAAA,MAAM,GAAA,GAAA,CAAO,KAAK,EAAA,IAAM,CAAA;AACxB,IAAA,MAAM,KAAA,GAAQ,aAAa,EAAE,GAAG,GAAG,UAAA,EAAY,GAAA,EAAK,CAAA,CAAE,KAAA;AACtD,IAAA,MAAM,OAAO,KAAA,GAAQ,WAAA;AACrB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,GAAI,KAAK,OAAO,GAAA;AACjC,IAAA,IAAI,IAAA,GAAO,GAAG,EAAA,GAAK,GAAA;AAAA,SACd,EAAA,GAAK,GAAA;AAAA,EACZ;AACA,EAAA,OAAO,IAAA;AACT;AAOO,SAAS,cAAc,MAAA,EAA4B;AACxD,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,IAAA,GAAO,MAAA,CAAO,CAAA,GAAI,CAAC,CAAA;AACzB,IAAA,IAAI,IAAA,KAAS,GAAG,GAAA,CAAI,IAAA,CAAA,CAAM,OAAO,CAAC,CAAA,GAAK,QAAQ,IAAI,CAAA;AAAA,EACrD;AACA,EAAA,OAAO,GAAA;AACT;AAEA,SAAS,KAAK,EAAA,EAAsB;AAClC,EAAA,OAAO,EAAA,CAAG,MAAA,GAAS,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,EAAA,CAAG,MAAA,GAAS,CAAA;AACjE;AAEA,SAAS,MAAM,EAAA,EAAsB;AACnC,EAAA,IAAI,EAAA,CAAG,MAAA,GAAS,CAAA,EAAG,OAAO,CAAA;AAC1B,EAAA,MAAM,CAAA,GAAI,KAAK,EAAE,CAAA;AACjB,EAAA,OAAO,IAAA,CAAK,IAAA,CAAK,EAAA,CAAG,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAA,CAAK,CAAA,GAAI,MAAM,CAAA,EAAG,CAAC,CAAA,IAAK,EAAA,CAAG,SAAS,CAAA,CAAE,CAAA;AAC7E;AAGO,SAAS,UAAA,CAAW,OAAA,EAAmB,IAAA,GAAyD,EAAC,EAAW;AACjH,EAAA,MAAM,EAAA,GAAK,MAAM,OAAO,CAAA;AACxB,EAAA,OAAO,IAAA,CAAK,cAAc,KAAA,GAAQ,EAAA,GAAK,KAAK,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,cAAA,IAAkB,GAAG,CAAA;AAClF;AAGO,SAAS,MAAA,CAAO,OAAA,EAAmB,IAAA,GAAuD,EAAC,EAAW;AAC3G,EAAA,MAAM,GAAA,GAAM,KAAK,cAAA,IAAkB,GAAA;AACnC,EAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,QAAA,IAAY,CAAA,IAAK,GAAA;AAC3C,EAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,WAAW,CAAA;AACjD,EAAA,MAAM,EAAA,GAAK,MAAM,MAAM,CAAA;AACvB,EAAA,IAAI,EAAA,KAAO,GAAG,OAAO,CAAA;AACrB,EAAA,OAAQ,KAAK,MAAM,CAAA,GAAI,EAAA,GAAM,IAAA,CAAK,KAAK,GAAG,CAAA;AAC5C;AAGO,SAAS,OAAA,CAAQ,OAAA,EAAmB,IAAA,GAAuD,EAAC,EAAW;AAC5G,EAAA,MAAM,GAAA,GAAM,KAAK,cAAA,IAAkB,GAAA;AACnC,EAAA,MAAM,WAAA,GAAA,CAAe,IAAA,CAAK,QAAA,IAAY,CAAA,IAAK,GAAA;AAC3C,EAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,CAAC,CAAA,KAAM,IAAI,WAAW,CAAA;AACjD,EAAA,MAAM,WAAW,MAAA,CAAO,MAAA,CAAO,CAAC,CAAA,KAAM,IAAI,CAAC,CAAA;AAC3C,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAQ,OAAO,CAAA;AAC7B,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,IAAA,CAAK,QAAA,CAAS,OAAO,CAAC,CAAA,EAAG,CAAA,KAAM,CAAA,GAAI,CAAA,GAAI,CAAA,EAAG,CAAC,CAAA,GAAI,SAAS,MAAM,CAAA;AAC9E,EAAA,IAAI,EAAA,KAAO,GAAG,OAAO,CAAA;AACrB,EAAA,OAAQ,KAAK,MAAM,CAAA,GAAI,EAAA,GAAM,IAAA,CAAK,KAAK,GAAG,CAAA;AAC5C;AAGO,SAAS,YAAY,MAAA,EAAmF;AAC7G,EAAA,IAAI,IAAA,GAAO,MAAA,CAAO,CAAC,CAAA,IAAK,CAAA;AACxB,EAAA,IAAI,OAAA,GAAU,CAAA;AACd,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,MAAA,GAAS,CAAA;AACb,EAAA,IAAI,QAAA,GAAW,CAAA;AACf,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,MAAA,CAAO,QAAQ,CAAA,EAAA,EAAK;AACtC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,IAAI,IAAI,IAAA,EAAM;AACZ,MAAA,IAAA,GAAO,CAAA;AACP,MAAA,OAAA,GAAU,CAAA;AAAA,IACZ;AACA,IAAA,MAAM,EAAA,GAAK,IAAA,GAAO,CAAA,GAAA,CAAK,IAAA,GAAO,KAAK,IAAA,GAAO,CAAA;AAC1C,IAAA,IAAI,KAAK,KAAA,EAAO;AACd,MAAA,KAAA,GAAQ,EAAA;AACR,MAAA,MAAA,GAAS,OAAA;AACT,MAAA,QAAA,GAAW,CAAA;AAAA,IACb;AAAA,EACF;AACA,EAAA,OAAO,EAAE,WAAA,EAAa,KAAA,EAAO,SAAA,EAAW,MAAA,EAAQ,aAAa,QAAA,EAAS;AACxE","file":"index.js","sourcesContent":["/**\n * @lacspace/market\n * The money & mechanics toolkit every stock-market app re-implements.\n *\n * P&L, returns, CAGR, XIRR, tick-size rounding, circuit limits, position sizing\n * — plus a real Indian brokerage & charges calculator (STT, GST, SEBI, stamp,\n * exchange txn) with discount-broker presets.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\n/* ------------------------------------------------------------------ *\n * Formatting\n * ------------------------------------------------------------------ */\n\nexport interface FormatMoneyOptions {\n symbol?: string;\n decimals?: number;\n}\n\n/**\n * Format a number in the Indian numbering system (lakh / crore grouping).\n * @example formatINR(1234567.5) // \"₹12,34,567.50\"\n */\nexport function formatINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\", decimals = 2 } = opts;\n const neg = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart = \"0\", frac = \"\"] = fixed.split(\".\");\n const last3 = intPart.slice(-3);\n const rest = intPart.slice(0, -3);\n const grouped = rest\n ? rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3\n : last3;\n return `${neg ? \"-\" : \"\"}${symbol}${grouped}${decimals > 0 ? \".\" + frac : \"\"}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Returns & P&L\n * ------------------------------------------------------------------ */\n\n/** Absolute profit/loss for a round-trip. */\nexport function pnl(o: { buy: number; sell: number; qty: number }): number {\n return (o.sell - o.buy) * o.qty;\n}\n\n/** Percentage change from `reference` to `current` (e.g. LTP vs prev close). */\nexport function changePercent(current: number, reference: number): number {\n if (reference === 0) return 0;\n return ((current - reference) / reference) * 100;\n}\n\n/** Profit/loss as a percentage of the buy price. */\nexport function pnlPercent(o: { buy: number; sell: number }): number {\n return changePercent(o.sell, o.buy);\n}\n\n/** Compound Annual Growth Rate as a fraction (0.15 = 15%). */\nexport function cagr(begin: number, end: number, years: number): number {\n if (begin <= 0 || years <= 0) return NaN;\n return Math.pow(end / begin, 1 / years) - 1;\n}\n\nexport interface CashFlow {\n /** Negative = money out (investment), positive = money in (redemption). */\n amount: number;\n date: Date | string | number;\n}\n\nfunction toMillis(d: Date | string | number): number {\n if (d instanceof Date) return d.getTime();\n if (typeof d === \"number\") return d;\n return new Date(d).getTime();\n}\n\n/**\n * Extended Internal Rate of Return for irregularly-spaced cash flows.\n * Returns an annualised rate as a fraction. Uses Newton–Raphson.\n * @example xirr([{amount:-10000, date:\"2024-01-01\"}, {amount:12000, date:\"2025-01-01\"}]) // ~0.20\n */\nexport function xirr(flows: CashFlow[], guess = 0.1): number {\n if (flows.length < 2) return NaN;\n const cf = flows\n .map((f) => ({ amount: f.amount, t: toMillis(f.date) }))\n .sort((a, b) => a.t - b.t);\n const t0 = cf[0]!.t;\n const yearFrac = (t: number) => (t - t0) / (365 * 24 * 3600 * 1000);\n const npv = (r: number) =>\n cf.reduce((s, c) => s + c.amount / Math.pow(1 + r, yearFrac(c.t)), 0);\n const dnpv = (r: number) =>\n cf.reduce((s, c) => {\n const y = yearFrac(c.t);\n return s - (y * c.amount) / Math.pow(1 + r, y + 1);\n }, 0);\n\n let r = guess;\n for (let i = 0; i < 100; i++) {\n const f = npv(r);\n if (Math.abs(f) < 1e-7) return r;\n const d = dnpv(r);\n if (d === 0) break;\n const next = r - f / d;\n if (!isFinite(next)) break;\n if (Math.abs(next - r) < 1e-10) return next;\n r = next;\n }\n return r;\n}\n\n/* ------------------------------------------------------------------ *\n * Position mechanics\n * ------------------------------------------------------------------ */\n\n/** Volume-weighted average price across a set of trades. */\nexport function averagePrice(trades: { price: number; qty: number }[]): number {\n let qty = 0;\n let value = 0;\n for (const t of trades) {\n qty += t.qty;\n value += t.price * t.qty;\n }\n return qty === 0 ? 0 : value / qty;\n}\n\n/**\n * Risk-based position sizing. Returns the whole-share quantity so that a stop-out\n * costs at most `riskPercent` of capital.\n * @example positionSize({ capital: 100000, riskPercent: 1, entry: 500, stop: 480 }) // 50\n */\nexport function positionSize(o: {\n capital: number;\n riskPercent: number;\n entry: number;\n stop: number;\n}): number {\n const riskAmount = o.capital * (o.riskPercent / 100);\n const perShareRisk = Math.abs(o.entry - o.stop);\n if (perShareRisk === 0) return 0;\n return Math.floor(riskAmount / perShareRisk);\n}\n\n/** Round a price to the nearest exchange tick (default ₹0.05 for NSE equity). */\nexport function roundToTick(price: number, tick = 0.05): number {\n if (tick <= 0) return price;\n return Number((Math.round(price / tick) * tick).toFixed(4));\n}\n\n/** Upper & lower circuit price for a given previous close and band percent. */\nexport function circuitLimits(\n prevClose: number,\n percent: number,\n): { upper: number; lower: number } {\n const delta = prevClose * (percent / 100);\n return {\n upper: roundToTick(prevClose + delta),\n lower: roundToTick(prevClose - delta),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Brokerage & statutory charges (India)\n * ------------------------------------------------------------------ */\n\nexport type Segment = \"delivery\" | \"intraday\" | \"futures\" | \"options\";\n\nexport interface SegmentRates {\n /** Brokerage as a fraction of turnover per side (0.0003 = 0.03%). */\n brokeragePct: number;\n /** Per-order brokerage cap (₹). */\n brokerageCap: number;\n /** Flat per-order brokerage (₹) — overrides the pct/cap model when set. */\n brokerageFlat?: number;\n sttBuy: number;\n sttSell: number;\n exchangeTxn: number;\n stampBuy: number;\n /** Depository (DP) charge per scrip on the sell leg (₹). */\n dpPerScrip: number;\n}\n\nexport interface ChargeConfig {\n segments: Record<Segment, SegmentRates>;\n sebi: number;\n gst: number;\n}\n\n/**\n * Default rates approximating an Indian discount broker (Zerodha-style) as of\n * FY2024–25. Statutory rates change — override any field via the `config`\n * argument of {@link charges} and always verify against the live rate card.\n */\nexport const IN_DISCOUNT_BROKER: ChargeConfig = {\n segments: {\n delivery: {\n brokeragePct: 0,\n brokerageCap: 0,\n sttBuy: 0.001,\n sttSell: 0.001,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00015,\n dpPerScrip: 13.5,\n },\n intraday: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.00025,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n futures: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.0002,\n exchangeTxn: 0.0000173,\n stampBuy: 0.00002,\n dpPerScrip: 0,\n },\n options: {\n brokeragePct: 0,\n brokerageCap: 20,\n brokerageFlat: 20,\n sttBuy: 0,\n sttSell: 0.001,\n exchangeTxn: 0.0003503,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n },\n sebi: 0.000001, // ₹10 per crore\n gst: 0.18,\n};\n\nexport interface ChargeInput {\n segment: Segment;\n /** Buy price per unit. Omit / 0 for a sell-only leg. */\n buy: number;\n /** Sell price per unit. Omit / 0 for a buy-only leg. */\n sell: number;\n qty: number;\n}\n\nexport interface ChargeBreakdown {\n turnover: number;\n brokerage: number;\n stt: number;\n exchangeTxn: number;\n sebi: number;\n stamp: number;\n gst: number;\n dp: number;\n totalCharges: number;\n grossPnl: number;\n netPnl: number;\n /** Per-share price move needed just to break even on charges. */\n breakeven: number;\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction legBrokerage(turnover: number, r: SegmentRates): number {\n if (turnover <= 0) return 0;\n if (r.brokerageFlat !== undefined) return r.brokerageFlat;\n if (r.brokeragePct === 0) return 0;\n return Math.min(turnover * r.brokeragePct, r.brokerageCap);\n}\n\n/**\n * Full brokerage + statutory charges breakdown for a trade, Indian market.\n * @example\n * charges({ segment: \"intraday\", buy: 100, sell: 102, qty: 500 });\n * // { brokerage, stt, gst, sebi, stamp, exchangeTxn, totalCharges, netPnl, breakeven, ... }\n */\nexport function charges(\n input: ChargeInput,\n config: ChargeConfig = IN_DISCOUNT_BROKER,\n): ChargeBreakdown {\n const r = config.segments[input.segment];\n const buyVal = (input.buy || 0) * input.qty;\n const sellVal = (input.sell || 0) * input.qty;\n const turnover = buyVal + sellVal;\n\n const brokerage = legBrokerage(buyVal, r) + legBrokerage(sellVal, r);\n const stt = buyVal * r.sttBuy + sellVal * r.sttSell;\n const exchangeTxn = turnover * r.exchangeTxn;\n const sebi = turnover * config.sebi;\n const stamp = buyVal * r.stampBuy;\n const gst = (brokerage + exchangeTxn + sebi) * config.gst;\n const dp = sellVal > 0 ? r.dpPerScrip : 0;\n\n const totalCharges = brokerage + stt + exchangeTxn + sebi + stamp + gst + dp;\n const grossPnl = sellVal - buyVal;\n\n return {\n turnover: round2(turnover),\n brokerage: round2(brokerage),\n stt: round2(stt),\n exchangeTxn: round2(exchangeTxn),\n sebi: round2(sebi),\n stamp: round2(stamp),\n gst: round2(gst),\n dp: round2(dp),\n totalCharges: round2(totalCharges),\n grossPnl: round2(grossPnl),\n netPnl: round2(grossPnl - totalCharges),\n breakeven: input.qty === 0 ? 0 : round2(totalCharges / input.qty),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Compact formatting\n * ------------------------------------------------------------------ */\n\nfunction trimTo2(n: number): string {\n return Number(n.toFixed(2)).toString();\n}\n\n/** Compact INR: `formatCompactINR(12345678)` → `\"₹1.23 Cr\"`. */\nexport function formatCompactINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\" } = opts;\n const neg = amount < 0;\n const a = Math.abs(amount);\n const units: [number, string][] = [\n [1e7, \"Cr\"],\n [1e5, \"L\"],\n [1e3, \"K\"],\n ];\n const u = units.find(([size]) => a >= size);\n const out = u ? `${trimTo2(a / u[0])} ${u[1]}` : trimTo2(a);\n return `${neg ? \"-\" : \"\"}${symbol}${out}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Options — Black-Scholes greeks\n * ------------------------------------------------------------------ */\n\nfunction normPdf(x: number): number {\n return Math.exp((-x * x) / 2) / Math.sqrt(2 * Math.PI);\n}\n\n/** Standard normal CDF (Abramowitz & Stegun 7.1.26 approximation). */\nfunction normCdf(x: number): number {\n const t = 1 / (1 + 0.2316419 * Math.abs(x));\n const d = 0.3989422804014327 * Math.exp((-x * x) / 2);\n const p = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n return x > 0 ? 1 - p : p;\n}\n\nexport interface OptionInput {\n type: \"call\" | \"put\";\n /** Spot price of the underlying. */\n spot: number;\n strike: number;\n /** Time to expiry in years (e.g. 30 days ≈ 30/365). */\n timeYears: number;\n /** Risk-free rate (annual, decimal — e.g. 0.07). */\n rate: number;\n /** Volatility (annual, decimal — e.g. 0.25). */\n volatility: number;\n /** Continuous dividend yield (annual, decimal). Default 0. */\n dividendYield?: number;\n}\n\nexport interface Greeks {\n price: number;\n delta: number;\n gamma: number;\n /** Per-year theta (divide by 365 for per-day). */\n theta: number;\n /** Per 1.00 change in volatility (divide by 100 for per 1%). */\n vega: number;\n /** Per 1.00 change in rate (divide by 100 for per 1%). */\n rho: number;\n}\n\n/** Black-Scholes price + greeks for a European option. */\nexport function blackScholes(o: OptionInput): Greeks {\n const { type, spot: S, strike: K, timeYears: t, rate: r } = o;\n const q = o.dividendYield ?? 0;\n const sigma = o.volatility;\n const sqrtT = Math.sqrt(t);\n const d1 = (Math.log(S / K) + (r - q + (sigma * sigma) / 2) * t) / (sigma * sqrtT);\n const d2 = d1 - sigma * sqrtT;\n const disc = Math.exp(-r * t);\n const dq = Math.exp(-q * t);\n const nd1 = normPdf(d1);\n const gamma = (dq * nd1) / (S * sigma * sqrtT);\n const vega = S * dq * nd1 * sqrtT;\n if (type === \"call\") {\n const Nd1 = normCdf(d1);\n const Nd2 = normCdf(d2);\n return {\n price: S * dq * Nd1 - K * disc * Nd2,\n delta: dq * Nd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) - r * K * disc * Nd2 + q * S * dq * Nd1,\n vega,\n rho: K * t * disc * Nd2,\n };\n }\n const Nnd1 = normCdf(-d1);\n const Nnd2 = normCdf(-d2);\n return {\n price: K * disc * Nnd2 - S * dq * Nnd1,\n delta: -dq * Nnd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) + r * K * disc * Nnd2 - q * S * dq * Nnd1,\n vega,\n rho: -K * t * disc * Nnd2,\n };\n}\n\n/** Solve implied volatility from an observed option price (bisection). */\nexport function impliedVolatility(\n marketPrice: number,\n o: Omit<OptionInput, \"volatility\">,\n opts: { tolerance?: number; maxIterations?: number } = {},\n): number | null {\n const tol = opts.tolerance ?? 1e-6;\n const maxIter = opts.maxIterations ?? 100;\n let lo = 1e-4;\n let hi = 5;\n for (let i = 0; i < maxIter; i++) {\n const mid = (lo + hi) / 2;\n const price = blackScholes({ ...o, volatility: mid }).price;\n const diff = price - marketPrice;\n if (Math.abs(diff) < tol) return mid;\n if (diff > 0) hi = mid;\n else lo = mid;\n }\n return null;\n}\n\n/* ------------------------------------------------------------------ *\n * Portfolio analytics\n * ------------------------------------------------------------------ */\n\n/** Period-over-period simple returns from a price/equity series. */\nexport function simpleReturns(series: number[]): number[] {\n const out: number[] = [];\n for (let i = 1; i < series.length; i++) {\n const prev = series[i - 1]!;\n if (prev !== 0) out.push((series[i]! - prev) / prev);\n }\n return out;\n}\n\nfunction mean(xs: number[]): number {\n return xs.length ? xs.reduce((s, x) => s + x, 0) / xs.length : 0;\n}\n\nfunction stdev(xs: number[]): number {\n if (xs.length < 2) return 0;\n const m = mean(xs);\n return Math.sqrt(xs.reduce((s, x) => s + (x - m) ** 2, 0) / (xs.length - 1));\n}\n\n/** Volatility (stdev of returns); annualized by default. */\nexport function volatility(returns: number[], opts: { annualize?: boolean; periodsPerYear?: number } = {}): number {\n const sd = stdev(returns);\n return opts.annualize === false ? sd : sd * Math.sqrt(opts.periodsPerYear ?? 252);\n}\n\n/** Annualized Sharpe ratio from a return series. */\nexport function sharpe(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const sd = stdev(excess);\n if (sd === 0) return 0;\n return (mean(excess) / sd) * Math.sqrt(ppy);\n}\n\n/** Annualized Sortino ratio (downside-deviation only). */\nexport function sortino(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const downside = excess.filter((r) => r < 0);\n if (!downside.length) return 0;\n const dd = Math.sqrt(downside.reduce((s, r) => s + r * r, 0) / downside.length);\n if (dd === 0) return 0;\n return (mean(excess) / dd) * Math.sqrt(ppy);\n}\n\n/** Maximum drawdown of an equity curve, as a positive fraction (0.2 = −20%). */\nexport function maxDrawdown(equity: number[]): { maxDrawdown: number; peakIndex: number; troughIndex: number } {\n let peak = equity[0] ?? 0;\n let peakIdx = 0;\n let maxDd = 0;\n let ddPeak = 0;\n let ddTrough = 0;\n for (let i = 0; i < equity.length; i++) {\n const v = equity[i]!;\n if (v > peak) {\n peak = v;\n peakIdx = i;\n }\n const dd = peak > 0 ? (peak - v) / peak : 0;\n if (dd > maxDd) {\n maxDd = dd;\n ddPeak = peakIdx;\n ddTrough = i;\n }\n }\n return { maxDrawdown: maxDd, peakIndex: ddPeak, troughIndex: ddTrough };\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts"],"names":["r"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * @lacspace/market\n * The money & mechanics toolkit every stock-market app re-implements.\n *\n * P&L, returns, CAGR, XIRR, tick-size rounding, circuit limits, position sizing\n * — plus a real Indian brokerage & charges calculator (STT, GST, SEBI, stamp,\n * exchange txn) with discount-broker presets.\n *\n * Zero dependencies · isomorphic · fully typed.\n */\n\n/* ------------------------------------------------------------------ *\n * Formatting\n * ------------------------------------------------------------------ */\n\nexport interface FormatMoneyOptions {\n symbol?: string;\n decimals?: number;\n}\n\n/**\n * Format a number in the Indian numbering system (lakh / crore grouping).\n * @example formatINR(1234567.5) // \"₹12,34,567.50\"\n */\nexport function formatINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\", decimals = 2 } = opts;\n const neg = amount < 0;\n const fixed = Math.abs(amount).toFixed(decimals);\n const [intPart = \"0\", frac = \"\"] = fixed.split(\".\");\n const last3 = intPart.slice(-3);\n const rest = intPart.slice(0, -3);\n const grouped = rest\n ? rest.replace(/\\B(?=(\\d{2})+(?!\\d))/g, \",\") + \",\" + last3\n : last3;\n return `${neg ? \"-\" : \"\"}${symbol}${grouped}${decimals > 0 ? \".\" + frac : \"\"}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Returns & P&L\n * ------------------------------------------------------------------ */\n\n/** Absolute profit/loss for a round-trip. */\nexport function pnl(o: { buy: number; sell: number; qty: number }): number {\n return (o.sell - o.buy) * o.qty;\n}\n\n/** Percentage change from `reference` to `current` (e.g. LTP vs prev close). */\nexport function changePercent(current: number, reference: number): number {\n if (reference === 0) return 0;\n return ((current - reference) / reference) * 100;\n}\n\n/** Profit/loss as a percentage of the buy price. */\nexport function pnlPercent(o: { buy: number; sell: number }): number {\n return changePercent(o.sell, o.buy);\n}\n\n/** Compound Annual Growth Rate as a fraction (0.15 = 15%). */\nexport function cagr(begin: number, end: number, years: number): number {\n if (begin <= 0 || years <= 0) return NaN;\n return Math.pow(end / begin, 1 / years) - 1;\n}\n\nexport interface CashFlow {\n /** Negative = money out (investment), positive = money in (redemption). */\n amount: number;\n date: Date | string | number;\n}\n\nfunction toMillis(d: Date | string | number): number {\n if (d instanceof Date) return d.getTime();\n if (typeof d === \"number\") return d;\n return new Date(d).getTime();\n}\n\n/**\n * Extended Internal Rate of Return for irregularly-spaced cash flows.\n * Returns an annualised rate as a fraction. Uses Newton–Raphson.\n *\n * Returns `NaN` when there are fewer than two flows OR when the solver fails to\n * converge within its iteration budget (e.g. no sign change in the flows, or a\n * diverging/oscillating series) — check with `Number.isNaN(result)` before use.\n * @example xirr([{amount:-10000, date:\"2024-01-01\"}, {amount:12000, date:\"2025-01-01\"}]) // ~0.20\n */\nexport function xirr(flows: CashFlow[], guess = 0.1): number {\n if (flows.length < 2) return NaN;\n const cf = flows\n .map((f) => ({ amount: f.amount, t: toMillis(f.date) }))\n .sort((a, b) => a.t - b.t);\n const t0 = cf[0]!.t;\n const yearFrac = (t: number) => (t - t0) / (365 * 24 * 3600 * 1000);\n const npv = (r: number) =>\n cf.reduce((s, c) => s + c.amount / Math.pow(1 + r, yearFrac(c.t)), 0);\n const dnpv = (r: number) =>\n cf.reduce((s, c) => {\n const y = yearFrac(c.t);\n return s - (y * c.amount) / Math.pow(1 + r, y + 1);\n }, 0);\n\n let r = guess;\n for (let i = 0; i < 100; i++) {\n const f = npv(r);\n if (Math.abs(f) < 1e-7) return r;\n const d = dnpv(r);\n if (d === 0) break;\n const next = r - f / d;\n if (!isFinite(next)) break;\n if (Math.abs(next - r) < 1e-10) return next;\n r = next;\n }\n // Exhausted the iteration budget without meeting the tolerance: did not converge.\n return NaN;\n}\n\n/* ------------------------------------------------------------------ *\n * Position mechanics\n * ------------------------------------------------------------------ */\n\n/** Volume-weighted average price across a set of trades. */\nexport function averagePrice(trades: { price: number; qty: number }[]): number {\n let qty = 0;\n let value = 0;\n for (const t of trades) {\n qty += t.qty;\n value += t.price * t.qty;\n }\n return qty === 0 ? 0 : value / qty;\n}\n\n/**\n * Risk-based position sizing. Returns the whole-share quantity so that a stop-out\n * costs at most `riskPercent` of capital.\n * @example positionSize({ capital: 100000, riskPercent: 1, entry: 500, stop: 480 }) // 50\n */\nexport function positionSize(o: {\n capital: number;\n riskPercent: number;\n entry: number;\n stop: number;\n}): number {\n const riskAmount = o.capital * (o.riskPercent / 100);\n const perShareRisk = Math.abs(o.entry - o.stop);\n if (perShareRisk === 0) return 0;\n return Math.floor(riskAmount / perShareRisk);\n}\n\n/** Round a price to the nearest exchange tick (default ₹0.05 for NSE equity). */\nexport function roundToTick(price: number, tick = 0.05): number {\n if (tick <= 0) return price;\n return Number((Math.round(price / tick) * tick).toFixed(4));\n}\n\n/** Upper & lower circuit price for a given previous close and band percent. */\nexport function circuitLimits(\n prevClose: number,\n percent: number,\n): { upper: number; lower: number } {\n const delta = prevClose * (percent / 100);\n return {\n upper: roundToTick(prevClose + delta),\n lower: roundToTick(prevClose - delta),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Brokerage & statutory charges (India)\n * ------------------------------------------------------------------ */\n\nexport type Segment = \"delivery\" | \"intraday\" | \"futures\" | \"options\";\n\nexport interface SegmentRates {\n /** Brokerage as a fraction of turnover per side (0.0003 = 0.03%). */\n brokeragePct: number;\n /** Per-order brokerage cap (₹). */\n brokerageCap: number;\n /** Flat per-order brokerage (₹) — overrides the pct/cap model when set. */\n brokerageFlat?: number;\n sttBuy: number;\n sttSell: number;\n exchangeTxn: number;\n stampBuy: number;\n /** Depository (DP) charge per scrip on the sell leg (₹). */\n dpPerScrip: number;\n}\n\nexport interface ChargeConfig {\n segments: Record<Segment, SegmentRates>;\n sebi: number;\n gst: number;\n}\n\n/**\n * Default rates approximating an Indian discount broker (Zerodha-style) as of\n * FY2024–25. Statutory rates change — override any field via the `config`\n * argument of {@link charges} and always verify against the live rate card.\n */\nexport const IN_DISCOUNT_BROKER: ChargeConfig = {\n segments: {\n delivery: {\n brokeragePct: 0,\n brokerageCap: 0,\n sttBuy: 0.001,\n sttSell: 0.001,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00015,\n dpPerScrip: 13.5,\n },\n intraday: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.00025,\n exchangeTxn: 0.0000297,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n futures: {\n brokeragePct: 0.0003,\n brokerageCap: 20,\n sttBuy: 0,\n sttSell: 0.0002,\n exchangeTxn: 0.0000173,\n stampBuy: 0.00002,\n dpPerScrip: 0,\n },\n options: {\n brokeragePct: 0,\n brokerageCap: 20,\n brokerageFlat: 20,\n sttBuy: 0,\n sttSell: 0.001,\n exchangeTxn: 0.0003503,\n stampBuy: 0.00003,\n dpPerScrip: 0,\n },\n },\n sebi: 0.000001, // ₹10 per crore\n gst: 0.18,\n};\n\nexport interface ChargeInput {\n segment: Segment;\n /** Buy price per unit. Omit / 0 for a sell-only leg. */\n buy: number;\n /** Sell price per unit. Omit / 0 for a buy-only leg. */\n sell: number;\n qty: number;\n}\n\nexport interface ChargeBreakdown {\n turnover: number;\n brokerage: number;\n stt: number;\n exchangeTxn: number;\n sebi: number;\n stamp: number;\n gst: number;\n dp: number;\n totalCharges: number;\n grossPnl: number;\n netPnl: number;\n /** Per-share price move needed just to break even on charges. */\n breakeven: number;\n}\n\nfunction round2(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nfunction legBrokerage(turnover: number, r: SegmentRates): number {\n if (turnover <= 0) return 0;\n if (r.brokerageFlat !== undefined) return r.brokerageFlat;\n if (r.brokeragePct === 0) return 0;\n return Math.min(turnover * r.brokeragePct, r.brokerageCap);\n}\n\n/**\n * Full brokerage + statutory charges breakdown for a trade, Indian market.\n * @example\n * charges({ segment: \"intraday\", buy: 100, sell: 102, qty: 500 });\n * // { brokerage, stt, gst, sebi, stamp, exchangeTxn, totalCharges, netPnl, breakeven, ... }\n */\nexport function charges(\n input: ChargeInput,\n config: ChargeConfig = IN_DISCOUNT_BROKER,\n): ChargeBreakdown {\n const r = config.segments[input.segment];\n const buyVal = (input.buy || 0) * input.qty;\n const sellVal = (input.sell || 0) * input.qty;\n const turnover = buyVal + sellVal;\n\n const brokerage = legBrokerage(buyVal, r) + legBrokerage(sellVal, r);\n const stt = buyVal * r.sttBuy + sellVal * r.sttSell;\n const exchangeTxn = turnover * r.exchangeTxn;\n const sebi = turnover * config.sebi;\n const stamp = buyVal * r.stampBuy;\n const gst = (brokerage + exchangeTxn + sebi) * config.gst;\n const dp = sellVal > 0 ? r.dpPerScrip : 0;\n\n const totalCharges = brokerage + stt + exchangeTxn + sebi + stamp + gst + dp;\n const grossPnl = sellVal - buyVal;\n\n return {\n turnover: round2(turnover),\n brokerage: round2(brokerage),\n stt: round2(stt),\n exchangeTxn: round2(exchangeTxn),\n sebi: round2(sebi),\n stamp: round2(stamp),\n gst: round2(gst),\n dp: round2(dp),\n totalCharges: round2(totalCharges),\n grossPnl: round2(grossPnl),\n netPnl: round2(grossPnl - totalCharges),\n breakeven: input.qty === 0 ? 0 : round2(totalCharges / input.qty),\n };\n}\n\n/* ------------------------------------------------------------------ *\n * Compact formatting\n * ------------------------------------------------------------------ */\n\nfunction trimTo2(n: number): string {\n return Number(n.toFixed(2)).toString();\n}\n\n/** Compact INR: `formatCompactINR(12345678)` → `\"₹1.23 Cr\"`. */\nexport function formatCompactINR(amount: number, opts: FormatMoneyOptions = {}): string {\n const { symbol = \"₹\" } = opts;\n const neg = amount < 0;\n const a = Math.abs(amount);\n const units: [number, string][] = [\n [1e7, \"Cr\"],\n [1e5, \"L\"],\n [1e3, \"K\"],\n ];\n const u = units.find(([size]) => a >= size);\n const out = u ? `${trimTo2(a / u[0])} ${u[1]}` : trimTo2(a);\n return `${neg ? \"-\" : \"\"}${symbol}${out}`;\n}\n\n/* ------------------------------------------------------------------ *\n * Options — Black-Scholes greeks\n * ------------------------------------------------------------------ */\n\nfunction normPdf(x: number): number {\n return Math.exp((-x * x) / 2) / Math.sqrt(2 * Math.PI);\n}\n\n/** Standard normal CDF (Abramowitz & Stegun 7.1.26 approximation). */\nfunction normCdf(x: number): number {\n const t = 1 / (1 + 0.2316419 * Math.abs(x));\n const d = 0.3989422804014327 * Math.exp((-x * x) / 2);\n const p = d * t * (0.3193815 + t * (-0.3565638 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))));\n return x > 0 ? 1 - p : p;\n}\n\nexport interface OptionInput {\n type: \"call\" | \"put\";\n /** Spot price of the underlying. */\n spot: number;\n strike: number;\n /** Time to expiry in years (e.g. 30 days ≈ 30/365). */\n timeYears: number;\n /** Risk-free rate (annual, decimal — e.g. 0.07). */\n rate: number;\n /** Volatility (annual, decimal — e.g. 0.25). */\n volatility: number;\n /** Continuous dividend yield (annual, decimal). Default 0. */\n dividendYield?: number;\n}\n\nexport interface Greeks {\n price: number;\n delta: number;\n gamma: number;\n /** Per-year theta (divide by 365 for per-day). */\n theta: number;\n /** Per 1.00 change in volatility (divide by 100 for per 1%). */\n vega: number;\n /** Per 1.00 change in rate (divide by 100 for per 1%). */\n rho: number;\n}\n\n/** Black-Scholes price + greeks for a European option. */\nexport function blackScholes(o: OptionInput): Greeks {\n const { type, spot: S, strike: K, timeYears: t, rate: r } = o;\n const q = o.dividendYield ?? 0;\n const sigma = o.volatility;\n\n // Degenerate inputs (expired option or zero vol) would divide by zero and\n // produce NaN/Infinity — fall back to the intrinsic value instead.\n if (t <= 0 || sigma <= 0) {\n if (type === \"call\") {\n return {\n price: Math.max(0, S - K),\n delta: S > K ? 1 : 0,\n gamma: 0,\n theta: 0,\n vega: 0,\n rho: 0,\n };\n }\n return {\n price: Math.max(0, K - S),\n delta: S < K ? -1 : 0,\n gamma: 0,\n theta: 0,\n vega: 0,\n rho: 0,\n };\n }\n\n const sqrtT = Math.sqrt(t);\n const d1 = (Math.log(S / K) + (r - q + (sigma * sigma) / 2) * t) / (sigma * sqrtT);\n const d2 = d1 - sigma * sqrtT;\n const disc = Math.exp(-r * t);\n const dq = Math.exp(-q * t);\n const nd1 = normPdf(d1);\n const gamma = (dq * nd1) / (S * sigma * sqrtT);\n const vega = S * dq * nd1 * sqrtT;\n if (type === \"call\") {\n const Nd1 = normCdf(d1);\n const Nd2 = normCdf(d2);\n return {\n price: S * dq * Nd1 - K * disc * Nd2,\n delta: dq * Nd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) - r * K * disc * Nd2 + q * S * dq * Nd1,\n vega,\n rho: K * t * disc * Nd2,\n };\n }\n const Nnd1 = normCdf(-d1);\n const Nnd2 = normCdf(-d2);\n return {\n price: K * disc * Nnd2 - S * dq * Nnd1,\n delta: -dq * Nnd1,\n gamma,\n theta: -(S * dq * nd1 * sigma) / (2 * sqrtT) + r * K * disc * Nnd2 - q * S * dq * Nnd1,\n vega,\n rho: -K * t * disc * Nnd2,\n };\n}\n\n/** Solve implied volatility from an observed option price (bisection). */\nexport function impliedVolatility(\n marketPrice: number,\n o: Omit<OptionInput, \"volatility\">,\n opts: { tolerance?: number; maxIterations?: number } = {},\n): number | null {\n const tol = opts.tolerance ?? 1e-6;\n const maxIter = opts.maxIterations ?? 100;\n let lo = 1e-4;\n let hi = 5;\n for (let i = 0; i < maxIter; i++) {\n const mid = (lo + hi) / 2;\n const price = blackScholes({ ...o, volatility: mid }).price;\n const diff = price - marketPrice;\n if (Math.abs(diff) < tol) return mid;\n if (diff > 0) hi = mid;\n else lo = mid;\n }\n return null;\n}\n\n/* ------------------------------------------------------------------ *\n * Portfolio analytics\n * ------------------------------------------------------------------ */\n\n/** Period-over-period simple returns from a price/equity series. */\nexport function simpleReturns(series: number[]): number[] {\n const out: number[] = [];\n for (let i = 1; i < series.length; i++) {\n const prev = series[i - 1]!;\n if (prev !== 0) out.push((series[i]! - prev) / prev);\n }\n return out;\n}\n\nfunction mean(xs: number[]): number {\n return xs.length ? xs.reduce((s, x) => s + x, 0) / xs.length : 0;\n}\n\nfunction stdev(xs: number[]): number {\n if (xs.length < 2) return 0;\n const m = mean(xs);\n return Math.sqrt(xs.reduce((s, x) => s + (x - m) ** 2, 0) / (xs.length - 1));\n}\n\n/** Volatility (stdev of returns); annualized by default. */\nexport function volatility(returns: number[], opts: { annualize?: boolean; periodsPerYear?: number } = {}): number {\n const sd = stdev(returns);\n return opts.annualize === false ? sd : sd * Math.sqrt(opts.periodsPerYear ?? 252);\n}\n\n/** Annualized Sharpe ratio from a return series. */\nexport function sharpe(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const sd = stdev(excess);\n if (sd === 0) return 0;\n return (mean(excess) / sd) * Math.sqrt(ppy);\n}\n\n/** Annualized Sortino ratio (downside-deviation only). */\nexport function sortino(returns: number[], opts: { riskFree?: number; periodsPerYear?: number } = {}): number {\n const ppy = opts.periodsPerYear ?? 252;\n const rfPerPeriod = (opts.riskFree ?? 0) / ppy;\n const excess = returns.map((r) => r - rfPerPeriod);\n const downside = excess.filter((r) => r < 0);\n if (!downside.length) return 0;\n const dd = Math.sqrt(downside.reduce((s, r) => s + r * r, 0) / downside.length);\n if (dd === 0) return 0;\n return (mean(excess) / dd) * Math.sqrt(ppy);\n}\n\n/** Maximum drawdown of an equity curve, as a positive fraction (0.2 = −20%). */\nexport function maxDrawdown(equity: number[]): { maxDrawdown: number; peakIndex: number; troughIndex: number } {\n let peak = equity[0] ?? 0;\n let peakIdx = 0;\n let maxDd = 0;\n let ddPeak = 0;\n let ddTrough = 0;\n for (let i = 0; i < equity.length; i++) {\n const v = equity[i]!;\n if (v > peak) {\n peak = v;\n peakIdx = i;\n }\n const dd = peak > 0 ? (peak - v) / peak : 0;\n if (dd > maxDd) {\n maxDd = dd;\n ddPeak = peakIdx;\n ddTrough = i;\n }\n }\n return { maxDrawdown: maxDd, peakIndex: ddPeak, troughIndex: ddTrough };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lacspace/market",
3
- "version": "1.1.0",
3
+ "version": "1.1.3",
4
4
  "description": "Stock-market money math — P&L, returns, CAGR, XIRR, tick-size rounding, circuit limits, position sizing and an Indian brokerage & charges calculator (STT, GST, SEBI, stamp). Zero-dependency.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -38,7 +38,13 @@
38
38
  "circuit-limits",
39
39
  "nse",
40
40
  "bse",
41
- "typescript"
41
+ "typescript",
42
+ "black-scholes",
43
+ "options-pricing",
44
+ "greeks",
45
+ "implied-volatility",
46
+ "sharpe-ratio",
47
+ "sortino"
42
48
  ],
43
49
  "author": "Lacspace <contact@lacspace.com>",
44
50
  "license": "SEE LICENSE IN LICENSE",
@@ -53,5 +59,8 @@
53
59
  },
54
60
  "engines": {
55
61
  "node": ">=18"
62
+ },
63
+ "publishConfig": {
64
+ "access": "public"
56
65
  }
57
66
  }