/** * Trading Bot Settings UI * * Beautiful interface for managing trading parameters */ 'use client' import { useState, useEffect } from 'react' interface TradingSettings { // Global fallback settings MAX_POSITION_SIZE_USD: number LEVERAGE: number USE_PERCENTAGE_SIZE: boolean // Per-symbol settings SOLANA_ENABLED: boolean SOLANA_POSITION_SIZE: number SOLANA_LEVERAGE: number SOLANA_USE_PERCENTAGE_SIZE: boolean ETHEREUM_ENABLED: boolean ETHEREUM_POSITION_SIZE: number ETHEREUM_LEVERAGE: number ETHEREUM_USE_PERCENTAGE_SIZE: boolean // Risk management STOP_LOSS_PERCENT: number TAKE_PROFIT_1_PERCENT: number TAKE_PROFIT_1_SIZE_PERCENT: number TAKE_PROFIT_2_PERCENT: number EMERGENCY_STOP_PERCENT: number BREAKEVEN_TRIGGER_PERCENT: number PROFIT_LOCK_TRIGGER_PERCENT: number PROFIT_LOCK_PERCENT: number USE_TRAILING_STOP: boolean TRAILING_STOP_PERCENT: number TRAILING_STOP_ATR_MULTIPLIER: number TRAILING_STOP_MIN_PERCENT: number TRAILING_STOP_MAX_PERCENT: number TRAILING_STOP_ACTIVATION: number // ATR-based Dynamic Targets USE_ATR_BASED_TARGETS: boolean ATR_MULTIPLIER_FOR_TP2: number MIN_TP2_PERCENT: number MAX_TP2_PERCENT: number // Position Scaling ENABLE_POSITION_SCALING: boolean MIN_SCALE_QUALITY_SCORE: number MIN_PROFIT_FOR_SCALE: number MAX_SCALE_MULTIPLIER: number SCALE_SIZE_PERCENT: number MIN_ADX_INCREASE: number MAX_PRICE_POSITION_FOR_SCALE: number // Adaptive Leverage (Quality-based) USE_ADAPTIVE_LEVERAGE: boolean HIGH_QUALITY_LEVERAGE: number LOW_QUALITY_LEVERAGE: number QUALITY_LEVERAGE_THRESHOLD_LONG: number // Quality threshold for LONG signals QUALITY_LEVERAGE_THRESHOLD_SHORT: number // Quality threshold for SHORT signals // Safety MAX_DAILY_DRAWDOWN: number MAX_TRADES_PER_HOUR: number MIN_TIME_BETWEEN_TRADES: number MIN_SIGNAL_QUALITY_SCORE: number MIN_SIGNAL_QUALITY_SCORE_LONG: number MIN_SIGNAL_QUALITY_SCORE_SHORT: number SLIPPAGE_TOLERANCE: number DRY_RUN: boolean } export default function SettingsPage() { const [settings, setSettings] = useState(null) const [loading, setLoading] = useState(true) const [saving, setSaving] = useState(false) const [restarting, setRestarting] = useState(false) const [testing, setTesting] = useState(false) const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null) const [collateral, setCollateral] = useState(560) // Dynamic collateral from Drift account useEffect(() => { loadSettings() loadCollateral() }, []) const loadCollateral = async () => { try { const response = await fetch('/api/drift/account-health') if (response.ok) { const data = await response.json() setCollateral(data.freeCollateral) console.log('✅ Loaded collateral from Drift:', data.freeCollateral) } else { console.warn('⚠️ Failed to load collateral, using fallback: 560') setCollateral(560) // Fallback if API fails } } catch (error) { console.error('❌ Error loading collateral:', error) setCollateral(560) // Fallback on error } } const loadSettings = async () => { try { const response = await fetch('/api/settings') const data = await response.json() setSettings(data) setLoading(false) } catch (error) { setMessage({ type: 'error', text: 'Failed to load settings' }) setLoading(false) } } const saveSettings = async () => { setSaving(true) setMessage(null) try { const response = await fetch('/api/settings', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(settings), }) if (response.ok) { setMessage({ type: 'success', text: 'Settings saved! Click "Restart Bot" to apply changes.' }) } else { setMessage({ type: 'error', text: 'Failed to save settings' }) } } catch (error) { setMessage({ type: 'error', text: 'Failed to save settings' }) } setSaving(false) } const restartBot = async () => { setRestarting(true) setMessage(null) try { const response = await fetch('/api/restart', { method: 'POST', }) if (response.ok) { setMessage({ type: 'success', text: 'Bot is restarting... Settings will be applied in ~10 seconds.' }) } else { setMessage({ type: 'error', text: 'Failed to restart bot. Please restart manually with: docker restart trading-bot' }) } } catch (error) { setMessage({ type: 'error', text: 'Failed to restart bot. Please restart manually with: docker restart trading-bot' }) } setRestarting(false) } const syncPositions = async () => { setLoading(true) setMessage(null) try { const response = await fetch('/api/trading/sync-positions', { method: 'POST', }) const data = await response.json() if (data.success) { const { results } = data let msg = '✅ Position sync complete! ' if (results.added.length > 0) msg += `Added: ${results.added.join(', ')}. ` if (results.removed.length > 0) msg += `Removed: ${results.removed.join(', ')}. ` if (results.unchanged.length > 0) msg += `Already tracking: ${results.unchanged.join(', ')}. ` if (results.errors.length > 0) msg += `⚠️ Errors: ${results.errors.length}` setMessage({ type: 'success', text: msg }) } else { setMessage({ type: 'error', text: `Sync failed: ${data.error || data.message}` }) } } catch (error) { setMessage({ type: 'error', text: `Sync failed: ${error instanceof Error ? error.message : 'Unknown error'}` }) } setLoading(false) } const testTrade = async (direction: 'long' | 'short', symbol: string = 'SOLUSDT') => { if (!confirm(`⚠️ This will execute a REAL ${direction.toUpperCase()} trade on ${symbol} with current settings. Continue?`)) { return } setTesting(true) setMessage(null) try { const response = await fetch('/api/trading/test', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ symbol: symbol, direction: direction, }), }) const data = await response.json() if (data.success) { const dualStopsMsg = data.useDualStops ? `Dual stops: Soft $${data.softStopPrice?.toFixed(4)} | Hard $${data.hardStopPrice?.toFixed(4)}` : `SL: $${data.stopLoss?.toFixed(4)}` setMessage({ type: 'success', text: `✅ ${symbol} ${direction.toUpperCase()} test trade executed! Size: $${data.positionSize?.toFixed(2)} | Entry: $${data.entryPrice?.toFixed(4)} | ${dualStopsMsg} | TX: ${data.positionId?.substring(0, 8)}...` }) } else { setMessage({ type: 'error', text: `Failed: ${data.error || data.message}` }) } } catch (error) { setMessage({ type: 'error', text: `Test trade failed: ${error instanceof Error ? error.message : 'Unknown error'}` }) } setTesting(false) } const updateSetting = (key: keyof TradingSettings, value: any) => { if (!settings) return setSettings({ ...settings, [key]: value }) } const calculateRisk = (baseSize?: number, leverage?: number) => { if (!settings) return null const size = baseSize ?? settings.MAX_POSITION_SIZE_USD const lev = leverage ?? settings.LEVERAGE const maxLoss = size * lev * (Math.abs(settings.STOP_LOSS_PERCENT) / 100) // Calculate gains/losses for risk calculator const tp1Gain = size * lev * (settings.TAKE_PROFIT_1_PERCENT / 100) * (settings.TAKE_PROFIT_1_SIZE_PERCENT / 100) const tp2RunnerSize = size * (1 - settings.TAKE_PROFIT_1_SIZE_PERCENT / 100) // Remaining % after TP1 const runnerPercent = 100 - settings.TAKE_PROFIT_1_SIZE_PERCENT // Calculate runner % for display // Use ATR-based TP2 if enabled, otherwise use static const tp2Percent = settings.USE_ATR_BASED_TARGETS ? `${settings.MIN_TP2_PERCENT}-${settings.MAX_TP2_PERCENT}% (ATR-based)` : `${settings.TAKE_PROFIT_2_PERCENT}% (static)` // For calculation, use max potential TP2 if ATR-based const tp2CalcPercent = settings.USE_ATR_BASED_TARGETS ? settings.MAX_TP2_PERCENT : settings.TAKE_PROFIT_2_PERCENT const runnerValue = tp2RunnerSize * lev * (tp2CalcPercent / 100) // Runner value at TP2 const fullWin = tp1Gain + runnerValue return { maxLoss, tp1Gain, runnerValue, fullWin, tp2Percent, runnerPercent } } if (loading) { return (
Loading settings...
) } if (!settings) return null const risk = calculateRisk() return (
{/* Header */}

⚙️ Trading Bot Settings

Configure your automated trading parameters

{/* Message */} {message && (
{message.text}
)} {/* Risk Calculator */} {risk && (

📊 Risk Calculator

Max Loss (SL)
-${risk.maxLoss.toFixed(2)}
TP1 Gain ({settings.TAKE_PROFIT_1_SIZE_PERCENT}%)
+${risk.tp1Gain.toFixed(2)}
Runner Value ({risk.runnerPercent}%)
+${risk.runnerValue.toFixed(2)}
{risk.tp2Percent}
Full Win
+${risk.fullWin.toFixed(2)}
Risk/Reward Ratio: 1:{(risk.fullWin / risk.maxLoss).toFixed(2)}
)} {/* Settings Sections */}
{/* Per-Symbol Position Sizing */}

Enable/disable Solana trading and set symbol-specific position sizing. When enabled, these settings override global defaults for SOL trades.

🟢 Enable Solana Trading
Accept SOL-PERP trade signals from TradingView
updateSetting('SOLANA_POSITION_SIZE', v)} min={1} max={settings.SOLANA_USE_PERCENTAGE_SIZE ? 100 : 10000} step={1} description={ settings.SOLANA_USE_PERCENTAGE_SIZE ? `Percentage of free collateral for SOL trades. With ${settings.SOLANA_LEVERAGE}x leverage.` : `Base capital for SOL trades. With ${settings.SOLANA_LEVERAGE}x leverage = $${(settings.SOLANA_POSITION_SIZE * settings.SOLANA_LEVERAGE).toFixed(0)} notional position.` } /> updateSetting('SOLANA_LEVERAGE', v)} min={1} max={20} step={1} description="Leverage multiplier for Solana positions only." /> {(() => { const solRisk = calculateRisk(settings.SOLANA_POSITION_SIZE, settings.SOLANA_LEVERAGE) return solRisk && (
SOL Risk/Reward
Max Loss: ${solRisk.maxLoss.toFixed(2)}
Full Win: ${solRisk.fullWin.toFixed(2)}
R:R 1:{(solRisk.fullWin / solRisk.maxLoss).toFixed(2)}
) })()}

