airmicrodrip / api_server.py
josephrw's picture
Upload folder using huggingface_hub
e9d4f6a verified
Raw
History Blame Contribute Delete
17.3 kB
#!/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"
@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()
# 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
@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()
# 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
@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()
# 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
@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
# 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
@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()
# 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
@app.route('/api/mining/stats', methods=['GET'])
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
@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:
# 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)