namespace BlueLaminate.Core.Options;
///
/// 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.
///
public enum StatTrakMode
{
/// Search both the non-ST and ST universes (default).
Both,
/// Only the non-ST universe (normal + souvenir inputs → normal output).
NonStatTrakOnly,
/// Only the StatTrak universe (ST inputs → ST output).
StatTrakOnly,
}
///
/// How to rank surviving candidates.
///
public enum TradeupRanking
{
/// By worst-case (minimum across outputs) net profit — low variance.
WorstCaseProfit,
/// By expected net profit across the output distribution.
ExpectedProfit,
}
///
/// Tuning for the tradeup finder, bound from the Tradeups 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.
///
public sealed class TradeupOptions
{
public const string SectionName = "Tradeups";
/// Number of inputs per contract. v1 supports 10-input weapon tradeups only.
public int ContractSize { get; set; } = 10;
///
/// Fraction of the sale price taken as marketplace commission when selling an output
/// (0.15 = 15%). Applied to the realised sell price.
///
public decimal SellFeeRate { get; set; } = 0.15m;
///
/// 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.
///
public decimal UndercutRate { get; set; } = 0.01m;
///
/// 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.
///
public decimal FractionBucket { get; set; } = 0.005m;
///
/// 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.
///
public bool GuaranteedOnly { get; set; } = true;
/// Minimum net profit (in the listing currency) for a candidate to be reported.
public decimal MinProfit { get; set; } = 0m;
/// How surviving candidates are ordered.
public TradeupRanking Ranking { get; set; } = TradeupRanking.WorstCaseProfit;
/// Which StatTrak universes to search.
public StatTrakMode StatTrak { get; set; } = StatTrakMode.Both;
///
/// Currency listings must be in to be comparable. The finder ignores listings in
/// other currencies rather than converting (v1 keeps a single money space).
///
public string Currency { get; set; } = "USD";
///
/// 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.
///
public int CsFloatThinOutputThreshold { get; set; } = 10;
///
/// Enables the live CSFloat re-pricing of thin outputs. Silently inert when no CSFloat
/// API key is configured.
///
public bool UseCsFloatForThinOutputs { get; set; } = true;
///
/// 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.
///
public int CsFloatMaxLookups { get; set; } = 120;
///
/// 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.
///
public bool MultiCollection { get; set; } = true;
///
/// 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.
///
public decimal MultiCollectionFloatGrid { get; set; } = 0.02m;
///
/// 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.
///
public int MultiCollectionPerTier { get; set; } = 8;
}