Files
uniswap_auto_clp/florida/tools/fetch_real_position_data.py
DiTus b22fdcf741 refactor: Standardize CLP Manager and Hedger modules & cleanup
- **clp_manager.py**: Renamed from 'uniswap_manager.py'. Standardized logic for Uniswap V3 liquidity provision.
- **clp_hedger.py**: Renamed from 'unified_hedger.py'. Consolidated hedging logic including Delta Calculation fixes, EAC (Edge Avoidance), and Fishing order implementation.
- **Cleanup**: Removed legacy 'aerodrome' folder and tools.
- **Monitoring**: Added Telegram monitoring scripts.
- **Config**: Updated gitignore to exclude market data CSVs.
2025-12-31 11:09:33 +01:00

143 lines
5.4 KiB
Python

import json
import os
import math
import sys
from decimal import Decimal, getcontext
from web3 import Web3
from web3.middleware import ExtraDataToPOAMiddleware
from eth_account import Account
from dotenv import load_dotenv
# Add project root to path
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from clp_config import CLP_PROFILES
# Load Env
load_dotenv()
# Config for PancakeSwap
PROFILE = CLP_PROFILES["PANCAKESWAP_BNB"]
RPC_URL = os.environ.get(PROFILE["RPC_ENV_VAR"])
STATUS_FILE = "PANCAKESWAP_BNB_status.json"
# Minimal ABI for NPM
NPM_ABI = [
{
"inputs": [{"internalType": "uint256", "name": "tokenId", "type": "uint256"}],
"name": "positions",
"outputs": [
{"internalType": "uint96", "name": "nonce", "type": "uint96"},
{"internalType": "address", "name": "operator", "type": "address"},
{"internalType": "address", "name": "token0", "type": "address"},
{"internalType": "address", "name": "token1", "type": "address"},
{"internalType": "uint24", "name": "fee", "type": "uint24"},
{"internalType": "int24", "name": "tickLower", "type": "int24"},
{"internalType": "int24", "name": "tickUpper", "type": "int24"},
{"internalType": "uint128", "name": "liquidity", "type": "uint128"},
{"internalType": "uint256", "name": "feeGrowthInside0LastX128", "type": "uint256"},
{"internalType": "uint256", "name": "feeGrowthInside1LastX128", "type": "uint256"},
{"internalType": "uint128", "name": "tokensOwed0", "type": "uint128"},
{"internalType": "uint128", "name": "tokensOwed1", "type": "uint128"}
],
"stateMutability": "view",
"type": "function"
}
]
def get_price_at_tick(tick):
return 1.0001 ** tick
def fetch_and_fix():
if not RPC_URL:
print("❌ Missing RPC URL in .env")
return
print(f"Connecting to RPC: {RPC_URL}")
w3 = Web3(Web3.HTTPProvider(RPC_URL))
w3.middleware_onion.inject(ExtraDataToPOAMiddleware, layer=0)
if not w3.is_connected():
print("❌ Failed to connect to Web3")
return
npm = w3.eth.contract(address=PROFILE["NPM_ADDRESS"], abi=NPM_ABI)
with open(STATUS_FILE, 'r') as f:
data = json.load(f)
updated_count = 0
for entry in data:
token_id = entry.get('token_id')
status = entry.get('status')
# We check ALL positions to be safe, or just the problematic ones.
# Let's check any that seem to have suspect data or just refresh all active/recently active.
# The user mentioned 6164702 specifically.
print(f"🔍 Checking Token ID: {token_id} ({status})")
try:
pos = npm.functions.positions(token_id).call()
# Pos structure:
# 0: nonce, 1: operator, 2: token0, 3: token1, 4: fee,
# 5: tickLower, 6: tickUpper, 7: liquidity ...
tick_lower = pos[5]
tick_upper = pos[6]
liquidity = pos[7]
# Calculate Ranges
price_lower = get_price_at_tick(tick_lower)
price_upper = get_price_at_tick(tick_upper)
# Format to 4 decimals
new_lower = round(price_lower, 4)
new_upper = round(price_upper, 4)
old_lower = entry.get('range_lower', 0)
old_upper = entry.get('range_upper', 0)
# Check deviation
if abs(new_lower - old_lower) > 0.1 or abs(new_upper - old_upper) > 0.1:
print(f" ⚠️ Mismatch Found!")
print(f" Old: {old_lower} - {old_upper}")
print(f" New: {new_lower} - {new_upper}")
entry['range_lower'] = new_lower
entry['range_upper'] = new_upper
entry['liquidity'] = str(liquidity)
# Fix Entry Price if it looks wrong (e.g. 0 or way off range)
# If single sided (e.g. 862-869), and spot is 860.
# If we provided only Token0 (BNB), we are selling BNB as it goes UP.
# So we entered 'below' the range.
# If we assume the user just opened it, the 'entry_price' should roughly match
# the current market price or at least be consistent.
# Since we don't know the exact historical price, we can't perfectly fix 'entry_price'
# without event logs.
# HOWEVER, for the bot's logic, 'range_lower' and 'range_upper' are critical for 'in_range' checks.
# 'entry_price' is mostly for PnL est.
# If entry_price is wildly different from range (e.g. 844 vs 862-869), it's confusing.
# Let's see if we can infer something.
# For now, we update ranges as that's the request.
updated_count += 1
else:
print(f" ✅ Data looks solid.")
except Exception as e:
print(f" ❌ Error fetching chain data: {e}")
if updated_count > 0:
with open(STATUS_FILE, 'w') as f:
json.dump(data, f, indent=2)
print(f"💾 Updated {updated_count} entries in {STATUS_FILE}")
else:
print("No updates needed.")
if __name__ == "__main__":
fetch_and_fix()