feat: Implement ATR-based dynamic TP2 system and fix P&L calculation
- Add ATR-based dynamic TP2 scaling from 0.7% to 3.0% based on volatility - New config options: useAtrBasedTargets, atrMultiplierForTp2, minTp2Percent, maxTp2Percent - Enhanced settings UI with ATR controls and updated risk calculator - Fix external closure P&L calculation using unrealized P&L instead of volatile current price - Update execute and test endpoints to use calculateDynamicTp2() function - Maintain 25% runner system for capturing extended moves (4-5% targets) - Add environment variables for ATR-based configuration - Better P&L accuracy for manual position closures
This commit is contained in:
@@ -25,6 +25,12 @@ export interface TradingConfig {
|
||||
takeProfit2Percent: number // Positive number (e.g., 1.5)
|
||||
emergencyStopPercent: number // Hard stop (e.g., -2.0)
|
||||
|
||||
// ATR-based dynamic targets
|
||||
useAtrBasedTargets: boolean // Enable ATR-based TP2 scaling
|
||||
atrMultiplierForTp2: number // Multiply ATR by this for dynamic TP2 (e.g., 2.0)
|
||||
minTp2Percent: number // Minimum TP2 level regardless of ATR
|
||||
maxTp2Percent: number // Maximum TP2 level cap
|
||||
|
||||
// Dual Stop System (Advanced)
|
||||
useDualStops: boolean // Enable dual stop system
|
||||
softStopPercent: number // Soft stop trigger (e.g., -1.5)
|
||||
@@ -105,6 +111,12 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
|
||||
takeProfit2Percent: 1.5, // +1.5% price = +15% account gain (closes 50%)
|
||||
emergencyStopPercent: -2.0, // -2% hard stop = -20% account loss
|
||||
|
||||
// ATR-based dynamic targets (NEW)
|
||||
useAtrBasedTargets: true, // Enable ATR-based TP2 scaling for big moves
|
||||
atrMultiplierForTp2: 2.0, // TP2 = ATR × 2.0 (adapts to volatility)
|
||||
minTp2Percent: 0.7, // Minimum TP2 (safety floor)
|
||||
maxTp2Percent: 3.0, // Maximum TP2 (cap at 3% for 30% account gain)
|
||||
|
||||
// Dual Stop System
|
||||
useDualStops: false, // Disabled by default
|
||||
softStopPercent: -1.5, // Soft stop (TRIGGER_LIMIT)
|
||||
@@ -230,6 +242,36 @@ export function getPositionSizeForSymbol(symbol: string, baseConfig: TradingConf
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate dynamic TP2 level based on ATR (Average True Range)
|
||||
* Higher ATR = higher volatility = larger TP2 target to capture big moves
|
||||
*/
|
||||
export function calculateDynamicTp2(
|
||||
basePrice: number,
|
||||
atrValue: number,
|
||||
config: TradingConfig
|
||||
): number {
|
||||
if (!config.useAtrBasedTargets || !atrValue) {
|
||||
return config.takeProfit2Percent // Fall back to static TP2
|
||||
}
|
||||
|
||||
// Convert ATR to percentage of current price
|
||||
const atrPercent = (atrValue / basePrice) * 100
|
||||
|
||||
// Calculate dynamic TP2: ATR × multiplier
|
||||
const dynamicTp2 = atrPercent * config.atrMultiplierForTp2
|
||||
|
||||
// Apply min/max bounds
|
||||
const boundedTp2 = Math.max(
|
||||
config.minTp2Percent,
|
||||
Math.min(config.maxTp2Percent, dynamicTp2)
|
||||
)
|
||||
|
||||
console.log(`📊 ATR-based TP2: ATR=${atrValue.toFixed(4)} (${atrPercent.toFixed(2)}%) × ${config.atrMultiplierForTp2} = ${dynamicTp2.toFixed(2)}% → ${boundedTp2.toFixed(2)}% (bounded)`)
|
||||
|
||||
return boundedTp2
|
||||
}
|
||||
|
||||
// Validate trading configuration
|
||||
export function validateTradingConfig(config: TradingConfig): void {
|
||||
if (config.positionSize <= 0) {
|
||||
@@ -325,6 +367,21 @@ export function getConfigFromEnv(): Partial<TradingConfig> {
|
||||
takeProfit2SizePercent: process.env.TAKE_PROFIT_2_SIZE_PERCENT
|
||||
? parseFloat(process.env.TAKE_PROFIT_2_SIZE_PERCENT)
|
||||
: undefined,
|
||||
|
||||
// ATR-based dynamic targets
|
||||
useAtrBasedTargets: process.env.USE_ATR_BASED_TARGETS
|
||||
? process.env.USE_ATR_BASED_TARGETS === 'true'
|
||||
: undefined,
|
||||
atrMultiplierForTp2: process.env.ATR_MULTIPLIER_FOR_TP2
|
||||
? parseFloat(process.env.ATR_MULTIPLIER_FOR_TP2)
|
||||
: undefined,
|
||||
minTp2Percent: process.env.MIN_TP2_PERCENT
|
||||
? parseFloat(process.env.MIN_TP2_PERCENT)
|
||||
: undefined,
|
||||
maxTp2Percent: process.env.MAX_TP2_PERCENT
|
||||
? parseFloat(process.env.MAX_TP2_PERCENT)
|
||||
: undefined,
|
||||
|
||||
breakEvenTriggerPercent: process.env.BREAKEVEN_TRIGGER_PERCENT
|
||||
? parseFloat(process.env.BREAKEVEN_TRIGGER_PERCENT)
|
||||
: undefined,
|
||||
|
||||
Reference in New Issue
Block a user