Enable/disable Ethereum trading and set symbol-specific position sizing. When enabled, these settings override global defaults for ETH trades.

🟢 Enable Ethereum Trading
Accept ETH-PERP trade signals from TradingView
updateSetting('ETHEREUM_POSITION_SIZE', v)} min={1} max={settings.ETHEREUM_USE_PERCENTAGE_SIZE ? 100 : 10000} step={1} description={ settings.ETHEREUM_USE_PERCENTAGE_SIZE ? `Percentage of free collateral for ETH trades. With ${settings.ETHEREUM_LEVERAGE}x leverage.` : `Base capital for ETH trades. With ${settings.ETHEREUM_LEVERAGE}x leverage = $${(settings.ETHEREUM_POSITION_SIZE * settings.ETHEREUM_LEVERAGE).toFixed(0)} notional position. Drift minimum: ~$38-40 (0.01 ETH).` } /> updateSetting('ETHEREUM_LEVERAGE', v)} min={1} max={20} step={1} description="Leverage multiplier for Ethereum positions only." /> {(() => { const ethRisk = calculateRisk(settings.ETHEREUM_POSITION_SIZE, settings.ETHEREUM_LEVERAGE) return ethRisk && (
ETH Risk/Reward
Max Loss: ${ethRisk.maxLoss.toFixed(2)}
Full Win: ${ethRisk.fullWin.toFixed(2)}
R:R 1:{(ethRisk.fullWin / ethRisk.maxLoss).toFixed(2)}
) })()}
{/* Global Position Sizing (Fallback) */}

