feat: add asymmetric compensation & exact liquidity support to hedger

This commit is contained in:
2025-12-26 23:01:00 +01:00
parent 4f7bb429b7
commit c04eb3f377
2 changed files with 79 additions and 52 deletions

View File

@ -222,7 +222,8 @@ def update_position_stats(token_id: int, stats_data: Dict):
class HyperliquidStrategy:
def __init__(self, entry_amount0: Decimal, entry_amount1: Decimal, target_value: Decimal,
entry_price: Decimal, low_range: Decimal, high_range: Decimal, start_price: Decimal):
entry_price: Decimal, low_range: Decimal, high_range: Decimal, start_price: Decimal,
liquidity: int = 0):
self.entry_amount0 = entry_amount0
self.entry_amount1 = entry_amount1
self.target_value = target_value
@ -235,40 +236,53 @@ class HyperliquidStrategy:
self.recovery_target = entry_price + (Decimal("2") * self.gap)
self.L = Decimal("0.0")
try:
sqrt_P = entry_price.sqrt()
sqrt_Pa = low_range.sqrt()
sqrt_Pb = high_range.sqrt()
# Priority: Use exact Liquidity from Contract if available
if liquidity > 0:
# Scale raw liquidity (uint128) to human liquidity
# Formula: L_human = L_raw * 10^(-(d0+d1)/2)
# For ETH(18) / USDC(6) -> 10^(-12)
scale = Decimal("1e-12")
self.L = Decimal(liquidity) * scale
# Method 1: Amount0 (WETH)
if entry_amount0 > 0:
# Assuming amount0 is already in standard units (ETH) from JSON
denom0 = (Decimal("1") / sqrt_P) - (Decimal("1") / sqrt_Pb)
if denom0 > Decimal("1e-10"):
self.L = entry_amount0 / denom0
logger.info(f"Calculated L from Amount0: {self.L:.4f}")
# Method 2: Amount1 (USDC)
if self.L == 0 and entry_amount1 > 0:
denom1 = sqrt_P - sqrt_Pa
if denom1 > Decimal("1e-10"):
self.L = entry_amount1 / denom1
logger.info(f"Calculated L from Amount1: {self.L:.4f}")
# Method 3: Target Value Heuristic
if self.L == 0:
logger.warning("Amounts missing. Using Target Value Heuristic.")
max_eth = target_value / low_range
denom_h = (Decimal("1") / sqrt_Pa) - (Decimal("1") / sqrt_Pb)
if denom_h > 0:
self.L = max_eth / denom_h
logger.info(f"Calculated L from Target Value: {self.L:.4f}")
else:
logger.error("Critical: Invalid Range for L calculation")
# Calculate implied delta at entry for verification
implied_delta = self.get_pool_delta(entry_price)
logger.info(f"Using Exact Liquidity: {self.L:.4f} (Raw: {liquidity}) -> Implied Delta: {implied_delta:.4f} ETH")
else:
try:
sqrt_P = entry_price.sqrt()
sqrt_Pa = low_range.sqrt()
sqrt_Pb = high_range.sqrt()
# Method 1: Amount0 (WETH)
if entry_amount0 > 0:
# Assuming amount0 is already in standard units (ETH) from JSON
denom0 = (Decimal("1") / sqrt_P) - (Decimal("1") / sqrt_Pb)
if denom0 > Decimal("1e-10"):
self.L = entry_amount0 / denom0
logger.info(f"Calculated L from Amount0: {self.L:.4f}")
# Method 2: Amount1 (USDC)
if self.L == 0 and entry_amount1 > 0:
denom1 = sqrt_P - sqrt_Pa
if denom1 > Decimal("1e-10"):
self.L = entry_amount1 / denom1
logger.info(f"Calculated L from Amount1: {self.L:.4f}")
# Method 3: Target Value Heuristic
if self.L == 0:
logger.warning("Amounts missing. Using Target Value Heuristic.")
max_eth = target_value / low_range
denom_h = (Decimal("1") / sqrt_Pa) - (Decimal("1") / sqrt_Pb)
if denom_h > 0:
self.L = max_eth / denom_h
logger.info(f"Calculated L from Target Value: {self.L:.4f}")
else:
logger.error("Critical: Invalid Range for L calculation")
except Exception as e:
logger.error(f"Error calculating liquidity: {e}")
sys.exit(1)
except Exception as e:
logger.error(f"Error calculating liquidity: {e}")
sys.exit(1)
def get_pool_delta(self, current_price: Decimal) -> Decimal:
if current_price >= self.high_range:
@ -286,21 +300,28 @@ class HyperliquidStrategy:
def calculate_rebalance(self, current_price: Decimal, current_short_size: Decimal) -> Dict:
pool_delta = self.get_pool_delta(current_price)
# Over-Hedge Logic
overhedge_pct = Decimal("0.0")
# --- ASYMMETRIC COMPENSATION (0.35% Leakage Fix) ---
# Over-hedge on drops, Under-hedge on rises to offset execution friction.
# Max adjustment at edges: 7.5%
adj_pct = Decimal("0.0")
range_width = self.high_range - self.low_range
if range_width > 0:
price_pct = (current_price - self.low_range) / range_width
# Distance from entry price
dist = current_price - self.entry_price
# Normalize to range half-width (approx)
half_width = range_width / Decimal("2")
norm_dist = dist / half_width
# Adjustment: -7.5% at +1.0 (High), +7.5% at -1.0 (Low)
max_boost = Decimal("0.075")
adj_pct = -norm_dist * max_boost
# Safety Cap
adj_pct = max(-max_boost, min(max_boost, adj_pct))
# If below 80% of range
if price_pct < Decimal("0.8"):
# Formula: 0.75% boost for every 0.1 drop below 0.8
diff_factor = (Decimal("0.8") - max(Decimal("0.0"), price_pct)) / Decimal("0.1")
overhedge_pct = diff_factor * Decimal("0.0075")
raw_target_short = pool_delta
adjusted_target_short = raw_target_short * (Decimal("1.0") + overhedge_pct)
adjusted_target_short = raw_target_short * (Decimal("1.0") + adj_pct)
diff = adjusted_target_short - abs(current_short_size)
@ -311,7 +332,7 @@ class HyperliquidStrategy:
"current_short": abs(current_short_size),
"diff": diff,
"action": "SELL" if diff > 0 else "BUY",
"overhedge_pct": overhedge_pct
"adj_pct": adj_pct
}
# --- MAIN HEDGER CLASS ---
@ -434,6 +455,8 @@ class ScalperHedger:
lower = to_decimal(position_data['range_lower'])
upper = to_decimal(position_data['range_upper'])
liquidity_val = int(position_data.get('liquidity', 0))
start_price = self.get_market_price(COIN_SYMBOL)
if start_price is None:
logger.warning("Waiting for initial price to start strategy...")
@ -446,7 +469,8 @@ class ScalperHedger:
entry_price=entry_price,
low_range=lower,
high_range=upper,
start_price=start_price
start_price=start_price,
liquidity=liquidity_val
)
# Reset State
@ -1017,7 +1041,7 @@ class ScalperHedger:
create_shadow = False
urgency = "URGENT" if bypass_cooldown else "NORMAL"
logger.info(f"[TRIG] Rebalance ({urgency}): {calc['action']} {diff_abs:.4f} > {rebalance_threshold:.4f} | Book: {levels['bid']}/{levels['ask']} | Vol: {vol_pct*100:.3f}% x{vol_multiplier:.1f} | Thresh: {final_threshold_pct*100:.1f}%")
logger.info(f"[TRIG] Rebalance ({urgency}): {calc['action']} {diff_abs:.4f} > {rebalance_threshold:.4f} | Adj: {calc['adj_pct']*100:+.1f}% | Book: {levels['bid']}/{levels['ask']} | Vol: {vol_pct*100:.3f}% x{vol_multiplier:.1f} | Thresh: {final_threshold_pct*100:.1f}%")
oid = self.place_limit_order(COIN_SYMBOL, is_buy, diff_abs, exec_price, order_type)
if oid:
@ -1074,7 +1098,7 @@ class ScalperHedger:
p_sell = self.strategy.low_range + safety_margin
net_pnl = self.accumulated_pnl - self.accumulated_fees
logger.info(f"[IDLE] Px: {price:.2f} | M: {p_mid:.1f} | B: {p_buy:.1f} / S: {p_sell:.1f} (Vol: {vol_pct*100:.3f}% x{vol_multiplier:.1f} | Thresh: {final_threshold_pct*100:.1f}%) | TotPnL: {net_pnl:.2f}")
logger.info(f"[IDLE] Px: {price:.2f} | M: {p_mid:.1f} | B: {p_buy:.1f} / S: {p_sell:.1f} | Adj: {calc['adj_pct']*100:+.1f}% (Vol: {vol_pct*100:.3f}% x{vol_multiplier:.1f} | Thresh: {final_threshold_pct*100:.1f}%) | TotPnL: {net_pnl:.2f}")
self.last_idle_log_time = time.time()
# --- FISHING ORDER LOGIC (SAFE ZONE) ---