Poinbase 订单簿、永续滑点减半、预测盘滑点调整、浏览器统一记账

- Poinbase 主池改为订单簿冲击曲线:第 38 天 2 PSC 约 0.1%、200 PSC 约 4%
- 永续成交深度 50,000 → 100,000,滑点减半
- 预测盘 b = 1.8 × 额度 / ln 2(5% 盘口押 50 约贵 10%),消息价 2% / 5% / 12%
- 统一记账函数 Chain:钱包每一笔进出写进浏览器和钱包记录,合约调用按执行前后余额差记账;Ponero 不上浏览器;账本上限 500
- 存档数据版本 3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ZHU MINCHAOandClaude Opus 5.5 committed 2026-11-07 22:39:18 +08:00
1 parent f0bbba2305
commit 6d8b05215c
24 files changed
+234 -81

No files matched your search

+24 -11
View File
@@ -416,9 +416,10 @@ internal static class Program
string a = ChainAddress.Make(1), b = ChainAddress.Make(2), c = ChainAddress.Make(3);
l.Add(new LedgerEntry { Block = 1, From = a, To = b, Asset = "PSC", Amount = 1 });
l.Add(new LedgerEntry { Block = 2, From = b, To = c, Asset = "CRC", Amount = 5, Fee = 1 });
l.Add(new LedgerEntry { Block = 3, From = c, To = a, Asset = "PSC", Amount = 0 });
Check(l.Entries.Count == 2 && l.Entries[0].Block == 2, "数额为 0 不记;最新的在前");
Check(l.Of(b, 10).Count == 2 && l.Of(a, 10).Count == 1 && l.Of(a.ToUpperInvariant(), 10).Count == 1 && l.Of("", 10).Count == 2, "按地址过滤,大小写不敏感,空地址是最近的全部");
l.Add(new LedgerEntry { Block = 3, From = c, To = a, Asset = "PSC", Amount = -1 });
l.Add(new LedgerEntry { Block = 4, From = c, To = a, Asset = "PSC", Amount = 0 });
Check(l.Entries.Count == 3 && l.Entries[0].Block == 4 && l.Entries[1].Block == 2, "负数不记,0 币转入(地址投毒)照记;最新的在前");
Check(l.Of(b, 10).Count == 2 && l.Of(a, 10).Count == 2 && l.Of(a.ToUpperInvariant(), 10).Count == 2 && l.Of("", 10).Count == 3, "按地址过滤,大小写不敏感,空地址是最近的全部");
for (int i = 0; i < Tuning.LedgerMax + 30; i++) l.Add(new LedgerEntry { Block = 100 + i, From = a, To = b, Asset = "PSC", Amount = 1 });
Check(l.Entries.Count == Tuning.LedgerMax && l.Entries[0].Block == 100 + Tuning.LedgerMax + 29 && l.Of("", 5).Count == 5, "上限 200 条");
var back = Newtonsoft.Json.JsonConvert.DeserializeObject<Ledger>(Newtonsoft.Json.JsonConvert.SerializeObject(l));
@@ -1296,17 +1297,26 @@ internal static class Program
Check(o.State == OrderState.Refunded && Math.Abs(b.Get(Assets.CRT) - bBefore) < 1e-6 && a.Get(Assets.CRT) == aBefore, $"骗子托管退款回 B:{o.State}");
});
Test("Poinbase 现货:按标的数量反算要付的计价币", () =>
Test("Poinbase 现货:订单簿冲击曲线、按标的数量反算要付的计价币", () =>
{
var m = Market.CreateDefault(38);
var p = m.Main;
Check(p.Book, "Poinbase 主池是订单簿");
double q = p.QuoteIn(2);
Check(Near(p.BaseOut(q), 2, 1e-9), $"买 2 PSC 要付 {q:0.00} CRC,反算回来正好 2 个");
Check(Near(p.BaseOut(q), 2, 1e-6), $"买 2 PSC 要付 {q:0.00} CRC,反算回来是 2 个");
double impact = q * (1 - p.Fee) / 2 / p.Price - 1;
Check(impact > 0 && impact < 0.0005, $"买 2 PSC 的滑点(不含手续费){impact * 100:0.000}% < 0.05%");
Check(impact > 0.0008 && impact < 0.0012, $"第 38 天买 2 PSC 的滑点(不含手续费)约 0.1%:{impact * 100:0.000}%");
double sell = 1 - p.QuoteOut(200) / (1 - p.Fee) / 200 / p.Price;
Check(sell > 0.01 && sell < 0.04, $"卖 200 PSC 的滑点 {sell * 100:0.0}%");
Check(double.IsPositiveInfinity(p.QuoteIn(p.BaseReserve)) && p.QuoteIn(0) == 0, "超出储备为无穷,0 个为 0");
Check(sell > 0.035 && sell < 0.045, $"第 38 天卖 200 PSC 的滑点约 4%:{sell * 100:0.00}%");
double p0 = p.Price, paid = p.QuoteIn(50);
double got = p.BuyBase(paid), back = p.SellBase(got);
Check(Near(got, 50, 1e-6) && Near(p.Price, p0, 1e-9) && back < paid && Near(back, paid * (1 - p.Fee) * (1 - p.Fee), paid * 1e-6), $"买进再卖出:价格回到原值,只损失两次手续费(付 {paid:0.00},回 {back:0.00})");
var one = Market.CreateDefault(38).Main; var split = Market.CreateDefault(38).Main;
double a1 = one.QuoteIn(100), a2 = 0;
for (int k = 0; k < 10; k++) { double c = split.QuoteIn(10); split.BuyBase(c); a2 += c; }
Check(Near(a1, a2, a1 * 1e-6), $"拆单不占便宜:一次买 100 付 {a1:0.00},拆十次付 {a2:0.00}");
var dex = m.DexPool(Assets.PSC);
Check(double.IsPositiveInfinity(dex.QuoteIn(dex.BaseReserve)) && dex.QuoteIn(0) == 0, "DEX 恒定乘积池:超出储备为无穷,0 个为 0");
});
Test("收黑币:事件对应币种、报价、收下后的污点", () =>
@@ -1339,6 +1349,12 @@ internal static class Program
Test("预测市场:LMSR 定价、最大亏损、买卖", () =>
{
// 流动性:第 38 天在 5% 的盘口押 50,均价比现价贵约 10%(与先验无关,50% 盘口押 50 约 0.5%)
var lo = PredictMarket.Create(1, PredictKind.Event, "x", "t", 0, 38, 39, 40, 0.05);
double slipLo = 50 / lo.SharesFor(true, 50) / 0.05 - 1;
var mid = PredictMarket.Create(1, PredictKind.Event, "x", "t", 0, 38, 39, 40, 0.5);
double slipMid = 50 / mid.SharesFor(true, 50) / 0.5 - 1;
Check(slipLo > 0.08 && slipLo < 0.12 && slipMid < 0.01, $"押 50 的滑点:5% 盘口 {slipLo * 100:0.0}%,50% 盘口 {slipMid * 100:0.0}%");
foreach (double p0 in new[] { 0.5, 0.08, 0.9 })
{
var m = PredictMarket.Create(1, PredictKind.Event, "x", "t", 0, 10, 11, 12, p0);
@@ -1347,9 +1363,6 @@ internal static class Program
double cost = 100, sh = m.SharesFor(true, cost);
Check(Math.Abs(m.BuyCost(true, sh) - cost) < 1e-6, $"闭式反解和成本函数一致({p0})");
Check(Math.Abs(m.SellValue(true, 0)) < 1e-9, "卖 0 份收回 0");
// 小额下注的滑点:100 的均价比现价贵不到 5%(低先验盘也一样)
double avg = cost / sh;
Check(avg / p0 - 1 < 0.05, $"下注 100 的滑点 {(avg / p0 - 1) * 100:0.0}%({p0})");
// 份额上限按额度:买满一边,系统最多亏份额上限
double paid = m.BuyCost(true, m.ShareCap);
Check(m.ShareCap - paid <= Tuning.PredictCap * m.Loss + 1e-6, $"买满上限系统亏 {m.ShareCap - paid:0.0}");