120 lines
4.8 KiB
C#
120 lines
4.8 KiB
C#
using Predictalytics.Domain.Enums;
|
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
|
|
namespace Predictalytics.Domain.Entities;
|
|
|
|
/// <summary>
|
|
/// Represents a single trade executed by a trader on a prediction market.
|
|
/// </summary>
|
|
public class Trade
|
|
{
|
|
public long Id { get; set; }
|
|
|
|
/// <summary>Foreign key to the trader who made this trade.</summary>
|
|
public int TraderId { get; set; }
|
|
|
|
/// <summary>Platform where the trade occurred.</summary>
|
|
public PlatformType Platform { get; set; }
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public string PlatformTradeId { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public string MarketId { get; set; } = string.Empty;
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public int? DbMarketId { get; set; }
|
|
|
|
/// <summary>
|
|
/// Platform-specific token/asset ID (clobTokenId on Polymarket). Links to MarketOutcome.TokenId.
|
|
/// Kept as VARCHAR(66) until MarketOutcomeId is resolved.
|
|
/// </summary>
|
|
public string AssetId { get; set; } = string.Empty;
|
|
|
|
/// <summary>Foreign key to the resolved MarketOutcome (nullable until resolved via market sync).</summary>
|
|
public int? MarketOutcomeId { get; set; }
|
|
|
|
/// <summary>The outcome the trader bet on (e.g. "Yes", "No").</summary>
|
|
public string Outcome { get; set; } = string.Empty;
|
|
|
|
/// <summary>Buy or Sell.</summary>
|
|
public TradeSide Side { get; set; }
|
|
|
|
/// <summary>Price per share at execution (0.00 to 1.00 on Polymarket).</summary>
|
|
public decimal Price { get; set; }
|
|
|
|
/// <summary>Number of shares/tokens traded.</summary>
|
|
public decimal Size { get; set; }
|
|
|
|
/// <summary>Total notional value in USD.</summary>
|
|
public decimal Amount { get; set; }
|
|
|
|
/// <summary>When the trade was executed on the platform.</summary>
|
|
public DateTime ExecutedAt { get; set; }
|
|
|
|
/// <summary>Transaction hash (for blockchain-based platforms).</summary>
|
|
public string? TransactionHash { get; set; }
|
|
|
|
/// <summary>USDC size of the trade (raw currency size traded).</summary>
|
|
[Column(TypeName = "decimal(18,6)")]
|
|
public decimal? UsdcSize { get; set; }
|
|
|
|
/// <summary>Outcome index traded.</summary>
|
|
public int? OutcomeIndex { get; set; }
|
|
|
|
// ── Context Enrichment (AI Strategy Detection) ───────────
|
|
|
|
/// <summary>Market price 1 minute before trade execution.</summary>
|
|
[Column(TypeName = "decimal(18,4)")]
|
|
public decimal? PreTradePrice1m { get; set; }
|
|
|
|
/// <summary>Market price 1 minute after trade execution.</summary>
|
|
[Column(TypeName = "decimal(18,4)")]
|
|
public decimal? PostTradePrice1m { get; set; }
|
|
|
|
/// <summary>Indicates if high-res price context was fetched.</summary>
|
|
public bool IsContextEnriched { get; set; }
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
public int? AggregatedCount { get; set; }
|
|
|
|
// ── Transient (not persisted) ──────────────────────────────────────────
|
|
|
|
/// <summary>
|
|
/// Wallet address of the trader, set by the provider during data ingestion.
|
|
/// NOT stored in the database — used transiently for trader discovery in MarketHistoryWorker.
|
|
/// </summary>
|
|
[NotMapped]
|
|
public string? TransientWallet { get; set; }
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
[NotMapped]
|
|
public string? TransientDisplayName { get; set; }
|
|
|
|
// ── Navigation ────────────────────────────────────────────────────────
|
|
public Trader Trader { get; set; } = null!;
|
|
public MarketOutcome? MarketOutcome { get; set; }
|
|
|
|
/// <summary>Analytics context containing high-resolution price data and slippage (if collected).</summary>
|
|
public TradeContext? Context { get; set; }
|
|
|
|
public Market? DbMarket { get; set; }
|
|
}
|