@railpath/finance-toolkit
Version:
Production-ready finance library for portfolio construction, risk analytics, quantitative metrics, and ML-based regime detection
80 lines (79 loc) • 3.12 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.VolatilityOptionsSchema = void 0;
const zod_1 = require("zod");
/**
* Zod schema for volatility calculation options
*/
exports.VolatilityOptionsSchema = zod_1.z.object({
method: zod_1.z.enum(['standard', 'exponential', 'parkinson', 'garman-klass']),
annualizationFactor: zod_1.z.number().positive().optional(),
lambda: zod_1.z.number().min(0).max(1).optional(),
highPrices: zod_1.z.array(zod_1.z.number().positive()).optional(),
lowPrices: zod_1.z.array(zod_1.z.number().positive()).optional(),
openPrices: zod_1.z.array(zod_1.z.number().positive()).optional(),
closePrices: zod_1.z.array(zod_1.z.number().positive()).optional(),
}).superRefine((data, ctx) => {
// EWMA-specific validation
if (data.method === 'exponential' && data.lambda === undefined) {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: 'Lambda is required for exponential method',
path: ['lambda'],
});
}
// Parkinson-specific validation
if (data.method === 'parkinson') {
if (!data.highPrices) {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: 'High prices required for Parkinson method',
path: ['highPrices'],
});
}
if (!data.lowPrices) {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: 'Low prices required for Parkinson method',
path: ['lowPrices'],
});
}
if (data.highPrices && data.lowPrices && data.highPrices.length !== data.lowPrices.length) {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: 'High and low prices must have equal length',
path: ['highPrices'],
});
}
}
// Garman-Klass-specific validation
if (data.method === 'garman-klass') {
const requiredFields = ['openPrices', 'highPrices', 'lowPrices', 'closePrices'];
const missing = requiredFields.filter(field => !data[field]);
if (missing.length > 0) {
missing.forEach(field => {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: `${field} required for Garman-Klass method`,
path: [field],
});
});
}
// Length validation
if (data.openPrices && data.highPrices && data.lowPrices && data.closePrices) {
const lengths = [
data.openPrices.length,
data.highPrices.length,
data.lowPrices.length,
data.closePrices.length,
];
if (new Set(lengths).size > 1) {
ctx.addIssue({
code: zod_1.z.ZodIssueCode.custom,
message: 'All OHLC arrays must have equal length',
path: ['openPrices'],
});
}
}
}
});