Prediction markets: news reaction, clues, gas/CRA/era markets, intel broker, bigger stakes
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ca3230e7d2
commit
002606056d
12 files changed
+637
-52
No files matched your search
@@ -4,7 +4,7 @@ using System.Linq;
|
||||
|
||||
namespace Decentralized.Domain
|
||||
{
|
||||
public enum PredictKind { Event, Faction, Purity, Price }
|
||||
public enum PredictKind { Event, Faction, Purity, Price, Gas, Cra, Era }
|
||||
|
||||
public enum PredictResult { Ok, Closed, Amount, Funds, Cap, Opposite, NoPosition }
|
||||
|
||||
@@ -75,6 +75,14 @@ namespace Decentralized.Domain
|
||||
public double Shares, Cost, Taint, Basis, Insider;
|
||||
}
|
||||
|
||||
/// <summary>情报贩子卖的内幕消息:对某个盘口给出"是 / 否"的说法,三档准确率,可能是假的(与真相相反)。</summary>
|
||||
public sealed class PredictTip
|
||||
{
|
||||
public int Market, Tier;
|
||||
public bool Claim;
|
||||
public double Paid;
|
||||
}
|
||||
|
||||
/// <summary>结算记录(盘口列表下面的"最近结果")。</summary>
|
||||
public sealed class PredictRecord
|
||||
{
|
||||
@@ -109,6 +117,7 @@ namespace Decentralized.Domain
|
||||
public List<PredictMarket> Markets = new List<PredictMarket>();
|
||||
public List<PredictPos> Positions = new List<PredictPos>();
|
||||
public List<PredictRecord> Recent = new List<PredictRecord>();
|
||||
public List<PredictTip> Tips = new List<PredictTip>();
|
||||
public int Seq;
|
||||
/// <summary>每晚观测:当天新出现的事件标识(和 "F:派系")。窗口里缺任何一天的观测,盘口作废退款。</summary>
|
||||
public Dictionary<int, List<string>> Started = new Dictionary<int, List<string>>();
|
||||
@@ -222,6 +231,7 @@ namespace Decentralized.Domain
|
||||
else Record(day, m, m.Outcome, 0, false);
|
||||
}
|
||||
Markets.RemoveAll(m => m.Outcome >= 0);
|
||||
Tips.RemoveAll(t => Find(t.Market) == null);
|
||||
return evs;
|
||||
}
|
||||
|
||||
@@ -231,6 +241,34 @@ namespace Decentralized.Domain
|
||||
while (Recent.Count > Tuning.PredictHistory) Recent.RemoveAt(0);
|
||||
}
|
||||
|
||||
public PredictTip TipFor(int market) => Tips.Find(t => t.Market == market);
|
||||
|
||||
/// <summary>造一条内幕消息:假情报(概率 IntelFake)说的与真相相反,否则按这一档的准确率说对或说错。</summary>
|
||||
public static PredictTip MakeTip(PredictMarket m, bool truth, int tier, Rng rng)
|
||||
{
|
||||
bool claim;
|
||||
if (rng.Chance(Tuning.IntelFake)) claim = !truth;
|
||||
else claim = rng.Chance(Tuning.IntelTipAcc[tier]) ? truth : !truth;
|
||||
return new PredictTip { Market = m.Id, Tier = tier, Claim = claim, Paid = Tuning.IntelTipPrice[tier] * m.MaxLoss };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 夜间的消息反应:还能交易的盘口(明天仍开着)向"公开信息下的合理概率"靠拢 PredictDrift,再加 logit 噪声(NPC 流量)。
|
||||
/// 价格在夜里才反应,所以白天先看到报纸、传闻的人可以抢在前面买、等涨价再卖。target 返回 null 表示这个盘口没有新信息。
|
||||
/// </summary>
|
||||
public void Drift(int day, Func<PredictMarket, double?> target, Rng rng)
|
||||
{
|
||||
foreach (var m in Markets.Where(x => x.Outcome < 0 && x.FromDay > day + 1))
|
||||
{
|
||||
double p = m.PYes, t = target(m) ?? p;
|
||||
t = Math.Max(Tuning.PredictPMin, Math.Min(Tuning.PredictPMax, t));
|
||||
double pt = p + Tuning.PredictDrift * (t - p);
|
||||
double lp = Math.Log(pt / (1 - pt)) + Tuning.PredictNoise * rng.Gauss();
|
||||
pt = Math.Max(Tuning.PredictPMin, Math.Min(Tuning.PredictPMax, 1 / (1 + Math.Exp(-lp))));
|
||||
m.QYes = m.QNo + m.B * Math.Log(pt / (1 - pt));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>读观测:窗口里每一天都有记录才能判断;有任何一天缺就返回 null(作废)。</summary>
|
||||
public bool? Happened(PredictMarket m)
|
||||
{
|
||||
@@ -260,7 +298,7 @@ namespace Decentralized.Domain
|
||||
{
|
||||
var c = pool[rng.Range(0, pool.Count - 1)];
|
||||
pool.RemoveAll(x => x.Kind == c.Kind && x.Key == c.Key);
|
||||
int from = c.Tomorrow ? day + 1 : day + 1 + rng.Range(0, 1);
|
||||
int from = c.Tomorrow ? day + 1 : day + 1 + rng.Range(0, 2);
|
||||
int to = c.Tomorrow ? from : from + rng.Range(0, 2);
|
||||
var m = PredictMarket.Create(++Seq, c.Kind, c.Key, c.Title, c.Param, day, from, to, c.Prob(from, to));
|
||||
Markets.Add(m); made.Add(m);
|
||||
@@ -279,6 +317,51 @@ namespace Decentralized.Domain
|
||||
return 1 - Math.Pow(1 - p1, days);
|
||||
}
|
||||
|
||||
/// <summary>某天 gas 不低于阈值的概率(已知相位):周期值 × (1 ± 噪声) 均匀分布。</summary>
|
||||
public static double GasAtLeast(int day, int phase, double threshold)
|
||||
{
|
||||
double c = TxRules.GasCycle(day, phase), hi = c * (1 + Tuning.TxGasNoise), lo = c * (1 - Tuning.TxGasNoise);
|
||||
return Math.Max(0, Math.Min(1, (hi - threshold) / (hi - lo)));
|
||||
}
|
||||
|
||||
/// <summary>不知道相位时的先验:七个相位等可能。</summary>
|
||||
public static double GasFlat(int day, double threshold)
|
||||
{
|
||||
double s = 0;
|
||||
for (int ph = 0; ph < Tuning.TxGasPeriod; ph++) s += GasAtLeast(day, ph, threshold);
|
||||
return s / Tuning.TxGasPeriod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CRA 预警在 [from, to] 夜里发出的概率:每晚补贴池先被消耗,归零那晚必发,否则按日概率;
|
||||
/// 窗口之前已经发出的不算(那就是"否")。subsidy / drain 是今天的补贴池和每晚消耗,today 是今晚。
|
||||
/// </summary>
|
||||
public static double CraWarnProb(double subsidy, double drain, int today, int from, int to, double dailyHazard)
|
||||
{
|
||||
double noWarn = 1, inWindow = 0;
|
||||
for (int d = today; d <= to; d++)
|
||||
{
|
||||
subsidy -= drain;
|
||||
double h = subsidy <= 0 ? 1 : dailyHazard;
|
||||
if (d >= from) inWindow += noWarn * h;
|
||||
noWarn *= 1 - h;
|
||||
}
|
||||
return inWindow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 矿机时代在 [from, to] 开始的概率:没出预警时在 [eraMin, eraMax] 里均匀;预警已出(warnDay >= 0)时落在预警后 EraWarnMin..EraWarnMax 天。
|
||||
/// 只算还没过去的日子(today 之后)。
|
||||
/// </summary>
|
||||
public static double EraProb(int today, int from, int to, int warnDay)
|
||||
{
|
||||
int lo = warnDay >= 0 ? warnDay + Tuning.EraWarnMin : Tuning.EraMin, hi = warnDay >= 0 ? warnDay + Tuning.EraWarnMax : Tuning.EraMax;
|
||||
lo = Math.Max(lo, today + 1);
|
||||
if (hi < lo) return 0;
|
||||
int a = Math.Max(lo, from), b = Math.Min(hi, to);
|
||||
return b < a ? 0 : (b - a + 1) / (double)(hi - lo + 1);
|
||||
}
|
||||
|
||||
public static double FactionProb(int days) => 1 - Math.Pow(1 - Tuning.PredictFactionDaily, days);
|
||||
|
||||
/// <summary>均匀整数 lo..hi 里不低于 threshold 的概率。</summary>
|
||||
|
||||
@@ -192,11 +192,17 @@ namespace Decentralized.Domain
|
||||
/// 同时开放的盘口数量范围、每天最多新开几个;内幕持仓达到上限份额的多少比例后结算被查的概率,查实后收益记罪证的比例与上限;
|
||||
/// 派系行动的日均开始概率(先验);先验概率的夹紧范围;结算记录保留条数。</summary>
|
||||
public const int PredictUnlockDay = 8;
|
||||
public const double PredictFee = 0.02, PredictLoss0 = 300, PredictLossPerDay = 10, PredictCap = 3;
|
||||
public const double PredictFee = 0.02, PredictLoss0 = 800, PredictLossPerDay = 25, PredictCap = 3;
|
||||
public const int PredictOpenMin = 3, PredictOpenMax = 6, PredictNewPerDay = 2;
|
||||
public const double PredictInsiderShare = 0.4, PredictInsiderCatch = 0.5, PredictFraudShare = 0.5, PredictFraudCap = 400;
|
||||
public const double PredictFactionDaily = 0.06, PredictPMin = 0.03, PredictPMax = 0.97;
|
||||
public const int PredictHistory = 8;
|
||||
/// <summary>盘口对消息的反应:每晚向"公开信息下的合理概率"靠拢的比例,以及盘口 logit 上的随机噪声(NPC 流量)。</summary>
|
||||
public const double PredictDrift = 0.5, PredictNoise = 0.35;
|
||||
/// <summary>情报贩子:局势简报价格(CRT)、三档内幕消息的价格(占盘口最大亏损的比例)与准确率、假情报概率(claim 与真相相反)、需要的黑市声望。</summary>
|
||||
public const double IntelBriefPrice = 120, IntelFake = 0.10;
|
||||
public static readonly double[] IntelTipPrice = { 0.01, 0.025, 0.05 }, IntelTipAcc = { 0.60, 0.80, 0.95 };
|
||||
public const int IntelRep = 20;
|
||||
|
||||
/// <summary>主交易对(信用点一侧)的深度随天数增长。</summary>
|
||||
public static double PoolDepth(int day) => PoolDepth0 * (1 + day / 60.0);
|
||||
|
||||
@@ -108,6 +108,14 @@ namespace Decentralized.Domain
|
||||
}
|
||||
|
||||
/// <summary>按价格表估值(信用点)。</summary>
|
||||
/// <summary>花掉(销毁)一笔币:污点与成本按这笔币占钱包总价值的比例一起带走。</summary>
|
||||
public void Spend(string asset, double amount, Func<string, double> price)
|
||||
{
|
||||
double total = Value(price), share = total > 0 ? Math.Min(1, amount * price(asset) / total) : 0;
|
||||
double taint = Taint * share, basis = Basis * share;
|
||||
Add(asset, -amount); Taint -= taint; Basis -= basis;
|
||||
}
|
||||
|
||||
public double Value(Func<string, double> price) => Balances.Sum(kv => kv.Value * price(kv.Key));
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in new issue
Block a user