| | |
| | """ |
| | FreqUI Setup Script for HF Spaces |
| | Downloads and configures FreqUI to work with our backend |
| | """ |
| |
|
| | import os |
| | import sys |
| | import shutil |
| | import requests |
| | import zipfile |
| | from pathlib import Path |
| | import subprocess |
| | import logging |
| |
|
| | logging.basicConfig(level=logging.INFO) |
| | logger = logging.getLogger(__name__) |
| |
|
| | class FreqUISetup: |
| | def __init__(self): |
| | self.app_dir = Path("/app") |
| | self.frequi_dir = self.app_dir / "frequi" |
| | self.dist_dir = self.frequi_dir / "dist" |
| | |
| | def setup_frequi(self): |
| | """Set up FreqUI for HF Spaces deployment""" |
| | logger.info("๐ฎ Setting up FreqUI for HF Spaces...") |
| | |
| | |
| | self.frequi_dir.mkdir(exist_ok=True) |
| | self.dist_dir.mkdir(exist_ok=True) |
| | |
| | |
| | self.create_minimal_frequi() |
| | |
| | logger.info("โ
FreqUI setup completed!") |
| | |
| | def create_minimal_frequi(self): |
| | """Create minimal FreqUI-compatible interface""" |
| | |
| | |
| | html_content = """ |
| | <!DOCTYPE html> |
| | <html lang="en"> |
| | <head> |
| | <meta charset="UTF-8"> |
| | <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| | <title>FreqUI - Freqtrade Web Interface</title> |
| | <style> |
| | * { margin: 0; padding: 0; box-sizing: border-box; } |
| | body { |
| | font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; |
| | background: #1a1a1a; |
| | color: #ffffff; |
| | overflow-x: hidden; |
| | } |
| | .container { |
| | max-width: 1400px; |
| | margin: 0 auto; |
| | padding: 20px; |
| | } |
| | .header { |
| | background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); |
| | padding: 20px; |
| | border-radius: 10px; |
| | margin-bottom: 20px; |
| | text-align: center; |
| | } |
| | .stats-grid { |
| | display: grid; |
| | grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); |
| | gap: 20px; |
| | margin-bottom: 30px; |
| | } |
| | .stat-card { |
| | background: #2d3748; |
| | padding: 20px; |
| | border-radius: 10px; |
| | border-left: 4px solid #48bb78; |
| | } |
| | .stat-value { |
| | font-size: 2em; |
| | font-weight: bold; |
| | color: #48bb78; |
| | } |
| | .stat-label { |
| | color: #a0aec0; |
| | margin-top: 5px; |
| | } |
| | .trades-table { |
| | background: #2d3748; |
| | border-radius: 10px; |
| | overflow: hidden; |
| | margin-bottom: 20px; |
| | } |
| | .table-header { |
| | background: #4a5568; |
| | padding: 15px 20px; |
| | font-weight: bold; |
| | } |
| | .trade-row { |
| | padding: 15px 20px; |
| | border-bottom: 1px solid #4a5568; |
| | display: grid; |
| | grid-template-columns: 1fr 1fr 1fr 1fr 1fr; |
| | gap: 20px; |
| | } |
| | .profit-positive { color: #48bb78; } |
| | .profit-negative { color: #f56565; } |
| | .status-indicator { |
| | width: 12px; |
| | height: 12px; |
| | border-radius: 50%; |
| | background: #48bb78; |
| | display: inline-block; |
| | margin-right: 10px; |
| | } |
| | .loading { |
| | text-align: center; |
| | padding: 40px; |
| | color: #a0aec0; |
| | } |
| | .demo-banner { |
| | background: linear-gradient(45deg, #ff6b6b, #feca57); |
| | color: #000; |
| | text-align: center; |
| | padding: 10px; |
| | font-weight: bold; |
| | margin-bottom: 20px; |
| | border-radius: 5px; |
| | } |
| | </style> |
| | </head> |
| | <body> |
| | <div class="demo-banner"> |
| | ๐ก๏ธ SECURE DEMO MODE - Educational Purpose Only - No Real Trading ๐ก๏ธ |
| | </div> |
| | |
| | <div class="container"> |
| | <div class="header"> |
| | <h1>๐ FreqUI - Freqtrade Dashboard</h1> |
| | <p>Real-time Trading Bot Interface</p> |
| | <div style="margin-top: 10px;"> |
| | <span class="status-indicator"></span> |
| | <strong>Bot Status: Running (Dry Run)</strong> |
| | </div> |
| | </div> |
| | |
| | <div class="stats-grid" id="stats-grid"> |
| | <div class="stat-card"> |
| | <div class="stat-value" id="balance">$10,000</div> |
| | <div class="stat-label">Total Balance</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-value" id="profit">+$1,250</div> |
| | <div class="stat-label">Total Profit</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-value" id="open-trades">3</div> |
| | <div class="stat-label">Open Trades</div> |
| | </div> |
| | <div class="stat-card"> |
| | <div class="stat-value" id="win-rate">68%</div> |
| | <div class="stat-label">Win Rate</div> |
| | </div> |
| | </div> |
| | |
| | <div class="trades-table"> |
| | <div class="table-header">๐ Recent Trades</div> |
| | <div id="trades-container" class="loading"> |
| | Loading trades... |
| | </div> |
| | </div> |
| | |
| | <div class="trades-table"> |
| | <div class="table-header">โ๏ธ Active Strategies</div> |
| | <div style="padding: 20px;"> |
| | <div style="margin-bottom: 15px;"> |
| | <strong>๐ฏ Supertrend Strategy</strong> - Trend following with dynamic support/resistance |
| | </div> |
| | <div style="margin-bottom: 15px;"> |
| | <strong>๐ MultiMA Strategy</strong> - Multiple moving average crossover system |
| | </div> |
| | <div style="margin-bottom: 15px;"> |
| | <strong>๐ค FreqAI Strategy</strong> - Machine learning predictions with LightGBM |
| | </div> |
| | </div> |
| | </div> |
| | </div> |
| | |
| | <script> |
| | // Simulate real-time data updates |
| | async function fetchData() { |
| | try { |
| | const response = await fetch('/api/v1/trades'); |
| | if (response.ok) { |
| | const trades = await response.json(); |
| | updateTradesTable(trades); |
| | } |
| | |
| | const statusResponse = await fetch('/api/v1/status'); |
| | if (statusResponse.ok) { |
| | const status = await statusResponse.json(); |
| | updateStats(status); |
| | } |
| | } catch (error) { |
| | console.log('Demo mode - using simulated data'); |
| | updateWithDemoData(); |
| | } |
| | } |
| | |
| | function updateTradesTable(trades) { |
| | const container = document.getElementById('trades-container'); |
| | const openTrades = trades.filter(t => t.is_open).slice(0, 10); |
| | |
| | if (openTrades.length === 0) { |
| | container.innerHTML = '<div style="padding: 20px; text-align: center;">No open trades</div>'; |
| | return; |
| | } |
| | |
| | container.innerHTML = openTrades.map(trade => ` |
| | <div class="trade-row"> |
| | <div><strong>${trade.pair}</strong></div> |
| | <div>${trade.strategy}</div> |
| | <div>$${trade.stake_amount}</div> |
| | <div class="${trade.profit_pct >= 0 ? 'profit-positive' : 'profit-negative'}"> |
| | ${trade.profit_pct >= 0 ? '+' : ''}${trade.profit_pct}% |
| | </div> |
| | <div>${new Date(trade.open_date).toLocaleTimeString()}</div> |
| | </div> |
| | `).join(''); |
| | } |
| | |
| | function updateStats(status) { |
| | document.getElementById('balance').textContent = `$${status.balance.toLocaleString()}`; |
| | document.getElementById('profit').textContent = `+$${status.profit.toLocaleString()}`; |
| | document.getElementById('open-trades').textContent = status.open_trades; |
| | } |
| | |
| | function updateWithDemoData() { |
| | // Demo data for when API is not available |
| | const demoTrades = [ |
| | { pair: 'BTC/USDT', strategy: 'Supertrend', stake_amount: 500, profit_pct: 2.3, open_date: new Date(), is_open: true }, |
| | { pair: 'ETH/USDT', strategy: 'MultiMA', stake_amount: 300, profit_pct: -0.5, open_date: new Date(), is_open: true }, |
| | { pair: 'ADA/USDT', strategy: 'FreqAI', stake_amount: 200, profit_pct: 1.8, open_date: new Date(), is_open: true } |
| | ]; |
| | updateTradesTable(demoTrades); |
| | } |
| | |
| | // Initial load and periodic updates |
| | fetchData(); |
| | setInterval(fetchData, 10000); // Update every 10 seconds |
| | |
| | // Show demo message |
| | setTimeout(() => { |
| | if (document.getElementById('trades-container').textContent.includes('Loading')) { |
| | updateWithDemoData(); |
| | } |
| | }, 2000); |
| | </script> |
| | </body> |
| | </html> |
| | """ |
| | |
| | |
| | with open(self.dist_dir / "index.html", "w", encoding="utf-8") as f: |
| | f.write(html_content) |
| | |
| | logger.info("โ
Created minimal FreqUI interface") |
| |
|
| | if __name__ == "__main__": |
| | setup = FreqUISetup() |
| | setup.setup_frequi() |