fix: spot-perp basis floating-point EPS, NORMAL regime fallback, realistic fee defaults
This commit is contained in:
@@ -107,6 +107,19 @@ STRATEGY_REGIME_AFFINITY = {
|
|||||||
"obi": 0.1,
|
"obi": 0.1,
|
||||||
"mean_rev": 0.1,
|
"mean_rev": 0.1,
|
||||||
},
|
},
|
||||||
|
"NORMAL": {
|
||||||
|
"pairs": 0.7,
|
||||||
|
"cross_sectional": 0.6,
|
||||||
|
"hurst_vpin": 0.5,
|
||||||
|
"momentum": 0.5,
|
||||||
|
"obi": 0.5,
|
||||||
|
"mean_rev": 0.5,
|
||||||
|
"grid_mm": 0.5,
|
||||||
|
"as_mm": 0.4,
|
||||||
|
"funding_arb": 0.3,
|
||||||
|
"queue_imbalance": 0.4,
|
||||||
|
"iceberg": 0.4,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ import numpy as np
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
EPS = 1e-10
|
||||||
|
|
||||||
|
|
||||||
class SpotPerpBasisArb:
|
class SpotPerpBasisArb:
|
||||||
"""Delta-neutral spot-perpetual basis arbitrage.
|
"""Delta-neutral spot-perpetual basis arbitrage.
|
||||||
@@ -47,13 +49,13 @@ class SpotPerpBasisArb:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
entry_threshold_bps: float = 3.0,
|
entry_threshold_bps: float = 5.0,
|
||||||
exit_threshold_bps: float = 1.0,
|
exit_threshold_bps: float = 1.0,
|
||||||
max_hold_hours: float = 48.0,
|
max_hold_hours: float = 48.0,
|
||||||
size_usd: float = 1000.0,
|
size_usd: float = 1000.0,
|
||||||
spot_fee_rate: float = 0.0010,
|
spot_fee_rate: float = 0.0004,
|
||||||
perp_fee_rate: float = 0.0007,
|
perp_fee_rate: float = 0.00015,
|
||||||
min_expected_profit_bps: float = 1.5,
|
min_expected_profit_bps: float = 1.0,
|
||||||
):
|
):
|
||||||
self.entry_threshold = entry_threshold_bps / 10000 # bps → decimal
|
self.entry_threshold = entry_threshold_bps / 10000 # bps → decimal
|
||||||
self.exit_threshold = exit_threshold_bps / 10000
|
self.exit_threshold = exit_threshold_bps / 10000
|
||||||
@@ -112,7 +114,7 @@ class SpotPerpBasisArb:
|
|||||||
funding_apr = abs(funding_rate) * 365 * 3 # 8h → annual
|
funding_apr = abs(funding_rate) * 365 * 3 # 8h → annual
|
||||||
funding_profit = funding_apr * (self.max_hold_hours / (365 * 24))
|
funding_profit = funding_apr * (self.max_hold_hours / (365 * 24))
|
||||||
|
|
||||||
if not in_position and abs(basis) > self.entry_threshold and expected_profit > self.min_expected_profit:
|
if not in_position and abs(basis) > self.entry_threshold and expected_profit >= self.min_expected_profit - EPS:
|
||||||
if basis > 0:
|
if basis > 0:
|
||||||
return {
|
return {
|
||||||
"action": "SELL_PERP_BUY_SPOT",
|
"action": "SELL_PERP_BUY_SPOT",
|
||||||
@@ -237,7 +239,7 @@ def multi_asset_basis_scan(
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
basis = (perp - spot) / spot
|
basis = (perp - spot) / spot
|
||||||
if abs(basis) > entry_threshold_bps / 10000:
|
if abs(basis) >= entry_threshold_bps / 10000 - EPS:
|
||||||
opportunities.append({
|
opportunities.append({
|
||||||
"coin": coin,
|
"coin": coin,
|
||||||
"spot": spot,
|
"spot": spot,
|
||||||
|
|||||||
Reference in New Issue
Block a user