These are fallback values used for any symbol that doesn't have its own specific settings (like BTC-PERP). SOL and ETH ignore these when their own settings are configured above.

updateSetting('MAX_POSITION_SIZE_USD', v)} min={10} max={10000} step={10} description="Base USD amount per trade for unspecified symbols." /> updateSetting('LEVERAGE', v)} min={1} max={20} step={1} description="Leverage multiplier for unspecified symbols." />
{/* Adaptive Leverage */}

Automatically adjust leverage based on signal quality score. High-quality signals get more leverage for maximum profit, borderline signals use lower leverage for risk management.

🎯 Enable Adaptive Leverage
Dynamically adjust leverage based on signal quality
updateSetting('HIGH_QUALITY_LEVERAGE', v)} min={1} max={20} step={1} description={`Leverage for exceptional signals (Quality ${settings.QUALITY_LEVERAGE_THRESHOLD_LONG}+ LONG, ${settings.QUALITY_LEVERAGE_THRESHOLD_SHORT}+ SHORT). Current: ${settings.HIGH_QUALITY_LEVERAGE}x leverage.`} /> updateSetting('LOW_QUALITY_LEVERAGE', v)} min={1} max={20} step={1} description={`Leverage for borderline signals (Quality 90-${settings.QUALITY_LEVERAGE_THRESHOLD_LONG-1} LONG, 80-${settings.QUALITY_LEVERAGE_THRESHOLD_SHORT-1} SHORT). Current: ${settings.LOW_QUALITY_LEVERAGE}x leverage.`} /> updateSetting('QUALITY_LEVERAGE_THRESHOLD_LONG', v)} min={80} max={100} step={1} description="Minimum quality score for high-quality leverage tier on LONG signals." /> updateSetting('QUALITY_LEVERAGE_THRESHOLD_SHORT', v)} min={80} max={100} step={1} description="Minimum quality score for high-quality leverage tier on SHORT signals." />
Leverage Tiers (with ${collateral.toFixed(0)} collateral)
🔥 High Quality (Q{settings.QUALITY_LEVERAGE_THRESHOLD_LONG}+ LONG, Q{settings.QUALITY_LEVERAGE_THRESHOLD_SHORT}+ SHORT): {settings.HIGH_QUALITY_LEVERAGE}x = ${(collateral * settings.HIGH_QUALITY_LEVERAGE).toFixed(0)} position
📊 Low Quality (Q90-{settings.QUALITY_LEVERAGE_THRESHOLD_LONG-1} LONG, Q80-{settings.QUALITY_LEVERAGE_THRESHOLD_SHORT-1} SHORT): {settings.LOW_QUALITY_LEVERAGE}x = ${(collateral * settings.LOW_QUALITY_LEVERAGE).toFixed(0)} position
❌ Below Threshold: Blocked (no trade)
{/* Risk Management */}
updateSetting('STOP_LOSS_PERCENT', v)} min={-10} max={-0.1} step={0.1} description="Close 100% of position when price drops this much. Protects from large losses." /> updateSetting('TAKE_PROFIT_1_PERCENT', v)} min={0.1} max={10} step={0.1} description="Price level for first take profit exit." /> updateSetting('TAKE_PROFIT_1_SIZE_PERCENT', v)} min={1} max={100} step={1} description="What % of position to close at TP1. Example: 50 = close half." /> updateSetting('TAKE_PROFIT_2_PERCENT', v)} min={0.1} max={20} step={0.1} description="Price level where runner trailing stop activates (no close operation)." /> updateSetting('EMERGENCY_STOP_PERCENT', v)} min={-20} max={-0.1} step={0.1} description="Hard stop for flash crashes. Should be wider than regular SL." />
{/* ATR-based Dynamic Targets */}

