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

123 lines
4.9 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
namespace BlueLaminate.Core.Options;
/// <summary>
/// Which StatTrak universes the finder searches. The two input pools are disjoint and
/// never mix in a contract: non-ST inputs (normal souvenir) produce a normal output,
/// ST inputs produce an ST output.
/// </summary>
public enum StatTrakMode
{
/// <summary>Search both the non-ST and ST universes (default).</summary>
Both,
/// <summary>Only the non-ST universe (normal + souvenir inputs → normal output).</summary>
NonStatTrakOnly,
/// <summary>Only the StatTrak universe (ST inputs → ST output).</summary>
StatTrakOnly,
}
/// <summary>
/// How to rank surviving candidates.
/// </summary>
public enum TradeupRanking
{
/// <summary>By worst-case (minimum across outputs) net profit — low variance.</summary>
WorstCaseProfit,
/// <summary>By expected net profit across the output distribution.</summary>
ExpectedProfit,
}
/// <summary>
/// Tuning for the tradeup finder, bound from the <c>Tradeups</c> configuration section.
/// Defaults are sensible for CS2 marketplaces (15% sell fee) and a conservative v1
/// (guaranteed-profit only). Everything here is economics/policy — none of it lives in
/// the CLI.
/// </summary>
public sealed class TradeupOptions
{
public const string SectionName = "Tradeups";
/// <summary>Number of inputs per contract. v1 supports 10-input weapon tradeups only.</summary>
public int ContractSize { get; set; } = 10;
/// <summary>
/// Fraction of the sale price taken as marketplace commission when selling an output
/// (0.15 = 15%). Applied to the realised sell price.
/// </summary>
public decimal SellFeeRate { get; set; } = 0.15m;
/// <summary>
/// Fraction shaved off the lowest active ask to model undercutting it for a quick
/// sale (0.01 = list 1% under the cheapest competitor). Applied before the fee.
/// </summary>
public decimal UndercutRate { get; set; } = 0.01m;
/// <summary>
/// Bucket width used to discretise normalised input fractions for the
/// cardinality-constrained selection DP. Smaller = finer output-float resolution at
/// higher cost. 0.005 resolves the wear boundaries to within 0.005 of output float.
/// </summary>
public decimal FractionBucket { get; set; } = 0.005m;
/// <summary>
/// When true (v1 default) only contracts whose worst-case output still clears input
/// cost survive — a guaranteed profit. When false, any positive-EV contract survives.
/// </summary>
public bool GuaranteedOnly { get; set; } = true;
/// <summary>Minimum net profit (in the listing currency) for a candidate to be reported.</summary>
public decimal MinProfit { get; set; } = 0m;
/// <summary>How surviving candidates are ordered.</summary>
public TradeupRanking Ranking { get; set; } = TradeupRanking.WorstCaseProfit;
/// <summary>Which StatTrak universes to search.</summary>
public StatTrakMode StatTrak { get; set; } = StatTrakMode.Both;
/// <summary>
/// Currency listings must be in to be comparable. The finder ignores listings in
/// other currencies rather than converting (v1 keeps a single money space).
/// </summary>
public string Currency { get; set; } = "USD";
/// <summary>
/// When a proposed output has fewer than this many active listings in our data, its
/// stored lowest-ask is fragile, so the finder re-prices it from the live CSFloat API.
/// </summary>
public int CsFloatThinOutputThreshold { get; set; } = 10;
/// <summary>
/// Enables the live CSFloat re-pricing of thin outputs. Silently inert when no CSFloat
/// API key is configured.
/// </summary>
public bool UseCsFloatForThinOutputs { get; set; } = true;
/// <summary>
/// Hard cap on live CSFloat lookups per search, so the re-pricing pass can't blow the
/// API rate-limit budget. Distinct (skin, ST, wear band) lookups are cached within a run.
/// </summary>
public int CsFloatMaxLookups { get; set; } = 120;
/// <summary>
/// Enables the multi-collection search: alongside the single-collection pass, it mixes
/// inputs from any collections at a rarity tier to maximise expected profit. Off keeps the
/// finder single-collection only.
/// </summary>
public bool MultiCollection { get; set; } = true;
/// <summary>
/// Step of the output-float target grid the multi-collection search sweeps. Each grid
/// point is an independent, parallelised chunk (one knapsack over the tier's pool), so a
/// finer grid is more thorough but does more work. 0.02 ≈ 50 chunks per tier × ST.
/// </summary>
public decimal MultiCollectionFloatGrid { get; set; } = 0.02m;
/// <summary>
/// How many distinct multi-collection contracts to keep per (rarity tier, StatTrak), best
/// expected-profit first, after de-duplicating by collection mix. Caps result volume.
/// </summary>
public int MultiCollectionPerTier { get; set; } = 8;
}