ui: skin poinbase spot and perp pages with crosshair pickers and right-aligned tables
This commit is contained in:
1 parent
698849c112
commit
68a53f6097
1 file changed
+48
-31
@@ -251,7 +251,7 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
var p = pool;
|
var p = pool;
|
||||||
b.AddLabel(L.T("trade.pair", p.Base, p.Quote, L.T("venue." + p.Venue)) + " " + L.T("trade.price", Fmt.Num(p.Price)));
|
b.AddLabel(L.T("trade.pair", p.Base, p.Quote, L.T("venue." + p.Venue)) + " " + L.T("trade.price", Fmt.Num(p.Price)));
|
||||||
b.BeginRow();
|
b.BeginRow(4f);
|
||||||
b.AddButton(L.T("trade.buy"), () => Trade(p, buy: true));
|
b.AddButton(L.T("trade.buy"), () => Trade(p, buy: true));
|
||||||
b.AddButton(L.T("trade.sell"), () => Trade(p, buy: false));
|
b.AddButton(L.T("trade.sell"), () => Trade(p, buy: false));
|
||||||
b.End();
|
b.End();
|
||||||
@@ -259,19 +259,25 @@ namespace Decentralized
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static readonly float[] HoldW = { 80f, 100f, 110f, 110f };
|
private static readonly float[] HoldW = { 80f, 100f, 110f, 110f };
|
||||||
|
private static readonly TextAnchor[] HoldAligns = { TextAnchor.MiddleLeft, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight };
|
||||||
|
|
||||||
private static void Holdings(CustomUIBuilder b, Wallet w, Func<string, bool> show)
|
private static void Holdings(CustomUIBuilder b, Wallet w, Func<string, bool> show)
|
||||||
{
|
{
|
||||||
TableHeader(b, HoldW, L.T("col.asset"), L.T("col.amount"), L.T("col.value"), L.T("col.avg"));
|
TableHeader(b, HoldW.Sum() + 8f, HoldW, HoldAligns, L.T("col.asset"), L.T("col.amount"), L.T("col.value"), L.T("col.avg"));
|
||||||
bool any = false;
|
bool any = false;
|
||||||
foreach (var kv in w.Balances.OrderBy(k => k.Key).Where(k => show(k.Key)))
|
foreach (var kv in w.Balances.OrderBy(k => k.Key).Where(k => show(k.Key)))
|
||||||
{
|
{
|
||||||
any = true;
|
any = true;
|
||||||
TableRow(b, HoldW, kv.Key, Fmt.Num(kv.Value), Fmt.Credits(kv.Value * Session.Price(kv.Key)), AvgText(w, kv.Key));
|
string asset = kv.Key;
|
||||||
|
bool selected = (_page == Page.Poinbase && asset == _poinAsset);
|
||||||
|
TableRow(b, HoldW.Sum() + 8f, HoldW, HoldAligns,
|
||||||
|
new[] { kv.Key, Fmt.Num(kv.Value), Fmt.Credits(kv.Value * Session.Price(kv.Key)), AvgText(w, kv.Key) },
|
||||||
|
selected,
|
||||||
|
() => { if (_page == Page.Poinbase) { _poinAsset = asset; Open(); } });
|
||||||
}
|
}
|
||||||
if (!any) b.AddLabel(L.T(w == Session.Data.Poinbase ? "poin.empty" : "wallet.empty"));
|
if (!any) b.AddLabel(L.T(w == Session.Data.Poinbase ? "poin.empty" : "wallet.empty"), "hold_empty_dim");
|
||||||
foreach (var kv in w.Frozen.OrderBy(k => k.Key).Where(k => show(k.Key)))
|
foreach (var kv in w.Frozen.OrderBy(k => k.Key).Where(k => show(k.Key)))
|
||||||
b.AddLabel(L.T("wallet.frozen", kv.Key, Fmt.Num(kv.Value), w.FrozenUntil.TryGetValue(kv.Key, out var u) ? u : 0));
|
b.AddLabel(L.T("wallet.frozen", kv.Key, Fmt.Num(kv.Value), w.FrozenUntil.TryGetValue(kv.Key, out var u) ? u : 0), "hold_frozen_note");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Poinbase:合规交易所。左边账户持仓,右边交易;信用点的存取在银行。</summary>
|
/// <summary>Poinbase:合规交易所。左边账户持仓,右边交易;信用点的存取在银行。</summary>
|
||||||
@@ -282,25 +288,25 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
var d = Session.Data;
|
var d = Session.Data;
|
||||||
var w = d.Poinbase;
|
var w = d.Poinbase;
|
||||||
b.BeginRow();
|
b.BeginRow(4f);
|
||||||
foreach (PoinTab t in Enum.GetValues(typeof(PoinTab)))
|
foreach (PoinTab t in Enum.GetValues(typeof(PoinTab)))
|
||||||
{
|
{
|
||||||
var tab = t;
|
var tab = t;
|
||||||
string name = L.T("poin.sub." + t.ToString().ToLowerInvariant());
|
string name = L.T("poin.sub." + t.ToString().ToLowerInvariant());
|
||||||
b.AddButton(tab == _poinTab ? $"[{name}]" : name, () => { _poinTab = tab; _message = null; Open(); });
|
PledgerSkin.Pick(b, name, tab == _poinTab, () => { _poinTab = tab; _message = null; Open(); }, _picked);
|
||||||
}
|
}
|
||||||
b.End();
|
b.End();
|
||||||
if (_poinTab == PoinTab.Perp) { PerpPage(b); return; }
|
if (_poinTab == PoinTab.Perp) { PerpPage(b); return; }
|
||||||
Columns(b, l =>
|
Columns(b, l =>
|
||||||
{
|
{
|
||||||
CandleChart.AddPicker(l, "poin", Assets.PSC, Open);
|
CandleChart.AddPicker(l, "poin", Assets.PSC, Open, _picked);
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
l.AddHeader(L.T("poin.account.h"));
|
l.AddHeader(L.T("poin.account.h"));
|
||||||
Holdings(l, w, a => true);
|
Holdings(l, w, a => true);
|
||||||
if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)));
|
if (w.Taint > 0.5) l.AddLabel(L.T("wallet.taint", Fmt.Credits(w.Taint)), "taint_note");
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
l.BeginRow(8f, TextAnchor.MiddleLeft);
|
l.BeginRow(8f, TextAnchor.MiddleLeft);
|
||||||
l.AddLabel(L.T("poin.deposit", d.Address("poinbase")));
|
l.AddLabel(L.T("poin.deposit", d.Address("poinbase")), "deposit_dim");
|
||||||
l.AddButton(L.T("hw.copy"), () => { Clipboard.Copy(d.Address("poinbase")); _message = L.T("hw.copied.addr", d.Address("poinbase")); Open(); });
|
l.AddButton(L.T("hw.copy"), () => { Clipboard.Copy(d.Address("poinbase")); _message = L.T("hw.copied.addr", d.Address("poinbase")); Open(); });
|
||||||
l.End();
|
l.End();
|
||||||
}, r =>
|
}, r =>
|
||||||
@@ -309,11 +315,11 @@ namespace Decentralized
|
|||||||
AmountRow(r);
|
AmountRow(r);
|
||||||
TradeRows(r, venue);
|
TradeRows(r, venue);
|
||||||
r.AddSeparator();
|
r.AddSeparator();
|
||||||
r.BeginRow();
|
r.BeginRow(4f);
|
||||||
foreach (var a in new[] { Assets.CRC, Assets.PSC })
|
foreach (var a in new[] { Assets.CRC, Assets.PSC })
|
||||||
{
|
{
|
||||||
var asset = a;
|
var asset = a;
|
||||||
r.AddButton(asset == _poinAsset ? $"[{asset}]" : asset, () => { _poinAsset = asset; Open(); });
|
PledgerSkin.Pick(r, asset, asset == _poinAsset, () => { _poinAsset = asset; Open(); }, _picked);
|
||||||
}
|
}
|
||||||
r.End();
|
r.End();
|
||||||
r.AddButton(L.T("poin.out", WalletWindow.NameOf(d.Hot)), PoinbaseOut);
|
r.AddButton(L.T("poin.out", WalletWindow.NameOf(d.Hot)), PoinbaseOut);
|
||||||
@@ -326,6 +332,7 @@ namespace Decentralized
|
|||||||
private static bool _perpLong = true;
|
private static bool _perpLong = true;
|
||||||
private static int _perpLev = 3;
|
private static int _perpLev = 3;
|
||||||
private static readonly float[] PerpW = { 118f, 60f, 104f, 60f, 58f };
|
private static readonly float[] PerpW = { 118f, 60f, 104f, 60f, 58f };
|
||||||
|
private static readonly TextAnchor[] PerpAligns = { TextAnchor.MiddleLeft, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight, TextAnchor.MiddleRight };
|
||||||
|
|
||||||
private static double PerpSpot(string p) => p == "SPARK" ? Session.Data.Stable.Spark : Session.Data.Market.Price;
|
private static double PerpSpot(string p) => p == "SPARK" ? Session.Data.Stable.Spark : Session.Data.Market.Price;
|
||||||
|
|
||||||
@@ -341,46 +348,56 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
l.AddHeader(L.T("perp.h"));
|
l.AddHeader(L.T("perp.h"));
|
||||||
l.AddLabel(L.T("perp.acct", Fmt.Num(acct.Avail(Assets.CRC))));
|
l.AddLabel(L.T("perp.acct", Fmt.Num(acct.Avail(Assets.CRC))));
|
||||||
if (bk.Debt > 0) l.AddLabel(L.T("perp.debt", Fmt.Credits(bk.Debt), Math.Max(0, Tuning.PerpDebtDays - (day - bk.DebtSince))));
|
if (bk.Debt > 0) l.AddLabel(L.T("perp.debt", Fmt.Credits(bk.Debt), Math.Max(0, Tuning.PerpDebtDays - (day - bk.DebtSince))), "perp_debt_note");
|
||||||
if (bk.Banned(day)) l.AddLabel(L.T("perp.banned", bk.BannedUntil - day + 1));
|
if (bk.Banned(day)) l.AddLabel(L.T("perp.banned", bk.BannedUntil - day + 1), "perp_banned_note");
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
if (bk.Positions.Count == 0) l.AddLabel(L.T("perp.none"));
|
if (bk.Positions.Count == 0) l.AddLabel(L.T("perp.none"), "perp_none_dim");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TableHeader(l, PerpW, L.T("perp.col.pos"), L.T("perp.col.notional"), L.T("perp.col.price"), L.T("perp.col.pnl"), L.T("perp.col.liq"));
|
TableHeader(l, PerpW.Sum() + 8f, PerpW, PerpAligns, L.T("perp.col.pos"), L.T("perp.col.notional"), L.T("perp.col.price"), L.T("perp.col.pnl"), L.T("perp.col.liq"));
|
||||||
foreach (var p in bk.Positions)
|
foreach (var p in bk.Positions)
|
||||||
{
|
{
|
||||||
double spot = PerpSpot(p.Product);
|
var pos = p;
|
||||||
TableRow(l, PerpW, p.Product + " " + L.T(p.Long ? "perp.long" : "perp.short") + " " + Math.Round(p.Leverage, 1) + "×", Fmt.Credits(p.Notional(spot)),
|
double spot = PerpSpot(pos.Product);
|
||||||
Fmt.Num(p.Entry) + " → " + Fmt.Num(spot), Fmt.Credits(p.Pnl(spot)), Fmt.Num(p.LiqPrice));
|
bool selPos = pos.Product == _perpProduct;
|
||||||
|
TableRow(l, PerpW.Sum() + 8f, PerpW, PerpAligns,
|
||||||
|
new[] {
|
||||||
|
pos.Product + " " + L.T(pos.Long ? "perp.long" : "perp.short") + " " + Math.Round(pos.Leverage, 1) + "×",
|
||||||
|
Fmt.Credits(pos.Notional(spot)),
|
||||||
|
Fmt.Num(pos.Entry) + " → " + Fmt.Num(spot),
|
||||||
|
Fmt.Credits(pos.Pnl(spot)),
|
||||||
|
Fmt.Num(pos.LiqPrice)
|
||||||
|
},
|
||||||
|
selPos,
|
||||||
|
() => { _perpProduct = pos.Product; Open(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
foreach (var p in PerpBook.Products)
|
foreach (var p in PerpBook.Products)
|
||||||
l.AddLabel(L.T("perp.rate", p, Fmt.Num(PerpSpot(p)), (bk.Rate(p) * 100).ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture)));
|
l.AddLabel(L.T("perp.rate", p, Fmt.Num(PerpSpot(p)), (bk.Rate(p) * 100).ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture)), "perp_rate_dim");
|
||||||
l.AddLabel(L.T("perp.fund", Fmt.Credits(bk.InsuranceFund)));
|
l.AddLabel(L.T("perp.fund", Fmt.Credits(bk.InsuranceFund)), "perp_fund_dim");
|
||||||
l.AddSeparator();
|
l.AddSeparator();
|
||||||
CandleChart.Add(l, "perp", _perpProduct);
|
CandleChart.Add(l, "perp", _perpProduct);
|
||||||
}, r =>
|
}, r =>
|
||||||
{
|
{
|
||||||
r.AddHeader(L.T("perp.open"));
|
r.AddHeader(L.T("perp.open"));
|
||||||
r.BeginRow();
|
r.BeginRow(4f);
|
||||||
foreach (var p in PerpBook.Products)
|
foreach (var p in PerpBook.Products)
|
||||||
{
|
{
|
||||||
var product = p;
|
var product = p;
|
||||||
r.AddButton(product == _perpProduct ? $"[{product}]" : product, () => { _perpProduct = product; Open(); });
|
PledgerSkin.Pick(r, product, product == _perpProduct, () => { _perpProduct = product; Open(); }, _picked);
|
||||||
}
|
}
|
||||||
r.End();
|
r.End();
|
||||||
r.BeginRow();
|
r.BeginRow(4f);
|
||||||
r.AddButton(_perpLong ? "[" + L.T("perp.long") + "]" : L.T("perp.long"), () => { _perpLong = true; Open(); });
|
PledgerSkin.Pick(r, L.T("perp.long"), _perpLong, () => { _perpLong = true; Open(); }, _picked);
|
||||||
r.AddButton(!_perpLong ? "[" + L.T("perp.short") + "]" : L.T("perp.short"), () => { _perpLong = false; Open(); });
|
PledgerSkin.Pick(r, L.T("perp.short"), !_perpLong, () => { _perpLong = false; Open(); }, _picked);
|
||||||
r.End();
|
r.End();
|
||||||
r.BeginRow();
|
r.BeginRow(4f);
|
||||||
foreach (int lev in new[] { 1, 2, 3, 5 })
|
foreach (int lev in new[] { 1, 2, 3, 5 })
|
||||||
{
|
{
|
||||||
if (lev > PerpBook.MaxLeverage(_perpProduct)) continue;
|
if (lev > PerpBook.MaxLeverage(_perpProduct)) continue;
|
||||||
int lv = lev;
|
int lv = lev;
|
||||||
r.AddButton(lv == _perpLev ? $"[{lv}×]" : lv + "×", () => { _perpLev = lv; Open(); });
|
PledgerSkin.Pick(r, lv + "×", lv == _perpLev, () => { _perpLev = lv; Open(); }, _picked);
|
||||||
}
|
}
|
||||||
r.End();
|
r.End();
|
||||||
r.AddLabel(L.T("perp.margin"));
|
r.AddLabel(L.T("perp.margin"));
|
||||||
@@ -389,10 +406,10 @@ namespace Decentralized
|
|||||||
{
|
{
|
||||||
double notional = m * _perpLev, spot = PerpSpot(_perpProduct), exec = bk.Exec(spot, notional, _perpLong, day);
|
double notional = m * _perpLev, spot = PerpSpot(_perpProduct), exec = bk.Exec(spot, notional, _perpLong, day);
|
||||||
var ghost = new PerpPosition { Long = _perpLong, Entry = exec, Size = notional / exec, Margin = m };
|
var ghost = new PerpPosition { Long = _perpLong, Entry = exec, Size = notional / exec, Margin = m };
|
||||||
r.AddLabel(L.T("perp.preview", Fmt.Credits(notional), Fmt.Num(exec)));
|
r.AddLabel(L.T("perp.preview", Fmt.Credits(notional), Fmt.Num(exec)), "perp_preview_dim");
|
||||||
r.AddLabel(L.T("perp.preview2", Fmt.Num(notional * Tuning.PerpFee), Fmt.Num(ghost.LiqPrice)));
|
r.AddLabel(L.T("perp.preview2", Fmt.Num(notional * Tuning.PerpFee), Fmt.Num(ghost.LiqPrice)), "perp_preview_dim");
|
||||||
}
|
}
|
||||||
r.BeginRow();
|
r.BeginRow(6f);
|
||||||
r.AddButton(L.T("perp.do.open"), PerpOpen);
|
r.AddButton(L.T("perp.do.open"), PerpOpen);
|
||||||
r.AddButton(L.T("perp.do.add"), PerpAdd);
|
r.AddButton(L.T("perp.do.add"), PerpAdd);
|
||||||
r.AddButton(L.T("perp.do.close"), PerpClose);
|
r.AddButton(L.T("perp.do.close"), PerpClose);
|
||||||
|
|||||||
Reference in new issue
Block a user