feat: Add adaptive leverage controls to settings UI
Complete implementation of adaptive leverage configuration via web interface:
Frontend (app/settings/page.tsx):
- Added 4 fields to TradingSettings interface:
* USE_ADAPTIVE_LEVERAGE: boolean
* HIGH_QUALITY_LEVERAGE: number
* LOW_QUALITY_LEVERAGE: number
* QUALITY_LEVERAGE_THRESHOLD: number
- Added complete Adaptive Leverage section with:
* Purple-themed informational box explaining quality-based leverage
* Toggle switch for enabling/disabling (🎯 Enable Adaptive Leverage)
* Number inputs for high leverage (1-20), low leverage (1-20), threshold (80-100)
* Visual tier display showing leverage multipliers and position sizes
* Dynamic calculation based on $560 free collateral
Backend (app/api/settings/route.ts):
- GET handler: Load 4 adaptive leverage fields from environment variables
- POST handler: Save 4 adaptive leverage fields to .env file
- Proper type conversion (boolean from 'true', numbers from parseInt/parseFloat)
Visual Tier Display Example:
Below Threshold: Blocked (no trade)
Changes enable users to adjust leverage settings via web UI instead of
manually editing .env file and restarting container.
This commit is contained in:
@@ -127,6 +127,12 @@ export async function GET() {
|
|||||||
MIN_SIGNAL_QUALITY_SCORE_SHORT: parseInt(env.MIN_SIGNAL_QUALITY_SCORE_SHORT || env.MIN_SIGNAL_QUALITY_SCORE || '60'),
|
MIN_SIGNAL_QUALITY_SCORE_SHORT: parseInt(env.MIN_SIGNAL_QUALITY_SCORE_SHORT || env.MIN_SIGNAL_QUALITY_SCORE || '60'),
|
||||||
SLIPPAGE_TOLERANCE: parseFloat(env.SLIPPAGE_TOLERANCE || '1.0'),
|
SLIPPAGE_TOLERANCE: parseFloat(env.SLIPPAGE_TOLERANCE || '1.0'),
|
||||||
DRY_RUN: env.DRY_RUN === 'true',
|
DRY_RUN: env.DRY_RUN === 'true',
|
||||||
|
|
||||||
|
// Adaptive Leverage (Dec 1, 2025)
|
||||||
|
USE_ADAPTIVE_LEVERAGE: env.USE_ADAPTIVE_LEVERAGE === 'true',
|
||||||
|
HIGH_QUALITY_LEVERAGE: parseFloat(env.HIGH_QUALITY_LEVERAGE || '5'),
|
||||||
|
LOW_QUALITY_LEVERAGE: parseFloat(env.LOW_QUALITY_LEVERAGE || '1'),
|
||||||
|
QUALITY_LEVERAGE_THRESHOLD: parseInt(env.QUALITY_LEVERAGE_THRESHOLD || '95'),
|
||||||
}
|
}
|
||||||
|
|
||||||
return NextResponse.json(settings)
|
return NextResponse.json(settings)
|
||||||
@@ -196,6 +202,12 @@ export async function POST(request: NextRequest) {
|
|||||||
MIN_SIGNAL_QUALITY_SCORE_SHORT: settings.MIN_SIGNAL_QUALITY_SCORE_SHORT.toString(),
|
MIN_SIGNAL_QUALITY_SCORE_SHORT: settings.MIN_SIGNAL_QUALITY_SCORE_SHORT.toString(),
|
||||||
SLIPPAGE_TOLERANCE: settings.SLIPPAGE_TOLERANCE.toString(),
|
SLIPPAGE_TOLERANCE: settings.SLIPPAGE_TOLERANCE.toString(),
|
||||||
DRY_RUN: settings.DRY_RUN.toString(),
|
DRY_RUN: settings.DRY_RUN.toString(),
|
||||||
|
|
||||||
|
// Adaptive Leverage (Dec 1, 2025)
|
||||||
|
USE_ADAPTIVE_LEVERAGE: settings.USE_ADAPTIVE_LEVERAGE.toString(),
|
||||||
|
HIGH_QUALITY_LEVERAGE: settings.HIGH_QUALITY_LEVERAGE.toString(),
|
||||||
|
LOW_QUALITY_LEVERAGE: settings.LOW_QUALITY_LEVERAGE.toString(),
|
||||||
|
QUALITY_LEVERAGE_THRESHOLD: settings.QUALITY_LEVERAGE_THRESHOLD.toString(),
|
||||||
}
|
}
|
||||||
|
|
||||||
const success = updateEnvFile(updates)
|
const success = updateEnvFile(updates)
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ interface TradingSettings {
|
|||||||
MIN_ADX_INCREASE: number
|
MIN_ADX_INCREASE: number
|
||||||
MAX_PRICE_POSITION_FOR_SCALE: 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: number
|
||||||
|
|
||||||
// Safety
|
// Safety
|
||||||
MAX_DAILY_DRAWDOWN: number
|
MAX_DAILY_DRAWDOWN: number
|
||||||
MAX_TRADES_PER_HOUR: number
|
MAX_TRADES_PER_HOUR: number
|
||||||
@@ -468,6 +474,79 @@ export default function SettingsPage() {
|
|||||||
/>
|
/>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
{/* Adaptive Leverage */}
|
||||||
|
<Section title="⚡ Adaptive Leverage" description="Quality-based dynamic leverage adjustment">
|
||||||
|
<div className="mb-4 p-3 bg-purple-500/10 border border-purple-500/30 rounded-lg">
|
||||||
|
<p className="text-sm text-purple-400">
|
||||||
|
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.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center justify-between p-4 bg-slate-700/30 rounded-lg mb-4">
|
||||||
|
<div className="flex-1">
|
||||||
|
<div className="text-white font-medium mb-1">🎯 Enable Adaptive Leverage</div>
|
||||||
|
<div className="text-slate-400 text-sm">
|
||||||
|
Dynamically adjust leverage based on signal quality
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
onClick={() => updateSetting('USE_ADAPTIVE_LEVERAGE', !settings.USE_ADAPTIVE_LEVERAGE)}
|
||||||
|
className={`relative inline-flex h-8 w-14 items-center rounded-full transition-colors ${
|
||||||
|
settings.USE_ADAPTIVE_LEVERAGE ? 'bg-green-500' : 'bg-slate-600'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={`inline-block h-6 w-6 transform rounded-full bg-white transition-transform ${
|
||||||
|
settings.USE_ADAPTIVE_LEVERAGE ? 'translate-x-7' : 'translate-x-1'
|
||||||
|
}`}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<Setting
|
||||||
|
label="High Quality Leverage"
|
||||||
|
value={settings.HIGH_QUALITY_LEVERAGE}
|
||||||
|
onChange={(v) => updateSetting('HIGH_QUALITY_LEVERAGE', v)}
|
||||||
|
min={1}
|
||||||
|
max={20}
|
||||||
|
step={1}
|
||||||
|
description={`Leverage for exceptional signals (Quality ${settings.QUALITY_LEVERAGE_THRESHOLD}+ LONG, 90+ SHORT). Current: ${settings.HIGH_QUALITY_LEVERAGE}x leverage.`}
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label="Low Quality Leverage"
|
||||||
|
value={settings.LOW_QUALITY_LEVERAGE}
|
||||||
|
onChange={(v) => updateSetting('LOW_QUALITY_LEVERAGE', v)}
|
||||||
|
min={1}
|
||||||
|
max={20}
|
||||||
|
step={1}
|
||||||
|
description={`Leverage for borderline signals (Quality 90-${settings.QUALITY_LEVERAGE_THRESHOLD-1} LONG, 80-89 SHORT). Current: ${settings.LOW_QUALITY_LEVERAGE}x leverage.`}
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label="Quality Threshold"
|
||||||
|
value={settings.QUALITY_LEVERAGE_THRESHOLD}
|
||||||
|
onChange={(v) => updateSetting('QUALITY_LEVERAGE_THRESHOLD', v)}
|
||||||
|
min={80}
|
||||||
|
max={100}
|
||||||
|
step={1}
|
||||||
|
description="Minimum quality score for high-quality leverage tier (applies to LONG signals, SHORT uses 90+)."
|
||||||
|
/>
|
||||||
|
<div className="p-4 bg-slate-700/50 rounded-lg">
|
||||||
|
<div className="text-sm text-slate-300 mb-2">Leverage Tiers (with $560 collateral)</div>
|
||||||
|
<div className="space-y-2 text-xs">
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-slate-400">🔥 High Quality (Q{settings.QUALITY_LEVERAGE_THRESHOLD}+ LONG, Q90+ SHORT):</span>
|
||||||
|
<span className="text-green-400 font-bold">{settings.HIGH_QUALITY_LEVERAGE}x = ${(560 * settings.HIGH_QUALITY_LEVERAGE).toFixed(0)} position</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-slate-400">📊 Low Quality (Q90-{settings.QUALITY_LEVERAGE_THRESHOLD-1} LONG, Q80-89 SHORT):</span>
|
||||||
|
<span className="text-yellow-400 font-bold">{settings.LOW_QUALITY_LEVERAGE}x = ${(560 * settings.LOW_QUALITY_LEVERAGE).toFixed(0)} position</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-between">
|
||||||
|
<span className="text-slate-400">❌ Below Threshold:</span>
|
||||||
|
<span className="text-red-400 font-bold">Blocked (no trade)</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
{/* Risk Management */}
|
{/* Risk Management */}
|
||||||
<Section title="🛡️ Risk Management" description="Stop loss and take profit levels">
|
<Section title="🛡️ Risk Management" description="Stop loss and take profit levels">
|
||||||
<Setting
|
<Setting
|
||||||
|
|||||||
Reference in New Issue
Block a user