Spaces:
Configuration error
Configuration error
| <html lang="en" class="scroll-smooth"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>SpotSync Alpha - Trading Replication Engine</title> | |
| <link rel="icon" type="image/x-icon" href="assets/favicon.ico"> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <script src="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js"></script> | |
| <script src="https://unpkg.com/feather-icons"></script> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <link rel="stylesheet" href="style.css"> | |
| <script> | |
| // Electron IPC communication | |
| const { ipcRenderer } = require('electron'); | |
| function minimizeWindow() { | |
| ipcRenderer.send('window-minimize'); | |
| } | |
| function maximizeWindow() { | |
| ipcRenderer.send('window-maximize'); | |
| } | |
| function closeWindow() { | |
| ipcRenderer.send('window-close'); | |
| } | |
| function hideWindow() { | |
| ipcRenderer.send('window-hide'); | |
| } | |
| </script> | |
| </head> | |
| <body class="bg-gradient-to-br from-gray-900 via-gray-800 to-black text-gray-100 h-screen overflow-hidden"> | |
| <!-- Custom Title Bar for Desktop App --> | |
| <div class="title-bar bg-gray-900/80 backdrop-blur-md border-b border-gray-800 flex items-center justify-between px-4 py-2 select-none draggable-region"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-8 h-8 rounded-lg bg-gradient-to-r from-cyan-500 to-blue-500 flex items-center justify-center"> | |
| <i data-feather="zap" class="w-4 h-4 text-white"></i> | |
| </div> | |
| <span class="font-semibold text-sm bg-clip-text text-transparent bg-gradient-to-r from-cyan-300 to-blue-300"> | |
| SpotSync Alpha | |
| </span> | |
| <span class="text-xs text-gray-400 px-2 py-1 bg-gray-800 rounded">v1.0.0</span> | |
| </div> | |
| <div class="flex items-center gap-2 non-draggable"> | |
| <button onclick="hideWindow()" class="w-8 h-8 flex items-center justify-center hover:bg-gray-700 rounded transition-colors" title="Minimize to Tray"> | |
| <i data-feather="minus" class="w-4 h-4"></i> | |
| </button> | |
| <button onclick="maximizeWindow()" class="w-8 h-8 flex items-center justify-center hover:bg-gray-700 rounded transition-colors" title="Maximize"> | |
| <i data-feather="square" class="w-3 h-3"></i> | |
| </button> | |
| <button onclick="closeWindow()" class="w-8 h-8 flex items-center justify-center hover:bg-red-500 rounded transition-colors" title="Close"> | |
| <i data-feather="x" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Main App Container --> | |
| <div class="flex h-[calc(100vh-40px)]"> | |
| <!-- Sidebar Navigation --> | |
| <div class="w-64 bg-gray-900/50 border-r border-gray-800 flex flex-col"> | |
| <!-- Navigation Links --> | |
| <div class="p-4 space-y-2"> | |
| <a href="#" class="nav-item active"> | |
| <i data-feather="home" class="w-4 h-4"></i> | |
| <span>Dashboard</span> | |
| </a> | |
| <a href="#engine" class="nav-item"> | |
| <i data-feather="cpu" class="w-4 h-4"></i> | |
| <span>Trading Engine</span> | |
| </a> | |
| <a href="#followers" class="nav-item"> | |
| <i data-feather="users" class="w-4 h-4"></i> | |
| <span>Followers</span> | |
| </a> | |
| <a href="#logs" class="nav-item"> | |
| <i data-feather="file-text" class="w-4 h-4"></i> | |
| <span>Trade Logs</span> | |
| </a> | |
| <a href="#settings" class="nav-item"> | |
| <i data-feather="settings" class="w-4 h-4"></i> | |
| <span>Settings</span> | |
| </a> | |
| </div> | |
| <!-- Engine Status --> | |
| <div class="mt-auto p-4 border-t border-gray-800"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-sm text-gray-400">Engine Status</span> | |
| <div class="relative"> | |
| <div class="w-3 h-3 rounded-full bg-green-500 animate-pulse"></div> | |
| </div> | |
| </div> | |
| <button class="w-full py-2 px-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 rounded-lg font-medium text-sm transition-all duration-300 flex items-center justify-center gap-2"> | |
| <i data-feather="pause" class="w-3 h-3"></i> | |
| Pause Engine | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Main Content Area --> | |
| <div class="flex-1 overflow-y-auto"> | |
| <!-- Main Content --> | |
| <main class="container mx-auto px-6 py-6 max-w-7xl"> | |
| <!-- Quick Stats Bar --> | |
| <div class="grid grid-cols-1 md:grid-cols-4 gap-4 mb-6"> | |
| <div class="stat-card"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm text-gray-400">Uptime</p> | |
| <p class="text-2xl font-bold" id="metric-uptime">99.8%</p> | |
| </div> | |
| <i data-feather="activity" class="w-8 h-8 text-green-400"></i> | |
| </div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm text-gray-400">Active Followers</p> | |
| <p class="text-2xl font-bold" id="metric-followers">3</p> | |
| </div> | |
| <i data-feather="users" class="w-8 h-8 text-blue-400"></i> | |
| </div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm text-gray-400">Trades Today</p> | |
| <p class="text-2xl font-bold" id="metric-trades">42</p> | |
| </div> | |
| <i data-feather="trending-up" class="w-8 h-8 text-purple-400"></i> | |
| </div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="flex items-center justify-between"> | |
| <div> | |
| <p class="text-sm text-gray-400">Success Rate</p> | |
| <p class="text-2xl font-bold" id="metric-success">98.5%</p> | |
| </div> | |
| <i data-feather="check-circle" class="w-8 h-8 text-cyan-400"></i> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Architecture Overview --> | |
| <section class="mb-16"> | |
| <h2 class="text-3xl font-bold mb-8 text-center">Architectural Principles</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6"> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700 hover:border-cyan-500/50 transition-all duration-300"> | |
| <div class="w-12 h-12 rounded-lg bg-gradient-to-r from-cyan-700/30 to-cyan-900/30 flex items-center justify-center mb-4"> | |
| <i data-feather="cpu" class="w-6 h-6 text-cyan-300"></i> | |
| </div> | |
| <h3 class="text-xl font-bold mb-2">Modularity & Separation</h3> | |
| <p class="text-gray-300">Distinct logical components with clear boundaries and responsibilities.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700 hover:border-blue-500/50 transition-all duration-300"> | |
| <div class="w-12 h-12 rounded-lg bg-gradient-to-r from-blue-700/30 to-blue-900/30 flex items-center justify-center mb-4"> | |
| <i data-feather="refresh-cw" class="w-6 h-6 text-blue-300"></i> | |
| </div> | |
| <h3 class="text-xl font-bold mb-2">Idempotency</h3> | |
| <p class="text-gray-300">Restart-safe design prevents trade duplication through meticulous state tracking.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700 hover:border-purple-500/50 transition-all duration-300"> | |
| <div class="w-12 h-12 rounded-lg bg-gradient-to-r from-purple-700/30 to-purple-900/30 flex items-center justify-center mb-4"> | |
| <i data-feather="database" class="w-6 h-6 text-purple-300"></i> | |
| </div> | |
| <h3 class="text-xl font-bold mb-2">Persistence First</h3> | |
| <p class="text-gray-300">Atomic commits to SQLite before any subsequent action ensures data integrity.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700 hover:border-green-500/50 transition-all duration-300"> | |
| <div class="w-12 h-12 rounded-lg bg-gradient-to-r from-green-700/30 to-green-900/30 flex items-center justify-center mb-4"> | |
| <i data-feather="shield" class="w-6 h-6 text-green-300"></i> | |
| </div> | |
| <h3 class="text-xl font-bold mb-2">Security by Design</h3> | |
| <p class="text-gray-300">API keys encrypted at rest with verification of limited permissions.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Code Preview Section --> | |
| <section id="engine" class="mb-16"> | |
| <h2 class="text-3xl font-bold mb-8 text-center">Core Implementation</h2> | |
| <div class="bg-gradient-to-br from-gray-900 to-black rounded-2xl p-1 shadow-2xl"> | |
| <div class="bg-gradient-to-br from-gray-800 to-gray-900 rounded-2xl p-6"> | |
| <div class="flex items-center justify-between mb-6"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-3 h-3 rounded-full bg-red-500"></div> | |
| <div class="w-3 h-3 rounded-full bg-yellow-500"></div> | |
| <div class="w-3 h-3 rounded-full bg-green-500"></div> | |
| <span class="text-sm font-mono font-medium ml-2">spot_copy_trade/</span> | |
| </div> | |
| <div class="flex gap-2"> | |
| <button class="text-sm px-3 py-1 bg-gray-700 hover:bg-gray-600 rounded transition-colors duration-200" onclick="copyCode()"> | |
| <i data-feather="copy" class="w-3 h-3 inline mr-1"></i> Copy All | |
| </button> | |
| </div> | |
| </div> | |
| <!-- Code Tabs --> | |
| <div class="flex overflow-x-auto mb-4 border-b border-gray-700"> | |
| <button class="px-4 py-2 font-medium text-sm border-b-2 border-cyan-500 text-cyan-300 whitespace-nowrap" onclick="showTab('main')"> | |
| <i data-feather="play" class="w-3 h-3 inline mr-2"></i>main.py | |
| </button> | |
| <button class="px-4 py-2 font-medium text-sm text-gray-400 hover:text-gray-200 whitespace-nowrap" onclick="showTab('watcher')"> | |
| <i data-feather="eye" class="w-3 h-3 inline mr-2"></i>trade_watcher.py | |
| </button> | |
| <button class="px-4 py-2 font-medium text-sm text-gray-400 hover:text-gray-200 whitespace-nowrap" onclick="showTab('executor')"> | |
| <i data-feather="arrow-right-circle" class="w-3 h-3 inline mr-2"></i>trade_executor.py | |
| </button> | |
| <button class="px-4 py-2 font-medium text-sm text-gray-400 hover:text-gray-200 whitespace-nowrap" onclick="showTab('models')"> | |
| <i data-feather="database" class="w-3 h-3 inline mr-2"></i>models.py | |
| </button> | |
| <button class="px-4 py-2 font-medium text-sm text-gray-400 hover:text-gray-200 whitespace-nowrap" onclick="showTab('security')"> | |
| <i data-feather="lock" class="w-3 h-3 inline mr-2"></i>encryption.py | |
| </button> | |
| </div> | |
| <!-- Code Content --> | |
| <div id="code-container" class="overflow-hidden"> | |
| <pre id="main-tab" class="font-mono text-sm overflow-x-auto whitespace-pre p-4 bg-gray-900/50 rounded-lg"> | |
| <span class="text-green-400">### File: main.py</span> | |
| <span class="text-cyan-400"><b>#!/usr/bin/env python3</b></span> | |
| <span class="text-gray-500">"""Main entry point for SpotSync Alpha - Master-Follower Replication Engine"""</span> | |
| <span class="text-purple-400">import</span> logging | |
| <span class="text-purple-400">import</span> signal | |
| <span class="text-purple-400">import</span> sys | |
| <span class="text-purple-400">import</span> time | |
| <span class="text-purple-400">from</span> datetime <span class="text-purple-400">import</span> datetime | |
| <span class="text-purple-400">from</span> typing <span class="text-purple-400">import</span> Dict, Optional | |
| <span class="text-purple-400">from</span> database.models <span class="text-purple-400">import</span> init_db, SessionLocal | |
| <span class="text-purple-400">from</span> core.trade_watcher <span class="text-purple-400">import</span> TradeWatcher | |
| <span class="text-purple-400">from</span> core.trade_executor <span class="text-purple-400">import</span> TradeExecutor | |
| <span class="text-purple-400">from</span> config.settings <span class="text-purple-400">import</span> MASTER_API_CONFIG | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">TradingEngine</span>: | |
| <span class="text-gray-500">"""Orchestrates the complete trade replication lifecycle"""</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">__init__</span>(<span class="text-blue-400">self</span>, poll_interval: <span class="text-blue-400">int</span> = 30): | |
| <span class="text-blue-400">self</span>.running = <span class="text-blue-400">False</span> | |
| <span class="text-blue-400">self</span>.poll_interval = poll_interval | |
| <span class="text-blue-400">self</span>.logger = logging.getLogger(__name__) | |
| <span class="text-green-400"># Initialize components</span> | |
| init_db() | |
| <span class="text-blue-400">self</span>.trade_watcher = TradeWatcher(MASTER_API_CONFIG) | |
| <span class="text-blue-400">self</span>.trade_executor = TradeExecutor() | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">start</span>(<span class="text-blue-400">self</span>): | |
| <span class="text-gray-500">"""Start the main engine loop"""</span> | |
| <span class="text-blue-400">self</span>.running = <span class="text-blue-400">True</span> | |
| <span class="text-blue-400">self</span>.logger.info(<span class="text-pink-400">"🚀 SpotSync Alpha Engine starting..."</span>) | |
| <span class="text-blue-400">self</span>.setup_signal_handlers() | |
| <span class="text-green-400"># Main execution loop</span> | |
| <span class="text-purple-400">while</span> <span class="text-blue-400">self</span>.running: | |
| <span class="text-purple-400">try</span>: | |
| <span class="text-green-400"># Poll for new trades from master</span> | |
| new_trades = <span class="text-blue-400">self</span>.trade_watcher.poll_for_new_trades() | |
| <span class="text-purple-400">if</span> new_trades: | |
| <span class="text-blue-400">self</span>.logger.info(f<span class="text-pink-400">"📊 Detected {len(new_trades)} new master trades to replicate"</span>) | |
| <span class="text-green-400"># Execute each trade on all active followers</span> | |
| <span class="text-purple-400">for</span> trade <span class="text-purple-400">in</span> new_trades: | |
| <span class="text-blue-400">self</span>.trade_executor.execute_trade_on_followers(trade) | |
| <span class="text-green-400"># Sleep until next poll</span> | |
| time.sleep(<span class="text-blue-400">self</span>.poll_interval) | |
| <span class="text-purple-400">except</span> KeyboardInterrupt: | |
| <span class="text-blue-400">self</span>.logger.info(<span class="text-pink-400">"⚠️ Shutdown signal received"</span>) | |
| <span class="text-purple-400">break</span> | |
| <span class="text-purple-400">except</span> Exception <span class="text-purple-400">as</span> e: | |
| <span class="text-blue-400">self</span>.logger.error(f<span class="text-pink-400">"❌ Unexpected error in main loop: {e}"</span>, exc_info=<span class="text-blue-400">True</span>) | |
| time.sleep(<span class="text-blue-400">self</span>.poll_interval) <span class="text-green-400"># Don't crash on single error</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">setup_signal_handlers</span>(<span class="text-blue-400">self</span>): | |
| <span class="text-gray-500">"""Handle graceful shutdown on SIGINT/SIGTERM"""</span> | |
| signal.signal(signal.SIGINT, <span class="text-blue-400">self</span>.shutdown_handler) | |
| signal.signal(signal.SIGTERM, <span class="text-blue-400">self</span>.shutdown_handler) | |
| <span class="text-gray-500"># More code follows...</span> | |
| </pre> | |
| <pre id="watcher-tab" class="font-mono text-sm overflow-x-auto whitespace-pre p-4 bg-gray-900/50 rounded-lg hidden"> | |
| <span class="text-green-400">### File: core/trade_watcher.py</span> | |
| <span class="text-cyan-400"><b>#!/usr/bin/env python3</b></span> | |
| <span class="text-gray-500">"""Poll master account for executed trades and filter new ones"""</span> | |
| <span class="text-purple-400">import</span> logging | |
| <span class="text-purple-400">from</span> typing <span class="text-purple-400">import</span> List, Dict, Optional | |
| <span class="text-purple-400">from</span> datetime <span class="text-purple-400">import</span> datetime | |
| <span class="text-purple-400">import</span> requests | |
| <span class="text-purple-400">from</span> sqlalchemy.orm <span class="text-purple-400">import</span> Session | |
| <span class="text-purple-400">from</span> database.models <span class="text-purple-400">import</span> get_session, SystemState | |
| <span class="text-purple-400">from</span> config.settings <span class="text-purple-400">import</span> MASTER_API_CONFIG | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">TradeWatcher</span>: | |
| <span class="text-gray-500">"""Monitors master account for new executed trades"""</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">__init__</span>(<span class="text-blue-400">self</span>, master_config: Dict): | |
| <span class="text-blue-400">self</span>.master_config = master_config | |
| <span class="text-blue-400">self</span>.logger = logging.getLogger(__name__) | |
| <span class="text-blue-400">self</span>.base_url = <span class="text-pink-400">"https://api.binance.com/api/v3"</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">get_master_trades</span>(<span class="text-blue-400">self</span>) -> <span class="text-blue-400">List</span>[<span class="text-blue-400">Dict</span>]: | |
| <span class="text-gray-500">"""Fetch recent executed trades from master account"""</span> | |
| headers = { | |
| <span class="text-pink-400">'X-MBX-APIKEY'</span>: <span class="text-blue-400">self</span>.master_config[<span class="text-pink-400">'api_key'</span>] | |
| } | |
| params = { | |
| <span class="text-pink-400">'timestamp'</span>: int(datetime.now().timestamp() * 1000), | |
| <span class="text-pink-400">'recvWindow'</span>: 5000 | |
| } | |
| <span class="text-purple-400">try</span>: | |
| response = requests.get( | |
| f<span class="text-pink-400">"{self.base_url}/myTrades"</span>, | |
| headers=headers, | |
| params=params | |
| ) | |
| response.raise_for_status() | |
| <span class="text-purple-400">return</span> response.json() | |
| <span class="text-purple-400">except</span> requests.RequestException <span class="text-purple-400">as</span> e: | |
| <span class="text-blue-400">self</span>.logger.error(f<span class="text-pink-400">"🔴 Failed to fetch master trades: {e}"</span>) | |
| <span class="text-purple-400">return</span> [] | |
| <span class="text-gray-500"># More code follows...</span> | |
| </pre> | |
| <pre id="executor-tab" class="font-mono text-sm overflow-x-auto whitespace-pre p-4 bg-gray-900/50 rounded-lg hidden"> | |
| <span class="text-green-400">### File: core/trade_executor.py</span> | |
| <span class="text-cyan-400"><b>#!/usr/bin/env python3</b></span> | |
| <span class="text-gray-500">"""Execute trades on follower accounts with idempotency guarantees"""</span> | |
| <span class="text-purple-400">import</span> logging | |
| <span class="text-purple-400">import</span> hashlib | |
| <span class="text-purple-400">from</span> typing <span class="text-purple-400">import</span> List, Dict, Optional | |
| <span class="text-purple-400">from</span> decimal <span class="text-purple-400">import</span> Decimal | |
| <span class="text-purple-400">import</span> requests | |
| <span class="text-purple-400">from</span> sqlalchemy.orm <span class="text-purple-400">import</span> Session | |
| <span class="text-purple-400">from</span> database.models <span class="text-purple-400">import</span> get_session, Follower, ExecutionLog | |
| <span class="text-purple-400">from</span> security.encryption <span class="text-purple-400">import</span> decrypt_api_key | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">TradeExecutor</span>: | |
| <span class="text-gray-500">"""Handles trade execution on all active follower accounts"""</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">__init__</span>(<span class="text-blue-400">self</span>): | |
| <span class="text-blue-400">self</span>.logger = logging.getLogger(__name__) | |
| <span class="text-blue-400">self</span>.base_url = <span class="text-pink-400">"https://api.binance.com/api/v3"</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">execute_trade_on_followers</span>(<span class="text-blue-400">self</span>, master_trade: <span class="text-blue-400">Dict</span>): | |
| <span class="text-gray-500">"""Replicate a single master trade to all active followers"""</span> | |
| session = get_session() | |
| <span class="text-green-400"># Get all active followers</span> | |
| followers = session.query(Follower).filter( | |
| Follower.status == <span class="text-pink-400">'ACTIVE'</span> | |
| ).all() | |
| <span class="text-purple-400">if</span> <span class="text-purple-400">not</span> followers: | |
| <span class="text-blue-400">self</span>.logger.info(<span class="text-pink-400">"📭 No active followers found for trade execution"</span>) | |
| <span class="text-purple-400">return</span> | |
| <span class="text-green-400"># Execute trade on each follower (idempotently)</span> | |
| <span class="text-purple-400">for</span> follower <span class="text-purple-400">in</span> followers: | |
| self.execute_trade_for_follower(session, follower, master_trade) | |
| session.commit() | |
| <span class="text-gray-500"># More code follows...</span> | |
| </pre> | |
| <pre id="models-tab" class="font-mono text-sm overflow-x-auto whitespace-pre p-4 bg-gray-900/50 rounded-lg hidden"> | |
| <span class="text-green-400">### File: database/models.py</span> | |
| <span class="text-cyan-400"><b>#!/usr/bin/env python3</b></span> | |
| <span class="text-gray-500">"""SQLAlchemy models for tracking system state and follower accounts"""</span> | |
| <span class="text-purple-400">from</span> datetime <span class="text-purple-400">import</span> datetime | |
| <span class="text-purple-400">from</span> enum <span class="text-purple-400">import</span> Enum | |
| <span class="text-purple-400">from</span> sqlalchemy <span class="text-purple-400">import</span> ( | |
| create_engine, Column, Integer, String, | |
| DateTime, Boolean, Text, Float, JSON, | |
| Enum <span class="text-purple-400">as</span> SQLAlchemyEnum, ForeignKey, | |
| event | |
| ) | |
| <span class="text-purple-400">from</span> sqlalchemy.ext.declarative <span class="text-purple-400">import</span> declarative_base | |
| <span class="text-purple-400">from</span> sqlalchemy.orm <span class="text-purple-400">import</span> sessionmaker, Session, relationship | |
| <span class="text-green-400"># Database URL (SQLite for simplicity, production would use PostgreSQL)</span> | |
| DATABASE_URL = <span class="text-pink-400">"sqlite:///./spot_sync.db"</span> | |
| engine = create_engine( | |
| DATABASE_URL, | |
| connect_args={<span class="text-pink-400">"check_same_thread"</span>: <span class="text-blue-400">False</span>}, | |
| echo=<span class="text-blue-400">False</span> <span class="text-green-400"># Set to True for debugging SQL</span> | |
| ) | |
| SessionLocal = sessionmaker(autocommit=<span class="text-blue-400">False</span>, autoflush=<span class="text-blue-400">False</span>, bind=engine) | |
| Base = declarative_base() | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">FollowerStatus</span>(<span class="text-blue-400">str</span>, Enum): | |
| <span class="text-gray-500">"""Valid states for a follower account"""</span> | |
| ACTIVE = <span class="text-pink-400">"ACTIVE"</span> | |
| PAUSED = <span class="text-pink-400">"PAUSED"</span> | |
| DISABLED = <span class="text-pink-400">"DISABLED"</span> | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">Follower</span>(<span class="text-blue-400">Base</span>): | |
| <span class="text-gray-500">"""Tracks a follower Binance account"""</span> | |
| __tablename__ = <span class="text-pink-400">"followers"</span> | |
| <span class="text-green-400"># Core fields</span> | |
| id = Column(Integer, primary_key=<span class="text-blue-400">True</span>, autoincrement=<span class="text-blue-400">True</span>) | |
| name = Column(String(100), nullable=<span class="text-blue-400">False</span>) | |
| api_key_encrypted = Column(Text, nullable=<span class="text-blue-400">False</span>) | |
| api_secret_encrypted = Column(Text, nullable=<span class="text-blue-400">False</span>) | |
| <span class="text-green-400"># Follower configuration</span> | |
| allocation_rule = Column(JSON, nullable=<span class="text-blue-400">False</span>) <span class="text-green-400"># e.g., {"type": "percentage", "value": 50}</span> | |
| status = Column(SQLAlchemyEnum(FollowerStatus), nullable=<span class="text-blue-400">False</span>, default=FollowerStatus.ACTIVE) | |
| <span class="text-green-400"># Safety controls</span> | |
| max_consecutive_errors = Column(Integer, default=<span class="text-blue-400">5</span>) | |
| current_consecutive_errors = Column(Integer, default=<span class="text-blue-400">0</span>) | |
| auto_pause_on_errors = Column(Boolean, default=<span class="text-blue-400">True</span>) | |
| <span class="text-gray-500"># More fields follow...</span> | |
| </pre> | |
| <pre id="security-tab" class="font-mono text-sm overflow-x-auto whitespace-pre p-4 bg-gray-900/50 rounded-lg hidden"> | |
| <span class="text-green-400">### File: security/encryption.py</span> | |
| <span class="text-cyan-400"><b>#!/usr/bin/env python3</b></span> | |
| <span class="text-gray-500">"""Cryptographic functions for API key protection"""</span> | |
| <span class="text-purple-400">import</span> base64 | |
| <span class="text-purple-400">import</span> logging | |
| <span class="text-purple-400">import</span> os | |
| <span class="text-purple-400">from</span> typing <span class="text-purple-400">import</span> Optional | |
| <span class="text-purple-400">from</span> cryptography.fernet <span class="text-purple-400">import</span> Fernet | |
| <span class="text-purple-400">from</span> cryptography.hazmat.primitives <span class="text-purple-400">import</span> hashes | |
| <span class="text-purple-400">from</span> cryptography.hazmat.primitives.kdf.pbkdf2 <span class="text-purple-400">import</span> PBKDF2HMAC | |
| <span class="text-cyan-400">class</span> <span class="text-yellow-400">KeyVault</span>: | |
| <span class="text-gray-400">"""Manages encryption/decryption of sensitive API credentials"""</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">__init__</span>(<span class="text-blue-400">self</span>, master_password: <span class="text-blue-400">str</span>, salt: Optional[<span class="text-blue-400">bytes</span>] = <span class="text-blue-400">None</span>): | |
| <span class="text-blue-400">self</span>.master_password = master_password.encode() | |
| <span class="text-blue-400">self</span>.salt = salt <span class="text-purple-400">or</span> os.urandom(<span class="text-blue-400">16</span>) | |
| <span class="text-blue-400">self</span>.logger = logging.getLogger(__name__) | |
| <span class="text-green-400"># Derive a Fernet key from master password</span> | |
| kdf = PBKDF2HMAC( | |
| algorithm=hashes.SHA256(), | |
| length=<span class="text-blue-400">32</span>, | |
| salt=<span class="text-blue-400">self</span>.salt, | |
| iterations=100000, | |
| ) | |
| key = base64.urlsafe_b64encode(kdf.derive(<span class="text-blue-400">self</span>.master_password)) | |
| <span class="text-blue-400">self</span>.cipher = Fernet(key) | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">encrypt</span>(<span class="text-blue-400">self</span>, plaintext: <span class="text-blue-400">str</span>) -> <span class="text-blue-400">str</span>: | |
| <span class="text-gray-400">"""Encrypt a string and return base64 encoded ciphertext"""</span> | |
| <span class="text-purple-400">try</span>: | |
| encrypted_bytes = <span class="text-blue-400">self</span>.cipher.encrypt(plaintext.encode()) | |
| <span class="text-purple-400">return</span> base64.urlsafe_b64encode(encrypted_bytes).decode() | |
| <span class="text-purple-400">except</span> Exception <span class="text-purple-400">as</span> e: | |
| <span class="text-blue-400">self</span>.logger.error(f<span class="text-pink-400">"🔴 Encryption failed: {e}"</span>) | |
| <span class="text-purple-400">raise</span> | |
| <span class="text-purple-400">def</span> <span class="text-yellow-400">decrypt</span>(<span class="text-blue-400">self</span>, ciphertext_b64: <span class="text-blue-400">str</span>) -> <span class="text-blue-400">str</span>: | |
| <span class="text-gray-400">"""Decrypt a base64 encoded ciphertext and return the plaintext string"""</span> | |
| <span class="text-purple-400">try</span>: | |
| encrypted_bytes = base64.urlsafe_b64decode(ciphertext_b64.encode()) | |
| decrypted_bytes = <span class="text-blue-400">self</span>.cipher.decrypt(encrypted_bytes) | |
| <span class="text-purple-400">return</span> decrypted_bytes.decode() | |
| <span class="text-purple-400">except</span> Exception <span class="text-purple-400">as</span> e: | |
| <span class="text-blue-400">self</span>.logger.error(f<span class="text-pink-400">"🔴 Decryption failed: {e}"</span>) | |
| <span class="text-purple-400">raise</span> | |
| <span class="text-gray-400"># More functions follow...</span> | |
| </pre> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Contract Section --> | |
| <section class="mb-16"> | |
| <h2 class="text-3xl font-bold mb-8 text-center">Behavioral Contracts</h2> | |
| <div class="grid grid-cols-1 lg:grid-cols-2 gap-8"> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-8 rounded-2xl border border-blue-500/30"> | |
| <div class="flex items-start gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-blue-500/20 flex items-center justify-center flex-shrink-0"> | |
| <i data-feather="check-circle" class="w-5 h-5 text-blue-300"></i> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-2">Trade Trigger Contract</h3> | |
| <p class="text-gray-300 mb-4">A trade is copied <span class="text-green-400 font-semibold">if and only if</span> it appears as a new, successfully executed trade in the master's <code class="bg-gray-700 px-1 py-0.5 rounded">get_my_trades</code> endpoint. No other event (balance changes, transfers, deposits) shall ever trigger a trade.</p> | |
| <div class="text-sm font-mono text-gray-400 bg-gray-900/50 p-3 rounded"> | |
| if trade_id > last_processed_trade_id:<br/> | |
| replicate_trade(trade)<br/> | |
| else:<br/> | |
| ignore() # Idempotency guarantee | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-8 rounded-2xl border border-purple-500/30"> | |
| <div class="flex items-start gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-purple-500/20 flex items-center justify-center flex-shrink-0"> | |
| <i data-feather="percent" class="w-5 h-5 text-purple-300"></i> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-2">Allocation Contract</h3> | |
| <p class="text-gray-300 mb-4">Follower trades are sized proportionally based on a pre-configured rule (e.g., percentage of available capital). The system must perform a balance check before every single trade execution.</p> | |
| <div class="text-sm font-mono text-gray-400 bg-gray-900/50 p-3 rounded"> | |
| follower_quantity = (<br/> | |
| (follower_balance / master_balance)<br/> | |
| * allocation_percentage<br/> | |
| * master_quantity<br/> | |
| )<br/> | |
| assert follower_balance >= follower_quantity | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-8 rounded-2xl border border-cyan-500/30"> | |
| <div class="flex items-start gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-cyan-500/20 flex items-center justify-center flex-shrink-0"> | |
| <i data-feather="alert-triangle" class="w-5 h-5 text-cyan-300"></i> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-2">Error Handling Contract</h3> | |
| <p class="text-gray-300 mb-4">The failure of one follower must not impact others. Repeated critical errors automatically move followers to a <code class="bg-gray-700 px-1 py-0.5 rounded">PAUSED</code> state. The system logs all execution failures with specific reasons and proceeds gracefully.</p> | |
| <div class="text-sm font-mono text-gray-400 bg-gray-900/50 p-3 rounded"> | |
| if follower.current_consecutive_errors <br/> | |
| >= follower.max_consecutive_errors:<br/> | |
| follower.status = 'PAUSED'<br/> | |
| commit_to_database() | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-8 rounded-2xl border border-green-500/30"> | |
| <div class="flex items-start gap-4"> | |
| <div class="w-10 h-10 rounded-full bg-green-500/20 flex items-center justify-center flex-shrink-0"> | |
| <i data-feather="database" class="w-5 h-5 text-green-300"></i> | |
| </div> | |
| <div> | |
| <h3 class="text-xl font-bold mb-2">State Management Contract</h3> | |
| <p class="text-gray-300 mb-4">Follower accounts exist in well-defined states (<code class="bg-gray-700 px-1 py-0.5 rounded">ACTIVE</code>, <code class="bg-gray-700 px-1 py-0.5 rounded">PAUSED</code>, <code class="bg-gray-700 px-1 py-0.5 rounded">DISABLED</code>). Only <code class="bg-gray-700 px-1 py-0.5 rounded">ACTIVE</code> followers are included in the trade execution loop.</p> | |
| <div class="text-sm font-mono text-gray-400 bg-gray-900/50 p-3 rounded"> | |
| active_followers = [<br/> | |
| f for f in followers<br/> | |
| if f.status == 'ACTIVE'<br/> | |
| ]<br/> | |
| for follower in active_followers:<br/> | |
| execute_trade(follower) | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Dashboard Demo --> | |
| <section class="mb-16"> | |
| <h2 class="text-3xl font-bold mb-8 text-center">Follower Management Dashboard</h2> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 rounded-2xl overflow-hidden border border-gray-700"> | |
| <div class="p-6 border-b border-gray-700"> | |
| <div class="flex items-center justify-between"> | |
| <h3 class="text-xl font-bold">Active Followers</h3> | |
| <span class="px-3 py-1 bg-gray-700 rounded-full text-sm">3 followers</span> | |
| </div> | |
| </div> | |
| <div class="overflow-x-auto"> | |
| <table class="w-full"> | |
| <thead> | |
| <tr class="border-b border-gray-700"> | |
| <th class="text-left p-4">Name</th> | |
| <th class="text-left p-4">Status</th> | |
| <th class="text-left p-4">Allocation</th> | |
| <th class="text-left p-4">Last Trade</th> | |
| <th class="text-left p-4">Consecutive Errors</th> | |
| <th class="text-left p-4">Actions</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr class="border-b border-gray-700/50"> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-r from-cyan-500 to-blue-500"></div> | |
| <span class="font-medium">Alpha Trader</span> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <span class="px-3 py-1 rounded-full text-xs font-medium bg-green-500/20 text-green-300">ACTIVE</span> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium">75%</span> | |
| <div class="w-32 h-2 bg-gray-700 rounded-full overflow-hidden"> | |
| <div class="h-full bg-cyan-500 rounded-full" style="width: 75%"></div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="p-4 text-sm text-gray-300">2024-03-15 14:30:22</td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium text-green-300">0</span> | |
| <i data-feather="check" class="w-4 h-4 text-green-300"></i> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex gap-2"> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="pause" class="w-4 h-4"></i> | |
| </button> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="eye-off" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </td> | |
| </tr> | |
| <tr class="border-b border-gray-700/50"> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-r from-purple-500 to-pink-500"></div> | |
| <span class="font-medium">Beta Follower</span> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <span class="px-3 py-1 rounded-full text-xs font-medium bg-yellow-500/20 text-yellow-300">PAUSED</span> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium">50%</span> | |
| <div class="w-32 h-2 bg-gray-700 rounded-full overflow-hidden"> | |
| <div class="h-full bg-purple-500 rounded-full" style="width: 50%"></div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="p-4 text-sm text-gray-300">2024-03-14 09:15:07</td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium text-yellow-300">5</span> | |
| <i data-feather="alert-triangle" class="w-4 h-4 text-yellow-300"></i> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex gap-2"> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="play" class="w-4 h-4"></i> | |
| </button> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="eye-off" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </td> | |
| </tr> | |
| <tr> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-8 h-8 rounded-full bg-gradient-to-r from-blue-600 to-indigo-600"></div> | |
| <span class="font-medium">Gamma Investor</span> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <span class="px-3 py-1 rounded-full text-xs font-medium bg-red-500/20 text-red-300">DISABLED</span> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium">25%</span> | |
| <div class="w-32 h-2 bg-gray-700 rounded-full overflow-hidden"> | |
| <div class="h-full bg-blue-500 rounded-full" style="width: 25%"></div> | |
| </div> | |
| </div> | |
| </td> | |
| <td class="p-4 text-sm text-gray-300">2024-03-10 16:45:33</td> | |
| <td class="p-4"> | |
| <div class="flex items-center gap-2"> | |
| <span class="font-medium text-red-300">12</span> | |
| <i data-feather="x-circle" class="w-4 h-4 text-red-300"></i> | |
| </div> | |
| </td> | |
| <td class="p-4"> | |
| <div class="flex gap-2"> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="play" class="w-4 h-4"></i> | |
| </button> | |
| <button class="p-2 bg-gray-700 hover:bg-gray-600 rounded transition-colors"> | |
| <i data-feather="trash-2" class="w-4 h-4"></i> | |
| </button> | |
| </div> | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| <div class="p-6 border-t border-gray-700"> | |
| <div class="flex flex-wrap gap-4"> | |
| <div class="flex-1 min-w-[200px]"> | |
| <h4 class="font-bold mb-2">Add New Follower</h4> | |
| <p class="text-sm text-gray-300 mb-3">Secure API key import with encryption at rest</p> | |
| <button class="px-4 py-2 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 rounded-lg font-medium transition-all duration-300"> | |
| <i data-feather="user-plus" class="w-4 h-4 inline mr-2"></i> Add Follower | |
| </button> | |
| </div> | |
| <div class="flex-1 min-w-[200px]"> | |
| <h4 class="font-bold mb-2">System Health Check</h4> | |
| <p class="text-sm text-gray-300 mb-3">Verify master connection and follower statuses</p> | |
| <button class="px-4 py-2 bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-500 hover:to-emerald-500 rounded-lg font-medium transition-all duration-300"> | |
| <i data-feather="activity" class="w-4 h-4 inline mr-2"></i> Run Diagnostics | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Features Grid --> | |
| <section class="mb-16"> | |
| <div class="text-center mb-12"> | |
| <h2 class="text-3xl font-bold mb-4">Built for Financial Grade Reliability</h2> | |
| <p class="text-gray-300 max-w-2xl mx-auto">Every component is engineered to withstand failures, ensure data integrity, and maintain perfect idempotency.</p> | |
| </div> | |
| <div class="grid grid-cols-1 md:grid-cols-3 gap-6"> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="shield" class="w-5 h-5 text-green-400"></i> | |
| API Security Verification | |
| </h3> | |
| <p class="text-gray-300">Validates API keys don't have withdrawal permissions. Automatic detection and rejection of over-privileged credentials.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="repeat" class="w-5 h-5 text-cyan-400"></i> | |
| Restart-Safe Operation | |
| </h3> | |
| <p class="text-gray-300">Persistent tracking of last processed trade ID ensures duplicate trades are never executed, no matter how many restarts.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="alert-octagon" class="w-5 h-5 text-yellow-400"></i> | |
| Error Isolation & Recovery | |
| </h3> | |
| <p class="text-gray-300">Follower failures are isolated. The system automatically pauses problematic followers while continuing normal operation.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="trending-up" class="w-5 h-5 text-purple-400"></i> | |
| Real-time Performance Analytics | |
| </h3> | |
| <p class="text-gray-300">Comprehensive dashboards track latency, success rates, execution delays, and allocation efficiency across all followers.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="file-text" class="w-5 h-5 text-blue-400"></i> | |
| Full Audit Trail | |
| </h3> | |
| <p class="text-gray-300">Every trade, error, and state change is logged with timestamps, providing a complete, verifiable history for compliance.</p> | |
| </div> | |
| <div class="bg-gradient-to-br from-gray-800/50 to-gray-900/50 p-6 rounded-xl border border-gray-700"> | |
| <h3 class="text-xl font-bold mb-3 flex items-center gap-2"> | |
| <i data-feather="sliders" class="w-5 h-5 text-orange-400"></i> | |
| Dynamic Allocation Strategies | |
| </h3> | |
| <p class="text-gray-300">Supports multiple allocation models: fixed percentages, dynamic ratio adjustment, and equity-based scaling for sophisticated strategies.</p> | |
| </div> | |
| </div> | |
| </section> | |
| </main> | |
| <!-- Hero Section --> | |
| <section class="text-center mb-8"> | |
| <div class="inline-flex items-center gap-2 mb-4 px-4 py-2 bg-gradient-to-r from-cyan-500/20 to-blue-600/20 rounded-full border border-cyan-500/30"> | |
| <i data-feather="zap" class="w-4 h-4 text-cyan-300"></i> | |
| <span class="text-sm font-medium text-cyan-300">DESKTOP APPLICATION - v1.0.0</span> | |
| </div> | |
| <h1 class="text-4xl md:text-5xl font-bold mb-4 bg-clip-text text-transparent bg-gradient-to-r from-cyan-300 via-blue-300 to-purple-300 leading-tight"> | |
| SpotSync Alpha Desktop | |
| </h1> | |
| <p class="text-lg text-gray-300 mb-6 max-w-2xl mx-auto"> | |
| Master-Follower Replication Engine running locally on your machine. | |
| Full control, complete privacy, no cloud dependencies. | |
| </p> | |
| <div class="flex flex-wrap justify-center gap-4"> | |
| <button class="px-6 py-3 bg-gradient-to-r from-cyan-600 to-blue-600 hover:from-cyan-500 hover:to-blue-500 rounded-lg font-semibold transition-all duration-300 hover:shadow-lg hover:shadow-cyan-500/20 flex items-center gap-2"> | |
| <i data-feather="play" class="w-4 h-4"></i> | |
| Start Engine | |
| </button> | |
| <button class="px-6 py-3 bg-gradient-to-r from-gray-700 to-gray-800 hover:from-gray-600 hover:to-gray-700 rounded-lg font-semibold transition-all duration-300 border border-gray-600 hover:border-gray-500 flex items-center gap-2"> | |
| <i data-feather="user-plus" class="w-4 h-4"></i> | |
| Add Follower | |
| </button> | |
| <button class="px-6 py-3 bg-gradient-to-r from-green-600 to-emerald-600 hover:from-green-500 hover:to-emerald-500 rounded-lg font-semibold transition-all duration-300 flex items-center gap-2"> | |
| <i data-feather="download" class="w-4 h-4"></i> | |
| Export Logs | |
| </button> | |
| </div> | |
| </section> | |
| <!-- Architecture Overview (Shortened for desktop) --> | |
| <section class="mb-8"> | |
| <h2 class="text-2xl font-bold mb-6">System Overview</h2> | |
| <div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> | |
| <div class="feature-card"> | |
| <div class="w-10 h-10 rounded-lg bg-gradient-to-r from-cyan-700/30 to-cyan-900/30 flex items-center justify-center mb-3"> | |
| <i data-feather="cpu" class="w-5 h-5 text-cyan-300"></i> | |
| </div> | |
| <h3 class="text-lg font-bold mb-2">Local Execution</h3> | |
| <p class="text-sm text-gray-300">All processing happens locally on your machine. No data leaves your computer.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="w-10 h-10 rounded-lg bg-gradient-to-r from-blue-700/30 to-blue-900/30 flex items-center justify-center mb-3"> | |
| <i data-feather="shield" class="w-5 h-5 text-blue-300"></i> | |
| </div> | |
| <h3 class="text-lg font-bold mb-2">Enhanced Security</h3> | |
| <p class="text-sm text-gray-300">API keys encrypted with local keychain. No cloud storage of sensitive data.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="w-10 h-10 rounded-lg bg-gradient-to-r from-purple-700/30 to-purple-900/30 flex items-center justify-center mb-3"> | |
| <i data-feather="zap" class="w-5 h-5 text-purple-300"></i> | |
| </div> | |
| <h3 class="text-lg font-bold mb-2">System Tray</h3> | |
| <p class="text-sm text-gray-300">Run minimized in system tray. Get notifications for trades and alerts.</p> | |
| </div> | |
| <div class="feature-card"> | |
| <div class="w-10 h-10 rounded-lg bg-gradient-to-r from-green-700/30 to-green-900/30 flex items-center justify-center mb-3"> | |
| <i data-feather="database" class="w-5 h-5 text-green-300"></i> | |
| </div> | |
| <h3 class="text-lg font-bold mb-2">Local Database</h3> | |
| <p class="text-sm text-gray-300">SQLite database for trade history and configuration. Full audit trail.</p> | |
| </div> | |
| </div> | |
| </section> | |
| <!-- Main content continues... (The rest of the existing content will be here) --> | |
| </main> | |
| </div> | |
| </div> | |
| <!-- External Scripts --> | |
| <script src="script.js"></script> | |
| <script> | |
| feather.replace(); | |
| // Update navigation active state | |
| document.querySelectorAll('.nav-item').forEach(item => { | |
| item.addEventListener('click', function(e) { | |
| e.preventDefault(); | |
| document.querySelectorAll('.nav-item').forEach(i => i.classList.remove('active')); | |
| this.classList.add('active'); | |
| }); | |
| }); | |
| // Initialize tooltips for desktop | |
| document.querySelectorAll('[title]').forEach(el => { | |
| el.addEventListener('mouseenter', function() { | |
| // Tooltip implementation for desktop | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> |