Spaces:
Paused
Paused
| #!/usr/bin/env python3 | |
| """ | |
| AirMicroDrip Perpetual Futures Trading Engine | |
| Core trading engine for perpetual futures with LLM liquidity | |
| No mocks - real order book, position management, and trade execution | |
| """ | |
| import json | |
| import sqlite3 | |
| import asyncio | |
| import requests | |
| from typing import Dict, List, Optional, Tuple | |
| from datetime import datetime, timedelta | |
| from dataclasses import dataclass, field | |
| from enum import Enum | |
| import uuid | |
| # Configuration | |
| PERP_CONFIG = { | |
| "max_leverage": 100, # Maximum 100x leverage | |
| "initial_margin_rate": 0.10, # 10% initial margin | |
| "maintenance_margin_rate": 0.05, # 5% maintenance margin | |
| "liquidation_threshold": 0.01, # 1% liquidation threshold | |
| "taker_fee_rate": 0.0002, # 0.02% taker fee | |
| "maker_fee_rate": 0.0001, # 0.01% maker fee | |
| "max_position_size_usd": 1000000, # $1M max position | |
| "price_impact_threshold": 0.001, # 0.1% price impact threshold | |
| } | |
| class Side(Enum): | |
| """Trade side""" | |
| LONG = "long" | |
| SHORT = "short" | |
| class OrderType(Enum): | |
| """Order type""" | |
| MARKET = "market" | |
| LIMIT = "limit" | |
| STOP_MARKET = "stop_market" | |
| STOP_LIMIT = "stop_limit" | |
| class OrderStatus(Enum): | |
| """Order status""" | |
| PENDING = "pending" | |
| OPEN = "open" | |
| FILLED = "filled" | |
| PARTIALLY_FILLED = "partially_filled" | |
| CANCELLED = "cancelled" | |
| REJECTED = "rejected" | |
| class Order: | |
| """Order dataclass""" | |
| order_id: str | |
| trader: str | |
| market: str | |
| side: Side | |
| order_type: OrderType | |
| size: float # Position size in base asset | |
| price: Optional[float] = None # Limit price | |
| stop_price: Optional[float] = None # Stop price | |
| leverage: int = 1 | |
| status: OrderStatus = OrderStatus.PENDING | |
| filled_size: float = 0.0 | |
| avg_fill_price: float = 0.0 | |
| created_at: datetime = field(default_factory=datetime.utcnow) | |
| updated_at: datetime = field(default_factory=datetime.utcnow) | |
| class Position: | |
| """Position dataclass""" | |
| position_id: str | |
| trader: str | |
| market: str | |
| side: Side | |
| size: float # Position size | |
| entry_price: float | |
| leverage: int | |
| margin: float # Margin amount | |
| unrealized_pnl: float = 0.0 | |
| realized_pnl: float = 0.0 | |
| liquidation_price: float = 0.0 | |
| opened_at: datetime = field(default_factory=datetime.utcnow) | |
| updated_at: datetime = field(default_factory=datetime.utcnow) | |
| class MarketState: | |
| """Market state dataclass""" | |
| market: str | |
| mark_price: float | |
| index_price: float | |
| funding_rate: float | |
| open_interest: float | |
| volume_24h: float | |
| last_updated: datetime = field(default_factory=datetime.utcnow) | |
| class OrderBook: | |
| """Order book for a market""" | |
| def __init__(self, market: str): | |
| self.market = market | |
| self.bids: List[Tuple[float, float]] = [] # (price, size) | |
| self.asks: List[Tuple[float, float]] = [] # (price, size) | |
| self.synthetic_liquidity: float = 0.0 # From LLM providers | |
| def add_bid(self, price: float, size: float): | |
| """Add bid to order book""" | |
| self.bids.append((price, size)) | |
| self.bids.sort(reverse=True) # Highest first | |
| def add_ask(self, price: float, size: float): | |
| """Add ask to order book""" | |
| self.asks.append((price, size)) | |
| self.asks.sort() # Lowest first | |
| def get_best_bid(self) -> Optional[float]: | |
| """Get best bid price""" | |
| return self.bids[0][0] if self.bids else None | |
| def get_best_ask(self) -> Optional[float]: | |
| """Get best ask price""" | |
| return self.asks[0][0] if self.asks else None | |
| def get_mid_price(self) -> Optional[float]: | |
| """Get mid price""" | |
| best_bid = self.get_best_bid() | |
| best_ask = self.get_best_ask() | |
| if best_bid and best_ask: | |
| return (best_bid + best_ask) / 2 | |
| return None | |
| def add_synthetic_liquidity(self, liquidity_usd: float): | |
| """Add synthetic liquidity from LLM providers""" | |
| self.synthetic_liquidity += liquidity_usd | |
| def get_total_liquidity(self) -> float: | |
| """Get total liquidity (book + synthetic)""" | |
| book_liquidity = sum(size for _, size in self.bids + self.asks) | |
| return book_liquidity + self.synthetic_liquidity | |
| class PerpTradingEngine: | |
| """Perpetual futures trading engine""" | |
| def __init__(self, db_path: str = "perp_trading.db"): | |
| self.db_path = db_path | |
| self.order_books: Dict[str, OrderBook] = {} | |
| self.market_states: Dict[str, MarketState] = {} | |
| self._init_database() | |
| self._init_markets() | |
| def _init_database(self): | |
| """Initialize SQLite database""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| # Create orders table | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS orders ( | |
| order_id TEXT PRIMARY KEY, | |
| trader TEXT, | |
| market TEXT, | |
| side TEXT, | |
| order_type TEXT, | |
| size REAL, | |
| price REAL, | |
| stop_price REAL, | |
| leverage INTEGER, | |
| status TEXT, | |
| filled_size REAL, | |
| avg_fill_price REAL, | |
| created_at TIMESTAMP, | |
| updated_at TIMESTAMP | |
| ) | |
| """) | |
| # Create positions table | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS positions ( | |
| position_id TEXT PRIMARY KEY, | |
| trader TEXT, | |
| market TEXT, | |
| side TEXT, | |
| size REAL, | |
| entry_price REAL, | |
| leverage INTEGER, | |
| margin REAL, | |
| unrealized_pnl REAL, | |
| realized_pnl REAL, | |
| liquidation_price REAL, | |
| opened_at TIMESTAMP, | |
| updated_at TIMESTAMP | |
| ) | |
| """) | |
| # Create trades table | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS trades ( | |
| trade_id TEXT PRIMARY KEY, | |
| order_id TEXT, | |
| market TEXT, | |
| side TEXT, | |
| size REAL, | |
| price REAL, | |
| fee REAL, | |
| timestamp TIMESTAMP | |
| ) | |
| """) | |
| # Create funding table | |
| cursor.execute(""" | |
| CREATE TABLE IF NOT EXISTS funding_rates ( | |
| market TEXT, | |
| rate REAL, | |
| timestamp TIMESTAMP, | |
| PRIMARY KEY (market, timestamp) | |
| ) | |
| """) | |
| conn.commit() | |
| conn.close() | |
| def _fetch_gateio_prices(self) -> Dict[str, float]: | |
| """Fetch real mark prices from Gate.io futures API""" | |
| prices = {} | |
| try: | |
| r = requests.get('https://api.gateio.ws/api/v4/futures/usdt/tickers', timeout=10) | |
| if r.status_code == 200: | |
| for t in r.json(): | |
| contract = t.get('contract', '') | |
| last = float(t.get('last', 0)) | |
| if contract == 'BTC_USDT': | |
| prices['BTC/USDC'] = last | |
| elif contract == 'ETH_USDT': | |
| prices['ETH/USDC'] = last | |
| elif contract == 'SOL_USDT': | |
| prices['SOL/USDC'] = last | |
| except Exception as e: | |
| import logging | |
| logging.warning(f"Price fetch failed: {e}") | |
| # Fallback only if API unreachable | |
| if 'BTC/USDC' not in prices: | |
| prices['BTC/USDC'] = 50000.0 | |
| if 'ETH/USDC' not in prices: | |
| prices['ETH/USDC'] = 3000.0 | |
| if 'SOL/USDC' not in prices: | |
| prices['SOL/USDC'] = 100.0 | |
| prices['MEMBRA/USDC'] = 0.05 | |
| return prices | |
| def _init_markets(self): | |
| """Initialize supported markets with real prices from Gate.io""" | |
| markets = ["BTC/USDC", "ETH/USDC", "SOL/USDC", "MEMBRA/USDC"] | |
| real_prices = self._fetch_gateio_prices() | |
| for market in markets: | |
| self.order_books[market] = OrderBook(market) | |
| mark = real_prices.get(market, 0.05) | |
| self.market_states[market] = MarketState( | |
| market=market, | |
| mark_price=mark, | |
| index_price=mark, | |
| funding_rate=0.0001, | |
| open_interest=0.0, | |
| volume_24h=0.0, | |
| ) | |
| def place_order( | |
| self, | |
| trader: str, | |
| market: str, | |
| side: Side, | |
| order_type: OrderType, | |
| size: float, | |
| price: Optional[float] = None, | |
| stop_price: Optional[float] = None, | |
| leverage: int = 1, | |
| ) -> Order: | |
| """Place new order""" | |
| # Validate market | |
| if market not in self.order_books: | |
| raise ValueError(f"Market {market} not supported") | |
| # Validate leverage | |
| if leverage > PERP_CONFIG["max_leverage"]: | |
| raise ValueError(f"Leverage exceeds maximum of {PERP_CONFIG['max_leverage']}x") | |
| # Validate size | |
| position_value = size * self.market_states[market].mark_price | |
| if position_value > PERP_CONFIG["max_position_size_usd"]: | |
| raise ValueError(f"Position size exceeds maximum of ${PERP_CONFIG['max_position_size_usd']}") | |
| # Create order | |
| order_id = str(uuid.uuid4()) | |
| order = Order( | |
| order_id=order_id, | |
| trader=trader, | |
| market=market, | |
| side=side, | |
| order_type=order_type, | |
| size=size, | |
| price=price, | |
| stop_price=stop_price, | |
| leverage=leverage, | |
| ) | |
| # Save to database | |
| self._save_order(order) | |
| # Execute order | |
| if order_type == OrderType.MARKET: | |
| self._execute_market_order(order) | |
| elif order_type == OrderType.LIMIT: | |
| self._execute_limit_order(order) | |
| return order | |
| def _execute_market_order(self, order: Order): | |
| """Execute market order""" | |
| order_book = self.order_books[order.market] | |
| market_state = self.market_states[order.market] | |
| # Get execution price | |
| if order.side == Side.LONG: | |
| execution_price = order_book.get_best_ask() or market_state.mark_price | |
| else: | |
| execution_price = order_book.get_best_bid() or market_state.mark_price | |
| # Calculate fee | |
| fee = order.size * execution_price * PERP_CONFIG["taker_fee_rate"] | |
| # Update order | |
| order.status = OrderStatus.FILLED | |
| order.filled_size = order.size | |
| order.avg_fill_price = execution_price | |
| order.updated_at = datetime.utcnow() | |
| # Update position | |
| self._update_position(order, execution_price, fee) | |
| # Record trade | |
| self._record_trade(order, execution_price, fee) | |
| # Update order in database | |
| self._update_order(order) | |
| def _execute_limit_order(self, order: Order): | |
| """Execute limit order""" | |
| order_book = self.order_books[order.market] | |
| if order.side == Side.LONG: | |
| order_book.add_bid(order.price, order.size) | |
| else: | |
| order_book.add_ask(order.price, order.size) | |
| order.status = OrderStatus.OPEN | |
| order.updated_at = datetime.utcnow() | |
| self._update_order(order) | |
| def _update_position(self, order: Order, fill_price: float, fee: float): | |
| """Update trader's position""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| # Check if position exists | |
| cursor.execute(""" | |
| SELECT position_id, size, entry_price, margin, realized_pnl | |
| FROM positions | |
| WHERE trader = ? AND market = ? AND side = ? | |
| """, (order.trader, order.market, order.side.value)) | |
| result = cursor.fetchone() | |
| position_value = order.size * fill_price | |
| margin = position_value / order.leverage | |
| if result: | |
| # Update existing position | |
| position_id, existing_size, entry_price, existing_margin, realized_pnl = result | |
| # Calculate new average entry price | |
| total_value = (existing_size * entry_price) + (order.size * fill_price) | |
| new_size = existing_size + order.size | |
| new_entry_price = total_value / new_size if new_size > 0 else entry_price | |
| cursor.execute(""" | |
| UPDATE positions | |
| SET size = ?, entry_price = ?, margin = margin + ?, updated_at = ? | |
| WHERE position_id = ? | |
| """, (new_size, new_entry_price, margin, datetime.utcnow().isoformat(), position_id)) | |
| # Calculate liquidation price | |
| self._update_liquidation_price(position_id, new_size, new_entry_price, order.leverage) | |
| else: | |
| # Create new position | |
| position_id = str(uuid.uuid4()) | |
| cursor.execute(""" | |
| INSERT INTO positions | |
| (position_id, trader, market, side, size, entry_price, leverage, margin, opened_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) | |
| """, ( | |
| position_id, | |
| order.trader, | |
| order.market, | |
| order.side.value, | |
| order.size, | |
| fill_price, | |
| order.leverage, | |
| margin, | |
| datetime.utcnow().isoformat(), | |
| datetime.utcnow().isoformat(), | |
| )) | |
| # Calculate liquidation price | |
| self._update_liquidation_price(position_id, order.size, fill_price, order.leverage) | |
| conn.commit() | |
| conn.close() | |
| def _update_liquidation_price(self, position_id: str, size: float, entry_price: float, leverage: int): | |
| """Update liquidation price for position""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| # Calculate liquidation price | |
| if leverage > 0: | |
| liquidation_price = entry_price * (1 - (1 / leverage) + PERP_CONFIG["maintenance_margin_rate"]) | |
| else: | |
| liquidation_price = 0 | |
| cursor.execute(""" | |
| UPDATE positions | |
| SET liquidation_price = ? | |
| WHERE position_id = ? | |
| """, (liquidation_price, position_id)) | |
| conn.commit() | |
| conn.close() | |
| def _record_trade(self, order: Order, price: float, fee: float): | |
| """Record trade to database""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| trade_id = str(uuid.uuid4()) | |
| cursor.execute(""" | |
| INSERT INTO trades | |
| (trade_id, order_id, market, side, size, price, fee, timestamp) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?) | |
| """, ( | |
| trade_id, | |
| order.order_id, | |
| order.market, | |
| order.side.value, | |
| order.size, | |
| price, | |
| fee, | |
| datetime.utcnow().isoformat(), | |
| )) | |
| conn.commit() | |
| conn.close() | |
| def _save_order(self, order: Order): | |
| """Save order to database""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| INSERT INTO orders | |
| (order_id, trader, market, side, order_type, size, price, stop_price, leverage, status, filled_size, avg_fill_price, created_at, updated_at) | |
| VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) | |
| """, ( | |
| order.order_id, | |
| order.trader, | |
| order.market, | |
| order.side.value, | |
| order.order_type.value, | |
| order.size, | |
| order.price, | |
| order.stop_price, | |
| order.leverage, | |
| order.status.value, | |
| order.filled_size, | |
| order.avg_fill_price, | |
| order.created_at.isoformat(), | |
| order.updated_at.isoformat(), | |
| )) | |
| conn.commit() | |
| conn.close() | |
| def _update_order(self, order: Order): | |
| """Update order in database""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| UPDATE orders | |
| SET status = ?, filled_size = ?, avg_fill_price = ?, updated_at = ? | |
| WHERE order_id = ? | |
| """, ( | |
| order.status.value, | |
| order.filled_size, | |
| order.avg_fill_price, | |
| order.updated_at.isoformat(), | |
| order.order_id, | |
| )) | |
| conn.commit() | |
| conn.close() | |
| def get_position(self, trader: str, market: str) -> Optional[Position]: | |
| """Get trader's position in market""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| cursor.execute(""" | |
| SELECT position_id, trader, market, side, size, entry_price, leverage, margin, | |
| unrealized_pnl, realized_pnl, liquidation_price, opened_at, updated_at | |
| FROM positions | |
| WHERE trader = ? AND market = ? | |
| """, (trader, market)) | |
| result = cursor.fetchone() | |
| conn.close() | |
| if result: | |
| return Position( | |
| position_id=result[0], | |
| trader=result[1], | |
| market=result[2], | |
| side=Side(result[3]), | |
| size=result[4], | |
| entry_price=result[5], | |
| leverage=result[6], | |
| margin=result[7], | |
| unrealized_pnl=result[8], | |
| realized_pnl=result[9], | |
| liquidation_price=result[10], | |
| opened_at=datetime.fromisoformat(result[11]), | |
| updated_at=datetime.fromisoformat(result[12]), | |
| ) | |
| return None | |
| def update_unrealized_pnl(self): | |
| """Update unrealized PnL for all positions""" | |
| conn = sqlite3.connect(self.db_path) | |
| cursor = conn.cursor() | |
| cursor.execute("SELECT position_id, market, side, size, entry_price FROM positions") | |
| positions = cursor.fetchall() | |
| for position_id, market, side, size, entry_price in positions: | |
| market_state = self.market_states[market] | |
| mark_price = market_state.mark_price | |
| if side == Side.LONG: | |
| unrealized_pnl = size * (mark_price - entry_price) | |
| else: | |
| unrealized_pnl = size * (entry_price - mark_price) | |
| cursor.execute(""" | |
| UPDATE positions | |
| SET unrealized_pnl = ?, updated_at = ? | |
| WHERE position_id = ? | |
| """, (unrealized_pnl, datetime.utcnow().isoformat(), position_id)) | |
| conn.commit() | |
| conn.close() | |
| def get_market_stats(self, market: str) -> Dict: | |
| """Get market statistics""" | |
| order_book = self.order_books[market] | |
| market_state = self.market_states[market] | |
| return { | |
| "market": market, | |
| "mark_price": market_state.mark_price, | |
| "index_price": market_state.index_price, | |
| "funding_rate": market_state.funding_rate, | |
| "best_bid": order_book.get_best_bid(), | |
| "best_ask": order_book.get_best_ask(), | |
| "mid_price": order_book.get_mid_price(), | |
| "total_liquidity": order_book.get_total_liquidity(), | |
| "synthetic_liquidity": order_book.synthetic_liquidity, | |
| "volume_24h": market_state.volume_24h, | |
| "open_interest": market_state.open_interest, | |
| } | |
| if __name__ == "__main__": | |
| # Initialize trading engine | |
| engine = PerpTradingEngine() | |
| # Example: Place a market order | |
| order = engine.place_order( | |
| trader="TRADER_ADDRESS", | |
| market="BTC/USDC", | |
| side=Side.LONG, | |
| order_type=OrderType.MARKET, | |
| size=0.1, # 0.1 BTC | |
| leverage=10, # 10x leverage | |
| ) | |
| print("\n" + "="*50) | |
| print("Order Placed") | |
| print("="*50) | |
| print(f"Order ID: {order.order_id}") | |
| print(f"Status: {order.status.value}") | |
| print(f"Filled Size: {order.filled_size}") | |
| print(f"Avg Fill Price: ${order.avg_fill_price}") | |
| # Get position | |
| position = engine.get_position("TRADER_ADDRESS", "BTC/USDC") | |
| if position: | |
| print("\n" + "="*50) | |
| print("Position Details") | |
| print("="*50) | |
| print(f"Position ID: {position.position_id}") | |
| print(f"Side: {position.side.value}") | |
| print(f"Size: {position.size}") | |
| print(f"Entry Price: ${position.entry_price}") | |
| print(f"Leverage: {position.leverage}x") | |
| print(f"Margin: ${position.margin}") | |
| print(f"Liquidation Price: ${position.liquidation_price}") | |
| # Get market stats | |
| stats = engine.get_market_stats("BTC/USDC") | |
| print("\n" + "="*50) | |
| print("Market Statistics") | |
| print("="*50) | |
| print(json.dumps(stats, indent=2)) | |