Restructured hedger modules: moved CLP hedger and auto hedger into separate folders, updated data fetchers and main app, removed deprecated files
This commit is contained in:
224
clp_auto_hedger/velocity_sqrt_fix.py
Normal file
224
clp_auto_hedger/velocity_sqrt_fix.py
Normal file
@ -0,0 +1,224 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Fix for velocity calculation sqrt domain error in CLP Scalper Hedger
|
||||
|
||||
The error occurs in the liquidity velocity calculation when trying to compute:
|
||||
sqrt((new_increased_liquidity ** 2) - (4 * net_cash_proceeds))
|
||||
|
||||
This happens when (new_increased_liquidity ** 2) < (4 * net_cash_proceeds),
|
||||
making the discriminant negative.
|
||||
|
||||
This fix provides defensive programming patterns to handle such cases.
|
||||
"""
|
||||
|
||||
import math
|
||||
import logging
|
||||
|
||||
def safe_sqrt_with_fallback(value: float, fallback_value: float = 0.0, context: str = "sqrt calculation") -> float:
|
||||
"""
|
||||
Safely compute square root with fallback for negative values
|
||||
|
||||
Args:
|
||||
value: The value to compute square root of
|
||||
fallback_value: Value to return if input is negative
|
||||
context: Context description for logging
|
||||
|
||||
Returns:
|
||||
Square root of value if positive, fallback_value if negative
|
||||
"""
|
||||
if value >= 0:
|
||||
return math.sqrt(value)
|
||||
else:
|
||||
logging.warning(
|
||||
f"Negative value in {context}: {value:.6f}. "
|
||||
f"Using fallback value: {fallback_value:.6f}"
|
||||
)
|
||||
return fallback_value
|
||||
|
||||
def calculate_liquidity_velocity_safe(
|
||||
current_liquidity: float,
|
||||
new_increased_liquidity: float,
|
||||
net_cash_proceeds: float,
|
||||
current_tick: int,
|
||||
lower_tick: int,
|
||||
upper_tick: int
|
||||
) -> tuple[float, float]:
|
||||
"""
|
||||
Safe calculation of liquidity velocity with proper error handling
|
||||
|
||||
Args:
|
||||
current_liquidity: Current liquidity amount
|
||||
new_increased_liquidity: New increased liquidity amount
|
||||
net_cash_proceeds: Net cash proceeds from liquidity change
|
||||
current_tick: Current price tick
|
||||
lower_tick: Lower tick boundary
|
||||
upper_tick: Upper tick boundary
|
||||
|
||||
Returns:
|
||||
Tuple of (velocity, price_impact)
|
||||
"""
|
||||
try:
|
||||
# Basic velocity calculation
|
||||
velocity = new_increased_liquidity - current_liquidity
|
||||
price_impact = 0.0
|
||||
|
||||
# Inside position range - use square root formula
|
||||
if lower_tick <= current_tick <= upper_tick:
|
||||
if net_cash_proceeds >= 0:
|
||||
# Validate discriminant to prevent sqrt of negative number
|
||||
discriminant = (new_increased_liquidity ** 2) - (4 * net_cash_proceeds)
|
||||
|
||||
if discriminant >= 0:
|
||||
# Safe calculation
|
||||
sqrt_term = math.sqrt(discriminant)
|
||||
denominator = 2 * max(current_liquidity, 1e-10) # Prevent division by zero
|
||||
price_impact = (new_increased_liquidity - sqrt_term) / denominator
|
||||
else:
|
||||
# Edge case: negative discriminant
|
||||
# This can happen due to:
|
||||
# 1. Floating point precision errors
|
||||
# 2. Extreme market conditions
|
||||
# 3. Invalid input parameters
|
||||
|
||||
logging.warning(
|
||||
f"Negative discriminant in liquidity velocity: {discriminant:.6f}. "
|
||||
f"Liquidity: {current_liquidity:.6f} -> {new_increased_liquidity:.6f}, "
|
||||
f"Cash: {net_cash_proceeds:.6f}. Using zero price impact."
|
||||
)
|
||||
|
||||
# Use approximation methods
|
||||
price_impact = 0.0
|
||||
|
||||
# Alternative: Use small positive approximation
|
||||
# discriminant = max(discriminant, 0)
|
||||
# sqrt_term = math.sqrt(discriminant)
|
||||
# price_impact = (new_increased_liquidity - sqrt_term) / (2 * current_liquidity)
|
||||
|
||||
else:
|
||||
# Negative cash flow means additional capital required
|
||||
# No price impact calculation needed
|
||||
price_impact = 0.0
|
||||
|
||||
return velocity, price_impact
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"Error in liquidity velocity calculation: {e}")
|
||||
# Return safe defaults
|
||||
return 0.0, 0.0
|
||||
|
||||
def validate_liquidity_inputs(
|
||||
current_liquidity: float,
|
||||
new_increased_liquidity: float,
|
||||
net_cash_proceeds: float
|
||||
) -> bool:
|
||||
"""
|
||||
Validate inputs for liquidity velocity calculation
|
||||
|
||||
Args:
|
||||
current_liquidity: Current liquidity amount
|
||||
new_increased_liquidity: New increased liquidity amount
|
||||
net_cash_proceeds: Net cash proceeds from liquidity change
|
||||
|
||||
Returns:
|
||||
True if inputs are valid, False otherwise
|
||||
"""
|
||||
# Check for NaN or infinite values
|
||||
if any(math.isnan(x) or math.isinf(x) for x in [current_liquidity, new_increased_liquidity, net_cash_proceeds]):
|
||||
logging.error("Invalid inputs: NaN or infinite values detected")
|
||||
return False
|
||||
|
||||
# Check for negative liquidity (should be non-negative)
|
||||
if current_liquidity < 0 or new_increased_liquidity < 0:
|
||||
logging.error(f"Invalid liquidity values: current={current_liquidity}, new={new_increased_liquidity}")
|
||||
return False
|
||||
|
||||
# Check for reasonable ranges (adjust based on your specific needs)
|
||||
max_liquidity = 1e20 # Very large number for safety
|
||||
if current_liquidity > max_liquidity or new_increased_liquidity > max_liquidity:
|
||||
logging.error(f"Liquidity values too large: current={current_liquidity}, new={new_increased_liquidity}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# Example usage and test cases
|
||||
def test_liquidity_velocity_calculation():
|
||||
"""Test the safe liquidity velocity calculation with various scenarios"""
|
||||
|
||||
test_cases = [
|
||||
# Normal case
|
||||
{
|
||||
"name": "Normal case",
|
||||
"current_liquidity": 1000.0,
|
||||
"new_increased_liquidity": 1200.0,
|
||||
"net_cash_proceeds": 100.0,
|
||||
"current_tick": 200000,
|
||||
"lower_tick": 195000,
|
||||
"upper_tick": 205000
|
||||
},
|
||||
|
||||
# Edge case: negative discriminant
|
||||
{
|
||||
"name": "Negative discriminant",
|
||||
"current_liquidity": 100.0,
|
||||
"new_increased_liquidity": 100.0,
|
||||
"net_cash_proceeds": 3000.0, # This will cause negative discriminant
|
||||
"current_tick": 200000,
|
||||
"lower_tick": 195000,
|
||||
"upper_tick": 205000
|
||||
},
|
||||
|
||||
# Edge case: very small liquidity
|
||||
{
|
||||
"name": "Small liquidity",
|
||||
"current_liquidity": 1e-10,
|
||||
"new_increased_liquidity": 2e-10,
|
||||
"net_cash_proceeds": 0.0,
|
||||
"current_tick": 200000,
|
||||
"lower_tick": 195000,
|
||||
"upper_tick": 205000
|
||||
}
|
||||
]
|
||||
|
||||
print("Testing Liquidity Velocity Calculation")
|
||||
print("=" * 50)
|
||||
|
||||
for case in test_cases:
|
||||
print(f"\nTest: {case['name']}")
|
||||
print(f"Inputs: {case}")
|
||||
|
||||
# Validate inputs
|
||||
if validate_liquidity_inputs(
|
||||
case["current_liquidity"],
|
||||
case["new_increased_liquidity"],
|
||||
case["net_cash_proceeds"]
|
||||
):
|
||||
# Calculate safely
|
||||
velocity, price_impact = calculate_liquidity_velocity_safe(
|
||||
case["current_liquidity"],
|
||||
case["new_increased_liquidity"],
|
||||
case["net_cash_proceeds"],
|
||||
case["current_tick"],
|
||||
case["lower_tick"],
|
||||
case["upper_tick"]
|
||||
)
|
||||
|
||||
print(f"Results: velocity={velocity:.6f}, price_impact={price_impact:.6f}")
|
||||
else:
|
||||
print("Results: Invalid inputs - calculation skipped")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Set up logging
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s'
|
||||
)
|
||||
|
||||
# Run tests
|
||||
test_liquidity_velocity_calculation()
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Integration Instructions:")
|
||||
print("1. Replace the problematic sqrt calculation with calculate_liquidity_velocity_safe()")
|
||||
print("2. Add input validation using validate_liquidity_inputs()")
|
||||
print("3. Use safe_sqrt_with_fallback() for any other sqrt operations")
|
||||
print("4. Add proper logging to track edge cases and errors")
|
||||
Reference in New Issue
Block a user