Files
trading_bot_v4/config/trading.ts
mindesbunister 17071fe7ec docs: Update minimum quality score from 60 to 81 across documentation
- Updated .github/copilot-instructions.md key constraints and signal quality system description
- Updated config/trading.ts minimum score from 60 to 81 with v8 performance rationale
- Updated SIGNAL_QUALITY_SETUP_GUIDE.md intro to reflect 81 threshold
- Updated SIGNAL_QUALITY_OPTIMIZATION_ROADMAP.md current system section
- Updated BLOCKED_SIGNALS_TRACKING.md quality score requirements

Context: After v8 Money Line indicator deployed with 0.6% flip threshold,
system achieving 66.7% win rate with average quality score 94.2. Raised
minimum threshold from 60 to 81 to maintain exceptional selectivity.

Current v8 stats: 6 trades, 4 wins, $649.32 profit, 94.2 avg quality
Account growth: $540 → $1,134.92 (110% gain in 2-3 days)
2025-11-21 15:49:26 +01:00

604 lines
23 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Trading Bot v4 - Configuration
*
* Optimized for 5-minute scalping with 10x leverage on Drift Protocol
*/
export interface SymbolSettings {
enabled: boolean
positionSize: number
leverage: number
usePercentageSize?: boolean // If true, positionSize is % of portfolio (0-100)
}
export interface TradingConfig {
// Position sizing (global fallback)
positionSize: number // USD amount to trade (or percentage if usePercentageSize=true)
leverage: number // Leverage multiplier
usePercentageSize: boolean // If true, positionSize is % of free collateral
// Per-symbol settings
solana?: SymbolSettings
ethereum?: SymbolSettings
// Risk management (as percentages of entry price - LEGACY, used as fallback)
stopLossPercent: number // Negative number (e.g., -1.5)
takeProfit1Percent: number // Positive number (e.g., 0.7)
takeProfit2Percent: number // Positive number (e.g., 1.5)
emergencyStopPercent: number // Hard stop (e.g., -2.0)
// ATR-based dynamic targets (NEW - PRIMARY SYSTEM)
useAtrBasedTargets: boolean // Enable ATR-based TP/SL (recommended)
atrMultiplierTp1: number // TP1 = ATR × this multiplier (e.g., 2.0)
atrMultiplierTp2: number // TP2 = ATR × this multiplier (e.g., 4.0)
atrMultiplierSl: number // SL = ATR × this multiplier (e.g., 3.0)
minTp1Percent: number // Minimum TP1 level (safety floor)
maxTp1Percent: number // Maximum TP1 level (cap)
minTp2Percent: number // Minimum TP2 level (safety floor)
maxTp2Percent: number // Maximum TP2 level (cap)
minSlPercent: number // Minimum SL distance (safety floor)
maxSlPercent: number // Maximum SL distance (cap)
// Dual Stop System (Advanced)
useDualStops: boolean // Enable dual stop system
softStopPercent: number // Soft stop trigger (e.g., -1.5)
softStopBuffer: number // Buffer for soft stop limit (e.g., 0.4)
hardStopPercent: number // Hard stop trigger (e.g., -2.5)
// Dynamic adjustments
profitLockAfterTP1Percent: number // Lock this % profit on remaining position after TP1
profitLockTriggerPercent: number // When to lock in profit
profitLockPercent: number // How much profit to lock
// Trailing stop for runner (after TP2)
useTrailingStop: boolean // Enable trailing stop for remaining position
trailingStopPercent: number // Legacy fixed trail percent (used as fallback)
trailingStopAtrMultiplier: number // Multiplier for ATR-based trailing distance
trailingStopMinPercent: number // Minimum trailing distance in percent
trailingStopMaxPercent: number // Maximum trailing distance in percent
trailingStopActivation: number // Activate when runner profits exceed this %
// Signal Quality
minSignalQualityScore: number // Minimum quality score for initial entry (0-100)
// Position Scaling (add to winning positions)
enablePositionScaling: boolean // Allow scaling into existing positions
minScaleQualityScore: number // Minimum quality score for scaling signal (0-100)
minProfitForScale: number // Position must be this % profitable to scale
maxScaleMultiplier: number // Max total position size (e.g., 2.0 = 200% of original)
scaleSizePercent: number // Scale size as % of original position (e.g., 50)
minAdxIncrease: number // ADX must increase by this much for scaling
maxPricePositionForScale: number // Don't scale if price position above this %
// DEX specific
priceCheckIntervalMs: number // How often to check prices
slippageTolerance: number // Max acceptable slippage (%)
// Risk limits
maxDailyDrawdown: number // USD stop trading threshold
maxTradesPerHour: number // Limit overtrading
minTimeBetweenTrades: number // Cooldown period (minutes)
// Execution
useMarketOrders: boolean // true = instant execution
confirmationTimeout: number // Max time to wait for confirmation
// Take profit size splits (percentages of position to close at TP1/TP2)
takeProfit1SizePercent: number
takeProfit2SizePercent: number
}
export interface MarketConfig {
symbol: string // e.g., 'SOL-PERP'
driftMarketIndex: number
pythPriceFeedId: string
minOrderSize: number
tickSize: number
// Position sizing overrides (optional)
positionSize?: number
leverage?: number
}
// Default configuration for 5-minute scalping with $1000 capital and 10x leverage
export const DEFAULT_TRADING_CONFIG: TradingConfig = {
// Position sizing (global fallback)
positionSize: 50, // $50 base capital (SAFE FOR TESTING) OR percentage if usePercentageSize=true
leverage: 10, // 10x leverage = $500 position size
usePercentageSize: false, // False = fixed USD, True = percentage of portfolio
// Per-symbol settings
solana: {
enabled: true,
positionSize: 210, // $210 base capital OR percentage if usePercentageSize=true
leverage: 10, // 10x leverage = $2100 notional
usePercentageSize: false,
},
ethereum: {
enabled: true,
positionSize: 4, // $4 base capital (DATA ONLY - minimum size)
leverage: 1, // 1x leverage = $4 notional
usePercentageSize: false,
},
// Risk parameters (LEGACY FALLBACK - used when ATR unavailable)
stopLossPercent: -1.5, // Fallback: -1.5% if no ATR
takeProfit1Percent: 0.8, // Fallback: +0.8% if no ATR
takeProfit2Percent: 1.8, // Fallback: +1.8% if no ATR
emergencyStopPercent: -2.0, // Emergency hard stop (always active)
// ATR-based dynamic targets (PRIMARY SYSTEM - Nov 17, 2025)
useAtrBasedTargets: true, // Enable ATR-based TP/SL for regime-agnostic trading
atrMultiplierTp1: 2.0, // TP1 = ATR × 2.0 (Example: 0.45% ATR = 0.90% TP1)
atrMultiplierTp2: 4.0, // TP2 = ATR × 4.0 (Example: 0.45% ATR = 1.80% TP2)
atrMultiplierSl: 3.0, // SL = ATR × 3.0 (Example: 0.45% ATR = 1.35% SL)
minTp1Percent: 0.5, // Floor: Never below +0.5%
maxTp1Percent: 1.5, // Cap: Never above +1.5%
minTp2Percent: 1.0, // Floor: Never below +1.0%
maxTp2Percent: 3.0, // Cap: Never above +3.0%
minSlPercent: 0.8, // Floor: Never tighter than -0.8%
maxSlPercent: 2.0, // Cap: Never wider than -2.0%
// Dual Stop System
useDualStops: false, // Disabled by default
softStopPercent: -1.5, // Soft stop (TRIGGER_LIMIT)
softStopBuffer: 0.4, // 0.4% buffer (limit at -1.9%)
hardStopPercent: -2.5, // Hard stop (TRIGGER_MARKET)
// Dynamic adjustments
profitLockAfterTP1Percent: 0.4, // Lock this % profit on remaining position after TP1
profitLockTriggerPercent: 1.0, // Lock profit at +1.0%
profitLockPercent: 0.4, // Lock +0.4% profit
// Trailing stop for runner (after TP2)
useTrailingStop: true, // Enable trailing stop for remaining position after TP2
trailingStopPercent: 0.3, // Legacy fallback (%, used if ATR data unavailable)
trailingStopAtrMultiplier: 1.5, // Trail ~1.5x ATR (converted to % of price)
trailingStopMinPercent: 0.25, // Never trail tighter than 0.25%
trailingStopMaxPercent: 0.9, // Cap trailing distance at 0.9%
trailingStopActivation: 0.5, // Activate trailing when runner is +0.5% in profit
// Signal Quality
minSignalQualityScore: 81, // Minimum quality score for initial entry (raised from 60 on Nov 21, 2025 - v8 averaging 94.2 with 66.7% WR)
// Position Scaling (conservative defaults)
enablePositionScaling: false, // Disabled by default - enable after testing
minScaleQualityScore: 75, // Only scale with strong signals (vs 65 for initial entry)
minProfitForScale: 0.4, // Position must be at/past TP1 to scale
maxScaleMultiplier: 2.0, // Max 2x original position size total
scaleSizePercent: 50, // Scale with 50% of original position size
minAdxIncrease: 5, // ADX must increase by 5+ points (trend strengthening)
maxPricePositionForScale: 70, // Don't scale if price >70% of range (near resistance)
// DEX settings
priceCheckIntervalMs: 2000, // Check every 2 seconds
slippageTolerance: 1.0, // 1% max slippage on market orders
// Risk limits
maxDailyDrawdown: -150, // Stop trading if daily loss exceeds $150 (-15%)
maxTradesPerHour: 6, // Max 6 trades per hour
minTimeBetweenTrades: 10, // 10 minutes cooldown
// Execution
useMarketOrders: true, // Use market orders for reliable fills
confirmationTimeout: 30000, // 30 seconds max wait
// Position sizing (percentages of position to close at each TP)
takeProfit1SizePercent: 75, // Close 75% at TP1 (leaves 25% for TP2 + runner)
takeProfit2SizePercent: 0, // Don't close at TP2 - let full 25% remaining become the runner
}
// Supported markets on Drift Protocol
export const SUPPORTED_MARKETS: Record<string, MarketConfig> = {
'SOL-PERP': {
symbol: 'SOL-PERP',
driftMarketIndex: 0,
pythPriceFeedId: '0xef0d8b6fda2ceba41da15d4095d1da392a0d2f8ed0c6c7bc0f4cfac8c280b56d',
minOrderSize: 0.1, // 0.1 SOL minimum
tickSize: 0.0001,
// Use default config values (positionSize: 50, leverage: 10)
},
'BTC-PERP': {
symbol: 'BTC-PERP',
driftMarketIndex: 1,
pythPriceFeedId: '0xe62df6c8b4a85fe1a67db44dc12de5db330f7ac66b72dc658afedf0f4a415b43',
minOrderSize: 0.001, // 0.001 BTC minimum
tickSize: 0.01,
// Use default config values
},
'ETH-PERP': {
symbol: 'ETH-PERP',
driftMarketIndex: 2,
pythPriceFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
minOrderSize: 0.001, // 0.001 ETH minimum (actual Drift minimum ~$4 at $4000/ETH)
tickSize: 0.01,
// DATA COLLECTION MODE: Minimal risk
positionSize: 40, // $40 base capital
leverage: 1, // 1x leverage = $40 total exposure
},
}
// Map TradingView symbols to Drift markets
export function normalizeTradingViewSymbol(tvSymbol: string): string {
const upper = tvSymbol.toUpperCase()
if (upper.includes('SOL')) return 'SOL-PERP'
if (upper.includes('BTC')) return 'BTC-PERP'
if (upper.includes('ETH')) return 'ETH-PERP'
// Default to SOL if unknown
console.warn(`Unknown symbol ${tvSymbol}, defaulting to SOL-PERP`)
return 'SOL-PERP'
}
// Get market configuration
export function getMarketConfig(symbol: string): MarketConfig {
const config = SUPPORTED_MARKETS[symbol]
if (!config) {
throw new Error(`Unsupported market: ${symbol}`)
}
return config
}
// Get position size for specific symbol (prioritizes per-symbol config)
export function getPositionSizeForSymbol(symbol: string, baseConfig: TradingConfig): { size: number; leverage: number; enabled: boolean } {
// Check per-symbol settings first
if (symbol === 'SOL-PERP' && baseConfig.solana) {
return {
size: baseConfig.solana.positionSize,
leverage: baseConfig.solana.leverage,
enabled: baseConfig.solana.enabled,
}
}
if (symbol === 'ETH-PERP' && baseConfig.ethereum) {
return {
size: baseConfig.ethereum.positionSize,
leverage: baseConfig.ethereum.leverage,
enabled: baseConfig.ethereum.enabled,
}
}
// Fallback to market-specific config, then global config
const marketConfig = getMarketConfig(symbol)
return {
size: marketConfig.positionSize ?? baseConfig.positionSize,
leverage: marketConfig.leverage ?? baseConfig.leverage,
enabled: true, // BTC or other markets default to enabled
}
}
/**
* Calculate actual USD position size from percentage or fixed amount
* @param configuredSize - The configured size (USD or percentage)
* @param usePercentage - Whether configuredSize is a percentage
* @param freeCollateral - Available collateral in USD (from Drift account)
* @returns Actual USD size to use for the trade
*/
export function calculateActualPositionSize(
configuredSize: number,
usePercentage: boolean,
freeCollateral: number
): number {
if (!usePercentage) {
// Fixed USD amount
return configuredSize
}
// Percentage of free collateral
let percentDecimal = configuredSize / 100
// CRITICAL: Safety buffer for 100% positions
// Drift's margin calculation includes fees and buffer, so 100% exact causes InsufficientCollateral
// Use 99% when user configures 100% to leave room for fees/slippage
if (configuredSize >= 100) {
percentDecimal = 0.99
console.log(`⚠️ Applying 99% safety buffer for 100% position (prevents InsufficientCollateral from fees/slippage)`)
}
const calculatedSize = freeCollateral * percentDecimal
console.log(`📊 Percentage sizing: ${configuredSize}% of $${freeCollateral.toFixed(2)} = $${calculatedSize.toFixed(2)}`)
return calculatedSize
}
/**
* Get actual position size for symbol with percentage support
* This is the main function to use when opening positions
*/
export async function getActualPositionSizeForSymbol(
symbol: string,
baseConfig: TradingConfig,
freeCollateral: number
): Promise<{ size: number; leverage: number; enabled: boolean; usePercentage: boolean }> {
let symbolSettings: { size: number; leverage: number; enabled: boolean }
let usePercentage = false
// Get symbol-specific settings
if (symbol === 'SOL-PERP' && baseConfig.solana) {
symbolSettings = {
size: baseConfig.solana.positionSize,
leverage: baseConfig.solana.leverage,
enabled: baseConfig.solana.enabled,
}
usePercentage = baseConfig.solana.usePercentageSize ?? false
} else if (symbol === 'ETH-PERP' && baseConfig.ethereum) {
symbolSettings = {
size: baseConfig.ethereum.positionSize,
leverage: baseConfig.ethereum.leverage,
enabled: baseConfig.ethereum.enabled,
}
usePercentage = baseConfig.ethereum.usePercentageSize ?? false
} else {
// Fallback to market-specific or global config
const marketConfig = getMarketConfig(symbol)
symbolSettings = {
size: marketConfig.positionSize ?? baseConfig.positionSize,
leverage: marketConfig.leverage ?? baseConfig.leverage,
enabled: true,
}
usePercentage = baseConfig.usePercentageSize
}
// Calculate actual size
const actualSize = calculateActualPositionSize(
symbolSettings.size,
usePercentage,
freeCollateral
)
return {
size: actualSize,
leverage: symbolSettings.leverage,
enabled: symbolSettings.enabled,
usePercentage,
}
}
/**
* Calculate dynamic TP2 level based on ATR (Average True Range)
* Higher ATR = higher volatility = larger TP2 target to capture big moves
* LEGACY FUNCTION - Kept for backward compatibility
*/
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 (use new field name)
const dynamicTp2 = atrPercent * config.atrMultiplierTp2
// 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.atrMultiplierTp2} = ${dynamicTp2.toFixed(2)}% → ${boundedTp2.toFixed(2)}% (bounded)`)
return boundedTp2
}
// Validate trading configuration
export function validateTradingConfig(config: TradingConfig): void {
if (config.positionSize <= 0) {
throw new Error('Position size must be positive')
}
if (config.leverage < 1 || config.leverage > 20) {
throw new Error('Leverage must be between 1 and 20')
}
if (config.stopLossPercent >= 0) {
throw new Error('Stop loss must be negative')
}
if (config.takeProfit1Percent <= 0 || config.takeProfit2Percent <= 0) {
throw new Error('Take profit values must be positive')
}
if (config.takeProfit1Percent >= config.takeProfit2Percent) {
throw new Error('TP2 must be greater than TP1')
}
if (config.slippageTolerance < 0 || config.slippageTolerance > 10) {
throw new Error('Slippage tolerance must be between 0 and 10%')
}
if (config.trailingStopAtrMultiplier <= 0) {
throw new Error('Trailing stop ATR multiplier must be positive')
}
if (config.trailingStopMinPercent < 0 || config.trailingStopMaxPercent < 0) {
throw new Error('Trailing stop bounds must be non-negative')
}
if (config.trailingStopMinPercent > config.trailingStopMaxPercent) {
throw new Error('Trailing stop min percent cannot exceed max percent')
}
}
// Environment-based configuration
export function getConfigFromEnv(): Partial<TradingConfig> {
const config: Partial<TradingConfig> = {
positionSize: process.env.MAX_POSITION_SIZE_USD
? parseFloat(process.env.MAX_POSITION_SIZE_USD)
: undefined,
usePercentageSize: process.env.USE_PERCENTAGE_SIZE
? process.env.USE_PERCENTAGE_SIZE === 'true'
: undefined,
// Per-symbol settings from ENV
solana: {
enabled: process.env.SOLANA_ENABLED !== 'false',
positionSize: process.env.SOLANA_POSITION_SIZE
? parseFloat(process.env.SOLANA_POSITION_SIZE)
: 210,
leverage: process.env.SOLANA_LEVERAGE
? parseInt(process.env.SOLANA_LEVERAGE)
: 10,
usePercentageSize: process.env.SOLANA_USE_PERCENTAGE_SIZE
? process.env.SOLANA_USE_PERCENTAGE_SIZE === 'true'
: false,
},
ethereum: {
enabled: process.env.ETHEREUM_ENABLED !== 'false',
positionSize: process.env.ETHEREUM_POSITION_SIZE
? parseFloat(process.env.ETHEREUM_POSITION_SIZE)
: 4,
leverage: process.env.ETHEREUM_LEVERAGE
? parseInt(process.env.ETHEREUM_LEVERAGE)
: 1,
usePercentageSize: process.env.ETHEREUM_USE_PERCENTAGE_SIZE
? process.env.ETHEREUM_USE_PERCENTAGE_SIZE === 'true'
: false,
},
leverage: process.env.LEVERAGE
? parseInt(process.env.LEVERAGE)
: undefined,
stopLossPercent: process.env.STOP_LOSS_PERCENT
? parseFloat(process.env.STOP_LOSS_PERCENT)
: undefined,
useDualStops: process.env.USE_DUAL_STOPS
? process.env.USE_DUAL_STOPS === 'true'
: undefined,
softStopPercent: process.env.SOFT_STOP_PERCENT
? parseFloat(process.env.SOFT_STOP_PERCENT)
: undefined,
softStopBuffer: process.env.SOFT_STOP_BUFFER
? parseFloat(process.env.SOFT_STOP_BUFFER)
: undefined,
hardStopPercent: process.env.HARD_STOP_PERCENT
? parseFloat(process.env.HARD_STOP_PERCENT)
: undefined,
takeProfit1Percent: process.env.TAKE_PROFIT_1_PERCENT
? parseFloat(process.env.TAKE_PROFIT_1_PERCENT)
: undefined,
takeProfit2Percent: process.env.TAKE_PROFIT_2_PERCENT
? parseFloat(process.env.TAKE_PROFIT_2_PERCENT)
: undefined,
takeProfit1SizePercent: process.env.TAKE_PROFIT_1_SIZE_PERCENT
? parseFloat(process.env.TAKE_PROFIT_1_SIZE_PERCENT)
: undefined,
takeProfit2SizePercent: process.env.TAKE_PROFIT_2_SIZE_PERCENT
? parseFloat(process.env.TAKE_PROFIT_2_SIZE_PERCENT)
: undefined,
// ATR-based dynamic targets (NEW - Nov 17, 2025)
useAtrBasedTargets: process.env.USE_ATR_BASED_TARGETS
? process.env.USE_ATR_BASED_TARGETS === 'true'
: undefined,
atrMultiplierTp1: process.env.ATR_MULTIPLIER_TP1
? parseFloat(process.env.ATR_MULTIPLIER_TP1)
: undefined,
atrMultiplierTp2: process.env.ATR_MULTIPLIER_TP2
? parseFloat(process.env.ATR_MULTIPLIER_TP2)
: undefined,
atrMultiplierSl: process.env.ATR_MULTIPLIER_SL
? parseFloat(process.env.ATR_MULTIPLIER_SL)
: undefined,
minTp1Percent: process.env.MIN_TP1_PERCENT
? parseFloat(process.env.MIN_TP1_PERCENT)
: undefined,
maxTp1Percent: process.env.MAX_TP1_PERCENT
? parseFloat(process.env.MAX_TP1_PERCENT)
: 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,
minSlPercent: process.env.MIN_SL_PERCENT
? parseFloat(process.env.MIN_SL_PERCENT)
: undefined,
maxSlPercent: process.env.MAX_SL_PERCENT
? parseFloat(process.env.MAX_SL_PERCENT)
: undefined,
profitLockAfterTP1Percent: process.env.PROFIT_LOCK_AFTER_TP1_PERCENT || process.env.BREAKEVEN_TRIGGER_PERCENT
? parseFloat(process.env.PROFIT_LOCK_AFTER_TP1_PERCENT || process.env.BREAKEVEN_TRIGGER_PERCENT!)
: undefined,
profitLockTriggerPercent: process.env.PROFIT_LOCK_TRIGGER_PERCENT
? parseFloat(process.env.PROFIT_LOCK_TRIGGER_PERCENT)
: undefined,
profitLockPercent: process.env.PROFIT_LOCK_PERCENT
? parseFloat(process.env.PROFIT_LOCK_PERCENT)
: undefined,
useTrailingStop: process.env.USE_TRAILING_STOP
? process.env.USE_TRAILING_STOP === 'true'
: undefined,
trailingStopPercent: process.env.TRAILING_STOP_PERCENT
? parseFloat(process.env.TRAILING_STOP_PERCENT)
: undefined,
trailingStopAtrMultiplier: process.env.TRAILING_STOP_ATR_MULTIPLIER
? parseFloat(process.env.TRAILING_STOP_ATR_MULTIPLIER)
: undefined,
trailingStopMinPercent: process.env.TRAILING_STOP_MIN_PERCENT
? parseFloat(process.env.TRAILING_STOP_MIN_PERCENT)
: undefined,
trailingStopMaxPercent: process.env.TRAILING_STOP_MAX_PERCENT
? parseFloat(process.env.TRAILING_STOP_MAX_PERCENT)
: undefined,
trailingStopActivation: process.env.TRAILING_STOP_ACTIVATION
? parseFloat(process.env.TRAILING_STOP_ACTIVATION)
: undefined,
minSignalQualityScore: process.env.MIN_SIGNAL_QUALITY_SCORE
? parseInt(process.env.MIN_SIGNAL_QUALITY_SCORE)
: undefined,
enablePositionScaling: process.env.ENABLE_POSITION_SCALING
? process.env.ENABLE_POSITION_SCALING === 'true'
: undefined,
minScaleQualityScore: process.env.MIN_SCALE_QUALITY_SCORE
? parseInt(process.env.MIN_SCALE_QUALITY_SCORE)
: undefined,
minProfitForScale: process.env.MIN_PROFIT_FOR_SCALE
? parseFloat(process.env.MIN_PROFIT_FOR_SCALE)
: undefined,
maxScaleMultiplier: process.env.MAX_SCALE_MULTIPLIER
? parseFloat(process.env.MAX_SCALE_MULTIPLIER)
: undefined,
scaleSizePercent: process.env.SCALE_SIZE_PERCENT
? parseFloat(process.env.SCALE_SIZE_PERCENT)
: undefined,
minAdxIncrease: process.env.MIN_ADX_INCREASE
? parseFloat(process.env.MIN_ADX_INCREASE)
: undefined,
maxPricePositionForScale: process.env.MAX_PRICE_POSITION_FOR_SCALE
? parseFloat(process.env.MAX_PRICE_POSITION_FOR_SCALE)
: undefined,
maxDailyDrawdown: process.env.MAX_DAILY_DRAWDOWN
? parseFloat(process.env.MAX_DAILY_DRAWDOWN)
: undefined,
maxTradesPerHour: process.env.MAX_TRADES_PER_HOUR
? parseInt(process.env.MAX_TRADES_PER_HOUR)
: undefined,
minTimeBetweenTrades: process.env.MIN_TIME_BETWEEN_TRADES
? parseInt(process.env.MIN_TIME_BETWEEN_TRADES)
: undefined,
}
return config
}
// Merge configurations
export function getMergedConfig(
overrides?: Partial<TradingConfig>
): TradingConfig {
const envConfig = getConfigFromEnv()
const config = {
...DEFAULT_TRADING_CONFIG,
...envConfig,
...overrides,
}
validateTradingConfig(config)
return config
}