| |
| """ |
| 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 |
|
|
| |
| 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 {} |
|
|
| |
| HOLDER_DB = "holder_tracker/holder_registry.db" |
| INFERENCE_DB = "llm_liquidity_provider/inference_registry.db" |
| TRADING_DB = "perp_trading_engine/perp_trading.db" |
|
|
|
|
| @app.route('/health', methods=['GET']) |
| 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", |
| } |
| }) |
|
|
|
|
| @app.route('/api/slippage/stats', methods=['GET']) |
| 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 |
|
|
|
|
| @app.route('/api/holders/stats', methods=['GET']) |
| def holder_stats(): |
| """Get holder statistics""" |
| try: |
| conn = sqlite3.connect(HOLDER_DB) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM holders") |
| total_holders = cursor.fetchone()[0] |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM holders WHERE eligible = TRUE") |
| eligible_holders = cursor.fetchone()[0] |
| |
| |
| today = datetime.utcnow().date() |
| cursor.execute(""" |
| SELECT COUNT(*) FROM holders |
| WHERE DATE(first_seen) = ? |
| """, (today.isoformat(),)) |
| new_holders_today = cursor.fetchone()[0] |
| |
| |
| 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 |
|
|
|
|
| @app.route('/api/holders/eligible', methods=['GET']) |
| 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 |
|
|
|
|
| @app.route('/api/liquidity/stats', methods=['GET']) |
| def liquidity_stats(): |
| """Get LLM liquidity statistics""" |
| try: |
| conn = sqlite3.connect(INFERENCE_DB) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM providers WHERE status = 'active'") |
| total_providers = cursor.fetchone()[0] |
| |
| |
| cursor.execute("SELECT SUM(total_earnings) FROM providers") |
| total_earnings = cursor.fetchone()[0] or 0 |
| |
| |
| 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() |
| |
| |
| 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 |
|
|
|
|
| @app.route('/api/liquidity/providers', methods=['GET']) |
| 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 |
|
|
|
|
| @app.route('/api/trading/stats', methods=['GET']) |
| def trading_stats(): |
| """Get trading statistics""" |
| try: |
| conn = sqlite3.connect(TRADING_DB) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM positions WHERE size > 0") |
| active_positions = cursor.fetchone()[0] |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM trades") |
| total_trades = cursor.fetchone()[0] |
| |
| |
| cursor.execute(""" |
| SELECT SUM(size * price) |
| FROM trades |
| WHERE timestamp > datetime('now', '-1 day') |
| """) |
| volume_24h = cursor.fetchone()[0] or 0 |
| |
| |
| cursor.execute("SELECT SUM(size) FROM positions WHERE size > 0") |
| total_size = cursor.fetchone()[0] or 0 |
|
|
| conn.close() |
|
|
| |
| 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 |
|
|
|
|
| @app.route('/api/trading/markets', methods=['GET']) |
| 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 |
|
|
|
|
| @app.route('/api/funding/stats', methods=['GET']) |
| 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 |
|
|
|
|
| @app.route('/api/liquidation/stats', methods=['GET']) |
| 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 |
|
|
| |
| 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 |
|
|
|
|
| @app.route('/api/liquidation/at-risk', methods=['GET']) |
| 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() |
| |
| |
| 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: |
| 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]) |
| except Exception as e: |
| return jsonify({"error": str(e)}), 500 |
|
|
|
|
| @app.route('/api/mining/stats', methods=['GET']) |
| def mining_stats(): |
| """Get mining rewards statistics""" |
| try: |
| conn = sqlite3.connect(INFERENCE_DB) |
| cursor = conn.cursor() |
| |
| |
| cursor.execute("SELECT COUNT(*) FROM providers WHERE status = 'active'") |
| active_providers = cursor.fetchone()[0] |
| |
| |
| cursor.execute("SELECT SUM(amount) FROM rewards") |
| total_rewards = cursor.fetchone()[0] or 0 |
| |
| |
| 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 |
|
|
|
|
| @app.route('/api/mining/leaderboard', methods=['GET']) |
| 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 {} |
|
|
|
|
| @app.route('/api/overview', methods=['GET']) |
| def overview(): |
| """Get overview statistics from all systems""" |
| try: |
| |
| 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__': |
| |
| os.makedirs('holder_tracker', exist_ok=True) |
| os.makedirs('llm_liquidity_provider', exist_ok=True) |
| os.makedirs('perp_trading_engine', exist_ok=True) |
| |
| |
| app.run(host='0.0.0.0', port=7861) |
|
|