|
| 1 | +from fastapi import APIRouter |
| 2 | +from driftpy.constants.numeric_constants import PRICE_PRECISION |
| 3 | + |
| 4 | +from backend.state import BackendRequest |
| 5 | + |
| 6 | +router = APIRouter() |
| 7 | + |
| 8 | +async def _get_open_interest_per_authority(request: BackendRequest) -> dict: |
| 9 | + vat = request.state.backend_state.vat |
| 10 | + slot = request.state.backend_state.last_oracle_slot |
| 11 | + |
| 12 | + oi_per_authority = {} |
| 13 | + |
| 14 | + for user_data in vat.users.values(): |
| 15 | + user_account = user_data.get_user_account() |
| 16 | + |
| 17 | + if user_account is None: |
| 18 | + # Optionally log this: print(f"Warning: Skipping user_data as get_user_account() returned None.") |
| 19 | + continue |
| 20 | + |
| 21 | + authority = str(user_account.authority) |
| 22 | + |
| 23 | + current_oi_for_authority = oi_per_authority.get(authority, { |
| 24 | + 'total_open_interest_usd': 0.0, |
| 25 | + 'authority': authority |
| 26 | + }) |
| 27 | + |
| 28 | + for position in user_account.perp_positions: |
| 29 | + if position.base_asset_amount == 0: |
| 30 | + continue |
| 31 | + |
| 32 | + market_index = position.market_index |
| 33 | + oracle_price_data = vat.perp_oracles.get(market_index) |
| 34 | + |
| 35 | + if oracle_price_data is None: |
| 36 | + print(f"Warning: Missing oracle price data for market_index {market_index} for authority {authority}. Skipping position.") |
| 37 | + continue |
| 38 | + |
| 39 | + try: |
| 40 | + oracle_price = float(oracle_price_data.price) / PRICE_PRECISION |
| 41 | + # All perpetual markets use BASE_PRECISION (10^9) for base asset amounts. |
| 42 | + decimals = 9 |
| 43 | + |
| 44 | + base_asset_amount_val = position.base_asset_amount |
| 45 | + if base_asset_amount_val is None: # Should not happen with base_asset_amount == 0 check, but good for safety |
| 46 | + print(f"Warning: Position base_asset_amount is None for authority {authority}, market {market_index}. Skipping position.") |
| 47 | + continue |
| 48 | + |
| 49 | + position_value_usd = (abs(base_asset_amount_val) / (10**decimals)) * oracle_price |
| 50 | + current_oi_for_authority['total_open_interest_usd'] += position_value_usd |
| 51 | + except (TypeError, ValueError) as e: |
| 52 | + base_val_repr = repr(getattr(position, 'base_asset_amount', 'N/A')) |
| 53 | + oracle_price_repr = repr(getattr(oracle_price_data, 'price', 'N/A')) |
| 54 | + print(f"Error calculating position_value_usd for authority {authority}, market {market_index}: {e}. Base: {base_val_repr}, OraclePriceRaw: {oracle_price_repr}. Skipping position.") |
| 55 | + continue |
| 56 | + |
| 57 | + if current_oi_for_authority['total_open_interest_usd'] > 0: |
| 58 | + oi_per_authority[authority] = current_oi_for_authority |
| 59 | + |
| 60 | + # Filtered values are now implicitly handled by only adding to oi_per_authority if OI > 0 |
| 61 | + result_list = sorted(list(oi_per_authority.values()), key=lambda x: x['total_open_interest_usd'], reverse=True) |
| 62 | + |
| 63 | + return { |
| 64 | + "slot": slot, |
| 65 | + "data": result_list, |
| 66 | + } |
| 67 | + |
| 68 | +@router.get("/per-authority") |
| 69 | +async def get_open_interest_per_authority(request: BackendRequest): |
| 70 | + return await _get_open_interest_per_authority(request) |
0 commit comments