🎯 Capture Big Moves: When ATR is high (volatile markets), TP2 automatically scales higher to catch 4-5% moves instead of exiting early at 0.7%.

Example: If ATR = 1.2% and multiplier = 2.0, then TP2 = 2.4% (instead of fixed 0.7%). Perfect for trending markets!

updateSetting('USE_ATR_BASED_TARGETS', v === 1)} min={0} max={1} step={1} description="Enable dynamic TP2 based on Average True Range (market volatility). 0 = fixed TP2, 1 = adaptive TP2." /> updateSetting('ATR_MULTIPLIER_FOR_TP2', v)} min={1.0} max={4.0} step={0.1} description="Multiply ATR by this value to get TP2 target. Higher = more aggressive targets in volatile markets." /> updateSetting('MIN_TP2_PERCENT', v)} min={0.3} max={2.0} step={0.1} description="Safety floor - TP2 will never go below this level even in low-volatility markets." /> updateSetting('MAX_TP2_PERCENT', v)} min={1.0} max={5.0} step={0.1} description="Safety cap - TP2 will never exceed this level. Example: 3.0% = 30% account gain at 10x leverage." />
{/* Dynamic Adjustments */}
updateSetting('BREAKEVEN_TRIGGER_PERCENT', v)} min={0} max={5} step={0.1} description="After TP1 closes, move SL to this profit level. Should be between 0% (breakeven) and TP1%. Example: 0.4% = locks in +4% account profit on remaining position." /> updateSetting('PROFIT_LOCK_TRIGGER_PERCENT', v)} min={0} max={10} step={0.1} description="After TP1, if price continues to this level, move SL higher to lock more profit. Must be > TP1 and < TP2." /> updateSetting('PROFIT_LOCK_PERCENT', v)} min={0} max={5} step={0.1} description="When Profit Lock Trigger hits, move SL to this profit level. Should be > Breakeven Trigger." />
{/* Trailing Stop */}

