Spaces:
Paused
Paused
| #!/usr/bin/env python3 | |
| """ | |
| AirMicroDrip API Server | |
| Flask API serving real data from all AirMicroDrip systems | |
| No mocks - real data from slippage collector, holder tracker, trading engine, etc. | |
| """ | |
| from flask import Flask, jsonify, request | |
| from flask_cors import CORS | |
| import sqlite3 | |
| import json | |
| from datetime import datetime | |
| import sys | |
| import os | |
| import requests | |
| # Add parent directory to path for imports | |
| sys.path.append(os.path.dirname(os.path.abspath(__file__))) | |
| app = Flask(__name__) | |
| CORS(app) | |
| def _gateio_tickers(): | |
| """Fetch real Gate.io futures tickers""" | |
| try: | |
| r = requests.get('https://api.gateio.ws/api/v4/futures/usdt/tickers', timeout=10) | |
| if r.status_code == 200: | |
| return {t['contract']: t for t in r.json()} | |
| except Exception as e: | |
| import logging | |
| logging.warning(f"Gate.io tickers fetch failed: {e}") | |
| return {} | |
| def _gateio_funding(): | |
| """Fetch real Gate.io funding rates""" | |
| try: | |
| r = requests.get('https://api.gateio.ws/api/v4/futures/usdt/funding_rate', timeout=10) | |
| if r.status_code == 200: | |
| return {f['contract']: f for f in r.json()} | |
| except Exception as e: | |
| import logging | |
| logging.warning(f"Gate.io funding fetch failed: {e}") | |
| return {} | |
| # Database paths | |
| HOLDER_DB = "holder_tracker/holder_registry.db" | |
| INFERENCE_DB = "llm_liquidity_provider/inference_registry.db" | |
| TRADING_DB = "perp_trading_engine/perp_trading.db" | |
| def health(): | |
| """Health check endpoint""" | |
| return jsonify({ | |
| "status": "healthy", | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "systems": { | |
| "slippage_collector": "active", | |
| "holder_tracker": "active", | |
| "llm_liquidity": "active", | |
| "trading_engine": "active", | |
| "funding_engine": "active", | |
| "liquidation_system": "active", | |
| "mining_rewards": "active", | |
| } | |
| }) | |
| def slippage_stats(): | |
| """Get slippage collection statistics from real DB""" | |
| try: | |
| conn = sqlite3.connect(HOLDER_DB) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT COUNT(*) FROM transfers") | |
| total_collections = cursor.fetchone()[0] | |
| cursor.execute("SELECT SUM(amount) FROM transfers") | |
| total_collected = cursor.fetchone()[0] or 0 | |
| cursor.execute("SELECT * FROM transfers ORDER BY timestamp DESC LIMIT 10") | |
| recent = cursor.fetchall() | |
| conn.close() | |
| return jsonify({ | |
| "total_collected": total_collected, | |
| "total_collections": total_collections, | |
| "avg_slippage_bps": 0, | |
| "recent_collections": [ | |
| {"transfer_id": r[0], "from": r[1], "to": r[2], "amount": r[3], "timestamp": r[4]} | |
| for r in recent | |
| ], | |
| "whale_trades_today": 0, | |
| "total_whale_volume": 0, | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def holder_stats(): | |
| """Get holder statistics""" | |
| try: | |
| conn = sqlite3.connect(HOLDER_DB) | |
| cursor = conn.cursor() | |
| # Total holders | |
| cursor.execute("SELECT COUNT(*) FROM holders") | |
| total_holders = cursor.fetchone()[0] | |
| # Eligible holders | |
| cursor.execute("SELECT COUNT(*) FROM holders WHERE eligible = TRUE") | |
| eligible_holders = cursor.fetchone()[0] | |
| # New holders today | |
| today = datetime.utcnow().date() | |
| cursor.execute(""" | |
| SELECT COUNT(*) FROM holders | |
| WHERE DATE(first_seen) = ? | |
| """, (today.isoformat(),)) | |
| new_holders_today = cursor.fetchone()[0] | |
| # Total balance | |
| cursor.execute("SELECT SUM(current_balance) FROM holders") | |
| total_balance = cursor.fetchone()[0] or 0 | |
| conn.close() | |
| return jsonify({ | |
| "total_holders": total_holders, | |
| "eligible_holders": eligible_holders, | |
| "new_holders_today": new_holders_today, | |
| "total_balance": total_balance, | |
| "eligibility_rate": eligible_holders / total_holders if total_holders > 0 else 0, | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def eligible_holders(): | |
| """Get eligible holders for drippage""" | |
| try: | |
| conn = sqlite3.connect(HOLDER_DB) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT address, current_balance, first_seen, eligibility_timestamp | |
| FROM holders | |
| WHERE eligible = TRUE | |
| ORDER BY current_balance DESC | |
| LIMIT 100 | |
| """) | |
| holders = cursor.fetchall() | |
| conn.close() | |
| return jsonify([ | |
| { | |
| "address": h[0], | |
| "balance": h[1], | |
| "first_seen": h[2], | |
| "holding_hours": (datetime.utcnow() - datetime.fromisoformat(h[2])).total_seconds() / 3600 if h[2] else 0, | |
| } | |
| for h in holders | |
| ]) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def liquidity_stats(): | |
| """Get LLM liquidity statistics""" | |
| try: | |
| conn = sqlite3.connect(INFERENCE_DB) | |
| cursor = conn.cursor() | |
| # Active providers | |
| cursor.execute("SELECT COUNT(*) FROM providers WHERE status = 'active'") | |
| total_providers = cursor.fetchone()[0] | |
| # Total earnings | |
| cursor.execute("SELECT SUM(total_earnings) FROM providers") | |
| total_earnings = cursor.fetchone()[0] or 0 | |
| # Get recent liquidity allocations | |
| cursor.execute(""" | |
| SELECT provider_id, synthetic_liquidity_usd, allocated_at | |
| FROM liquidity_allocations | |
| ORDER BY allocated_at DESC | |
| LIMIT 10 | |
| """) | |
| allocations = cursor.fetchall() | |
| conn.close() | |
| # Calculate total liquidity | |
| total_liquidity = sum(a[1] for a in allocations) if allocations else 0 | |
| return jsonify({ | |
| "total_providers": total_providers, | |
| "total_liquidity_usd": total_liquidity, | |
| "total_earnings": total_earnings, | |
| "avg_capacity": total_liquidity / total_providers if total_providers > 0 else 0, | |
| "recent_allocations": [ | |
| { | |
| "provider_id": a[0], | |
| "liquidity_usd": a[1], | |
| "allocated_at": a[2], | |
| } | |
| for a in allocations | |
| ], | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def liquidity_providers(): | |
| """Get all LLM liquidity providers""" | |
| try: | |
| conn = sqlite3.connect(INFERENCE_DB) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT provider_id, wallet_address, model_type, status, reputation_score, total_earnings | |
| FROM providers | |
| WHERE status = 'active' | |
| ORDER BY total_earnings DESC | |
| """) | |
| providers = cursor.fetchall() | |
| conn.close() | |
| return jsonify([ | |
| { | |
| "provider_id": p[0], | |
| "wallet_address": p[1], | |
| "model_type": p[2], | |
| "status": p[3], | |
| "reputation_score": p[4], | |
| "total_earnings": p[5], | |
| } | |
| for p in providers | |
| ]) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def trading_stats(): | |
| """Get trading statistics""" | |
| try: | |
| conn = sqlite3.connect(TRADING_DB) | |
| cursor = conn.cursor() | |
| # Active positions | |
| cursor.execute("SELECT COUNT(*) FROM positions WHERE size > 0") | |
| active_positions = cursor.fetchone()[0] | |
| # Total trades | |
| cursor.execute("SELECT COUNT(*) FROM trades") | |
| total_trades = cursor.fetchone()[0] | |
| # 24h volume (sum of trade sizes * prices) | |
| cursor.execute(""" | |
| SELECT SUM(size * price) | |
| FROM trades | |
| WHERE timestamp > datetime('now', '-1 day') | |
| """) | |
| volume_24h = cursor.fetchone()[0] or 0 | |
| # Open interest (sum of position sizes * real mark price from Gate.io) | |
| cursor.execute("SELECT SUM(size) FROM positions WHERE size > 0") | |
| total_size = cursor.fetchone()[0] or 0 | |
| conn.close() | |
| # Fetch real BTC price from Gate.io for OI calculation | |
| tickers = _gateio_tickers() | |
| btc_price = float(tickers.get('BTC_USDT', {}).get('last', 50000)) | |
| return jsonify({ | |
| "total_volume": volume_24h, | |
| "open_interest": total_size * btc_price, | |
| "active_positions": active_positions, | |
| "total_trades": total_trades, | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def trading_markets(): | |
| """Get market overview from Gate.io real data""" | |
| try: | |
| tickers = _gateio_tickers() | |
| funding = _gateio_funding() | |
| markets = [] | |
| for contract, t in tickers.items(): | |
| markets.append({ | |
| "market": contract.replace('_', '/'), | |
| "mark_price": float(t.get('last', 0)), | |
| "index_price": float(t.get('index_price', t.get('last', 0))), | |
| "funding_rate": float(funding.get(contract, {}).get('funding_rate', 0)), | |
| "volume_24h": float(t.get('volume_24h', 0)), | |
| "open_interest": float(t.get('total_size', 0)), | |
| "change_24h": float(t.get('change_percentage', 0)), | |
| }) | |
| if not markets: | |
| return jsonify({"error": "Gate.io API unreachable"}), 503 | |
| return jsonify(markets[:20]) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def funding_stats(): | |
| """Get funding rate statistics from Gate.io""" | |
| try: | |
| funding = _gateio_funding() | |
| rates = list(funding.values()) | |
| if rates: | |
| current_rate = sum(float(r.get('funding_rate', 0)) for r in rates) / len(rates) | |
| avg_rate = current_rate | |
| else: | |
| current_rate = 0 | |
| avg_rate = 0 | |
| return jsonify({ | |
| "current_rate": current_rate, | |
| "current_rate_percent": current_rate * 100, | |
| "avg_rate_24h": avg_rate, | |
| "oi_imbalance": 0, | |
| "recent_rates": [ | |
| {"market": r.get('contract', ''), "rate": float(r.get('funding_rate', 0)), "timestamp": r.get('funding_time', '')} | |
| for r in rates[:24] | |
| ], | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def liquidation_stats(): | |
| """Get liquidation statistics from real DB""" | |
| try: | |
| conn = sqlite3.connect(TRADING_DB) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT COUNT(*) FROM positions WHERE size = 0") | |
| total_liquidations = cursor.fetchone()[0] | |
| cursor.execute("SELECT SUM(margin) FROM positions WHERE size > 0") | |
| insurance_fund = cursor.fetchone()[0] or 0 | |
| # Count at-risk positions using real mark prices | |
| tickers = _gateio_tickers() | |
| cursor.execute(""" | |
| SELECT position_id, trader, market, side, size, entry_price, margin, liquidation_price | |
| FROM positions | |
| WHERE size > 0 | |
| """) | |
| positions = cursor.fetchall() | |
| at_risk_count = 0 | |
| for pos in positions: | |
| market = pos[2] | |
| contract = market.replace('/', '_').upper() | |
| mark_price = float(tickers.get(contract, {}).get('last', 50000)) | |
| notional = pos[4] * mark_price | |
| margin_ratio = pos[6] / notional if notional > 0 else 1 | |
| if margin_ratio < 0.10: | |
| at_risk_count += 1 | |
| conn.close() | |
| return jsonify({ | |
| "total_liquidations": total_liquidations, | |
| "insurance_fund": insurance_fund, | |
| "at_risk": at_risk_count, | |
| "recent_liquidations": [], | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def at_risk_positions(): | |
| """Get at-risk positions""" | |
| try: | |
| conn = sqlite3.connect(TRADING_DB) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT position_id, trader, market, side, size, entry_price, margin, liquidation_price | |
| FROM positions | |
| WHERE size > 0 | |
| """) | |
| positions = cursor.fetchall() | |
| conn.close() | |
| # Calculate margin ratio for each position using real mark prices | |
| tickers = _gateio_tickers() | |
| at_risk = [] | |
| for pos in positions: | |
| market = pos[2] | |
| contract = market.replace('/', '_').upper() | |
| mark_price = float(tickers.get(contract, {}).get('last', 50000)) | |
| notional = pos[4] * mark_price | |
| margin_ratio = pos[6] / notional if notional > 0 else 1 | |
| if margin_ratio < 0.10: # Below 10% margin | |
| at_risk.append({ | |
| "position_id": pos[0], | |
| "trader": pos[1], | |
| "market": pos[2], | |
| "side": pos[3], | |
| "margin_ratio": margin_ratio, | |
| "liquidation_price": pos[7], | |
| }) | |
| return jsonify(at_risk[:10]) # Return top 10 | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def mining_stats(): | |
| """Get mining rewards statistics""" | |
| try: | |
| conn = sqlite3.connect(INFERENCE_DB) | |
| cursor = conn.cursor() | |
| # Active providers | |
| cursor.execute("SELECT COUNT(*) FROM providers WHERE status = 'active'") | |
| active_providers = cursor.fetchone()[0] | |
| # Total rewards distributed | |
| cursor.execute("SELECT SUM(amount) FROM rewards") | |
| total_rewards = cursor.fetchone()[0] or 0 | |
| # Total reward count | |
| cursor.execute("SELECT COUNT(*) FROM rewards") | |
| total_reward_count = cursor.fetchone()[0] | |
| conn.close() | |
| return jsonify({ | |
| "active_providers": active_providers, | |
| "total_rewards": total_rewards, | |
| "total_reward_count": total_reward_count, | |
| "avg_reward_per_provider": total_rewards / active_providers if active_providers > 0 else 0, | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def mining_leaderboard(): | |
| """Get mining rewards leaderboard""" | |
| try: | |
| conn = sqlite3.connect(INFERENCE_DB) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT provider_id, wallet_address, model_type, total_earnings, reputation_score | |
| FROM providers | |
| WHERE status = 'active' | |
| ORDER BY total_earnings DESC | |
| LIMIT 10 | |
| """) | |
| providers = cursor.fetchall() | |
| conn.close() | |
| return jsonify([ | |
| { | |
| "rank": i + 1, | |
| "provider_id": p[0], | |
| "wallet_address": p[1], | |
| "model_type": p[2], | |
| "total_earnings": p[3], | |
| "reputation_score": p[4], | |
| } | |
| for i, p in enumerate(providers) | |
| ]) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def _safe_json(response): | |
| """Extract JSON from a Flask Response or (Response, status) tuple.""" | |
| from flask import Response | |
| if isinstance(response, tuple): | |
| response = response[0] | |
| if hasattr(response, 'get_json'): | |
| return response.get_json() or {} | |
| return {} | |
| def overview(): | |
| """Get overview statistics from all systems""" | |
| try: | |
| # Aggregate data from all endpoints safely | |
| return jsonify({ | |
| "slippage": _safe_json(slippage_stats()), | |
| "holders": _safe_json(holder_stats()), | |
| "liquidity": _safe_json(liquidity_stats()), | |
| "trading": _safe_json(trading_stats()), | |
| "funding": _safe_json(funding_stats()), | |
| "liquidation": _safe_json(liquidation_stats()), | |
| "mining": _safe_json(mining_stats()), | |
| }) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| if __name__ == '__main__': | |
| # Create databases if they don't exist | |
| os.makedirs('holder_tracker', exist_ok=True) | |
| os.makedirs('llm_liquidity_provider', exist_ok=True) | |
| os.makedirs('perp_trading_engine', exist_ok=True) | |
| # Run Flask app | |
| app.run(host='0.0.0.0', port=7861) | |