Files
Operation-Blue-Laminate-v2/BlueLaminate/BlueLaminate.Core/Tradeups/TradeupCandidate.cs
2026-06-02 13:31:27 -05:00

68 lines
2.8 KiB
C#

namespace BlueLaminate.Core.Tradeups;
/// <summary>One possible result of a contract and what it would net if it lands.</summary>
/// <param name="Probability">Chance this specific output is produced (single-collection: 1/k).</param>
/// <param name="NetSellPrice">
/// Realisable sale value after undercut + sell fee, or null when nothing comparable is
/// listed (treated as unsellable for the worst-case test).
/// </param>
/// <param name="Liquidity">Active listings backing the price, in the same wear band.</param>
/// <param name="PriceSource">Where the price came from: "market" (our stored listings) or
/// "csfloat-live" (re-priced from the CSFloat API because the stored liquidity was thin).</param>
public sealed record TradeupOutcome(
int SkinId,
string Name,
decimal OutputFloat,
WearBand Band,
decimal Probability,
decimal? NetSellPrice,
int Liquidity,
string PriceSource = "market");
/// <summary>
/// One collection's share of a (possibly multi-collection) contract: how many of the ten
/// inputs came from it, and which output tier those inputs roll into. Single-collection
/// contracts have exactly one of these.
/// </summary>
public sealed record TradeupContribution(
int CollectionId,
string CollectionName,
WeaponRarity OutputRarity,
int InputCount);
/// <summary>
/// A concrete, actionable tradeup: which ten copies to buy, what they cost, the output
/// distribution, and the resulting economics. The finder returns these ranked; a frontend
/// only formats them.
/// <para>
/// A contract may mix several collections (all inputs share the input rarity, but each
/// collection rolls into its own next tier). <see cref="Composition"/> records the per-
/// collection split; <see cref="CollectionCount"/> is its length. <see cref="OutputRarity"/>
/// is the tier of the largest contributor (a display convenience for the common case).
/// </para>
/// </summary>
public sealed record TradeupCandidate(
int CollectionId,
string CollectionName,
WeaponRarity InputRarity,
WeaponRarity OutputRarity,
bool StatTrak,
decimal AverageFraction,
decimal InputCost,
decimal ExpectedNet,
decimal WorstCaseNet,
bool Guaranteed,
IReadOnlyList<InputListing> Inputs,
IReadOnlyList<TradeupOutcome> Outcomes,
IReadOnlyList<TradeupContribution> Composition)
{
/// <summary>Number of distinct collections the inputs are drawn from (1 = single-collection).</summary>
public int CollectionCount => Composition.Count;
/// <summary>Expected profit across the output distribution, net of cost.</summary>
public decimal ExpectedProfit => ExpectedNet - InputCost;
/// <summary>Profit if the worst (lowest-value) output lands — negative unless guaranteed.</summary>
public decimal WorstCaseProfit => WorstCaseNet - InputCost;
}