Initial commit: Predictalytics solution

Clean Architecture .NET 8 solution (Domain/Application/Infrastructure/Api/Worker/WinFormsHost)
for analyzing Polymarket traders for copytrading/strategy-replication candidates.

Includes EF Core InitialBaseline migration and DB secrets removed from source/config
in preparation for version control.
This commit is contained in:
Richard
2026-07-01 19:53:29 +02:00
commit afb251acfc
107 changed files with 9613 additions and 0 deletions
@@ -0,0 +1,82 @@
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; }
// ── 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; }
// ── Navigation ────────────────────────────────────────────────────────
public Trader Trader { get; set; } = null!;
public MarketOutcome? MarketOutcome { get; set; }
public Market? DbMarket { get; set; }
}