From 79dbfe4abcfc7ea10eb50a2a96a56ef66d2e96c5 Mon Sep 17 00:00:00 2001 From: Alexandre Catarino Date: Fri, 8 May 2026 21:47:15 +0100 Subject: [PATCH] Align QuiverQuantCongressUniverse Python stub with sibling Quiver universes Hoist QuiverCongressDataPoint per-row fields onto QuiverQuantCongressUniverse and emit instances of the universe class itself from Reader, matching the pattern used by QuiverInsiderTradingUniverse, QuiverLobbyingUniverse, QuiverCNBCsUniverse, and QuiverGovernmentContractUniverse. Closes #4. Co-Authored-By: Claude Opus 4.7 (1M context) --- QuiverQuantCongressUniverse.cs | 130 ++++++++++++++++-- ...QuantCongressUniverseSelectionAlgorithm.cs | 4 +- tests/QuiverCongressTests.cs | 3 +- 3 files changed, 125 insertions(+), 12 deletions(-) diff --git a/QuiverQuantCongressUniverse.cs b/QuiverQuantCongressUniverse.cs index 550bbeb..6d14f23 100644 --- a/QuiverQuantCongressUniverse.cs +++ b/QuiverQuantCongressUniverse.cs @@ -15,10 +15,12 @@ */ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; -using System.Linq; +using NodaTime; using QuantConnect.Data; +using QuantConnect.Data.UniverseSelection; using QuantConnect.Orders; using static QuantConnect.StringExtensions; @@ -27,8 +29,73 @@ namespace QuantConnect.DataSource /// /// Universe Selection helper class for QuiverQuant Congress dataset /// - public class QuiverQuantCongressUniverse : QuiverCongress + public class QuiverQuantCongressUniverse : BaseDataCollection { + /// + /// The date the transaction was recorded by QuiverQuant. Value will always exist. + /// + public DateTime RecordDate { get; set; } + + /// + /// The date the recorded transaction was updated by QuiverQuant. Alias for EndTime. + /// + public DateTime UpdatedAt => EndTime; + + /// + /// The date the transaction was reported. Value will always exist. + /// + public DateTime? ReportDate { get; set; } + + /// + /// The date the transaction took place + /// + public DateTime TransactionDate { get; set; } + + /// + /// The Representative making the transaction + /// + public string Representative { get; set; } + + /// + /// The type of transaction + /// + public OrderDirection Transaction { get; set; } + + /// + /// The amount of the transaction (in USD). The Representative can report a range (see ). + /// + public decimal? Amount { get; set; } + + /// + /// The maximum amount of the transaction (in USD). The Representative can report a range (see ). + /// + public decimal? MaximumAmount { get; set; } + + /// + /// The Chamber of Congress that the trader belongs to + /// + public Congress House { get; set; } + + /// + /// The political party that the trader belongs to + /// + public Party Party { get; set; } + + /// + /// The district that the trader belongs to (null or empty for Senators) + /// + public string District { get; set; } + + /// + /// The state that the trader belongs to + /// + public string State { get; set; } + + /// + /// Time the data became available + /// + public override DateTime EndTime => Time.AddDays(1); + /// /// Return the URL string source of the file. This will be converted to a stream /// @@ -66,12 +133,12 @@ public override BaseData Reader(SubscriptionDataConfig config, string line, Date var amount = csv[7].IfNotNullOrEmpty(s => decimal.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); var maximumAmount = csv[8].IfNotNullOrEmpty(s => decimal.Parse(s, NumberStyles.Any, CultureInfo.InvariantCulture)); - return new QuiverCongressDataPoint + return new QuiverQuantCongressUniverse { RecordDate = Parse.DateTimeExact(csv[2], "yyyyMMdd"), ReportDate = Parse.DateTimeExact(csv[3], "yyyyMMdd"), TransactionDate = Parse.DateTimeExact(csv[4], "yyyyMMdd"), - Representative = csv[5].Replace(";",","), + Representative = csv[5].Replace(";", ","), Transaction = (OrderDirection)Enum.Parse(typeof(OrderDirection), csv[6], true), Amount = amount, MaximumAmount = maximumAmount, @@ -85,19 +152,52 @@ public override BaseData Reader(SubscriptionDataConfig config, string line, Date }; } + /// + /// Indicates whether the data is sparse. + /// If true, we disable logging for missing files + /// + /// true + public override bool IsSparseData() + { + return true; + } + /// /// Converts the instance to string /// public override string ToString() { - return Invariant($"{EndTime:yyyyMMdd}: {string.Join(",", Data.Select(x => x.ToString()))}"); + return Invariant($"{Symbol}({EndTime:yyyyMMdd}) :: ") + + Invariant($"Representative: {Representative} ") + + Invariant($"House: {House} ") + + Invariant($"Transaction: {Transaction} ") + + Invariant($"Amount: {Amount}"); + } + + /// + /// Gets the default resolution for this data and security type + /// + public override Resolution DefaultResolution() + { + return Resolution.Daily; + } + + /// + /// Gets the supported resolution for this data and security type + /// + public override List SupportedResolutions() + { + return DailyResolution; } /// - /// Indicates if there is support for mapping + /// Specifies the data time zone for this data type. This is useful for custom data types /// - /// True indicates mapping should be used - public override bool RequiresMapping() => false; + /// The of this data type + public override DateTimeZone DataTimeZone() + { + return TimeZones.Utc; + } /// /// Clones the data @@ -109,8 +209,20 @@ public override BaseData Clone() { Symbol = Symbol, Time = Time, - EndTime = EndTime, Data = Data, + Value = Value, + + RecordDate = RecordDate, + ReportDate = ReportDate, + TransactionDate = TransactionDate, + Representative = Representative, + Transaction = Transaction, + Amount = Amount, + MaximumAmount = MaximumAmount, + House = House, + Party = Party, + District = District, + State = State, }; } } diff --git a/QuiverQuantCongressUniverseSelectionAlgorithm.cs b/QuiverQuantCongressUniverseSelectionAlgorithm.cs index bb2d18e..ce353b8 100644 --- a/QuiverQuantCongressUniverseSelectionAlgorithm.cs +++ b/QuiverQuantCongressUniverseSelectionAlgorithm.cs @@ -37,13 +37,13 @@ public override void Initialize() // add a custom universe data source (defaults to usa-equity) var universe = AddUniverse(data => { - foreach (QuiverCongressDataPoint datum in data) + foreach (QuiverQuantCongressUniverse datum in data) { Log($"{datum.Symbol},{datum.Representative},{datum.Amount},{datum.Transaction}"); } // define our selection criteria - return from QuiverCongressDataPoint d in data + return from QuiverQuantCongressUniverse d in data where d.Amount > 200000 && d.Transaction == OrderDirection.Buy select d.Symbol; }); diff --git a/tests/QuiverCongressTests.cs b/tests/QuiverCongressTests.cs index e4cddb5..1749054 100644 --- a/tests/QuiverCongressTests.cs +++ b/tests/QuiverCongressTests.cs @@ -68,8 +68,9 @@ public void UniverseReaderTest() var instance = new QuiverQuantCongressUniverse(); var config = new SubscriptionDataConfig(typeof(QuiverQuantCongressUniverse), Symbol.None, Resolution.Daily, DateTimeZone.Utc, DateTimeZone.Utc, false, false, false); - var data = instance.Reader(config, content, date, false) as QuiverCongressDataPoint; + var data = instance.Reader(config, content, date, false) as QuiverQuantCongressUniverse; + Assert.IsNotNull(data); Assert.AreEqual(date, data.Time); Assert.AreEqual(_symbol, data.Symbol); Assert.AreEqual(new DateTime(2023, 9, 18), data.ReportDate);