feat: Add customizable TP size percentages and fix settings save
**New Features:** - Added TAKE_PROFIT_1_SIZE_PERCENT (default: 50%) - Added TAKE_PROFIT_2_SIZE_PERCENT (default: 50%) - Users can now control WHAT % to close at each TP level - Risk calculator now shows actual TP sizes dynamically **Bug Fixes:** - Fixed settings save failure by mounting .env file to container - Added .env volume mount in docker-compose.yml - Fixed permission issues (.env must be chmod 666) **UI Changes:** - Split TP controls into Price % and Size % - TP1 Price: When to exit first partial - TP1 Size: What % of position to close (1-100%) - TP2 Price: When to exit second partial - TP2 Size: What % of remaining to close (1-100%) - Risk calculator displays dynamic percentages **Example:** - TP1 at +1% price, close 60% of position - TP2 at +2% price, close 40% of remaining (24% of original) - Total exit: 84% of position at TP levels
This commit is contained in:
36
.env
36
.env
@@ -61,55 +61,63 @@ PYTH_HERMES_URL=https://hermes.pyth.network
|
|||||||
# Position sizing
|
# Position sizing
|
||||||
# Base position size in USD (default: 50 for safe testing)
|
# Base position size in USD (default: 50 for safe testing)
|
||||||
# Example: 50 with 10x leverage = $500 notional position
|
# Example: 50 with 10x leverage = $500 notional position
|
||||||
MAX_POSITION_SIZE_USD=50
|
MAX_POSITION_SIZE_USD=75
|
||||||
|
|
||||||
# Leverage multiplier (1-20, default: 10)
|
# Leverage multiplier (1-20, default: 10)
|
||||||
# Higher leverage = bigger gains AND bigger losses
|
# Higher leverage = bigger gains AND bigger losses
|
||||||
LEVERAGE=5
|
LEVERAGE=8
|
||||||
|
|
||||||
# Risk parameters (as percentages)
|
# Risk parameters (as percentages)
|
||||||
# Stop Loss: Close 100% of position when price drops this much
|
# Stop Loss: Close 100% of position when price drops this much
|
||||||
# Example: -1.5% on 10x = -15% account loss
|
# Example: -1.5% on 10x = -15% account loss
|
||||||
STOP_LOSS_PERCENT=-1.5
|
STOP_LOSS_PERCENT=-2
|
||||||
|
|
||||||
# Take Profit 1: Close 50% of position at this profit level
|
# Take Profit 1: Close 50% of position at this profit level
|
||||||
# Example: +0.7% on 10x = +7% account gain
|
# Example: +0.7% on 10x = +7% account gain
|
||||||
TAKE_PROFIT_1_PERCENT=0.7
|
TAKE_PROFIT_1_PERCENT=1
|
||||||
|
|
||||||
|
# Take Profit 1 Size: What % of position to close at TP1
|
||||||
|
# Example: 50 = close 50% of position
|
||||||
|
TAKE_PROFIT_1_SIZE_PERCENT=60
|
||||||
|
|
||||||
# Take Profit 2: Close remaining 50% at this profit level
|
# Take Profit 2: Close remaining 50% at this profit level
|
||||||
# Example: +1.5% on 10x = +15% account gain
|
# Example: +1.5% on 10x = +15% account gain
|
||||||
TAKE_PROFIT_2_PERCENT=1.5
|
TAKE_PROFIT_2_PERCENT=2
|
||||||
|
|
||||||
|
# Take Profit 2 Size: What % of remaining position to close at TP2
|
||||||
|
# Example: 100 = close all remaining position
|
||||||
|
TAKE_PROFIT_2_SIZE_PERCENT=40
|
||||||
|
|
||||||
# Emergency Stop: Hard stop if this level is breached
|
# Emergency Stop: Hard stop if this level is breached
|
||||||
# Example: -2.0% on 10x = -20% account loss (rare but protects from flash crashes)
|
# Example: -2.0% on 10x = -20% account loss (rare but protects from flash crashes)
|
||||||
EMERGENCY_STOP_PERCENT=-2.0
|
EMERGENCY_STOP_PERCENT=-3
|
||||||
|
|
||||||
# Dynamic stop-loss adjustments
|
# Dynamic stop-loss adjustments
|
||||||
# Move SL to breakeven when profit reaches this level
|
# Move SL to breakeven when profit reaches this level
|
||||||
BREAKEVEN_TRIGGER_PERCENT=0.4
|
BREAKEVEN_TRIGGER_PERCENT=0.5
|
||||||
|
|
||||||
# Lock in profit when price reaches this level
|
# Lock in profit when price reaches this level
|
||||||
PROFIT_LOCK_TRIGGER_PERCENT=1.0
|
PROFIT_LOCK_TRIGGER_PERCENT=1.2
|
||||||
|
|
||||||
# How much profit to lock (move SL to this profit level)
|
# How much profit to lock (move SL to this profit level)
|
||||||
PROFIT_LOCK_PERCENT=0.4
|
PROFIT_LOCK_PERCENT=0.5
|
||||||
|
|
||||||
# Risk limits
|
# Risk limits
|
||||||
# Stop trading if daily loss exceeds this amount (USD)
|
# Stop trading if daily loss exceeds this amount (USD)
|
||||||
# Example: -150 = stop trading after losing $150 in a day
|
# Example: -150 = stop trading after losing $150 in a day
|
||||||
MAX_DAILY_DRAWDOWN=-50
|
MAX_DAILY_DRAWDOWN=-100
|
||||||
|
|
||||||
# Maximum number of trades allowed per hour (prevents overtrading)
|
# Maximum number of trades allowed per hour (prevents overtrading)
|
||||||
MAX_TRADES_PER_HOUR=6
|
MAX_TRADES_PER_HOUR=8
|
||||||
|
|
||||||
# Minimum time between trades in seconds (cooldown period)
|
# Minimum time between trades in seconds (cooldown period)
|
||||||
# Example: 600 = 10 minutes between trades
|
# Example: 600 = 10 minutes between trades
|
||||||
MIN_TIME_BETWEEN_TRADES=600
|
MIN_TIME_BETWEEN_TRADES=300
|
||||||
|
|
||||||
# DEX execution settings
|
# DEX execution settings
|
||||||
# Maximum acceptable slippage on market orders (percentage)
|
# Maximum acceptable slippage on market orders (percentage)
|
||||||
# Example: 1.0 = accept up to 1% slippage
|
# Example: 1.0 = accept up to 1% slippage
|
||||||
SLIPPAGE_TOLERANCE=1.0
|
SLIPPAGE_TOLERANCE=1.5
|
||||||
|
|
||||||
# How often to check prices (milliseconds)
|
# How often to check prices (milliseconds)
|
||||||
# Example: 2000 = check every 2 seconds
|
# Example: 2000 = check every 2 seconds
|
||||||
@@ -229,7 +237,7 @@ DEBUG=drift:*,pyth:*,trading:*
|
|||||||
|
|
||||||
# Enable dry run mode (simulate trades without executing)
|
# Enable dry run mode (simulate trades without executing)
|
||||||
# Set to 'true' for testing without real money
|
# Set to 'true' for testing without real money
|
||||||
DRY_RUN=false
|
DRY_RUN=true
|
||||||
|
|
||||||
# API server port (default: 3000)
|
# API server port (default: 3000)
|
||||||
PORT=3000
|
PORT=3000
|
||||||
|
|||||||
@@ -66,7 +66,9 @@ export async function GET() {
|
|||||||
LEVERAGE: parseFloat(env.LEVERAGE || '5'),
|
LEVERAGE: parseFloat(env.LEVERAGE || '5'),
|
||||||
STOP_LOSS_PERCENT: parseFloat(env.STOP_LOSS_PERCENT || '-1.5'),
|
STOP_LOSS_PERCENT: parseFloat(env.STOP_LOSS_PERCENT || '-1.5'),
|
||||||
TAKE_PROFIT_1_PERCENT: parseFloat(env.TAKE_PROFIT_1_PERCENT || '0.7'),
|
TAKE_PROFIT_1_PERCENT: parseFloat(env.TAKE_PROFIT_1_PERCENT || '0.7'),
|
||||||
|
TAKE_PROFIT_1_SIZE_PERCENT: parseFloat(env.TAKE_PROFIT_1_SIZE_PERCENT || '50'),
|
||||||
TAKE_PROFIT_2_PERCENT: parseFloat(env.TAKE_PROFIT_2_PERCENT || '1.5'),
|
TAKE_PROFIT_2_PERCENT: parseFloat(env.TAKE_PROFIT_2_PERCENT || '1.5'),
|
||||||
|
TAKE_PROFIT_2_SIZE_PERCENT: parseFloat(env.TAKE_PROFIT_2_SIZE_PERCENT || '50'),
|
||||||
EMERGENCY_STOP_PERCENT: parseFloat(env.EMERGENCY_STOP_PERCENT || '-2.0'),
|
EMERGENCY_STOP_PERCENT: parseFloat(env.EMERGENCY_STOP_PERCENT || '-2.0'),
|
||||||
BREAKEVEN_TRIGGER_PERCENT: parseFloat(env.BREAKEVEN_TRIGGER_PERCENT || '0.4'),
|
BREAKEVEN_TRIGGER_PERCENT: parseFloat(env.BREAKEVEN_TRIGGER_PERCENT || '0.4'),
|
||||||
PROFIT_LOCK_TRIGGER_PERCENT: parseFloat(env.PROFIT_LOCK_TRIGGER_PERCENT || '1.0'),
|
PROFIT_LOCK_TRIGGER_PERCENT: parseFloat(env.PROFIT_LOCK_TRIGGER_PERCENT || '1.0'),
|
||||||
@@ -97,7 +99,9 @@ export async function POST(request: NextRequest) {
|
|||||||
LEVERAGE: settings.LEVERAGE.toString(),
|
LEVERAGE: settings.LEVERAGE.toString(),
|
||||||
STOP_LOSS_PERCENT: settings.STOP_LOSS_PERCENT.toString(),
|
STOP_LOSS_PERCENT: settings.STOP_LOSS_PERCENT.toString(),
|
||||||
TAKE_PROFIT_1_PERCENT: settings.TAKE_PROFIT_1_PERCENT.toString(),
|
TAKE_PROFIT_1_PERCENT: settings.TAKE_PROFIT_1_PERCENT.toString(),
|
||||||
|
TAKE_PROFIT_1_SIZE_PERCENT: settings.TAKE_PROFIT_1_SIZE_PERCENT.toString(),
|
||||||
TAKE_PROFIT_2_PERCENT: settings.TAKE_PROFIT_2_PERCENT.toString(),
|
TAKE_PROFIT_2_PERCENT: settings.TAKE_PROFIT_2_PERCENT.toString(),
|
||||||
|
TAKE_PROFIT_2_SIZE_PERCENT: settings.TAKE_PROFIT_2_SIZE_PERCENT.toString(),
|
||||||
EMERGENCY_STOP_PERCENT: settings.EMERGENCY_STOP_PERCENT.toString(),
|
EMERGENCY_STOP_PERCENT: settings.EMERGENCY_STOP_PERCENT.toString(),
|
||||||
BREAKEVEN_TRIGGER_PERCENT: settings.BREAKEVEN_TRIGGER_PERCENT.toString(),
|
BREAKEVEN_TRIGGER_PERCENT: settings.BREAKEVEN_TRIGGER_PERCENT.toString(),
|
||||||
PROFIT_LOCK_TRIGGER_PERCENT: settings.PROFIT_LOCK_TRIGGER_PERCENT.toString(),
|
PROFIT_LOCK_TRIGGER_PERCENT: settings.PROFIT_LOCK_TRIGGER_PERCENT.toString(),
|
||||||
@@ -127,3 +131,4 @@ export async function POST(request: NextRequest) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ interface TradingSettings {
|
|||||||
LEVERAGE: number
|
LEVERAGE: number
|
||||||
STOP_LOSS_PERCENT: number
|
STOP_LOSS_PERCENT: number
|
||||||
TAKE_PROFIT_1_PERCENT: number
|
TAKE_PROFIT_1_PERCENT: number
|
||||||
|
TAKE_PROFIT_1_SIZE_PERCENT: number
|
||||||
TAKE_PROFIT_2_PERCENT: number
|
TAKE_PROFIT_2_PERCENT: number
|
||||||
|
TAKE_PROFIT_2_SIZE_PERCENT: number
|
||||||
EMERGENCY_STOP_PERCENT: number
|
EMERGENCY_STOP_PERCENT: number
|
||||||
BREAKEVEN_TRIGGER_PERCENT: number
|
BREAKEVEN_TRIGGER_PERCENT: number
|
||||||
PROFIT_LOCK_TRIGGER_PERCENT: number
|
PROFIT_LOCK_TRIGGER_PERCENT: number
|
||||||
@@ -96,9 +98,9 @@ export default function SettingsPage() {
|
|||||||
const calculateRisk = () => {
|
const calculateRisk = () => {
|
||||||
if (!settings) return null
|
if (!settings) return null
|
||||||
const maxLoss = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (Math.abs(settings.STOP_LOSS_PERCENT) / 100)
|
const maxLoss = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (Math.abs(settings.STOP_LOSS_PERCENT) / 100)
|
||||||
const tp1Gain = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (settings.TAKE_PROFIT_1_PERCENT / 100)
|
const tp1Gain = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (settings.TAKE_PROFIT_1_PERCENT / 100) * (settings.TAKE_PROFIT_1_SIZE_PERCENT / 100)
|
||||||
const tp2Gain = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (settings.TAKE_PROFIT_2_PERCENT / 100)
|
const tp2Gain = settings.MAX_POSITION_SIZE_USD * settings.LEVERAGE * (settings.TAKE_PROFIT_2_PERCENT / 100) * (settings.TAKE_PROFIT_2_SIZE_PERCENT / 100)
|
||||||
const fullWin = tp1Gain / 2 + tp2Gain / 2 // 50% at each TP
|
const fullWin = tp1Gain + tp2Gain
|
||||||
|
|
||||||
return { maxLoss, tp1Gain, tp2Gain, fullWin }
|
return { maxLoss, tp1Gain, tp2Gain, fullWin }
|
||||||
}
|
}
|
||||||
@@ -143,12 +145,12 @@ export default function SettingsPage() {
|
|||||||
<div className="text-white text-2xl font-bold">-${risk.maxLoss.toFixed(2)}</div>
|
<div className="text-white text-2xl font-bold">-${risk.maxLoss.toFixed(2)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-blue-500/10 border border-blue-500/50 rounded-lg p-4">
|
<div className="bg-blue-500/10 border border-blue-500/50 rounded-lg p-4">
|
||||||
<div className="text-blue-400 text-sm mb-1">TP1 Gain (50%)</div>
|
<div className="text-blue-400 text-sm mb-1">TP1 Gain ({settings.TAKE_PROFIT_1_SIZE_PERCENT}%)</div>
|
||||||
<div className="text-white text-2xl font-bold">+${(risk.tp1Gain / 2).toFixed(2)}</div>
|
<div className="text-white text-2xl font-bold">+${risk.tp1Gain.toFixed(2)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-green-500/10 border border-green-500/50 rounded-lg p-4">
|
<div className="bg-green-500/10 border border-green-500/50 rounded-lg p-4">
|
||||||
<div className="text-green-400 text-sm mb-1">TP2 Gain (50%)</div>
|
<div className="text-green-400 text-sm mb-1">TP2 Gain ({settings.TAKE_PROFIT_2_SIZE_PERCENT}%)</div>
|
||||||
<div className="text-white text-2xl font-bold">+${(risk.tp2Gain / 2).toFixed(2)}</div>
|
<div className="text-white text-2xl font-bold">+${risk.tp2Gain.toFixed(2)}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-purple-500/10 border border-purple-500/50 rounded-lg p-4">
|
<div className="bg-purple-500/10 border border-purple-500/50 rounded-lg p-4">
|
||||||
<div className="text-purple-400 text-sm mb-1">Full Win</div>
|
<div className="text-purple-400 text-sm mb-1">Full Win</div>
|
||||||
@@ -197,22 +199,40 @@ export default function SettingsPage() {
|
|||||||
description="Close 100% of position when price drops this much. Protects from large losses."
|
description="Close 100% of position when price drops this much. Protects from large losses."
|
||||||
/>
|
/>
|
||||||
<Setting
|
<Setting
|
||||||
label="Take Profit 1 (%)"
|
label="Take Profit 1 Price (%)"
|
||||||
value={settings.TAKE_PROFIT_1_PERCENT}
|
value={settings.TAKE_PROFIT_1_PERCENT}
|
||||||
onChange={(v) => updateSetting('TAKE_PROFIT_1_PERCENT', v)}
|
onChange={(v) => updateSetting('TAKE_PROFIT_1_PERCENT', v)}
|
||||||
min={0.1}
|
min={0.1}
|
||||||
max={10}
|
max={10}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
description="Close 50% of position at this profit level. Locks in early gains."
|
description="Price level for first take profit exit."
|
||||||
/>
|
/>
|
||||||
<Setting
|
<Setting
|
||||||
label="Take Profit 2 (%)"
|
label="Take Profit 1 Size (%)"
|
||||||
|
value={settings.TAKE_PROFIT_1_SIZE_PERCENT}
|
||||||
|
onChange={(v) => 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."
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label="Take Profit 2 Price (%)"
|
||||||
value={settings.TAKE_PROFIT_2_PERCENT}
|
value={settings.TAKE_PROFIT_2_PERCENT}
|
||||||
onChange={(v) => updateSetting('TAKE_PROFIT_2_PERCENT', v)}
|
onChange={(v) => updateSetting('TAKE_PROFIT_2_PERCENT', v)}
|
||||||
min={0.1}
|
min={0.1}
|
||||||
max={20}
|
max={20}
|
||||||
step={0.1}
|
step={0.1}
|
||||||
description="Close remaining 50% at this profit level. Captures larger moves."
|
description="Price level for second take profit exit."
|
||||||
|
/>
|
||||||
|
<Setting
|
||||||
|
label="Take Profit 2 Size (%)"
|
||||||
|
value={settings.TAKE_PROFIT_2_SIZE_PERCENT}
|
||||||
|
onChange={(v) => updateSetting('TAKE_PROFIT_2_SIZE_PERCENT', v)}
|
||||||
|
min={1}
|
||||||
|
max={100}
|
||||||
|
step={1}
|
||||||
|
description="What % of remaining position to close at TP2. Example: 100 = close rest."
|
||||||
/>
|
/>
|
||||||
<Setting
|
<Setting
|
||||||
label="Emergency Stop (%)"
|
label="Emergency Stop (%)"
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ services:
|
|||||||
DRY_RUN: ${DRY_RUN:-false}
|
DRY_RUN: ${DRY_RUN:-false}
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
# Mount .env file for settings persistence
|
||||||
|
- ./.env:/app/.env
|
||||||
|
|
||||||
# Mount logs directory
|
# Mount logs directory
|
||||||
- ./logs:/app/logs
|
- ./logs:/app/logs
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user