feat: Add per-symbol trading controls for SOL and ETH
- Add SymbolSettings interface with enabled/positionSize/leverage fields - Implement per-symbol ENV variables (SOLANA_*, ETHEREUM_*) - Add SOL and ETH sections to settings UI with enable/disable toggles - Add symbol-specific test buttons (SOL LONG/SHORT, ETH LONG/SHORT) - Update execute and test endpoints to check symbol enabled status - Add real-time risk/reward calculator per symbol - Rename 'Position Sizing' to 'Global Fallback' for clarity - Fix position manager P&L calculation for externally closed positions - Fix zero P&L bug affecting 12 historical trades - Add SQL scripts for recalculating historical P&L data - Move archive TypeScript files to .archive to fix build Defaults: - SOL: 10 base × 10x leverage = 100 notional (profit trading) - ETH: base × 1x leverage = notional (data collection) - Global: 10 × 10x for BTC and other symbols Configuration priority: Per-symbol ENV > Market config > Global ENV > Defaults
This commit is contained in:
@@ -4,11 +4,21 @@
|
||||
* Optimized for 5-minute scalping with 10x leverage on Drift Protocol
|
||||
*/
|
||||
|
||||
export interface SymbolSettings {
|
||||
enabled: boolean
|
||||
positionSize: number
|
||||
leverage: number
|
||||
}
|
||||
|
||||
export interface TradingConfig {
|
||||
// Position sizing
|
||||
// Position sizing (global fallback)
|
||||
positionSize: number // USD amount to trade
|
||||
leverage: number // Leverage multiplier
|
||||
|
||||
// Per-symbol settings
|
||||
solana?: SymbolSettings
|
||||
ethereum?: SymbolSettings
|
||||
|
||||
// Risk management (as percentages of entry price)
|
||||
stopLossPercent: number // Negative number (e.g., -1.5)
|
||||
takeProfit1Percent: number // Positive number (e.g., 0.7)
|
||||
@@ -39,7 +49,6 @@ export interface TradingConfig {
|
||||
maxDailyDrawdown: number // USD stop trading threshold
|
||||
maxTradesPerHour: number // Limit overtrading
|
||||
minTimeBetweenTrades: number // Cooldown period (minutes)
|
||||
minQualityScore: number // Minimum signal quality score (0-100) to accept trade
|
||||
|
||||
// Execution
|
||||
useMarketOrders: boolean // true = instant execution
|
||||
@@ -62,10 +71,22 @@ export interface MarketConfig {
|
||||
|
||||
// Default configuration for 5-minute scalping with $1000 capital and 10x leverage
|
||||
export const DEFAULT_TRADING_CONFIG: TradingConfig = {
|
||||
// Position sizing
|
||||
// Position sizing (global fallback)
|
||||
positionSize: 50, // $50 base capital (SAFE FOR TESTING)
|
||||
leverage: 10, // 10x leverage = $500 position size
|
||||
|
||||
// Per-symbol settings
|
||||
solana: {
|
||||
enabled: true,
|
||||
positionSize: 210, // $210 base capital
|
||||
leverage: 10, // 10x leverage = $2100 notional
|
||||
},
|
||||
ethereum: {
|
||||
enabled: true,
|
||||
positionSize: 4, // $4 base capital (DATA ONLY - minimum size)
|
||||
leverage: 1, // 1x leverage = $4 notional
|
||||
},
|
||||
|
||||
// Risk parameters (wider for DEX slippage/wicks)
|
||||
stopLossPercent: -1.5, // -1.5% price = -15% account loss (closes 100%)
|
||||
takeProfit1Percent: 0.7, // +0.7% price = +7% account gain (closes 50%)
|
||||
@@ -96,7 +117,6 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
|
||||
maxDailyDrawdown: -150, // Stop trading if daily loss exceeds $150 (-15%)
|
||||
maxTradesPerHour: 6, // Max 6 trades per hour
|
||||
minTimeBetweenTrades: 10, // 10 minutes cooldown
|
||||
minQualityScore: 60, // Minimum 60/100 quality score to accept trade
|
||||
|
||||
// Execution
|
||||
useMarketOrders: true, // Use market orders for reliable fills
|
||||
@@ -127,11 +147,11 @@ export const SUPPORTED_MARKETS: Record<string, MarketConfig> = {
|
||||
symbol: 'ETH-PERP',
|
||||
driftMarketIndex: 2,
|
||||
pythPriceFeedId: '0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace',
|
||||
minOrderSize: 0.002, // 0.002 ETH minimum (~$7-8 for safety above $4 Drift minimum)
|
||||
minOrderSize: 0.01, // 0.01 ETH minimum
|
||||
tickSize: 0.01,
|
||||
// DATA COLLECTION MODE: Minimal risk
|
||||
positionSize: 8, // $8 base capital (ensures 0.002 ETH at ~$4000/ETH)
|
||||
leverage: 1, // 1x leverage = $8 total exposure
|
||||
// DATA COLLECTION MODE: Minimal risk (Drift minimum 0.01 ETH = ~$38)
|
||||
positionSize: 40, // $40 base capital (meets exchange minimum)
|
||||
leverage: 1, // 1x leverage = $40 total exposure
|
||||
},
|
||||
}
|
||||
|
||||
@@ -157,13 +177,31 @@ export function getMarketConfig(symbol: string): MarketConfig {
|
||||
return config
|
||||
}
|
||||
|
||||
// Get position size for specific symbol (with market-specific overrides)
|
||||
export function getPositionSizeForSymbol(symbol: string, baseConfig: TradingConfig): { size: number; leverage: number } {
|
||||
const marketConfig = getMarketConfig(symbol)
|
||||
// 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
|
||||
leverage: marketConfig.leverage ?? baseConfig.leverage,
|
||||
enabled: true, // BTC or other markets default to enabled
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +234,30 @@ export function validateTradingConfig(config: TradingConfig): void {
|
||||
|
||||
// Environment-based configuration
|
||||
export function getConfigFromEnv(): Partial<TradingConfig> {
|
||||
return {
|
||||
const config: Partial<TradingConfig> = {
|
||||
positionSize: process.env.MAX_POSITION_SIZE_USD
|
||||
? parseFloat(process.env.MAX_POSITION_SIZE_USD)
|
||||
: 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,
|
||||
},
|
||||
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,
|
||||
},
|
||||
leverage: process.env.LEVERAGE
|
||||
? parseInt(process.env.LEVERAGE)
|
||||
: undefined,
|
||||
@@ -257,10 +315,9 @@ export function getConfigFromEnv(): Partial<TradingConfig> {
|
||||
minTimeBetweenTrades: process.env.MIN_TIME_BETWEEN_TRADES
|
||||
? parseInt(process.env.MIN_TIME_BETWEEN_TRADES)
|
||||
: undefined,
|
||||
minQualityScore: process.env.MIN_QUALITY_SCORE
|
||||
? parseInt(process.env.MIN_QUALITY_SCORE)
|
||||
: undefined,
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
||||
// Merge configurations
|
||||
|
||||
Reference in New Issue
Block a user