NEW SYSTEM: When TP2 price is hit, no position is closed. Instead, trailing stop activates on the full {100 - settings.TAKE_PROFIT_1_SIZE_PERCENT}% remaining position for maximum runner potential. Current split: {settings.TAKE_PROFIT_1_SIZE_PERCENT}% at TP1, {100 - settings.TAKE_PROFIT_1_SIZE_PERCENT}% becomes runner.

updateSetting('USE_TRAILING_STOP', v === 1)} min={0} max={1} step={1} description={`Enable trailing stop for ${100 - settings.TAKE_PROFIT_1_SIZE_PERCENT}% runner position when TP2 triggers. 0 = disabled, 1 = enabled.`} /> updateSetting('TRAILING_STOP_PERCENT', v)} min={0.1} max={2} step={0.1} description="Legacy fallback used only if ATR data is unavailable. Normally, ATR-based trailing is used instead." /> updateSetting('TRAILING_STOP_ATR_MULTIPLIER', v)} min={1.0} max={3.0} step={0.1} description="🔥 NEW: Trailing distance = (ATR × multiplier). Example: 0.5% ATR × 1.5 = 0.75% trailing. Higher = more room for runner, lower = tighter protection." /> updateSetting('TRAILING_STOP_MIN_PERCENT', v)} min={0.1} max={1.0} step={0.05} description="Minimum trailing distance cap. Prevents ultra-tight stops in low ATR conditions." /> updateSetting('TRAILING_STOP_MAX_PERCENT', v)} min={0.5} max={2.0} step={0.1} description="Maximum trailing distance cap. Prevents excessively wide stops in high ATR conditions." /> updateSetting('TRAILING_STOP_ACTIVATION', v)} min={0.1} max={5} step={0.1} description={`${100 - settings.TAKE_PROFIT_1_SIZE_PERCENT}% runner must reach this profit % before trailing stop activates. Prevents premature stops. Example: 0.5% = wait until runner is +0.5% profit.`} />
{/* Position Scaling */}

⚠️ Advanced Feature: Scale into existing profitable positions when high-quality signals confirm trend strength.

When enabled: Same-direction signals will ADD to position (not rejected) if quality ≥{settings?.MIN_SCALE_QUALITY_SCORE || 75}, profit ≥{settings?.MIN_PROFIT_FOR_SCALE || 0.4}%, ADX increased ≥{settings?.MIN_ADX_INCREASE || 5}, and price position <{settings?.MAX_PRICE_POSITION_FOR_SCALE || 70}%.

