using Predictalytics.Domain.Enums; using System.ComponentModel.DataAnnotations.Schema; namespace Predictalytics.Domain.Entities; /// /// Represents a single trade executed by a trader on a prediction market. /// public class Trade { public long Id { get; set; } /// Foreign key to the trader who made this trade. public int TraderId { get; set; } /// Platform where the trade occurred. public PlatformType Platform { get; set; } /// /// Platform-specific trade ID for deduplication. /// Format: "{txHash}_{assetId}_{side}" (max ~143 chars for new trades). /// Legacy trades may include wallet address as 2nd segment. /// public string PlatformTradeId { get; set; } = string.Empty; /// /// Platform-specific market identifier string (conditionId on Polymarket, address on Limitless). /// Kept as VARCHAR(66) for cross-referencing during import and reconciliation. /// After full linking, prefer DbMarketId. /// public string MarketId { get; set; } = string.Empty; /// /// Foreign key to the internal Markets table. Populated during import when the market is known. /// Null for trades whose market has not yet been synced. /// public int? DbMarketId { get; set; } /// /// Platform-specific token/asset ID (clobTokenId on Polymarket). Links to MarketOutcome.TokenId. /// Kept as VARCHAR(66) until MarketOutcomeId is resolved. /// public string AssetId { get; set; } = string.Empty; /// Foreign key to the resolved MarketOutcome (nullable until resolved via market sync). public int? MarketOutcomeId { get; set; } /// The outcome the trader bet on (e.g. "Yes", "No"). public string Outcome { get; set; } = string.Empty; /// Buy or Sell. public TradeSide Side { get; set; } /// Price per share at execution (0.00 to 1.00 on Polymarket). public decimal Price { get; set; } /// Number of shares/tokens traded. public decimal Size { get; set; } /// Total notional value in USD. public decimal Amount { get; set; } /// When the trade was executed on the platform. public DateTime ExecutedAt { get; set; } /// Transaction hash (for blockchain-based platforms). public string? TransactionHash { get; set; } /// USDC size of the trade (raw currency size traded). [Column(TypeName = "decimal(18,6)")] public decimal? UsdcSize { get; set; } /// Outcome index traded. public int? OutcomeIndex { get; set; } // ── Context Enrichment (AI Strategy Detection) ─────────── /// Market price 1 minute before trade execution. [Column(TypeName = "decimal(18,4)")] public decimal? PreTradePrice1m { get; set; } /// Market price 1 minute after trade execution. [Column(TypeName = "decimal(18,4)")] public decimal? PostTradePrice1m { get; set; } /// Indicates if high-res price context was fetched. public bool IsContextEnriched { get; set; } /// /// For aggregated trades (compacted history or HF trader hourly bucket), this stores /// the number of original trades that were grouped into this single row. Null means 1. /// public int? AggregatedCount { get; set; } // ── Transient (not persisted) ────────────────────────────────────────── /// /// Wallet address of the trader, set by the provider during data ingestion. /// NOT stored in the database — used transiently for trader discovery in MarketHistoryWorker. /// [NotMapped] public string? TransientWallet { get; set; } /// /// Transient reference to the trader's display name from the platform, used to opportunistically /// update the local name if it's currently a placeholder or empty. /// [NotMapped] public string? TransientDisplayName { get; set; } // ── Navigation ──────────────────────────────────────────────────────── public Trader Trader { get; set; } = null!; public MarketOutcome? MarketOutcome { get; set; } /// Analytics context containing high-resolution price data and slippage (if collected). public TradeContext? Context { get; set; } public Market? DbMarket { get; set; } }