diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 9169ce5..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1 +0,0 @@ -// This file is deprecated in ESLint v9. Use eslint.config.js instead. diff --git a/apps/dashboard/src/app/components/notifications/notifications.ts b/apps/dashboard/src/app/components/notifications/notifications.ts index f2a70fb..f41cf90 100644 --- a/apps/dashboard/src/app/components/notifications/notifications.ts +++ b/apps/dashboard/src/app/components/notifications/notifications.ts @@ -82,11 +82,17 @@ export class NotificationsComponent { const diff = now.getTime() - timestamp.getTime(); const minutes = Math.floor(diff / 60000); - if (minutes < 1) {return 'Just now';} - if (minutes < 60) {return `${minutes}m ago`;} + if (minutes < 1) { + return 'Just now'; + } + if (minutes < 60) { + return `${minutes}m ago`; + } const hours = Math.floor(minutes / 60); - if (hours < 24) {return `${hours}h ago`;} + if (hours < 24) { + return `${hours}h ago`; + } const days = Math.floor(hours / 24); return `${days}d ago`; diff --git a/apps/dashboard/src/app/pages/portfolio/portfolio.component.ts b/apps/dashboard/src/app/pages/portfolio/portfolio.component.ts index 507870c..eff680d 100644 --- a/apps/dashboard/src/app/pages/portfolio/portfolio.component.ts +++ b/apps/dashboard/src/app/pages/portfolio/portfolio.component.ts @@ -161,8 +161,12 @@ export class PortfolioComponent implements OnInit, OnDestroy { } getPnLColor(value: number): string { - if (value > 0) {return 'text-green-600';} - if (value < 0) {return 'text-red-600';} + if (value > 0) { + return 'text-green-600'; + } + if (value < 0) { + return 'text-red-600'; + } return 'text-gray-600'; } } diff --git a/apps/dashboard/src/app/pages/strategies/components/drawdown-chart.component.ts b/apps/dashboard/src/app/pages/strategies/components/drawdown-chart.component.ts index 88df548..6edd138 100644 --- a/apps/dashboard/src/app/pages/strategies/components/drawdown-chart.component.ts +++ b/apps/dashboard/src/app/pages/strategies/components/drawdown-chart.component.ts @@ -40,7 +40,9 @@ export class DrawdownChartComponent implements OnChanges { } private renderChart(): void { - if (!this.chartElement || !this.backtestResult) {return;} + if (!this.chartElement || !this.backtestResult) { + return; + } // Clean up previous chart if it exists if (this.chart) { diff --git a/apps/dashboard/src/app/pages/strategies/components/equity-chart.component.ts b/apps/dashboard/src/app/pages/strategies/components/equity-chart.component.ts index 48ada6b..72008fa 100644 --- a/apps/dashboard/src/app/pages/strategies/components/equity-chart.component.ts +++ b/apps/dashboard/src/app/pages/strategies/components/equity-chart.component.ts @@ -40,7 +40,9 @@ export class EquityChartComponent implements OnChanges { } private renderChart(): void { - if (!this.chartElement || !this.backtestResult) {return;} + if (!this.chartElement || !this.backtestResult) { + return; + } // Clean up previous chart if it exists if (this.chart) { diff --git a/apps/dashboard/src/app/pages/strategies/components/performance-metrics.component.ts b/apps/dashboard/src/app/pages/strategies/components/performance-metrics.component.ts index 52a33eb..0e6ab69 100644 --- a/apps/dashboard/src/app/pages/strategies/components/performance-metrics.component.ts +++ b/apps/dashboard/src/app/pages/strategies/components/performance-metrics.component.ts @@ -278,27 +278,45 @@ export class PerformanceMetricsComponent { // Conditional classes getReturnClass(value: number): string { - if (value > 0) {return 'positive';} - if (value < 0) {return 'negative';} + if (value > 0) { + return 'positive'; + } + if (value < 0) { + return 'negative'; + } return ''; } getRatioClass(value: number): string { - if (value >= 1.5) {return 'positive';} - if (value >= 1) {return 'neutral';} - if (value < 0) {return 'negative';} + if (value >= 1.5) { + return 'positive'; + } + if (value >= 1) { + return 'neutral'; + } + if (value < 0) { + return 'negative'; + } return ''; } getWinRateClass(value: number): string { - if (value >= 0.55) {return 'positive';} - if (value >= 0.45) {return 'neutral';} + if (value >= 0.55) { + return 'positive'; + } + if (value >= 0.45) { + return 'neutral'; + } return 'negative'; } getProfitFactorClass(value: number): string { - if (value >= 1.5) {return 'positive';} - if (value >= 1) {return 'neutral';} + if (value >= 1.5) { + return 'positive'; + } + if (value >= 1) { + return 'neutral'; + } return 'negative'; } } diff --git a/apps/dashboard/src/app/pages/strategies/dialogs/backtest-dialog.component.ts b/apps/dashboard/src/app/pages/strategies/dialogs/backtest-dialog.component.ts index 359e988..b28dabb 100644 --- a/apps/dashboard/src/app/pages/strategies/dialogs/backtest-dialog.component.ts +++ b/apps/dashboard/src/app/pages/strategies/dialogs/backtest-dialog.component.ts @@ -139,7 +139,9 @@ export class BacktestDialogComponent implements OnInit { } addSymbol(symbol: string): void { - if (!symbol || this.selectedSymbols.includes(symbol)) {return;} + if (!symbol || this.selectedSymbols.includes(symbol)) { + return; + } this.selectedSymbols.push(symbol); } diff --git a/apps/dashboard/src/app/pages/strategies/dialogs/strategy-dialog.component.ts b/apps/dashboard/src/app/pages/strategies/dialogs/strategy-dialog.component.ts index b19fae6..59fe03e 100644 --- a/apps/dashboard/src/app/pages/strategies/dialogs/strategy-dialog.component.ts +++ b/apps/dashboard/src/app/pages/strategies/dialogs/strategy-dialog.component.ts @@ -126,7 +126,9 @@ export class StrategyDialogComponent implements OnInit { } addSymbol(symbol: string): void { - if (!symbol || this.selectedSymbols.includes(symbol)) {return;} + if (!symbol || this.selectedSymbols.includes(symbol)) { + return; + } this.selectedSymbols.push(symbol); } diff --git a/apps/data-service/src/providers/proxy.tasks.ts b/apps/data-service/src/providers/proxy.tasks.ts index eb39262..16cc8ec 100644 --- a/apps/data-service/src/providers/proxy.tasks.ts +++ b/apps/data-service/src/providers/proxy.tasks.ts @@ -172,8 +172,12 @@ let proxyStats: ProxySource[] = PROXY_CONFIG.PROXY_SOURCES.map(source => ({ async function updateProxyStats(sourceId: string, success: boolean) { const source = proxyStats.find(s => s.id === sourceId); if (source !== undefined) { - if (typeof source.working !== 'number') {source.working = 0;} - if (typeof source.total !== 'number') {source.total = 0;} + if (typeof source.working !== 'number') { + source.working = 0; + } + if (typeof source.total !== 'number') { + source.total = 0; + } source.total += 1; if (success) { source.working += 1; @@ -400,7 +404,9 @@ export async function fetchProxiesFromSource(source: ProxySource): Promise sum + ret, 0) / returns.length; return Math.pow(1 + avgReturn, 252) - 1; // 252 trading days per year } private calculateVolatility(returns: number[]): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const avgReturn = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -109,19 +117,25 @@ export class PerformanceAnalyzer { } private calculateSharpeRatio(returns: number[], riskFreeRate: number): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const avgReturn = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const annualizedReturn = Math.pow(1 + avgReturn, 252) - 1; const volatility = this.calculateVolatility(returns); - if (volatility === 0) {return 0;} + if (volatility === 0) { + return 0; + } return (annualizedReturn - riskFreeRate) / volatility; } private calculateMaxDrawdown(): number { - if (this.snapshots.length === 0) {return 0;} + if (this.snapshots.length === 0) { + return 0; + } let maxDrawdown = 0; let peak = this.snapshots[0].totalValue; @@ -139,7 +153,9 @@ export class PerformanceAnalyzer { } private calculateBeta(returns: number[]): number { - if (returns.length === 0 || this.benchmarkReturns.length === 0) {return 1.0;} + if (returns.length === 0 || this.benchmarkReturns.length === 0) { + return 1.0; + } // Simple beta calculation - would need actual benchmark data return 1.0; // Placeholder @@ -157,7 +173,9 @@ export class PerformanceAnalyzer { const annualizedReturn = this.calculateAnnualizedReturn(returns); const maxDrawdown = this.calculateMaxDrawdown(); - if (maxDrawdown === 0) {return 0;} + if (maxDrawdown === 0) { + return 0; + } return annualizedReturn / maxDrawdown; } @@ -166,16 +184,22 @@ export class PerformanceAnalyzer { const annualizedReturn = this.calculateAnnualizedReturn(returns); const downsideDeviation = this.calculateDownsideDeviation(returns); - if (downsideDeviation === 0) {return 0;} + if (downsideDeviation === 0) { + return 0; + } return (annualizedReturn - riskFreeRate) / downsideDeviation; } private calculateDownsideDeviation(returns: number[]): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const negativeReturns = returns.filter(ret => ret < 0); - if (negativeReturns.length === 0) {return 0;} + if (negativeReturns.length === 0) { + return 0; + } const avgNegativeReturn = negativeReturns.reduce((sum, ret) => sum + ret, 0) / negativeReturns.length; @@ -187,7 +211,9 @@ export class PerformanceAnalyzer { } private calculateVaR(returns: number[], confidence: number): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const sortedReturns = returns.slice().sort((a, b) => a - b); const index = Math.floor((1 - confidence) * sortedReturns.length); @@ -196,13 +222,17 @@ export class PerformanceAnalyzer { } private calculateCVaR(returns: number[], confidence: number): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const sortedReturns = returns.slice().sort((a, b) => a - b); const cutoffIndex = Math.floor((1 - confidence) * sortedReturns.length); const tailReturns = sortedReturns.slice(0, cutoffIndex + 1); - if (tailReturns.length === 0) {return 0;} + if (tailReturns.length === 0) { + return 0; + } const avgTailReturn = tailReturns.reduce((sum, ret) => sum + ret, 0) / tailReturns.length; return -avgTailReturn; // Return as positive value diff --git a/apps/strategy-service/src/cli/index.ts b/apps/strategy-service/src/cli/index.ts index f9b8b0f..24ce69f 100644 --- a/apps/strategy-service/src/cli/index.ts +++ b/apps/strategy-service/src/cli/index.ts @@ -172,7 +172,9 @@ async function saveResults(result: any, outputPath: string): Promise { } function convertTradesToCSV(trades: any[]): string { - if (trades.length === 0) {return 'No trades executed\n';} + if (trades.length === 0) { + return 'No trades executed\n'; + } const headers = Object.keys(trades[0]).join(','); const rows = trades.map(trade => diff --git a/libs/cache/src/redis-cache.ts b/libs/cache/src/redis-cache.ts index 970648d..a42a21c 100644 --- a/libs/cache/src/redis-cache.ts +++ b/libs/cache/src/redis-cache.ts @@ -87,7 +87,9 @@ export class RedisCache implements CacheProvider { } private updateStats(hit: boolean, error = false): void { - if (!this.enableMetrics) {return;} + if (!this.enableMetrics) { + return; + } if (error) { this.stats.errors++; diff --git a/libs/data-frame/src/index.ts b/libs/data-frame/src/index.ts index 056ba88..17ec275 100644 --- a/libs/data-frame/src/index.ts +++ b/libs/data-frame/src/index.ts @@ -35,7 +35,9 @@ export class DataFrame { } private inferColumns(): string[] { - if (this.data.length === 0) {return [];} + if (this.data.length === 0) { + return []; + } const columns = new Set(); for (const row of this.data) { @@ -46,7 +48,9 @@ export class DataFrame { } private validateAndCleanData(): void { - if (this.data.length === 0) {return;} + if (this.data.length === 0) { + return; + } // Ensure all rows have the same columns for (let i = 0; i < this.data.length; i++) { @@ -224,7 +228,9 @@ export class DataFrame { const aVal = a[column]; const bVal = b[column]; - if (aVal === bVal) {return 0;} + if (aVal === bVal) { + return 0; + } const comparison = aVal > bVal ? 1 : -1; return ascending ? comparison : -comparison; diff --git a/libs/mongodb-client/src/aggregation.ts b/libs/mongodb-client/src/aggregation.ts index 2a28964..a767d46 100644 --- a/libs/mongodb-client/src/aggregation.ts +++ b/libs/mongodb-client/src/aggregation.ts @@ -141,7 +141,9 @@ export class MongoDBAggregationBuilder { this.from('sentiment_data'); const matchConditions: any = {}; - if (symbol) {matchConditions.symbol = symbol;} + if (symbol) { + matchConditions.symbol = symbol; + } if (timeframe) { matchConditions.timestamp = { $gte: timeframe.start, diff --git a/libs/postgres-client/src/client.ts b/libs/postgres-client/src/client.ts index 9a5baab..e61ea2d 100644 --- a/libs/postgres-client/src/client.ts +++ b/libs/postgres-client/src/client.ts @@ -327,7 +327,9 @@ export class PostgreSQLClient { } private setupErrorHandlers(): void { - if (!this.pool) {return;} + if (!this.pool) { + return; + } this.pool.on('error', error => { this.logger.error('PostgreSQL pool error:', error); diff --git a/libs/utils/src/calculations/basic-calculations.ts b/libs/utils/src/calculations/basic-calculations.ts index b8a5dac..eec0f31 100644 --- a/libs/utils/src/calculations/basic-calculations.ts +++ b/libs/utils/src/calculations/basic-calculations.ts @@ -7,7 +7,9 @@ * Calculate percentage change between two values */ export function percentageChange(oldValue: number, newValue: number): number { - if (oldValue === 0) {return 0;} + if (oldValue === 0) { + return 0; + } return ((newValue - oldValue) / oldValue) * 100; } @@ -15,7 +17,9 @@ export function percentageChange(oldValue: number, newValue: number): number { * Calculate simple return */ export function simpleReturn(initialPrice: number, finalPrice: number): number { - if (initialPrice === 0) {return 0;} + if (initialPrice === 0) { + return 0; + } return (finalPrice - initialPrice) / initialPrice; } @@ -23,7 +27,9 @@ export function simpleReturn(initialPrice: number, finalPrice: number): number { * Calculate logarithmic return */ export function logReturn(initialPrice: number, finalPrice: number): number { - if (initialPrice <= 0 || finalPrice <= 0) {return 0;} + if (initialPrice <= 0 || finalPrice <= 0) { + return 0; + } return Math.log(finalPrice / initialPrice); } @@ -31,7 +37,9 @@ export function logReturn(initialPrice: number, finalPrice: number): number { * Calculate compound annual growth rate (CAGR) */ export function cagr(startValue: number, endValue: number, years: number): number { - if (years <= 0 || startValue <= 0 || endValue <= 0) {return 0;} + if (years <= 0 || startValue <= 0 || endValue <= 0) { + return 0; + } return Math.pow(endValue / startValue, 1 / years) - 1; } @@ -91,8 +99,12 @@ export function internalRateOfReturn( dnpv += (-j * cashFlows[j]) / Math.pow(1 + rate, j + 1); } - if (Math.abs(npv) < 1e-10) {break;} - if (Math.abs(dnpv) < 1e-10) {break;} + if (Math.abs(npv) < 1e-10) { + break; + } + if (Math.abs(dnpv) < 1e-10) { + break; + } rate = rate - npv / dnpv; } @@ -186,7 +198,9 @@ export function bondYield( ); const diff = calculatedPrice - price; - if (Math.abs(diff) < tolerance) {break;} + if (Math.abs(diff) < tolerance) { + break; + } // Numerical derivative const delta = 0.0001; @@ -199,7 +213,9 @@ export function bondYield( ); const derivative = (priceUp - calculatedPrice) / delta; - if (Math.abs(derivative) < tolerance) {break;} + if (Math.abs(derivative) < tolerance) { + break; + } yield_ = yield_ - diff / derivative; } @@ -358,7 +374,9 @@ export function dividendDiscountModel( growthRate: number, discountRate: number ): number { - if (discountRate <= growthRate) {return NaN;} // Indeterminate + if (discountRate <= growthRate) { + return NaN; + } // Indeterminate return (currentDividend * (1 + growthRate)) / (discountRate - growthRate); } diff --git a/libs/utils/src/calculations/correlation-analysis.ts b/libs/utils/src/calculations/correlation-analysis.ts index bfbc77f..6a80981 100644 --- a/libs/utils/src/calculations/correlation-analysis.ts +++ b/libs/utils/src/calculations/correlation-analysis.ts @@ -918,7 +918,9 @@ function shuffleArray(array: T[]): T[] { * Helper function to calculate the average of an array of numbers */ function average(arr: number[]): number { - if (arr.length === 0) {return 0;} + if (arr.length === 0) { + return 0; + } return arr.reduce((a, b) => a + b, 0) / arr.length; } @@ -963,8 +965,12 @@ function erf(x: number): number { function betaIncomplete(a: number, b: number, x: number): number { // Better approximation of incomplete beta function - if (x === 0) {return 0;} - if (x === 1) {return 1;} + if (x === 0) { + return 0; + } + if (x === 1) { + return 1; + } // Use continued fraction approximation (Lentz's algorithm) const fpmin = 1e-30; @@ -984,7 +990,9 @@ function betaIncomplete(a: number, b: number, x: number): number { function betaContinuedFraction(a: number, b: number, x: number): number { let c = 1; let d = 1 - ((a + b) * x) / (a + 1); - if (Math.abs(d) < fpmin) {d = fpmin;} + if (Math.abs(d) < fpmin) { + d = fpmin; + } d = 1 / d; let h = d; @@ -992,22 +1000,32 @@ function betaIncomplete(a: number, b: number, x: number): number { const m2 = 2 * m; const aa = (m * (b - m) * x) / ((a + m2 - 1) * (a + m2)); d = 1 + aa * d; - if (Math.abs(d) < fpmin) {d = fpmin;} + if (Math.abs(d) < fpmin) { + d = fpmin; + } c = 1 + aa / c; - if (Math.abs(c) < fpmin) {c = fpmin;} + if (Math.abs(c) < fpmin) { + c = fpmin; + } d = 1 / d; h *= d * c; const bb = (-(a + m) * (a + b + m) * x) / ((a + m2) * (a + m2 + 1)); d = 1 + bb * d; - if (Math.abs(d) < fpmin) {d = fpmin;} + if (Math.abs(d) < fpmin) { + d = fpmin; + } c = 1 + bb / c; - if (Math.abs(c) < fpmin) {c = fpmin;} + if (Math.abs(c) < fpmin) { + c = fpmin; + } d = 1 / d; const del = d * c; h *= del; - if (Math.abs(del - 1) < eps) {break;} + if (Math.abs(del - 1) < eps) { + break; + } } return h; @@ -1055,11 +1073,15 @@ function eigenDecomposition(matrix: number[][]): { const newLambda = Av.reduce((sum, val, i) => sum + val * v[i], 0); const norm = Math.sqrt(Av.reduce((sum, val) => sum + val * val, 0)); - if (norm === 0) {break;} + if (norm === 0) { + break; + } v = Av.map(val => val / norm); - if (Math.abs(newLambda - lambda) < 1e-10) {break;} + if (Math.abs(newLambda - lambda) < 1e-10) { + break; + } lambda = newLambda; } @@ -1215,8 +1237,12 @@ function arModel(y: number[], lag: number): { rss: number } { function fCDF(f: number, df1: number, df2: number): number { // Approximation for F distribution CDF - if (f <= 0) {return 0;} - if (f === Infinity) {return 1;} + if (f <= 0) { + return 0; + } + if (f === Infinity) { + return 1; + } const x = df2 / (df2 + df1 * f); return 1 - betaIncomplete(df2 / 2, df1 / 2, x); diff --git a/libs/utils/src/calculations/market-statistics.ts b/libs/utils/src/calculations/market-statistics.ts index 84f9fd6..7a6858f 100644 --- a/libs/utils/src/calculations/market-statistics.ts +++ b/libs/utils/src/calculations/market-statistics.ts @@ -55,7 +55,9 @@ export interface MarketRegime { * Volume Weighted Average Price (VWAP) */ export function VWAP(ohlcv: OHLCVData[]): number[] { - if (ohlcv.length === 0) {return [];} + if (ohlcv.length === 0) { + return []; + } const vwap: number[] = []; let cumulativeVolumePrice = 0; @@ -76,7 +78,9 @@ export function VWAP(ohlcv: OHLCVData[]): number[] { * Time Weighted Average Price (TWAP) */ export function TWAP(prices: number[], timeWeights?: number[]): number { - if (prices.length === 0) {return 0;} + if (prices.length === 0) { + return 0; + } if (!timeWeights) { return prices.reduce((sum, price) => sum + price, 0) / prices.length; @@ -227,9 +231,13 @@ export function identifyMarketRegime( // Determine volatility level let volatilityLevel: 'low' | 'medium' | 'high'; - if (volatility < 0.01) {volatilityLevel = 'low';} - else if (volatility < 0.03) {volatilityLevel = 'medium';} - else {volatilityLevel = 'high';} + if (volatility < 0.01) { + volatilityLevel = 'low'; + } else if (volatility < 0.03) { + volatilityLevel = 'medium'; + } else { + volatilityLevel = 'high'; + } // Determine regime let regime: 'trending' | 'ranging' | 'volatile' | 'quiet'; @@ -281,7 +289,9 @@ export function OrderBookImbalance( const totalVolume = totalBidVolume + totalAskVolume; - if (totalVolume === 0) {return 0;} + if (totalVolume === 0) { + return 0; + } return (totalBidVolume - totalAskVolume) / totalVolume; } @@ -452,10 +462,15 @@ export function MarketStress( const overallStress = volatilityStress * 0.4 + liquidityStress * 0.3 + correlationStress * 0.3; let stressLevel: 'low' | 'medium' | 'high' | 'extreme'; - if (overallStress < 0.25) {stressLevel = 'low';} - else if (overallStress < 0.5) {stressLevel = 'medium';} - else if (overallStress < 0.75) {stressLevel = 'high';} - else {stressLevel = 'extreme';} + if (overallStress < 0.25) { + stressLevel = 'low'; + } else if (overallStress < 0.5) { + stressLevel = 'medium'; + } else if (overallStress < 0.75) { + stressLevel = 'high'; + } else { + stressLevel = 'extreme'; + } return { stressLevel, @@ -474,7 +489,9 @@ export function RealizedSpread( midPrices: number[], timeWindow: number = 5 // minutes ): number { - if (trades.length === 0 || midPrices.length === 0) {return 0;} + if (trades.length === 0 || midPrices.length === 0) { + return 0; + } let totalSpread = 0; let count = 0; @@ -541,7 +558,9 @@ export function ImplementationShortfall( * Amihud Illiquidity Measure (price impact per unit of volume) */ export function amihudIlliquidity(ohlcv: OHLCVData[], lookbackPeriod: number = 252): number { - if (ohlcv.length < lookbackPeriod) {return 0;} + if (ohlcv.length < lookbackPeriod) { + return 0; + } const recentData = ohlcv.slice(-lookbackPeriod); let illiquiditySum = 0; @@ -566,7 +585,9 @@ export function amihudIlliquidity(ohlcv: OHLCVData[], lookbackPeriod: number = 2 * Roll's Spread Estimator (effective spread from serial covariance) */ export function rollSpreadEstimator(prices: number[]): number { - if (prices.length < 3) {return 0;} + if (prices.length < 3) { + return 0; + } // Calculate price changes const priceChanges: number[] = []; @@ -594,7 +615,9 @@ export function kyleLambda( priceChanges: number[], orderFlow: number[] // Signed order flow (positive for buys, negative for sells) ): number { - if (priceChanges.length !== orderFlow.length || priceChanges.length < 2) {return 0;} + if (priceChanges.length !== orderFlow.length || priceChanges.length < 2) { + return 0; + } // Calculate regression: priceChange = lambda * orderFlow + error const n = priceChanges.length; @@ -623,7 +646,9 @@ export function probabilityInformedTrading( sellVolumes: number[], period: number = 20 ): number { - if (buyVolumes.length !== sellVolumes.length || buyVolumes.length < period) {return 0;} + if (buyVolumes.length !== sellVolumes.length || buyVolumes.length < period) { + return 0; + } const recentBuys = buyVolumes.slice(-period); const recentSells = sellVolumes.slice(-period); @@ -647,11 +672,15 @@ export function probabilityInformedTrading( * Herfindahl-Hirschman Index for Volume Concentration */ export function volumeConcentrationHHI(exchanges: Array<{ name: string; volume: number }>): number { - if (exchanges.length === 0) {return 0;} + if (exchanges.length === 0) { + return 0; + } const totalVolume = exchanges.reduce((sum, exchange) => sum + exchange.volume, 0); - if (totalVolume === 0) {return 0;} + if (totalVolume === 0) { + return 0; + } let hhi = 0; for (const exchange of exchanges) { @@ -670,7 +699,9 @@ export function volumeProfile( ): { [price: number]: number } { const profile: { [price: number]: number } = {}; - if (ohlcv.length === 0) {return profile;} + if (ohlcv.length === 0) { + return profile; + } const minPrice = Math.min(...ohlcv.map(candle => candle.low)); const maxPrice = Math.max(...ohlcv.map(candle => candle.high)); @@ -813,8 +844,9 @@ export function garmanKlassVolatility( openPrices.length !== lowPrices.length || openPrices.length !== closePrices.length || openPrices.length < 2 - ) - {return 0;} + ) { + return 0; + } let sumSquaredTerm1 = 0; let sumSquaredTerm2 = 0; @@ -849,8 +881,9 @@ export function yangZhangVolatility( openPrices.length !== closePrices.length || openPrices.length !== previousClosePrices.length || openPrices.length < 2 - ) - {return 0;} + ) { + return 0; + } const k = 0.34 / (1.34 + (openPrices.length + 1) / (previousClosePrices.length - 1)); @@ -877,7 +910,9 @@ export function yangZhangVolatility( * Volume Order Imbalance (VOI) */ export function volumeOrderImbalance(buyVolumes: number[], sellVolumes: number[]): number[] { - if (buyVolumes.length !== sellVolumes.length) {return [];} + if (buyVolumes.length !== sellVolumes.length) { + return []; + } const voi: number[] = []; for (let i = 0; i < buyVolumes.length; i++) { @@ -890,7 +925,9 @@ export function volumeOrderImbalance(buyVolumes: number[], sellVolumes: number[] * Cumulative Volume Delta (CVD) */ export function cumulativeVolumeDelta(buyVolumes: number[], sellVolumes: number[]): number[] { - if (buyVolumes.length !== sellVolumes.length) {return [];} + if (buyVolumes.length !== sellVolumes.length) { + return []; + } const cvd: number[] = []; let cumulativeDelta = 0; @@ -905,7 +942,9 @@ export function cumulativeVolumeDelta(buyVolumes: number[], sellVolumes: number[ * Market Order Ratio */ export function marketOrderRatio(marketOrders: number[], limitOrders: number[]): number[] { - if (marketOrders.length !== limitOrders.length) {return [];} + if (marketOrders.length !== limitOrders.length) { + return []; + } const ratios: number[] = []; for (let i = 0; i < marketOrders.length; i++) { @@ -920,12 +959,16 @@ export function marketOrderRatio(marketOrders: number[], limitOrders: number[]): */ function average(arr: number[]): number { - if (arr.length === 0) {return 0;} + if (arr.length === 0) { + return 0; + } return arr.reduce((a, b) => a + b, 0) / arr.length; } function calculateVolatility(returns: number[]): number { - if (returns.length < 2) {return 0;} + if (returns.length < 2) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -935,7 +978,9 @@ function calculateVolatility(returns: number[]): number { } function calculateCorrelation(x: number[], y: number[]): number { - if (x.length !== y.length || x.length < 2) {return 0;} + if (x.length !== y.length || x.length < 2) { + return 0; + } const n = x.length; const meanX = x.reduce((sum, val) => sum + val, 0) / n; @@ -960,14 +1005,18 @@ function calculateCorrelation(x: number[], y: number[]): number { } function calculateVariance(values: number[]): number { - if (values.length < 2) {return 0;} + if (values.length < 2) { + return 0; + } const mean = values.reduce((sum, val) => sum + val, 0) / values.length; return values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / (values.length - 1); } function calculateCovariance(x: number[], y: number[]): number { - if (x.length !== y.length || x.length < 2) {return 0;} + if (x.length !== y.length || x.length < 2) { + return 0; + } const n = x.length; const meanX = x.reduce((sum, val) => sum + val, 0) / n; diff --git a/libs/utils/src/calculations/performance-metrics.ts b/libs/utils/src/calculations/performance-metrics.ts index 284c21c..72a8f7f 100644 --- a/libs/utils/src/calculations/performance-metrics.ts +++ b/libs/utils/src/calculations/performance-metrics.ts @@ -297,7 +297,9 @@ export function calculateRollingMetrics( windowSize: number, metricType: 'sharpe' | 'volatility' | 'return' = 'sharpe' ): number[] { - if (returns.length < windowSize) {return [];} + if (returns.length < windowSize) { + return []; + } const rollingMetrics: number[] = []; @@ -377,7 +379,9 @@ export function strategyPerformanceAttribution( * Calculate Omega ratio */ export function omegaRatio(returns: number[], threshold: number = 0): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const gains = returns .filter(ret => ret > threshold) @@ -393,7 +397,9 @@ export function omegaRatio(returns: number[], threshold: number = 0): number { * Calculate gain-to-pain ratio */ export function gainToPainRatio(returns: number[]): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const totalGain = returns.reduce((sum, ret) => sum + ret, 0); const totalPain = returns.filter(ret => ret < 0).reduce((sum, ret) => sum + Math.abs(ret), 0); @@ -405,12 +411,16 @@ export function gainToPainRatio(returns: number[]): number { * Calculate Martin ratio (modified Sharpe with downside deviation) */ export function martinRatio(returns: number[], riskFreeRate: number = 0): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const averageReturn = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const downsideReturns = returns.filter(ret => ret < riskFreeRate); - if (downsideReturns.length === 0) {return Infinity;} + if (downsideReturns.length === 0) { + return Infinity; + } const downsideDeviation = Math.sqrt( downsideReturns.reduce((sum, ret) => sum + Math.pow(ret - riskFreeRate, 2), 0) / returns.length @@ -610,7 +620,9 @@ export function tailRatio(returns: number[], tailPercent: number = 0.1): number const numReturns = returns.length; const tailSize = Math.floor(numReturns * tailPercent); - if (tailSize === 0) {return 0;} + if (tailSize === 0) { + return 0; + } const sortedReturns = [...returns].sort((a, b) => a - b); const worstTail = sortedReturns.slice(0, tailSize); @@ -630,8 +642,9 @@ export function calculateRollingBeta( marketReturns: number[], windowSize: number ): number[] { - if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < windowSize) - {return [];} + if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < windowSize) { + return []; + } const rollingBetas: number[] = []; @@ -667,8 +680,9 @@ export function calculateRollingAlpha( riskFreeRate: number, windowSize: number ): number[] { - if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < windowSize) - {return [];} + if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < windowSize) { + return []; + } const rollingAlphas: number[] = []; @@ -728,7 +742,9 @@ export function moneyWeightedRateOfReturn( // Helper functions function calculateSharpeRatio(returns: number[], riskFreeRate: number = 0): number { - if (returns.length < 2) {return 0;} + if (returns.length < 2) { + return 0; + } const avgReturn = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -739,7 +755,9 @@ function calculateSharpeRatio(returns: number[], riskFreeRate: number = 0): numb } function calculateVolatility(returns: number[]): number { - if (returns.length < 2) {return 0;} + if (returns.length < 2) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -749,7 +767,9 @@ function calculateVolatility(returns: number[]): number { } function calculateBeta(portfolioReturns: number[], marketReturns: number[]): number { - if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < 2) {return 0;} + if (portfolioReturns.length !== marketReturns.length || portfolioReturns.length < 2) { + return 0; + } const portfolioMean = portfolioReturns.reduce((sum, ret) => sum + ret, 0) / portfolioReturns.length; @@ -786,13 +806,17 @@ function calculateAlpha( } function calculateSkewness(returns: number[]): number { - if (returns.length < 3) {return 0;} + if (returns.length < 3) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / returns.length; const stdDev = Math.sqrt(variance); - if (stdDev === 0) {return 0;} + if (stdDev === 0) { + return 0; + } const skew = returns.reduce((sum, ret) => sum + Math.pow((ret - mean) / stdDev, 3), 0) / returns.length; @@ -801,13 +825,17 @@ function calculateSkewness(returns: number[]): number { } function calculateKurtosis(returns: number[]): number { - if (returns.length < 4) {return 0;} + if (returns.length < 4) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / returns.length; const stdDev = Math.sqrt(variance); - if (stdDev === 0) {return 0;} + if (stdDev === 0) { + return 0; + } const kurt = returns.reduce((sum, ret) => sum + Math.pow((ret - mean) / stdDev, 4), 0) / returns.length; diff --git a/libs/utils/src/calculations/portfolio-analytics.ts b/libs/utils/src/calculations/portfolio-analytics.ts index 606d8c6..5fe1708 100644 --- a/libs/utils/src/calculations/portfolio-analytics.ts +++ b/libs/utils/src/calculations/portfolio-analytics.ts @@ -209,7 +209,9 @@ export function riskParityOptimization(covarianceMatrix: number[][]): PortfolioO const sum = newWeights.reduce((s, w) => s + w, 0); weights = newWeights.map(w => w / sum); - if (converged) {break;} + if (converged) { + break; + } } const portfolioVariance = calculatePortfolioVariance(weights, covarianceMatrix); @@ -402,7 +404,9 @@ export function calculateEfficientFrontier( volatility: number; sharpeRatio: number; }> { - if (returns.length !== symbols.length || returns.length < 2) {return [];} + if (returns.length !== symbols.length || returns.length < 2) { + return []; + } const n = returns.length; const results: Array<{ @@ -456,7 +460,9 @@ export function findMinimumVariancePortfolio( returns: number[][], symbols: string[] ): PortfolioOptimizationResult | null { - if (returns.length !== symbols.length || returns.length < 2) {return null;} + if (returns.length !== symbols.length || returns.length < 2) { + return null; + } const covarianceMatrix = calculateCovarianceMatrix(returns); const n = returns.length; @@ -517,7 +523,9 @@ function calculateCovarianceMatrix(returns: number[][]): number[][] { } function calculateCovariance(x: number[], y: number[]): number { - if (x.length !== y.length || x.length < 2) {return 0;} + if (x.length !== y.length || x.length < 2) { + return 0; + } const n = x.length; const meanX = x.reduce((sum, val) => sum + val, 0) / n; @@ -559,7 +567,9 @@ function findMinimumVarianceWeights( const currentReturn = weights.reduce((sum, w, i) => sum + w * expectedReturns[i], 0); const returnDiff = targetReturn - currentReturn; - if (Math.abs(returnDiff) < 0.001) {break;} + if (Math.abs(returnDiff) < 0.001) { + break; + } // Adjust weights proportionally to expected returns const totalExpectedReturn = expectedReturns.reduce((sum, r) => sum + Math.abs(r), 0); diff --git a/libs/utils/src/calculations/position-sizing.ts b/libs/utils/src/calculations/position-sizing.ts index 2f6dd8f..28348a3 100644 --- a/libs/utils/src/calculations/position-sizing.ts +++ b/libs/utils/src/calculations/position-sizing.ts @@ -31,8 +31,12 @@ export function fixedRiskPositionSize(params: PositionSizeParams): number { const { accountSize, riskPercentage, entryPrice, stopLoss, leverage = 1 } = params; // Input validation - if (accountSize <= 0 || riskPercentage <= 0 || entryPrice <= 0 || leverage <= 0) {return 0;} - if (entryPrice === stopLoss) {return 0;} + if (accountSize <= 0 || riskPercentage <= 0 || entryPrice <= 0 || leverage <= 0) { + return 0; + } + if (entryPrice === stopLoss) { + return 0; + } const riskAmount = accountSize * (riskPercentage / 100); const riskPerShare = Math.abs(entryPrice - stopLoss); @@ -48,7 +52,9 @@ export function kellyPositionSize(params: KellyParams, accountSize: number): num const { winRate, averageWin, averageLoss } = params; // Validate inputs - if (averageLoss === 0 || winRate <= 0 || winRate >= 1 || averageWin <= 0) {return 0;} + if (averageLoss === 0 || winRate <= 0 || winRate >= 1 || averageWin <= 0) { + return 0; + } const lossRate = 1 - winRate; const winLossRatio = averageWin / Math.abs(averageLoss); @@ -72,7 +78,9 @@ export function fractionalKellyPositionSize( fraction: number = 0.25 ): number { // Input validation - if (fraction <= 0 || fraction > 1) {return 0;} + if (fraction <= 0 || fraction > 1) { + return 0; + } const fullKelly = kellyPositionSize(params, accountSize); return fullKelly * fraction; @@ -88,7 +96,9 @@ export function volatilityTargetPositionSize( const { price, volatility, targetVolatility } = params; // Input validation - if (volatility <= 0 || price <= 0 || targetVolatility <= 0 || accountSize <= 0) {return 0;} + if (volatility <= 0 || price <= 0 || targetVolatility <= 0 || accountSize <= 0) { + return 0; + } const volatilityRatio = targetVolatility / volatility; const basePositionValue = accountSize * Math.min(volatilityRatio, 2); // Cap at 2x leverage @@ -105,7 +115,9 @@ export function equalWeightPositionSize( price: number ): number { // Input validation - if (numberOfPositions <= 0 || price <= 0 || accountSize <= 0) {return 0;} + if (numberOfPositions <= 0 || price <= 0 || accountSize <= 0) { + return 0; + } const positionValue = accountSize / numberOfPositions; return Math.floor(positionValue / price); @@ -121,7 +133,9 @@ export function atrBasedPositionSize( atrMultiplier: number = 2, price: number ): number { - if (atrValue === 0 || price === 0) {return 0;} + if (atrValue === 0 || price === 0) { + return 0; + } const riskAmount = accountSize * (riskPercentage / 100); const stopDistance = atrValue * atrMultiplier; @@ -142,12 +156,15 @@ export function expectancyPositionSize( maxRiskPercentage: number = 2 ): number { // Input validation - if (accountSize <= 0 || winRate <= 0 || winRate >= 1 || averageWin <= 0 || averageLoss === 0) - {return 0;} + if (accountSize <= 0 || winRate <= 0 || winRate >= 1 || averageWin <= 0 || averageLoss === 0) { + return 0; + } const expectancy = winRate * averageWin - (1 - winRate) * Math.abs(averageLoss); - if (expectancy <= 0) {return 0;} + if (expectancy <= 0) { + return 0; + } // Scale position size based on expectancy relative to average loss // Higher expectancy relative to risk allows for larger position @@ -167,7 +184,9 @@ export function monteCarloPositionSize( simulations: number = 1000, confidenceLevel: number = 0.95 ): number { - if (historicalReturns.length === 0) {return 0;} + if (historicalReturns.length === 0) { + return 0; + } const outcomes: number[] = []; const mean = historicalReturns.reduce((sum, ret) => sum + ret, 0) / historicalReturns.length; @@ -229,8 +248,9 @@ export function sharpeOptimizedPositionSize( maxLeverage: number = 3 ): number { // Input validation - if (volatility <= 0 || accountSize <= 0 || expectedReturn <= riskFreeRate || maxLeverage <= 0) - {return 0;} + if (volatility <= 0 || accountSize <= 0 || expectedReturn <= riskFreeRate || maxLeverage <= 0) { + return 0; + } // Kelly criterion with Sharpe ratio optimization const excessReturn = expectedReturn - riskFreeRate; const kellyFraction = excessReturn / (volatility * volatility); @@ -251,7 +271,9 @@ export function fixedFractionalPositionSize( price: number ): number { // Input validation - if (stopLossPercentage <= 0 || price <= 0 || riskPercentage <= 0 || accountSize <= 0) {return 0;} + if (stopLossPercentage <= 0 || price <= 0 || riskPercentage <= 0 || accountSize <= 0) { + return 0; + } const riskAmount = accountSize * (riskPercentage / 100); const stopLossAmount = price * (stopLossPercentage / 100); @@ -269,7 +291,9 @@ export function volatilityAdjustedPositionSize( price: number ): number { // Input validation - if (assetVolatility <= 0 || price <= 0 || targetVolatility <= 0 || accountSize <= 0) {return 0;} + if (assetVolatility <= 0 || price <= 0 || targetVolatility <= 0 || accountSize <= 0) { + return 0; + } const volatilityRatio = targetVolatility / assetVolatility; const cappedRatio = Math.min(volatilityRatio, 3); // Cap at 3x leverage @@ -286,7 +310,9 @@ export function correlationAdjustedPositionSize( existingPositions: Array<{ size: number; correlation: number }>, maxCorrelationRisk: number = 0.3 ): number { - if (existingPositions.length === 0 || basePositionSize <= 0) {return basePositionSize;} + if (existingPositions.length === 0 || basePositionSize <= 0) { + return basePositionSize; + } // Calculate portfolio correlation risk // This should consider the correlation between the new position and existing ones @@ -310,7 +336,9 @@ export function calculatePortfolioHeat( accountSize: number ): number { // Input validation - if (accountSize <= 0 || positions.length === 0) {return 0;} + if (accountSize <= 0 || positions.length === 0) { + return 0; + } const totalRisk = positions.reduce((sum, position) => { // Ensure risk values are positive @@ -331,8 +359,12 @@ export function dynamicPositionSize( maxDrawdownThreshold: number = 0.1 ): number { // Input validation - if (basePositionSize <= 0 || marketVolatility <= 0 || normalVolatility <= 0) {return 0;} - if (drawdownLevel < 0 || maxDrawdownThreshold <= 0) {return basePositionSize;} + if (basePositionSize <= 0 || marketVolatility <= 0 || normalVolatility <= 0) { + return 0; + } + if (drawdownLevel < 0 || maxDrawdownThreshold <= 0) { + return basePositionSize; + } // Volatility adjustment - reduce size when volatility is high const volatilityAdjustment = Math.min(normalVolatility / marketVolatility, 2); // Cap at 2x @@ -354,7 +386,9 @@ export function liquidityConstrainedPositionSize( maxVolumePercentage: number = 0.05, price: number ): number { - if (averageDailyVolume === 0 || price === 0) {return 0;} + if (averageDailyVolume === 0 || price === 0) { + return 0; + } const maxShares = averageDailyVolume * maxVolumePercentage; @@ -372,7 +406,9 @@ export function multiTimeframePositionSize( baseRiskPercentage: number = 1 ): number { // Input validation - if (accountSize <= 0 || baseRiskPercentage <= 0) {return 0;} + if (accountSize <= 0 || baseRiskPercentage <= 0) { + return 0; + } // Clamp signals to valid range const clampedShort = Math.max(-1, Math.min(1, shortTermSignal)); @@ -396,18 +432,26 @@ export function riskParityPositionSize( targetRisk: number, accountSize: number ): number[] { - if (assets.length === 0) {return [];} + if (assets.length === 0) { + return []; + } // Calculate inverse volatility weights const totalInverseVol = assets.reduce((sum, asset) => { - if (asset.volatility === 0) {return sum;} + if (asset.volatility === 0) { + return sum; + } return sum + 1 / asset.volatility; }, 0); - if (totalInverseVol === 0) {return assets.map(() => 0);} + if (totalInverseVol === 0) { + return assets.map(() => 0); + } return assets.map(asset => { - if (asset.volatility === 0 || asset.price === 0) {return 0;} + if (asset.volatility === 0 || asset.price === 0) { + return 0; + } // Calculate weight based on inverse volatility const weight = 1 / asset.volatility / totalInverseVol; @@ -468,7 +512,9 @@ export function optimalFPositionSize( historicalReturns: number[], maxIterations: number = 100 ): number { - if (historicalReturns.length === 0 || accountSize <= 0) {return 0;} + if (historicalReturns.length === 0 || accountSize <= 0) { + return 0; + } // Convert returns to P&L per unit const pnlValues = historicalReturns.map(ret => ret * 1000); // Assuming $1000 per unit @@ -512,7 +558,9 @@ export function secureFPositionSize( historicalReturns: number[], confidenceLevel: number = 0.95 ): number { - if (historicalReturns.length === 0 || accountSize <= 0) {return 0;} + if (historicalReturns.length === 0 || accountSize <= 0) { + return 0; + } // Sort returns to find worst-case scenarios const sortedReturns = [...historicalReturns].sort((a, b) => a - b); @@ -523,7 +571,9 @@ export function secureFPositionSize( const maxLoss = Math.abs(worstCaseReturn); const maxRiskPercentage = 0.02; // Never risk more than 2% on worst case - if (maxLoss === 0) {return accountSize * 0.1;} // Default to 10% if no historical losses + if (maxLoss === 0) { + return accountSize * 0.1; + } // Default to 10% if no historical losses const secureF = Math.min(maxRiskPercentage / maxLoss, 0.25); // Cap at 25% diff --git a/libs/utils/src/calculations/risk-metrics.ts b/libs/utils/src/calculations/risk-metrics.ts index f0d4c45..ffb2343 100644 --- a/libs/utils/src/calculations/risk-metrics.ts +++ b/libs/utils/src/calculations/risk-metrics.ts @@ -9,7 +9,9 @@ import { RiskMetrics, treynorRatio } from './index'; * Calculate Value at Risk (VaR) using historical simulation */ export function valueAtRisk(returns: number[], confidenceLevel: number = 0.95): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const sortedReturns = [...returns].sort((a, b) => a - b); const index = Math.floor((1 - confidenceLevel) * sortedReturns.length); @@ -21,12 +23,16 @@ export function valueAtRisk(returns: number[], confidenceLevel: number = 0.95): * Calculate Conditional Value at Risk (CVaR/Expected Shortfall) */ export function conditionalValueAtRisk(returns: number[], confidenceLevel: number = 0.95): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const sortedReturns = [...returns].sort((a, b) => a - b); const cutoffIndex = Math.floor((1 - confidenceLevel) * sortedReturns.length); - if (cutoffIndex === 0) {return sortedReturns[0];} + if (cutoffIndex === 0) { + return sortedReturns[0]; + } const tailReturns = sortedReturns.slice(0, cutoffIndex); return tailReturns.reduce((sum, ret) => sum + ret, 0) / tailReturns.length; @@ -40,7 +46,9 @@ export function parametricVaR( confidenceLevel: number = 0.95, portfolioValue: number = 1 ): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -57,7 +65,9 @@ export function parametricVaR( * Calculate maximum drawdown */ export function maxDrawdown(equityCurve: number[]): number { - if (equityCurve.length < 2) {return 0;} + if (equityCurve.length < 2) { + return 0; + } let maxDD = 0; let peak = equityCurve[0]; @@ -78,11 +88,15 @@ export function maxDrawdown(equityCurve: number[]): number { * Calculate downside deviation */ export function downsideDeviation(returns: number[], targetReturn: number = 0): number { - if (returns.length === 0) {return 0;} + if (returns.length === 0) { + return 0; + } const downsideReturns = returns.filter(ret => ret < targetReturn); - if (downsideReturns.length === 0) {return 0;} + if (downsideReturns.length === 0) { + return 0; + } const sumSquaredDownside = downsideReturns.reduce( (sum, ret) => sum + Math.pow(ret - targetReturn, 2), @@ -96,14 +110,18 @@ export function downsideDeviation(returns: number[], targetReturn: number = 0): * Calculate Sharpe ratio */ export function sharpeRatio(returns: number[], riskFreeRate: number = 0): number { - if (returns.length < 2) {return 0;} + if (returns.length < 2) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / (returns.length - 1); const stdDev = Math.sqrt(variance); - if (stdDev === 0) {return 0;} + if (stdDev === 0) { + return 0; + } return (mean - riskFreeRate) / stdDev; } @@ -172,7 +190,9 @@ export function trackingError(portfolioReturns: number[], benchmarkReturns: numb * Calculate volatility (standard deviation of returns) */ export function volatility(returns: number[]): number { - if (returns.length < 2) {return 0;} + if (returns.length < 2) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = @@ -192,13 +212,17 @@ export function annualizedVolatility(returns: number[], periodsPerYear: number = * Calculate skewness (measure of asymmetry) */ export function skewness(returns: number[]): number { - if (returns.length < 3) {return 0;} + if (returns.length < 3) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / returns.length; const stdDev = Math.sqrt(variance); - if (stdDev === 0) {return 0;} + if (stdDev === 0) { + return 0; + } const skew = returns.reduce((sum, ret) => sum + Math.pow((ret - mean) / stdDev, 3), 0) / returns.length; @@ -210,13 +234,17 @@ export function skewness(returns: number[]): number { * Calculate kurtosis (measure of tail heaviness) */ export function kurtosis(returns: number[]): number { - if (returns.length < 4) {return 0;} + if (returns.length < 4) { + return 0; + } const mean = returns.reduce((sum, ret) => sum + ret, 0) / returns.length; const variance = returns.reduce((sum, ret) => sum + Math.pow(ret - mean, 2), 0) / returns.length; const stdDev = Math.sqrt(variance); - if (stdDev === 0) {return 0;} + if (stdDev === 0) { + return 0; + } const kurt = returns.reduce((sum, ret) => sum + Math.pow((ret - mean) / stdDev, 4), 0) / returns.length; @@ -317,12 +345,18 @@ function getZScore(confidenceLevel: number): number { }; const key = confidenceLevel.toString(); - if (zScores[key]) {return zScores[key];} + if (zScores[key]) { + return zScores[key]; + } // For arbitrary confidence levels, use approximation - if (confidenceLevel < 0.5) {return -getZScore(1 - confidenceLevel);} + if (confidenceLevel < 0.5) { + return -getZScore(1 - confidenceLevel); + } - if (confidenceLevel >= 0.999) {return 3.09;} // Cap at 99.9% for numerical stability + if (confidenceLevel >= 0.999) { + return 3.09; + } // Cap at 99.9% for numerical stability // Approximation of inverse normal CDF const y = Math.sqrt(-2.0 * Math.log(1.0 - confidenceLevel)); @@ -382,6 +416,8 @@ export function riskAdjustedReturn( portfolioRisk: number, riskFreeRate: number = 0 ): number { - if (portfolioRisk === 0) {return 0;} + if (portfolioRisk === 0) { + return 0; + } return (portfolioReturn - riskFreeRate) / portfolioRisk; } diff --git a/libs/utils/src/calculations/technical-indicators.ts b/libs/utils/src/calculations/technical-indicators.ts index 8860849..23f8e68 100644 --- a/libs/utils/src/calculations/technical-indicators.ts +++ b/libs/utils/src/calculations/technical-indicators.ts @@ -9,7 +9,9 @@ import { OHLCVData } from './index'; * Simple Moving Average */ export function sma(values: number[], period: number): number[] { - if (period > values.length) {return [];} + if (period > values.length) { + return []; + } const result: number[] = []; @@ -25,7 +27,9 @@ export function sma(values: number[], period: number): number[] { * Exponential Moving Average */ export function ema(values: number[], period: number): number[] { - if (period > values.length) {return [];} + if (period > values.length) { + return []; + } const result: number[] = []; const multiplier = 2 / (period + 1); @@ -46,7 +50,9 @@ export function ema(values: number[], period: number): number[] { * Relative Strength Index (RSI) */ export function rsi(prices: number[], period: number = 14): number[] { - if (period >= prices.length) {return [];} + if (period >= prices.length) { + return []; + } const gains: number[] = []; const losses: number[] = []; @@ -141,7 +147,9 @@ export function bollingerBands( * Average True Range (ATR) */ export function atr(ohlcv: OHLCVData[], period: number = 14): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const trueRanges: number[] = []; @@ -166,7 +174,9 @@ export function stochastic( kPeriod: number = 14, dPeriod: number = 3 ): { k: number[]; d: number[] } { - if (kPeriod >= ohlcv.length) {return { k: [], d: [] };} + if (kPeriod >= ohlcv.length) { + return { k: [], d: [] }; + } const kValues: number[] = []; @@ -193,7 +203,9 @@ export function stochastic( * Williams %R */ export function williamsR(ohlcv: OHLCVData[], period: number = 14): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const result: number[] = []; @@ -218,7 +230,9 @@ export function williamsR(ohlcv: OHLCVData[], period: number = 14): number[] { * Commodity Channel Index (CCI) */ export function cci(ohlcv: OHLCVData[], period: number = 20): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const typicalPrices = ohlcv.map(d => (d.high + d.low + d.close) / 3); const smaTP = sma(typicalPrices, period); @@ -244,7 +258,9 @@ export function cci(ohlcv: OHLCVData[], period: number = 20): number[] { * Momentum */ export function momentum(prices: number[], period: number = 10): number[] { - if (period >= prices.length) {return [];} + if (period >= prices.length) { + return []; + } const result: number[] = []; @@ -260,7 +276,9 @@ export function momentum(prices: number[], period: number = 10): number[] { * Rate of Change (ROC) */ export function roc(prices: number[], period: number = 10): number[] { - if (period >= prices.length) {return [];} + if (period >= prices.length) { + return []; + } const result: number[] = []; @@ -280,7 +298,9 @@ export function roc(prices: number[], period: number = 10): number[] { * Money Flow Index (MFI) */ export function mfi(ohlcv: OHLCVData[], period: number = 14): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const typicalPrices = ohlcv.map(d => (d.high + d.low + d.close) / 3); const moneyFlows = ohlcv.map((d, i) => typicalPrices[i] * d.volume); @@ -317,7 +337,9 @@ export function mfi(ohlcv: OHLCVData[], period: number = 14): number[] { * On-Balance Volume (OBV) */ export function obv(ohlcv: OHLCVData[]): number[] { - if (ohlcv.length === 0) {return [];} + if (ohlcv.length === 0) { + return []; + } const result: number[] = [ohlcv[0].volume]; @@ -341,7 +363,9 @@ export function obv(ohlcv: OHLCVData[]): number[] { * Accumulation/Distribution Line */ export function accumulationDistribution(ohlcv: OHLCVData[]): number[] { - if (ohlcv.length === 0) {return [];} + if (ohlcv.length === 0) { + return []; + } const result: number[] = []; let adLine = 0; @@ -367,7 +391,9 @@ export function accumulationDistribution(ohlcv: OHLCVData[]): number[] { * Chaikin Money Flow (CMF) */ export function chaikinMoneyFlow(ohlcv: OHLCVData[], period: number = 20): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const adValues: number[] = []; @@ -406,7 +432,9 @@ export function parabolicSAR( step: number = 0.02, maxStep: number = 0.2 ): number[] { - if (ohlcv.length < 2) {return [];} + if (ohlcv.length < 2) { + return []; + } const result: number[] = []; let trend = 1; // 1 for uptrend, -1 for downtrend @@ -467,7 +495,9 @@ export function parabolicSAR( * Aroon Indicator */ export function aroon(ohlcv: OHLCVData[], period: number = 14): { up: number[]; down: number[] } { - if (period >= ohlcv.length) {return { up: [], down: [] };} + if (period >= ohlcv.length) { + return { up: [], down: [] }; + } const up: number[] = []; const down: number[] = []; @@ -505,7 +535,9 @@ export function adx( ohlcv: OHLCVData[], period: number = 14 ): { adx: number[]; plusDI: number[]; minusDI: number[] } { - if (period >= ohlcv.length) {return { adx: [], plusDI: [], minusDI: [] };} + if (period >= ohlcv.length) { + return { adx: [], plusDI: [], minusDI: [] }; + } const trueRanges: number[] = []; const plusDM: number[] = []; @@ -572,7 +604,9 @@ export function adx( * Volume Weighted Moving Average (VWMA) */ export function vwma(ohlcv: OHLCVData[], period: number = 20): number[] { - if (period >= ohlcv.length) {return [];} + if (period >= ohlcv.length) { + return []; + } const result: number[] = []; @@ -607,7 +641,9 @@ export function pivotPoints(ohlcv: OHLCVData[]): Array<{ support2: number; support3: number; }> { - if (ohlcv.length === 0) {return [];} + if (ohlcv.length === 0) { + return []; + } const result: Array<{ pivot: number; diff --git a/libs/utils/src/calculations/volatility-models.ts b/libs/utils/src/calculations/volatility-models.ts index 6ed23a8..74ee7e8 100644 --- a/libs/utils/src/calculations/volatility-models.ts +++ b/libs/utils/src/calculations/volatility-models.ts @@ -242,7 +242,9 @@ export function identifyVolatilityRegimes( // Classify returns into regimes const regimeSequence = absReturns.map(absRet => { for (let i = 0; i < thresholds.length; i++) { - if (absRet <= thresholds[i]) {return i;} + if (absRet <= thresholds[i]) { + return i; + } } return numRegimes - 1; }); @@ -537,7 +539,9 @@ export function calculateYangZhangVolatility( * Parkinson volatility estimator */ export function parkinsonVolatility(ohlcv: OHLCVData[], annualizationFactor: number = 252): number { - if (ohlcv.length < 2) {return 0;} + if (ohlcv.length < 2) { + return 0; + } const sum = ohlcv.slice(1).reduce((acc, curr) => { const range = Math.log(curr.high / curr.low); return acc + range * range; diff --git a/libs/vector-engine/src/index.ts b/libs/vector-engine/src/index.ts index 4815cc0..5f38097 100644 --- a/libs/vector-engine/src/index.ts +++ b/libs/vector-engine/src/index.ts @@ -326,7 +326,9 @@ export class VectorEngine { let peak = equity[0]; for (const eq of equity) { - if (eq > peak) {peak = eq;} + if (eq > peak) { + peak = eq; + } drawdown.push((peak - eq) / peak); }