updateSetting('ENABLE_POSITION_SCALING', v === 1)} min={0} max={1} step={1} description="🔴 DISABLED by default. Enable to allow scaling into profitable positions. 0 = block duplicates (safe), 1 = allow scaling (aggressive)." /> updateSetting('MIN_SCALE_QUALITY_SCORE', v)} min={60} max={90} step={5} description="Scaling signal must score this high (0-100). Higher = more selective. Recommended: 75 (vs 60 for initial entry)." /> updateSetting('MIN_PROFIT_FOR_SCALE', v)} min={0} max={2} step={0.1} description="Position must be this profitable before scaling. Example: 0.4% = must be at/past TP1. NEVER scales into losing positions." /> updateSetting('SCALE_SIZE_PERCENT', v)} min={10} max={100} step={10} description="Add this % of original position size. Example: 50% = if original was $2100, scale adds $1050." /> updateSetting('MAX_SCALE_MULTIPLIER', v)} min={1} max={3} step={0.5} description="Max total position size after scaling. Example: 2.0 = can scale to 200% of original (original + 1 scale of 100%)." /> updateSetting('MIN_ADX_INCREASE', v)} min={0} max={15} step={1} description="ADX must increase by this much since entry. Example: 5 = if entered at ADX 15, scale requires ADX ≥20. Confirms trend strengthening." /> updateSetting('MAX_PRICE_POSITION_FOR_SCALE', v)} min={50} max={90} step={5} description="Don't scale if price is above this % of range. Example: 70% = blocks scaling near resistance. Prevents chasing." /> {/* Risk Calculator for Scaling */} {settings.ENABLE_POSITION_SCALING && (

📊 Scaling Impact (SOL Example)

Original Position: ${settings.SOLANA_POSITION_SIZE * settings.SOLANA_LEVERAGE}
Scale Addition ({settings.SCALE_SIZE_PERCENT}%): +${((settings.SOLANA_POSITION_SIZE * settings.SOLANA_LEVERAGE) * (settings.SCALE_SIZE_PERCENT / 100)).toFixed(0)}
Total After 1 Scale: ${((settings.SOLANA_POSITION_SIZE * settings.SOLANA_LEVERAGE) * (1 + settings.SCALE_SIZE_PERCENT / 100)).toFixed(0)}
Max Position ({settings.MAX_SCALE_MULTIPLIER}x): ${((settings.SOLANA_POSITION_SIZE * settings.SOLANA_LEVERAGE) * settings.MAX_SCALE_MULTIPLIER).toFixed(0)}
)}
{/* Trade Limits */}
updateSetting('MAX_DAILY_DRAWDOWN', v)} min={-1000} max={-10} step={10} description="Stop trading if daily loss exceeds this amount." /> updateSetting('MAX_TRADES_PER_HOUR', v)} min={1} max={20} step={1} description="Maximum number of trades allowed per hour." /> updateSetting('MIN_TIME_BETWEEN_TRADES', v)} min={0} max={60} step={1} description="Minimum wait time between trades to prevent overtrading." /> updateSetting('MIN_SIGNAL_QUALITY_SCORE', v)} min={0} max={100} step={5} description="Global fallback minimum quality score (used for BTC and other symbols). Direction-specific thresholds override this for SOL/ETH." /> updateSetting('MIN_SIGNAL_QUALITY_SCORE_LONG', v)} min={0} max={100} step={5} description="Minimum quality for LONG signals. Set to 90 based on data: quality 90-94 longs show 71.4% WR (+$44.77 profit)." /> updateSetting('MIN_SIGNAL_QUALITY_SCORE_SHORT', v)} min={0} max={100} step={5} description="Minimum quality for SHORT signals. Set to 95 based on data: quality 90-94 shorts show 28.6% WR (-$553.76 toxic). Blocks low-quality shorts." />
{/* Execution */}
updateSetting('SLIPPAGE_TOLERANCE', v)} min={0.1} max={5} step={0.1} description="Maximum acceptable price slippage on market orders." />
🧪 Dry Run Mode
Simulate trades without executing. Enable for testing.
{/* Action Buttons */}
{/* Primary Actions */}
{/* Test Trade Buttons */}
🧪 Test Trades (REAL MONEY)
💡 Save settings first, then click Restart Bot to apply changes
) } function Section({ title, description, children }: { title: string, description: string, children: React.ReactNode }) { return (

{title}

{description}

{children}
) } function Setting({ label, value, onChange, min, max, step, description }: { label: string value: number onChange: (value: number) => void min: number max: number step: number description: string }) { return (
onChange(parseFloat(e.target.value))} min={min} max={max} step={step} className="w-24 bg-slate-700 text-white px-3 py-2 rounded-lg border border-slate-600 focus:border-blue-500 focus:outline-none" />
onChange(parseFloat(e.target.value))} min={min} max={max} step={step} className="w-full h-2 bg-slate-700 rounded-lg appearance-none cursor-pointer slider" />

{description}

) }