123 lines
4.9 KiB
C#
123 lines
4.9 KiB
C#
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;
|
||
}
|