版本 1.0.0-rc8:卖货橱窗重构、收款币种、Gas 档位速度、区块自然增长、钱包持仓
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
018ee7d0d2
commit
93e26fc4f5
20 files changed
+582
-498
No files matched your search
@@ -24,8 +24,14 @@ namespace Decentralized.Domain
|
||||
/// <summary>成交后扣掉抽成的货款(信用点)与其中带的污点。</summary>
|
||||
public int Proceeds;
|
||||
public double Taint;
|
||||
/// <summary>成交那一轮的收款币(空 = CRT,旧存档):货款到期后以这个币付给钱包。</summary>
|
||||
public string PayAsset;
|
||||
/// <summary>终态原因:fake(买家看穿假卡退货)/ rug / delist。</summary>
|
||||
public string Why;
|
||||
|
||||
/// <summary>聚合键:同一种商品(标识、型号、真伪、成色取整)算一组,同组倍率相同。</summary>
|
||||
public static string KeyOf(string item, string model, string fakeOf, double health) => item + "|" + model + "|" + fakeOf + "|" + Math.Round(health);
|
||||
public string Key => KeyOf(Item, Model, FakeOf, Health);
|
||||
}
|
||||
|
||||
public sealed partial class BlackMarket
|
||||
@@ -57,7 +63,41 @@ namespace Decentralized.Domain
|
||||
return Math.Min(Tuning.BmVolumeTaintMax, v / Tuning.BmVolumeRef * Tuning.BmVolumeTaintMax);
|
||||
}
|
||||
|
||||
/// <summary>收款币:愿意接受的币(存档),至少一种;默认只有 CRT。</summary>
|
||||
public List<string> SellAccepts = new List<string> { Assets.CRT };
|
||||
public static readonly string[] SellCoins = { Assets.PSC, Assets.CRT, Assets.CRA, Assets.Ponero };
|
||||
|
||||
public static double CoinWeight(string asset) =>
|
||||
asset == Assets.PSC ? Tuning.BmWeightPsc : asset == Assets.CRT ? Tuning.BmWeightCrt : asset == Assets.CRA ? Tuning.BmWeightCra : asset == Assets.Ponero ? Tuning.BmWeightPonero : 0;
|
||||
|
||||
public IEnumerable<string> AcceptedCoins => SellAccepts.Count == 0 ? new[] { Assets.CRT } : SellAccepts.Where(a => CoinWeight(a) > 0).Distinct().ToArray();
|
||||
|
||||
/// <summary>开关一种收款币;最后一种不能关掉。</summary>
|
||||
public bool ToggleCoin(string asset)
|
||||
{
|
||||
if (SellAccepts.Count == 0) SellAccepts.Add(Assets.CRT);
|
||||
if (SellAccepts.Contains(asset)) { if (SellAccepts.Count <= 1) return false; SellAccepts.Remove(asset); return true; }
|
||||
if (CoinWeight(asset) <= 0) return false;
|
||||
SellAccepts.Add(asset);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>在架的件数(全部)、种数、某一组的件数与倍率(没有在架返回 null)。</summary>
|
||||
public int ActiveListings => Sales.Count(x => x.State == SaleState.Listed);
|
||||
public int ActiveKinds => Sales.Where(x => x.State == SaleState.Listed).Select(x => x.Key).Distinct().Count();
|
||||
public int ActiveOf(string key) => Sales.Count(x => x.State == SaleState.Listed && x.Key == key);
|
||||
public double? MultOf(string key) { var s = Sales.FirstOrDefault(x => x.State == SaleState.Listed && x.Key == key); return s == null ? (double?)null : s.Mult; }
|
||||
|
||||
/// <summary>某一组再上架 add 件、倍率 m 时的限制:null = 可以;stack = 超过每种上限;kinds = 超过种数上限;mult = 与已在架的同种货倍率不同。</summary>
|
||||
public string ListBlock(string key, double m, int add = 1)
|
||||
{
|
||||
int have = ActiveOf(key);
|
||||
if (have + add > Tuning.BmMaxStack) return "stack";
|
||||
if (have == 0 && ActiveKinds >= Tuning.BmMaxKinds) return "kinds";
|
||||
var cur = MultOf(key);
|
||||
if (cur != null && Math.Abs(cur.Value - m) > 1e-9) return "mult";
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int ListPriceOf(long refValue, double m) => (int)Math.Max(1, Math.Round(refValue * m));
|
||||
public static int ListFee(int listPrice) => (int)Math.Ceiling(listPrice * Tuning.BmListFee);
|
||||
@@ -65,7 +105,7 @@ namespace Decentralized.Domain
|
||||
/// <summary>上架:交付一件货,收上架费(付给 feeAsset 币,污点与成本按比例带走)。倍率超出范围、平台关闭或余额不足返回 null。</summary>
|
||||
public BmSale List(string item, string model, string fakeOf, double health, long refValue, double m, Wallet w, string feeAsset, int day, Func<string, double> price)
|
||||
{
|
||||
if (m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || refValue <= 0 || Closed(day) || feeAsset == Assets.CRC || ActiveListings >= Tuning.BmMaxListings) return null;
|
||||
if (m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || refValue <= 0 || Closed(day) || feeAsset == Assets.CRC || ListBlock(BmSale.KeyOf(item, model, fakeOf, health), m) != null) return null;
|
||||
int listPrice = ListPriceOf(refValue, m);
|
||||
double p = price(feeAsset);
|
||||
if (p <= 0) return null;
|
||||
@@ -80,26 +120,6 @@ namespace Decentralized.Domain
|
||||
return s;
|
||||
}
|
||||
|
||||
public static int RepriceFee(int newPrice) => (int)Math.Ceiling(newPrice * Tuning.BmRepriceFee);
|
||||
|
||||
/// <summary>改价:上架中的货换一个倍率,按参考价重算标价,收改价费;不改变上架日。</summary>
|
||||
public bool Reprice(BmSale s, double m, Wallet w, string feeAsset, int day, Func<string, double> price)
|
||||
{
|
||||
if (s == null || s.State != SaleState.Listed || s.Ref <= 0 || Math.Abs(m - s.Mult) < 1e-9 || m < Tuning.BmSellMin - 1e-9 || m > Tuning.BmSellMax + 1e-9 || Closed(day) || feeAsset == Assets.CRC) return false;
|
||||
int listPrice = ListPriceOf(s.Ref, m);
|
||||
double p = price(feeAsset);
|
||||
if (p <= 0) return false;
|
||||
int fee = RepriceFee(listPrice);
|
||||
double qty = fee / p;
|
||||
if (w.Avail(feeAsset) + 1e-9 < qty) return false;
|
||||
double total = w.Value(price);
|
||||
double share = total > 0 ? Math.Min(1, fee / total) : 0;
|
||||
w.Taint -= w.Taint * share; w.Basis -= w.Basis * share;
|
||||
w.Add(feeAsset, -qty);
|
||||
s.Mult = m; s.ListPrice = listPrice;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Delist(BmSale s) { s.State = SaleState.Delisted; s.Why = "delist"; }
|
||||
|
||||
/// <summary>未到账的货款(信用点):跑路时一并归零,也推高跑路概率。</summary>
|
||||
@@ -111,7 +131,13 @@ namespace Decentralized.Domain
|
||||
if (crackdown) return;
|
||||
foreach (var s in Sales.Where(x => x.State == SaleState.Listed && x.ListedDay < day).ToList())
|
||||
{
|
||||
if (!rng.Chance(SaleChance(s.Mult))) continue;
|
||||
// 每接受一种币算一轮成交:轮次顺序随机,任一轮命中即成交,货款用命中的币付
|
||||
string hit = null;
|
||||
double chance = SaleChance(s.Mult);
|
||||
foreach (var c in AcceptedCoins.OrderBy(_ => rng.NextDouble()).ToList())
|
||||
if (rng.Chance(Math.Min(1, chance * CoinWeight(c)))) { hit = c; break; }
|
||||
if (hit == null) continue;
|
||||
s.PayAsset = hit;
|
||||
if (s.FakeOf != null && rng.Chance(Tuning.BmFakeDetect))
|
||||
{
|
||||
s.State = SaleState.Delisted; s.Why = "fake";
|
||||
@@ -130,10 +156,11 @@ namespace Decentralized.Domain
|
||||
}
|
||||
foreach (var s in Sales.Where(x => x.State == SaleState.Sold && day >= x.PayDay).ToList())
|
||||
{
|
||||
double p = price(Assets.CRT);
|
||||
string pa = s.PayAsset ?? Assets.CRT;
|
||||
double p = price(pa);
|
||||
if (p <= 0) continue;
|
||||
var w = wallet(s.Wallet);
|
||||
w.Add(Assets.CRT, s.Proceeds / p);
|
||||
w.Add(pa, s.Proceeds / p);
|
||||
w.Taint += s.Taint;
|
||||
w.Basis += s.Proceeds;
|
||||
s.State = SaleState.Paid;
|
||||
|
||||
@@ -134,16 +134,22 @@ namespace Decentralized.Domain
|
||||
public const double BmTrapShare = 0.4, BmTrapWindowCap = 400;
|
||||
/// <summary>货架上除违禁品外的两类货:高科技物品(需中档声望)和显卡的出现概率、加价(在现货溢价 / 订单价之外再加),显卡里夹假卡的比例、是全新卡(成色 100、封条完好、不会是假卡)的概率。</summary>
|
||||
public const double BmTechChance = 0.30, BmGpuChance = 0.30, BmTechMarkup = 0.5, BmGpuMarkup = 0.2, BmGpuFake = 0.20, BmGpuNew = 0.15;
|
||||
/// <summary>玩家上架出售:标价倍率范围(相对参考价)、上架费、改价费、成交抽成、成交后货款托管天数、假卡被买家看穿的概率;
|
||||
/// <summary>玩家上架出售:标价倍率范围(相对参考价)、上架费、成交抽成、成交后货款托管天数、假卡被买家看穿的概率;
|
||||
/// 倍率 ≤0.9 / 1.0 / 1.8 时的期望成交天数(之间插值);货款带污点的概率与比例随倍率从下限涨到上限;卖家好评的初始值、看穿一次扣的点数、同时上架的件数上限。</summary>
|
||||
public const double BmListFee = 0.05, BmRepriceFee = 0.02, BmCommission = 0.08, BmSellMin = 0.6, BmSellMax = 1.8, BmFakeDetect = 0.5;
|
||||
public const double BmListFee = 0.05, BmCommission = 0.08, BmSellMin = 0.6, BmSellMax = 1.8, BmFakeDetect = 0.5;
|
||||
/// <summary>出售成交天数的倍率界线:不高于 BmSellFastMult 倍用 BmSellDaysFast 天,BmSellDay1Mult 倍用 BmSellDays1 天,之间线性,再往上指数到 BmSellMax。</summary>
|
||||
public const double BmSellFastMult = 0.9, BmSellDay1Mult = 1.0;
|
||||
/// <summary>出售页可选的标价倍率档位。</summary>
|
||||
public static readonly double[] BmSellMults = { 0.6, 0.8, 0.9, 1.0, 1.2, 1.5, 1.8 };
|
||||
public const double BmSellDaysFast = 1, BmSellDays1 = 2, BmSellDaysMax = 14;
|
||||
public const double BmSaleTaintChanceMin = 0.2, BmSaleTaintChanceMax = 0.9, BmSaleTaintRatioMin = 0.2, BmSaleTaintRatioMax = 0.8;
|
||||
public const int BmSaleHold = 3, BmRatingStart = 90, BmRatingFakeLoss = 10, BmMaxListings = 10;
|
||||
public const int BmSaleHold = 3, BmRatingStart = 90, BmRatingFakeLoss = 10;
|
||||
/// <summary>同时上架的货:最多几种(按商品标识),每种最多几件。</summary>
|
||||
public const int BmMaxKinds = 6, BmMaxStack = 5;
|
||||
/// <summary>收款币的买家权重:每接受一种币,夜间多一轮成交判定,轮次概率 = 成交概率 × 权重(CRT 为 1 即原有节奏)。</summary>
|
||||
public const double BmWeightPsc = 0.8, BmWeightCrt = 1, BmWeightCra = 0.6, BmWeightPonero = 0.4;
|
||||
/// <summary>PLEDGER 区块高度每晚自然增长的范围(区块数,含两端)。</summary>
|
||||
public const int BlocksPerDayMin = 120, BlocksPerDayMax = 170;
|
||||
/// <summary>商家货架:每周的商家数(其中 2 家从矿卡 / 矿架 / 模组 4 类里抽,其余从其他类型里抽)、每家的货种数、每种货的库存范围;大宗商家出现概率、库存范围、送货天数;
|
||||
/// 各类商家的价格系数范围(订单价 = 基础价 × 系数);批量折扣档(件数、折扣)。</summary>
|
||||
public const int BmMerchantCount = 7, BmCoreMerchants = 2, BmMerchantListings = 3, BmQtyMin = 2, BmQtyMax = 6, BmBulkQtyMin = 10, BmBulkQtyMax = 25, BmBulkDays = 6;
|
||||
@@ -174,6 +180,8 @@ namespace Decentralized.Domain
|
||||
|
||||
/// <summary>转账手续费(信用点等值,按转出的币扣):慢 / 普通 / 快;拥堵时乘以倍数。</summary>
|
||||
public const double TxFeeSlow = 0.5, TxFeeNormal = 1.5, TxFeeFast = 4, TxCongestedFeeMult = 4;
|
||||
/// <summary>Gas 档位的确认速度倍数(时间乘它):Gas 越高确认越快、进度条走得越快;Poinbase 出金固定普通档。</summary>
|
||||
public const double TxSpeedSlow = 1.5, TxSpeedNormal = 1, TxSpeedFast = 0.5;
|
||||
/// <summary>Gas 价格指数:以 GasPeriod 天为周期正弦涨跌,振幅 GasAmp(0.5×–1.5×),每天再乘 1 ± GasNoise 的随机波动。</summary>
|
||||
public const int TxGasPeriod = 7;
|
||||
public const double TxGasAmp = 0.5, TxGasNoise = 0.15;
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Decentralized.Domain
|
||||
["AsicWeightM2"] = Tuning.AsicWeightM2,
|
||||
["AsicWeightM3"] = Tuning.AsicWeightM3,
|
||||
["BlockReward"] = Tuning.BlockReward,
|
||||
["BlocksPerDayMax"] = Tuning.BlocksPerDayMax,
|
||||
["BlocksPerDayMin"] = Tuning.BlocksPerDayMin,
|
||||
["BmAdvanceDiscount"] = Tuning.BmAdvanceDiscount,
|
||||
["BmAdvanceMinTrades"] = Tuning.BmAdvanceMinTrades,
|
||||
["BmAutoSwapSlip"] = Tuning.BmAutoSwapSlip,
|
||||
@@ -90,7 +92,8 @@ namespace Decentralized.Domain
|
||||
["BmInterceptCrackdown"] = Tuning.BmInterceptCrackdown,
|
||||
["BmInterceptDoor"] = Tuning.BmInterceptDoor,
|
||||
["BmListFee"] = Tuning.BmListFee,
|
||||
["BmMaxListings"] = Tuning.BmMaxListings,
|
||||
["BmMaxKinds"] = Tuning.BmMaxKinds,
|
||||
["BmMaxStack"] = Tuning.BmMaxStack,
|
||||
["BmMaxUnitValue"] = Tuning.BmMaxUnitValue,
|
||||
["BmMerchantCount"] = Tuning.BmMerchantCount,
|
||||
["BmMerchantListings"] = Tuning.BmMerchantListings,
|
||||
@@ -118,7 +121,6 @@ namespace Decentralized.Domain
|
||||
["BmRatingFakeLoss"] = Tuning.BmRatingFakeLoss,
|
||||
["BmRatingStart"] = Tuning.BmRatingStart,
|
||||
["BmRefreshDays"] = Tuning.BmRefreshDays,
|
||||
["BmRepriceFee"] = Tuning.BmRepriceFee,
|
||||
["BmRugBase"] = Tuning.BmRugBase,
|
||||
["BmRugClosedDays"] = Tuning.BmRugClosedDays,
|
||||
["BmRugMax"] = Tuning.BmRugMax,
|
||||
@@ -151,6 +153,10 @@ namespace Decentralized.Domain
|
||||
["BmUnlockPrice"] = Tuning.BmUnlockPrice,
|
||||
["BmVolumeRef"] = Tuning.BmVolumeRef,
|
||||
["BmVolumeTaintMax"] = Tuning.BmVolumeTaintMax,
|
||||
["BmWeightCra"] = Tuning.BmWeightCra,
|
||||
["BmWeightCrt"] = Tuning.BmWeightCrt,
|
||||
["BmWeightPonero"] = Tuning.BmWeightPonero,
|
||||
["BmWeightPsc"] = Tuning.BmWeightPsc,
|
||||
["CardBracketScratch"] = Tuning.CardBracketScratch,
|
||||
["CardFanChipped"] = Tuning.CardFanChipped,
|
||||
["CardFanDust"] = Tuning.CardFanDust,
|
||||
@@ -397,6 +403,9 @@ namespace Decentralized.Domain
|
||||
["TxPoisonChance"] = Tuning.TxPoisonChance,
|
||||
["TxPoisonDelayMax"] = Tuning.TxPoisonDelayMax,
|
||||
["TxSlowDrop"] = Tuning.TxSlowDrop,
|
||||
["TxSpeedFast"] = Tuning.TxSpeedFast,
|
||||
["TxSpeedNormal"] = Tuning.TxSpeedNormal,
|
||||
["TxSpeedSlow"] = Tuning.TxSpeedSlow,
|
||||
["UnlockPrice"] = Tuning.UnlockPrice,
|
||||
["UsedFakeMiddleman"] = Tuning.UsedFakeMiddleman,
|
||||
["UsedFakeScammer"] = Tuning.UsedFakeScammer,
|
||||
|
||||
@@ -31,12 +31,18 @@ namespace Decentralized.Domain
|
||||
public static int Confirmations(double valueCredits) =>
|
||||
valueCredits >= Tuning.TxConfirmBigValue ? Tuning.TxConfirmBig : valueCredits >= Tuning.TxConfirmMidValue ? Tuning.TxConfirmMid : Tuning.TxConfirmBase;
|
||||
|
||||
/// <summary>每次确认的间隔倍数:拥堵时慢档、普通档变慢。</summary>
|
||||
public static double Slowdown(FeeTier t, bool congested) => !congested ? 1 : t == FeeTier.Fast ? 1 : t == FeeTier.Normal ? Tuning.TxCongestedNormalSlow : Tuning.TxCongestedSlowSlow;
|
||||
/// <summary>Gas 档位本身的速度倍数:越高越快。</summary>
|
||||
public static double TierSpeed(FeeTier t) => t == FeeTier.Fast ? Tuning.TxSpeedFast : t == FeeTier.Normal ? Tuning.TxSpeedNormal : Tuning.TxSpeedSlow;
|
||||
|
||||
/// <summary>整条确认时间线的时间倍数:档位速度 × 拥堵时慢档、普通档变慢(快档不受拥堵影响)。</summary>
|
||||
public static double Slowdown(FeeTier t, bool congested) => TierSpeed(t) * (!congested ? 1 : t == FeeTier.Fast ? 1 : t == FeeTier.Normal ? Tuning.TxCongestedNormalSlow : Tuning.TxCongestedSlowSlow);
|
||||
|
||||
/// <summary>拥堵时慢档交易被挤出内存池的概率(交易作废,手续费照扣)。</summary>
|
||||
public static double DropChance(FeeTier t, bool congested) => congested && t == FeeTier.Slow ? Tuning.TxSlowDrop : 0;
|
||||
|
||||
/// <summary>夜间区块高度的自然增长。</summary>
|
||||
public static int BlocksPerDay(Rng rng) => rng.Range(Tuning.BlocksPerDayMin, Tuning.BlocksPerDayMax);
|
||||
|
||||
/// <summary>转账记录最多保留几条。</summary>
|
||||
public const int HistoryMax = 20;
|
||||
|
||||
|
||||
Reference in new issue
Block a user