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
@@ -350,10 +350,27 @@ namespace Decentralized
|
||||
}
|
||||
|
||||
private static int _predPick;
|
||||
private enum PredTab { Markets, Intel }
|
||||
private static PredTab _predTab = PredTab.Markets;
|
||||
|
||||
/// <summary>预测页:左边盘口列表和最近结果,右边选中盘口的买卖。下注和卖出是链上合约调用,用当前钱包的 CRC,要在钱包上签名;持仓记在签名的钱包名下。</summary>
|
||||
private static string P2(double x) => x.ToString("0.00", CultureInfo.InvariantCulture);
|
||||
|
||||
/// <summary>预测页:盘口(左边列表与最近结果,右边选中盘口的价格、线索、买卖)和情报(情报贩子)。下注和卖出是链上合约调用,用当前钱包的 CRC,要在钱包上签名;持仓记在签名的钱包名下。</summary>
|
||||
private static void PredictPage(CustomUIBuilder b)
|
||||
{
|
||||
if (_predTab == PredTab.Intel && !Unlock.BlackUnlocked) _predTab = PredTab.Markets;
|
||||
if (Unlock.BlackUnlocked)
|
||||
{
|
||||
b.BeginRow();
|
||||
foreach (PredTab t in Enum.GetValues(typeof(PredTab)))
|
||||
{
|
||||
var tab = t;
|
||||
string name = L.T("predict.tab." + t.ToString().ToLowerInvariant());
|
||||
b.AddButton(tab == _predTab ? $"[{name}]" : name, () => { _predTab = tab; _message = null; Open(); });
|
||||
}
|
||||
b.End();
|
||||
}
|
||||
if (_predTab == PredTab.Intel) { IntelPage(b); return; }
|
||||
var d = Session.Data;
|
||||
var bk = d.Predict;
|
||||
var w = d.Hot;
|
||||
@@ -376,7 +393,7 @@ namespace Decentralized
|
||||
l.AddButton(m.Id == _predPick ? "[" + q + "]" : q, () => { _predPick = mk.Id; _message = null; Open(); });
|
||||
l.End();
|
||||
string state = m.IsOpen(day) ? "" : " " + L.T("predict.closed");
|
||||
l.AddLabel(L.T("predict.row", (m.PYes * 100).ToString("0"), ((1 - m.PYes) * 100).ToString("0")) + (all.Count > 0 ? " " + L.T("predict.held", L.T(all[0].Yes ? "predict.yes" : "predict.no"), Fmt.Num(all.Sum(x => x.Cost)), Fmt.Num(all.Sum(x => x.Shares))) : "") + state);
|
||||
l.AddLabel(L.T("predict.row", P2(m.PYes), P2(1 - m.PYes)) + (all.Count > 0 ? " " + L.T("predict.held", L.T(all[0].Yes ? "predict.yes" : "predict.no"), Fmt.Num(all.Sum(x => x.Shares)), Fmt.Num(all.Sum(x => x.Cost))) : "") + state);
|
||||
}
|
||||
if (bk.Recent.Count > 0)
|
||||
{
|
||||
@@ -389,14 +406,19 @@ namespace Decentralized
|
||||
if (sel == null) { r.AddHeader(L.T("predict.h")); return; }
|
||||
r.AddHeader(L.T("predict.pick"));
|
||||
r.AddLabel(PredictGame.Question(sel));
|
||||
r.AddLabel(L.T("predict.price", (sel.PYes * 100).ToString("0.0"), ((1 - sel.PYes) * 100).ToString("0.0")));
|
||||
r.AddLabel(L.T("predict.price", P2(sel.PYes), P2(1 - sel.PYes)));
|
||||
foreach (var clue in PredictGame.Clues(sel)) r.AddLabel("· " + clue);
|
||||
foreach (var pos in bk.PosAll(sel.Id))
|
||||
{
|
||||
var ow = d.Own(pos.Wallet);
|
||||
r.AddLabel(L.T("predict.pos", ow != null ? WalletWindow.NameOf(ow) : pos.Wallet, L.T(pos.Yes ? "predict.yes" : "predict.no"), Fmt.Num(pos.Shares)));
|
||||
if (pos.Wallet == w.Address)
|
||||
{
|
||||
r.AddLabel(L.T("predict.pos3", P2(pos.Cost / pos.Shares), P2(sel.PriceOf(pos.Yes))));
|
||||
r.AddLabel(L.T("predict.pos2", Fmt.Num(pos.Cost), Fmt.Num(pos.Shares)));
|
||||
r.AddLabel(L.T("predict.pos4", Fmt.Num(sel.SellValue(pos.Yes, pos.Shares) * (1 - Tuning.PredictFee))));
|
||||
}
|
||||
}
|
||||
var mine = bk.PosOf(sel.Id, w.Address);
|
||||
if (mine != null) r.AddLabel(L.T("predict.pos2", Fmt.Num(mine.Cost), Fmt.Num(sel.SellValue(mine.Yes, mine.Shares) * (1 - Tuning.PredictFee))));
|
||||
if (!sel.IsOpen(day)) { r.AddLabel(L.T("predict.closed.note")); return; }
|
||||
AmountRow(r);
|
||||
if (double.TryParse((_amount ?? "").Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out double v) && v > 0 && v < 1e7)
|
||||
@@ -404,7 +426,7 @@ namespace Decentralized
|
||||
foreach (bool yes in new[] { true, false })
|
||||
{
|
||||
double shares = sel.SharesFor(yes, v / (1 + Tuning.PredictFee));
|
||||
r.AddLabel(L.T("predict.preview", L.T(yes ? "predict.yes" : "predict.no"), Fmt.Num(shares), Fmt.Num(shares - v)));
|
||||
r.AddLabel(L.T("predict.preview", L.T(yes ? "predict.yes" : "predict.no"), Fmt.Num(shares), P2(v / shares), Fmt.Num(shares - v)));
|
||||
}
|
||||
}
|
||||
r.BeginRow();
|
||||
@@ -415,6 +437,97 @@ namespace Decentralized
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>情报页:局势简报,以及对派系行动、矿机时代盘口的内幕消息。付款是 CRT 的合约调用(销毁),要签名。</summary>
|
||||
private static void IntelPage(CustomUIBuilder b)
|
||||
{
|
||||
var d = Session.Data;
|
||||
var w = d.Hot;
|
||||
int day = StoreStation.GetDayCounter();
|
||||
Columns(b, l =>
|
||||
{
|
||||
l.AddHeader(L.T("intel.h"));
|
||||
if (!PredictGame.BrokerOpen) { l.AddLabel(L.T("intel.locked", Tuning.IntelRep)); return; }
|
||||
l.AddLabel(L.T("predict.acct.crt", WalletWindow.NameOf(w), Fmt.Num(w.Avail(Assets.CRT))));
|
||||
l.AddButton(L.T("intel.brief.buy", Fmt.Num(Tuning.IntelBriefPrice)), IntelBuyBrief);
|
||||
l.AddSeparator();
|
||||
if (d.Brief.Count == 0) l.AddLabel(L.T("intel.brief.none"));
|
||||
else
|
||||
{
|
||||
l.AddLabel(L.T("intel.brief.day", d.BriefDay));
|
||||
foreach (var line in d.Brief) l.AddLabel(line);
|
||||
}
|
||||
}, r =>
|
||||
{
|
||||
r.AddHeader(L.T("intel.tips.h"));
|
||||
if (!PredictGame.BrokerOpen) return;
|
||||
var list = d.Predict.Markets.Where(m => PredictGame.Tippable(m, day)).OrderBy(m => m.FromDay).ToList();
|
||||
if (list.Count == 0) r.AddLabel(L.T("intel.tips.none"));
|
||||
foreach (var m in list)
|
||||
{
|
||||
var mk = m;
|
||||
r.AddLabel(PredictGame.Question(m));
|
||||
var tip = d.Predict.TipFor(m.Id);
|
||||
if (tip != null) { r.AddLabel(L.T("predict.clue.tip", L.T("predict.tier." + tip.Tier), L.T(tip.Claim ? "predict.yes" : "predict.no"))); continue; }
|
||||
for (int t = 0; t < 3; t++)
|
||||
{
|
||||
int tier = t;
|
||||
r.AddButton(L.T("intel.tip.buy", (int)Math.Round(Tuning.IntelTipAcc[t] * 100), Fmt.Num(Tuning.IntelTipPrice[t] * m.MaxLoss)), () => IntelBuyTip(mk, tier));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void IntelBuyBrief()
|
||||
{
|
||||
var d = Session.Data;
|
||||
double price = Tuning.IntelBriefPrice;
|
||||
if (d.Hot.Avail(Assets.CRT) + 1e-9 < price) { _message = L.T("intel.err.funds"); Open(); return; }
|
||||
_message = L.T("hw.wait");
|
||||
Open();
|
||||
WalletWindow.OpenForBill(new WalletWindow.Bill
|
||||
{
|
||||
Contract = true, Asset = Assets.CRT, Amount = price, Summary = L.T("intel.brief.sum", Fmt.Num(price)),
|
||||
Execute = pw =>
|
||||
{
|
||||
if (pw.Avail(Assets.CRT) + 1e-9 < price) { _message = L.T("intel.err.funds"); Open(); return; }
|
||||
pw.Spend(Assets.CRT, price, Session.Price);
|
||||
int day = StoreStation.GetDayCounter();
|
||||
bool fake = d.Rng.Chance(Tuning.IntelFake);
|
||||
d.Brief = PredictGame.MakeBrief(fake, day); d.BriefDay = day;
|
||||
Log.Info($"局势简报:{(fake ? "假情报" : "真")},{string.Join(" | ", d.Brief)}");
|
||||
_message = L.T("intel.brief.done");
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static void IntelBuyTip(PredictMarket m, int tier)
|
||||
{
|
||||
var d = Session.Data;
|
||||
double price = Tuning.IntelTipPrice[tier] * m.MaxLoss;
|
||||
if (d.Hot.Avail(Assets.CRT) + 1e-9 < price) { _message = L.T("intel.err.funds"); Open(); return; }
|
||||
_message = L.T("hw.wait");
|
||||
Open();
|
||||
WalletWindow.OpenForBill(new WalletWindow.Bill
|
||||
{
|
||||
Contract = true, Asset = Assets.CRT, Amount = price, Summary = L.T("intel.tip.sum", Fmt.Num(price), PredictGame.Question(m)),
|
||||
Execute = pw =>
|
||||
{
|
||||
int day = StoreStation.GetDayCounter();
|
||||
var truth = PredictGame.Truth(m);
|
||||
if (pw.Avail(Assets.CRT) + 1e-9 < price || truth == null || !m.IsOpen(day) || d.Predict.TipFor(m.Id) != null) { _message = L.T("intel.err.funds"); Open(); return; }
|
||||
pw.Spend(Assets.CRT, price, Session.Price);
|
||||
var tip = PredictBook.MakeTip(m, truth.Value, tier, d.Rng);
|
||||
d.Predict.Tips.Add(tip);
|
||||
Log.Info($"内幕消息 #{m.Id} 第 {tier + 1} 档:说{(tip.Claim ? "是" : "否")},真相{(truth.Value ? "是" : "否")}");
|
||||
_message = L.T("intel.tip.done", L.T(tip.Claim ? "predict.yes" : "predict.no"));
|
||||
Session.Save();
|
||||
Open();
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private static void PredictBuy(PredictMarket m, bool yes)
|
||||
{
|
||||
if (!ReadAmount(out double v)) return;
|
||||
|
||||
Reference in new issue
Block a user