This commit is contained in:
Boki 2025-06-11 10:35:15 -04:00
parent d85cd58acd
commit 597c6efc9b
91 changed files with 2224 additions and 1400 deletions

View file

@ -31,8 +31,8 @@ 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 +48,7 @@ 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 +72,7 @@ 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 +88,7 @@ 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 +105,7 @@ 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 +121,7 @@ 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;
@ -143,11 +143,11 @@ export function expectancyPositionSize(
): number {
// Input validation
if (accountSize <= 0 || winRate <= 0 || winRate >= 1 || averageWin <= 0 || averageLoss === 0)
return 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 +167,7 @@ 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;
@ -230,7 +230,7 @@ export function sharpeOptimizedPositionSize(
): number {
// Input validation
if (volatility <= 0 || accountSize <= 0 || expectedReturn <= riskFreeRate || maxLeverage <= 0)
return 0;
{return 0;}
// Kelly criterion with Sharpe ratio optimization
const excessReturn = expectedReturn - riskFreeRate;
const kellyFraction = excessReturn / (volatility * volatility);
@ -251,7 +251,7 @@ 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 +269,7 @@ 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 +286,7 @@ 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 +310,7 @@ 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 +331,8 @@ 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 +354,7 @@ 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 +372,7 @@ 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 +396,18 @@ 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 +468,7 @@ 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 +512,7 @@ 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 +523,7 @@ 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%