feat: Deploy HA auto-failover with database promotion

- Enhanced DNS failover monitor on secondary (72.62.39.24)
- Auto-promotes database: pg_ctl promote on failover
- Creates DEMOTED flag on primary via SSH (split-brain protection)
- Telegram notifications with database promotion status
- Startup safety script ready (integration pending)
- 90-second automatic recovery vs 10-30 min manual
- Zero-cost 95% enterprise HA benefit

Status: DEPLOYED and MONITORING (14:52 CET)
Next: Controlled failover test during maintenance
This commit is contained in:
mindesbunister
2025-12-12 15:54:03 +01:00
parent 7ff5c5b3a4
commit d637aac2d7
25 changed files with 1071 additions and 170 deletions

View File

@@ -16,6 +16,7 @@ export interface TradingConfig {
positionSize: number // USD amount to trade (or percentage if usePercentageSize=true)
leverage: number // Leverage multiplier (LEGACY - used when adaptive disabled)
usePercentageSize: boolean // If true, positionSize is % of free collateral
enableSizeTraceLogging?: boolean // Optional verbose sizing logs for debugging
// Adaptive Leverage (Quality-based risk adjustment - Nov 24, 2025)
useAdaptiveLeverage: boolean // Enable quality-based leverage tiers
@@ -66,6 +67,9 @@ export interface TradingConfig {
trailingStopMinPercent: number // Minimum trailing distance in percent
trailingStopMaxPercent: number // Maximum trailing distance in percent
trailingStopActivation: number // Activate when runner profits exceed this %
// TP2-as-trigger handling
useTp2AsTriggerOnly: boolean // If true and TP2 size is 0, do not place TP2 order (trigger only)
// Signal Quality (Direction-specific thresholds - Nov 23, 2025)
minSignalQualityScore: number // Global fallback (0-100)
@@ -115,6 +119,7 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
positionSize: 50, // $50 base capital (SAFE FOR TESTING) OR percentage if usePercentageSize=true
leverage: 10, // 10x leverage = $500 position size (LEGACY - used when adaptive disabled)
usePercentageSize: false, // False = fixed USD, True = percentage of portfolio
enableSizeTraceLogging: false, // Disable verbose sizing logs by default
// Adaptive Leverage (Quality-based risk adjustment - Nov 24, 2025)
// Data-driven: v8 quality 95+ = 100% WR (4/4 wins), quality 90-94 more volatile
@@ -179,6 +184,9 @@ export const DEFAULT_TRADING_CONFIG: TradingConfig = {
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
// TP2-as-trigger handling
useTp2AsTriggerOnly: true, // Default: TP2=0 acts as trigger only (no on-chain TP2 order)
// Signal Quality (Direction-specific thresholds - Nov 23, 2025 DATA-DRIVEN UPDATE)
minSignalQualityScore: 91, // Global fallback (unchanged)
@@ -332,12 +340,10 @@ export function calculateActualPositionSize(
// 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
// Safety buffer for 100% positions to avoid InsufficientCollateral from fees/slippage
if (configuredSize >= 100) {
percentDecimal = 0.99
console.log(`⚠️ Applying 99% safety buffer for 100% position (prevents InsufficientCollateral from fees/slippage)`)
console.log('⚠️ Applying 99% safety buffer for 100% position (prevents InsufficientCollateral from fees/slippage)')
}
const calculatedSize = freeCollateral * percentDecimal
@@ -420,6 +426,31 @@ export async function getActualPositionSizeForSymbol(
console.log(`📊 Adaptive leverage: Quality ${qualityScore}${finalLeverage}x leverage (threshold: ${baseConfig.qualityLeverageThreshold})`)
}
}
if (baseConfig.enableSizeTraceLogging) {
const configuredSize = symbolSettings.size
const safetyBufferApplied = usePercentage && configuredSize >= 100
const appliedPercent = usePercentage
? safetyBufferApplied
? 99
: configuredSize
: undefined
const notional = actualSize * finalLeverage
console.log('🧮 SIZE TRACE', {
symbol,
direction: direction ?? 'n/a',
usePercentage,
configuredSize,
safetyBufferApplied,
appliedPercent,
freeCollateral,
calculatedSize: actualSize,
leverageSelected: finalLeverage,
notional,
qualityScore,
adaptiveLeverage: baseConfig.useAdaptiveLeverage && qualityScore !== undefined,
})
}
return {
size: actualSize,
@@ -509,6 +540,10 @@ export function getConfigFromEnv(): Partial<TradingConfig> {
usePercentageSize: process.env.USE_PERCENTAGE_SIZE
? process.env.USE_PERCENTAGE_SIZE === 'true'
: undefined,
enableSizeTraceLogging: process.env.ENABLE_SIZE_TRACE_LOGS
? process.env.ENABLE_SIZE_TRACE_LOGS === 'true'
: undefined,
// Per-symbol settings from ENV
solana: {
@@ -659,6 +694,9 @@ export function getConfigFromEnv(): Partial<TradingConfig> {
trailingStopActivation: process.env.TRAILING_STOP_ACTIVATION
? parseFloat(process.env.TRAILING_STOP_ACTIVATION)
: undefined,
useTp2AsTriggerOnly: process.env.USE_TP2_AS_TRIGGER_ONLY
? process.env.USE_TP2_AS_TRIGGER_ONLY === 'true'
: undefined,
minSignalQualityScore: process.env.MIN_SIGNAL_QUALITY_SCORE
? parseInt(process.env.MIN_SIGNAL_QUALITY_SCORE)
: undefined,