// Prisma Schema for Trading Bot v4 // Database: PostgreSQL generator client { provider = "prisma-client-js" } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // Trade records for analysis and performance tracking model Trade { id String @id @default(cuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt // Trade identification positionId String @unique // Transaction signature from entry order symbol String // e.g., "SOL-PERP" direction String // "long" or "short" // Entry details entryPrice Float entryTime DateTime entrySlippage Float? positionSizeUSD Float // NOTIONAL position size (with leverage) collateralUSD Float? // ACTUAL margin/collateral used (positionSizeUSD / leverage) leverage Float // Exit targets (planned) stopLossPrice Float softStopPrice Float? // Dual stop: soft stop-limit trigger hardStopPrice Float? // Dual stop: hard stop-market trigger takeProfit1Price Float takeProfit2Price Float tp1SizePercent Float tp2SizePercent Float // Exit details (actual) exitPrice Float? exitTime DateTime? exitReason String? // "TP1", "TP2", "SL", "SOFT_SL", "HARD_SL", "manual", "emergency" // Performance metrics realizedPnL Float? realizedPnLPercent Float? holdTimeSeconds Int? maxDrawdown Float? // Peak to valley during trade maxGain Float? // Peak gain reached // MAE/MFE Analysis (Maximum Adverse/Favorable Excursion) maxFavorableExcursion Float? // Best profit % reached during trade maxAdverseExcursion Float? // Worst drawdown % during trade maxFavorablePrice Float? // Best price hit (direction-aware) maxAdversePrice Float? // Worst price hit (direction-aware) // Exit details - which levels actually filled tp1Filled Boolean @default(false) tp2Filled Boolean @default(false) softSlFilled Boolean @default(false) hardSlFilled Boolean @default(false) tp1FillPrice Float? tp2FillPrice Float? slFillPrice Float? // Timing metrics timeToTp1 Int? // Seconds from entry to TP1 fill timeToTp2 Int? // Seconds from entry to TP2 fill timeToSl Int? // Seconds from entry to SL hit // Market context at entry atrAtEntry Float? // ATR% when trade opened adxAtEntry Float? // ADX trend strength (0-50) rsiAtEntry Float? // RSI momentum (0-100) volumeAtEntry Float? // Volume relative to MA pricePositionAtEntry Float? // Price position in range (0-100%) signalQualityScore Int? // Calculated quality score (0-100) signalQualityVersion String? @default("v4") // Tracks which scoring logic was used indicatorVersion String? // Pine Script version (v5, v6, etc.) fundingRateAtEntry Float? // Perp funding rate at entry basisAtEntry Float? // Perp-spot basis at entry // Slippage tracking expectedEntryPrice Float? // Target entry from signal entrySlippagePct Float? // Actual slippage % expectedExitPrice Float? // Which TP/SL should have hit exitSlippagePct Float? // Exit slippage % // Order signatures entryOrderTx String tp1OrderTx String? tp2OrderTx String? slOrderTx String? softStopOrderTx String? // Dual stop: soft stop tx hardStopOrderTx String? // Dual stop: hard stop tx exitOrderTx String? // Configuration snapshot configSnapshot Json // Store settings used for this trade // Signal data signalSource String? // "tradingview", "manual", etc. signalStrength String? // "strong", "moderate", "weak" timeframe String? // "5", "15", "60" // Status status String @default("open") // "open", "closed", "failed", "phantom" isTestTrade Boolean @default(false) // Flag test trades for exclusion from analytics // Phantom trade detection isPhantom Boolean @default(false) // Position opened but size mismatch >50% expectedSizeUSD Float? // Expected position size (when phantom) actualSizeUSD Float? // Actual position size from Drift (when phantom) phantomReason String? // "ORACLE_PRICE_MISMATCH", "PARTIAL_FILL", "ORDER_REJECTED" // Relations priceUpdates PriceUpdate[] @@index([symbol]) @@index([createdAt]) @@index([status]) @@index([exitReason]) } // Real-time price updates during trade (for analysis) model PriceUpdate { id String @id @default(cuid()) createdAt DateTime @default(now()) tradeId String trade Trade @relation(fields: [tradeId], references: [id], onDelete: Cascade) price Float pnl Float pnlPercent Float @@index([tradeId]) @@index([createdAt]) } // System events and errors model SystemEvent { id String @id @default(cuid()) createdAt DateTime @default(now()) eventType String // "error", "warning", "info", "trade_executed", etc. message String details Json? @@index([eventType]) @@index([createdAt]) } // Blocked signals for analysis (signals that didn't pass quality checks) model BlockedSignal { id String @id @default(cuid()) createdAt DateTime @default(now()) // Signal identification symbol String // e.g., "SOL-PERP" direction String // "long" or "short" timeframe String? // "5", "15", "60" // Price at signal time signalPrice Float // Price when signal was generated // Market metrics at signal time atr Float? // ATR% at signal adx Float? // ADX trend strength rsi Float? // RSI momentum volumeRatio Float? // Volume relative to average pricePosition Float? // Position in range (0-100%) // Quality scoring signalQualityScore Int // 0-100 score signalQualityVersion String? // Which scoring version scoreBreakdown Json? // Detailed breakdown of score components minScoreRequired Int // What threshold was used (e.g., 65) indicatorVersion String? // Pine Script version (v5, v6, etc.) // Block reason blockReason String // "QUALITY_SCORE_TOO_LOW", "DUPLICATE", "COOLDOWN", "DATA_COLLECTION_ONLY", etc. blockDetails String? // Human-readable details // Entry tracking (for multi-timeframe analysis) entryPrice Float @default(0) // Price at signal time // For later analysis: track if it would have been profitable priceAfter1Min Float? // Price 1 minute after (filled by monitoring job) priceAfter5Min Float? // Price 5 minutes after priceAfter15Min Float? // Price 15 minutes after priceAfter30Min Float? // Price 30 minutes after // EXTENDED TRACKING (Dec 2, 2025): Track up to 8 hours for slow developers // User directive: "30 minutes...simply not long enough to know whats going to happen" // Purpose: Capture low ADX signals that take 4+ hours to reach targets priceAfter1Hr Float? // Price 1 hour after (60 minutes) priceAfter2Hr Float? // Price 2 hours after (120 minutes) priceAfter4Hr Float? // Price 4 hours after (240 minutes) priceAfter8Hr Float? // Price 8 hours after (480 minutes) wouldHitTP1 Boolean? // Would TP1 have been hit? wouldHitTP2 Boolean? // Would TP2 have been hit? wouldHitSL Boolean? // Would SL have been hit? // EXACT TIMING (Dec 2, 2025): Minute-precision timestamps for TP/SL hits // Purpose: Answer "EXACTLY when TP1/TP2 would have been hit" using 1-minute granular data // Uses: MarketData query instead of Drift oracle polling (480 data points vs. 8 checkpoints) tp1HitTime DateTime? @map("tp1_hit_time") // Exact timestamp when TP1 first hit tp2HitTime DateTime? @map("tp2_hit_time") // Exact timestamp when TP2 first hit slHitTime DateTime? @map("sl_hit_time") // Exact timestamp when SL first hit // Max favorable/adverse excursion (mirror Trade model) maxFavorablePrice Float? // Price at max profit maxAdversePrice Float? // Price at max loss maxFavorableExcursion Float? // Best profit % during tracking maxAdverseExcursion Float? // Worst loss % during tracking analysisComplete Boolean @default(false) // Has post-analysis been done? @@index([symbol]) @@index([createdAt]) @@index([signalQualityScore]) @@index([blockReason]) } // Stop Hunt Revenge Tracker (Nov 20, 2025) // Tracks high-quality stop-outs and auto re-enters when stop hunt reverses model StopHunt { id String @id @default(cuid()) createdAt DateTime @default(now()) // Original trade that got stopped out originalTradeId String // References Trade.id symbol String // e.g., "SOL-PERP" direction String // "long" or "short" // Stop hunt details stopHuntPrice Float // Price where we got stopped out originalEntryPrice Float // Where we originally entered originalQualityScore Int // Must be 85+ to qualify originalADX Float? // Trend strength at entry originalATR Float? // Volatility at entry stopLossAmount Float // How much we lost stopHuntTime DateTime // When stop hunt occurred // Revenge tracking revengeTradeId String? // References Trade.id if revenge executed revengeExecuted Boolean @default(false) revengeEntryPrice Float? // Where revenge trade entered revengeTime DateTime? // When revenge executed revengeWindowExpired Boolean @default(false) revengeExpiresAt DateTime // 4 hours after stop hunt slDistanceAtEntry Float? // Distance from entry to stop zone (for Enhancement #6 analysis) // Monitoring state highestPriceAfterStop Float? // Track if stop hunt reverses lowestPriceAfterStop Float? // Track if stop hunt reverses // Zone tracking persistence (Nov 27, 2025 - Enhancement #10) firstCrossTime DateTime? // When price entered revenge zone lowestInZone Float? // Lowest price while in zone (LONG) highestInZone Float? // Highest price while in zone (SHORT) zoneResetCount Int @default(0) // How many times price left zone // Revenge outcome tracking (Nov 27, 2025 - Enhancement #4) revengeOutcome String? // "TP1", "TP2", "SL", "TRAILING_SL", null (pending) revengePnL Float? // Realized P&L from revenge trade revengeFailedReason String? // Why revenge failed: "stopped_again", "chop", "insufficient_capital" @@index([symbol]) @@index([revengeExecuted]) @@index([revengeWindowExpired]) @@index([stopHuntTime]) @@index([revengeOutcome]) } // Historical 1-minute market data (Dec 2, 2025) // Stores ALL TradingView webhook data for comprehensive analysis // Retention: 4 weeks (auto-cleanup of older data) model MarketData { id String @id @default(cuid()) createdAt DateTime @default(now()) // Market identification symbol String // e.g., "SOL-PERP" timeframe String // "1" for 1-minute data // Price data price Float // Close price at this minute // Technical indicators (from TradingView webhook) atr Float // Average True Range (volatility %) adx Float // Average Directional Index (trend strength) rsi Float // Relative Strength Index (momentum) volumeRatio Float // Current volume / average volume pricePosition Float // Position in recent range (0-100%) maGap Float? // MA50-MA200 gap percentage (v9+) // Volume data volume Float? // Raw volume if available // Timestamp tracking timestamp DateTime // Exact time of this 1-minute candle close @@index([symbol, timestamp]) // Query by symbol and time range @@index([createdAt]) // For cleanup of old data @@index([timestamp]) // For time-based queries } // Performance analytics (daily aggregates) model DailyStats { id String @id @default(cuid()) date DateTime @unique tradesCount Int winningTrades Int losingTrades Int totalPnL Float totalPnLPercent Float winRate Float avgWin Float avgLoss Float profitFactor Float maxDrawdown Float sharpeRatio Float? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([date]) }