From 2c40e5a89a5f318d5618b21585b0140ceff80c72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=B7=E7=94=B5=E8=8A=BD=E8=A1=A3?= Date: Mon, 5 Oct 2026 14:28:19 -0400 Subject: [PATCH] Trading: components 161-180 --- bid_ask_bar.go | 60 ++++ bid_ask_bar_test.go | 34 +++ depth_ladder.go | 178 +++++++++++ depth_ladder_test.go | 113 +++++++ docs/components/161-ticker-tape.md | 46 +++ docs/components/162-quote-card.md | 43 +++ docs/components/163-price-text.md | 46 +++ docs/components/164-price-change-badge.md | 42 +++ docs/components/165-order-book.md | 52 ++++ docs/components/166-level2-quotes.md | 46 +++ docs/components/167-time-and-sales.md | 48 +++ docs/components/168-depth-ladder.md | 50 +++ docs/components/169-spread-indicator.md | 41 +++ docs/components/170-bid-ask-bar.md | 41 +++ docs/components/171-order-entry.md | 52 ++++ docs/components/172-quick-trade-buttons.md | 47 +++ docs/components/173-position-table.md | 49 +++ docs/components/174-order-table.md | 48 +++ docs/components/175-trade-history-table.md | 49 +++ docs/components/176-pnl-display.md | 44 +++ docs/components/177-leverage-slider.md | 46 +++ docs/components/178-margin-indicator.md | 41 +++ docs/components/179-risk-meter.md | 41 +++ docs/components/180-order-confirm-dialog.md | 52 ++++ example_trading_test.go | 221 ++++++++++++++ examples/gallery/pages_trading.go | 275 ++++++++++++++++- examples/gallery/pages_trading_code.go | 156 ++++++++++ examples/gallery/pages_trading_orders.go | 286 ++++++++++++++++++ level2_quotes.go | 123 ++++++++ level2_quotes_test.go | 63 ++++ leverage_slider.go | 159 ++++++++++ leverage_slider_test.go | 94 ++++++ margin_indicator.go | 71 +++++ margin_indicator_test.go | 39 +++ messages_trading.go | 161 ++++++++++ order_book.go | 260 ++++++++++++++++ order_book_test.go | 123 ++++++++ order_confirm_dialog.go | 88 ++++++ order_confirm_dialog_test.go | 78 +++++ order_entry.go | 222 ++++++++++++++ order_entry_test.go | 137 +++++++++ order_table.go | 194 ++++++++++++ order_table_test.go | 118 ++++++++ pnl_display.go | 82 +++++ pnl_display_test.go | 43 +++ position_table.go | 107 +++++++ position_table_test.go | 84 +++++ price_change_badge.go | 37 +++ price_change_badge_test.go | 35 +++ price_text.go | 171 +++++++++++ price_text_test.go | 106 +++++++ quick_trade_buttons.go | 127 ++++++++ quick_trade_buttons_test.go | 86 ++++++ quote_card.go | 52 ++++ quote_card_test.go | 43 +++ risk_meter.go | 84 +++++ risk_meter_test.go | 42 +++ spread_indicator.go | 53 ++++ spread_indicator_test.go | 42 +++ .../snapshots/darwin/bid_ask_bar-dark.png | Bin 0 -> 5801 bytes .../snapshots/darwin/bid_ask_bar-light.png | Bin 0 -> 5715 bytes .../snapshots/darwin/depth_ladder-dark.png | Bin 0 -> 11744 bytes .../snapshots/darwin/depth_ladder-light.png | Bin 0 -> 11140 bytes .../snapshots/darwin/level2_quotes-dark.png | Bin 0 -> 15272 bytes .../snapshots/darwin/level2_quotes-light.png | Bin 0 -> 14620 bytes .../snapshots/darwin/leverage_slider-dark.png | Bin 0 -> 8567 bytes .../darwin/leverage_slider-light.png | Bin 0 -> 8234 bytes .../darwin/margin_indicator-dark.png | Bin 0 -> 8169 bytes .../darwin/margin_indicator-light.png | Bin 0 -> 7925 bytes testdata/snapshots/darwin/order_book-dark.png | Bin 0 -> 18445 bytes .../snapshots/darwin/order_book-light.png | Bin 0 -> 17683 bytes .../darwin/order_confirm_dialog-dark.png | Bin 0 -> 27098 bytes .../darwin/order_confirm_dialog-light.png | Bin 0 -> 27676 bytes .../snapshots/darwin/order_entry-dark.png | Bin 0 -> 25738 bytes .../snapshots/darwin/order_entry-light.png | Bin 0 -> 24671 bytes .../snapshots/darwin/order_table-dark.png | Bin 0 -> 33166 bytes .../snapshots/darwin/order_table-light.png | Bin 0 -> 31963 bytes .../snapshots/darwin/pnl_display-dark.png | Bin 0 -> 9651 bytes .../snapshots/darwin/pnl_display-light.png | Bin 0 -> 9489 bytes .../snapshots/darwin/position_table-dark.png | Bin 0 -> 27714 bytes .../snapshots/darwin/position_table-light.png | Bin 0 -> 27071 bytes .../darwin/price_change_badge-dark.png | Bin 0 -> 5715 bytes .../darwin/price_change_badge-light.png | Bin 0 -> 5632 bytes testdata/snapshots/darwin/price_text-dark.png | Bin 0 -> 6387 bytes .../snapshots/darwin/price_text-light.png | Bin 0 -> 6279 bytes .../darwin/quick_trade_buttons-dark.png | Bin 0 -> 5194 bytes .../darwin/quick_trade_buttons-light.png | Bin 0 -> 5097 bytes testdata/snapshots/darwin/quote_card-dark.png | Bin 0 -> 9126 bytes .../snapshots/darwin/quote_card-light.png | Bin 0 -> 8893 bytes testdata/snapshots/darwin/risk_meter-dark.png | Bin 0 -> 5465 bytes .../snapshots/darwin/risk_meter-light.png | Bin 0 -> 5229 bytes .../darwin/spread_indicator-dark.png | Bin 0 -> 7438 bytes .../darwin/spread_indicator-light.png | Bin 0 -> 7308 bytes .../snapshots/darwin/ticker_tape-dark.png | Bin 0 -> 8071 bytes .../snapshots/darwin/ticker_tape-light.png | Bin 0 -> 7578 bytes .../snapshots/darwin/time_and_sales-dark.png | Bin 0 -> 28841 bytes .../snapshots/darwin/time_and_sales-light.png | Bin 0 -> 27613 bytes .../darwin/trade_history_table-dark.png | Bin 0 -> 23321 bytes .../darwin/trade_history_table-light.png | Bin 0 -> 22690 bytes ticker_tape.go | 155 ++++++++++ ticker_tape_test.go | 93 ++++++ time_and_sales.go | 137 +++++++++ time_and_sales_test.go | 90 ++++++ trade_history_table.go | 110 +++++++ trade_history_table_test.go | 87 ++++++ 105 files changed, 6042 insertions(+), 1 deletion(-) create mode 100644 bid_ask_bar.go create mode 100644 bid_ask_bar_test.go create mode 100644 depth_ladder.go create mode 100644 depth_ladder_test.go create mode 100644 docs/components/161-ticker-tape.md create mode 100644 docs/components/162-quote-card.md create mode 100644 docs/components/163-price-text.md create mode 100644 docs/components/164-price-change-badge.md create mode 100644 docs/components/165-order-book.md create mode 100644 docs/components/166-level2-quotes.md create mode 100644 docs/components/167-time-and-sales.md create mode 100644 docs/components/168-depth-ladder.md create mode 100644 docs/components/169-spread-indicator.md create mode 100644 docs/components/170-bid-ask-bar.md create mode 100644 docs/components/171-order-entry.md create mode 100644 docs/components/172-quick-trade-buttons.md create mode 100644 docs/components/173-position-table.md create mode 100644 docs/components/174-order-table.md create mode 100644 docs/components/175-trade-history-table.md create mode 100644 docs/components/176-pnl-display.md create mode 100644 docs/components/177-leverage-slider.md create mode 100644 docs/components/178-margin-indicator.md create mode 100644 docs/components/179-risk-meter.md create mode 100644 docs/components/180-order-confirm-dialog.md create mode 100644 example_trading_test.go create mode 100644 examples/gallery/pages_trading_code.go create mode 100644 examples/gallery/pages_trading_orders.go create mode 100644 level2_quotes.go create mode 100644 level2_quotes_test.go create mode 100644 leverage_slider.go create mode 100644 leverage_slider_test.go create mode 100644 margin_indicator.go create mode 100644 margin_indicator_test.go create mode 100644 messages_trading.go create mode 100644 order_book.go create mode 100644 order_book_test.go create mode 100644 order_confirm_dialog.go create mode 100644 order_confirm_dialog_test.go create mode 100644 order_entry.go create mode 100644 order_entry_test.go create mode 100644 order_table.go create mode 100644 order_table_test.go create mode 100644 pnl_display.go create mode 100644 pnl_display_test.go create mode 100644 position_table.go create mode 100644 position_table_test.go create mode 100644 price_change_badge.go create mode 100644 price_change_badge_test.go create mode 100644 price_text.go create mode 100644 price_text_test.go create mode 100644 quick_trade_buttons.go create mode 100644 quick_trade_buttons_test.go create mode 100644 quote_card.go create mode 100644 quote_card_test.go create mode 100644 risk_meter.go create mode 100644 risk_meter_test.go create mode 100644 spread_indicator.go create mode 100644 spread_indicator_test.go create mode 100644 testdata/snapshots/darwin/bid_ask_bar-dark.png create mode 100644 testdata/snapshots/darwin/bid_ask_bar-light.png create mode 100644 testdata/snapshots/darwin/depth_ladder-dark.png create mode 100644 testdata/snapshots/darwin/depth_ladder-light.png create mode 100644 testdata/snapshots/darwin/level2_quotes-dark.png create mode 100644 testdata/snapshots/darwin/level2_quotes-light.png create mode 100644 testdata/snapshots/darwin/leverage_slider-dark.png create mode 100644 testdata/snapshots/darwin/leverage_slider-light.png create mode 100644 testdata/snapshots/darwin/margin_indicator-dark.png create mode 100644 testdata/snapshots/darwin/margin_indicator-light.png create mode 100644 testdata/snapshots/darwin/order_book-dark.png create mode 100644 testdata/snapshots/darwin/order_book-light.png create mode 100644 testdata/snapshots/darwin/order_confirm_dialog-dark.png create mode 100644 testdata/snapshots/darwin/order_confirm_dialog-light.png create mode 100644 testdata/snapshots/darwin/order_entry-dark.png create mode 100644 testdata/snapshots/darwin/order_entry-light.png create mode 100644 testdata/snapshots/darwin/order_table-dark.png create mode 100644 testdata/snapshots/darwin/order_table-light.png create mode 100644 testdata/snapshots/darwin/pnl_display-dark.png create mode 100644 testdata/snapshots/darwin/pnl_display-light.png create mode 100644 testdata/snapshots/darwin/position_table-dark.png create mode 100644 testdata/snapshots/darwin/position_table-light.png create mode 100644 testdata/snapshots/darwin/price_change_badge-dark.png create mode 100644 testdata/snapshots/darwin/price_change_badge-light.png create mode 100644 testdata/snapshots/darwin/price_text-dark.png create mode 100644 testdata/snapshots/darwin/price_text-light.png create mode 100644 testdata/snapshots/darwin/quick_trade_buttons-dark.png create mode 100644 testdata/snapshots/darwin/quick_trade_buttons-light.png create mode 100644 testdata/snapshots/darwin/quote_card-dark.png create mode 100644 testdata/snapshots/darwin/quote_card-light.png create mode 100644 testdata/snapshots/darwin/risk_meter-dark.png create mode 100644 testdata/snapshots/darwin/risk_meter-light.png create mode 100644 testdata/snapshots/darwin/spread_indicator-dark.png create mode 100644 testdata/snapshots/darwin/spread_indicator-light.png create mode 100644 testdata/snapshots/darwin/ticker_tape-dark.png create mode 100644 testdata/snapshots/darwin/ticker_tape-light.png create mode 100644 testdata/snapshots/darwin/time_and_sales-dark.png create mode 100644 testdata/snapshots/darwin/time_and_sales-light.png create mode 100644 testdata/snapshots/darwin/trade_history_table-dark.png create mode 100644 testdata/snapshots/darwin/trade_history_table-light.png create mode 100644 ticker_tape.go create mode 100644 ticker_tape_test.go create mode 100644 time_and_sales.go create mode 100644 time_and_sales_test.go create mode 100644 trade_history_table.go create mode 100644 trade_history_table_test.go diff --git a/bid_ask_bar.go b/bid_ask_bar.go new file mode 100644 index 0000000..b8d23ec --- /dev/null +++ b/bid_ask_bar.go @@ -0,0 +1,60 @@ +package mujica + +import ( + "fmt" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// BidAskBarOptions configure a BidAskBar. +type BidAskBarOptions struct { + // Decimals of the volumes shown; zero shows whole numbers. + Decimals int + // Label names the bar; empty uses the built-in name. + Label string +} + +// BidAskBar compares buy and sell volume in a split bar. +func BidAskBar(c *ui.Context, bid, ask float64, opts BidAskBarOptions) *ui.Element { + if bid < 0 || ask < 0 || math.IsNaN(bid+ask) { + panic("mujica: BidAskBar volumes must be zero or more") + } + if opts.Decimals < 0 { + panic("mujica: BidAskBar with negative Decimals") + } + k := Tokens(c) + u := Density(c).Unit() + total := bid + ask + share := 0.5 + if total > 0 { + share = bid / total + } + label := opts.Label + if label == "" { + label = msg(c, "bid_ask_bar.label") + } + buy := fmt.Sprintf(msg(c, "bid_ask_bar.buy"), statisticFormat(share*100, 1), statisticFormat(bid, opts.Decimals)) + sell := fmt.Sprintf(msg(c, "bid_ask_bar.sell"), statisticFormat(ask, opts.Decimals), statisticFormat((1-share)*100, 1)) + up, down := trendColor(c, 1), trendColor(c, -1) + upText, downText := up, down + if total == 0 { + up, down, upText, downText = k.Border, k.Border, k.TextMuted, k.TextMuted + } + e := ui.Column(c).Gap(u).MinWidth(160).Role(ui.RoleMeter).Label(label).Description(buy + ", " + sell) + e.Children(func() { + ui.Row(c).Justify(ui.SpaceBetween).Gap(u * 2).Children(func() { + ui.Text(c, buy).TextColor(upText).FontSize(FontSize(c, theme.CaptionSize)).FontFeatures("tnum").FontWeight(600).SingleLine() + ui.Text(c, sell).TextColor(downText).FontSize(FontSize(c, theme.CaptionSize)).FontFeatures("tnum").FontWeight(600).SingleLine() + }) + ui.Box(c).Height(8).FillWidth().Draw(func(p *ui.Painter, r ui.Rect) { + split := r.X + r.W*float32(share) + const gap = 2 + p.Fill(ui.Rect{X: r.X, Y: r.Y, W: max(0, split-r.X-gap/2), H: r.H}, up, theme.ControlRadius) + p.Fill(ui.Rect{X: split + gap/2, Y: r.Y, W: max(0, r.X+r.W-split-gap/2), H: r.H}, down, theme.ControlRadius) + }) + }) + return e +} diff --git a/bid_ask_bar_test.go b/bid_ask_bar_test.go new file mode 100644 index 0000000..89084d8 --- /dev/null +++ b/bid_ask_bar_test.go @@ -0,0 +1,34 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestBidAskBarShares(t *testing.T) { + bid, ask := 620.0, 380.0 + tt := tradingTester(GreenUp, 400, 100, func(c *ui.Context) { + ui.Box(c).Width(300).Children(func() { BidAskBar(c, bid, ask, BidAskBarOptions{}) }) + }) + if !tt.HasText("Buy 62.0% · 620") || !tt.HasText("380 · Sell 38.0%") { + t.Fatalf("texts %q", tt.Texts()) + } + bid, ask = 0, 0 + tt.Frame() + if !tt.HasText("Buy 50.0% · 0") { + t.Fatalf("empty: %q", tt.Texts()) + } + defer func() { + if recover() == nil { + t.Fatal("negative volume accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { BidAskBar(c, -1, 2, BidAskBarOptions{}) }) +} + +func TestBidAskBarSnapshot(t *testing.T) { + snapshot(t, "bid_ask_bar", 340, 80, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { BidAskBar(c, 6234, 3820, BidAskBarOptions{}) }) + }) +} diff --git a/depth_ladder.go b/depth_ladder.go new file mode 100644 index 0000000..6b76af6 --- /dev/null +++ b/depth_ladder.go @@ -0,0 +1,178 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/internal" + "mujicaui/theme" +) + +// DepthLadderOptions configure a DepthLadder. TickSize is required. +type DepthLadderOptions struct { + TickSize float64 + // Decimals of prices and sizes; zero means 2 and 0. + Decimals, SizeDecimals int + // Rows shown; zero means 15. + Rows int + Disabled bool +} + +// DepthLadderState is the ladder's scroll from last price, in ticks. +type DepthLadderState struct { + Offset int + cache depthLadderCache +} + +type depthLadderCache struct { + key bookKey + bids, asks map[int64]float64 +} + +// DepthLadderResult is a built DepthLadder and its clicked cell. +type DepthLadderResult struct { + Element *ui.Element + price float64 + side OrderSide +} + +// Clicked returns the clicked cell's price and side. +func (r DepthLadderResult) Clicked() (price float64, side OrderSide, ok bool) { + return r.price, r.side, r.side != 0 +} + +// DepthLadder is a price ladder around last; cell clicks order. +func DepthLadder(c *ui.Context, s *DepthLadderState, last float64, book OrderBookData, opts DepthLadderOptions) DepthLadderResult { + dec := priceDecimals("DepthLadder", opts.Decimals) + if opts.SizeDecimals < 0 || opts.Rows < 0 { + panic("mujica: DepthLadder SizeDecimals and Rows cannot be negative") + } + scale := math.Pow(10, float64(dec)) + tick := int64(math.Round(opts.TickSize * scale)) + if tick < 1 || math.Abs(opts.TickSize*scale-float64(tick)) > 1e-6 { + panic(fmt.Sprintf("mujica: DepthLadder TickSize %v is not a whole number of %d-decimal units", opts.TickSize, dec)) + } + rows := opts.Rows + if rows == 0 { + rows = 15 + } + depthLadderRefresh(s, book, scale, tick) + center := int64(math.Round(last*scale/float64(tick))) * tick + k := Tokens(c) + d := Density(c) + var r DepthLadderResult + r.Element = ui.Column(c).Gap(d.Unit()).Disabled(opts.Disabled).Role(ui.RoleTable).Label(msg(c, "depth_ladder.label")) + disabled := r.Element.IsDisabled() + move := func(by int) { + if !disabled && by != 0 { + s.Offset += by + slog.Debug("mujica: depth_ladder scrolled", "offset", s.Offset) + } + } + if r.Element.Shortcut(0, ui.KeyPageUp) { + move(rows / 2) + } + if r.Element.Shortcut(0, ui.KeyPageDown) { + move(-rows / 2) + } + r.Element.Children(func() { + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, msg(c, "depth_ladder.bid")).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).Grow(1).Basis(0).TextAlign(ui.End) + ui.Text(c, msg(c, "depth_ladder.price")).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).Grow(1).Basis(0).TextAlign(ui.Center) + ui.Text(c, msg(c, "depth_ladder.ask")).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).Grow(1).Basis(0) + }) + grid := ui.Column(c).FocusGroup(ui.Vertical | ui.Horizontal) + grid.HandleInput(func(ev ui.InputEvent) bool { + if ev.Kind != ui.InputScroll || disabled || ev.DY == 0 { + return false + } + move(int(math.Copysign(1, float64(-ev.DY)))) + return true + }) + grid.Children(func() { + top := center + int64(s.Offset+rows/2)*tick + for i := range rows { + t := top - int64(i)*tick + depthLadderRow(c, &r, s, t, t == center, scale, dec, opts.SizeDecimals) + } + }) + if s.Offset != 0 { + if Button(c, msg(c, "depth_ladder.recenter"), ButtonOptions{Variant: Ghost, Icon: icons.Must("refresh-cw"), Disabled: disabled}).Clicked() { + s.Offset = 0 + } + } + }) + return r +} + +// depthLadderRow is a buy cell, the price, a sell cell. +func depthLadderRow(c *ui.Context, r *DepthLadderResult, s *DepthLadderState, t int64, current bool, scale float64, dec, sizeDec int) { + k := Tokens(c) + d := Density(c) + price := float64(t) / scale + text := statisticFormat(price, dec) + ui.Row(c).Key(t).MinHeight(d.ControlHeight()).AlignItems(ui.Stretch).BorderWidth(0, 0, theme.BorderWidth, 0).BorderColor(k.Border).Children(func() { + cell := func(side OrderSide, size float64) { + label := fmt.Sprintf(msg(c, fmt.Sprintf("depth_ladder.order%d", side)), text) + b := ui.ButtonBase(c).Grow(1).Basis(0).Padding(0, d.Unit()*2).Label(label) + if side == SideBuy { + b.Justify(ui.End) + } else { + b.Justify(ui.Start) + } + internal.Ring(b, k.Focus, 0) + if b.Hovered() { + b.Background(trendColor(c, side.sign()).Alpha(0.14)) + } + b.Children(func() { + if size > 0 { + ui.Text(c, statisticFormat(size, sizeDec)).TextColor(trendColor(c, side.sign())).FontFeatures("tnum").FontWeight(600).SingleLine() + } + }) + if b.Clicked() && !b.IsDisabled() { + r.price, r.side = price, side + slog.Debug("mujica: depth_ladder order", "side", side) + } + } + cell(SideBuy, s.cache.bids[t]) + mid := ui.Row(c).Grow(1).Basis(0).Justify(ui.Center).AlignItems(ui.Center).Gap(d.Unit()).Background(k.Background) + if current { + mid.Background(k.Selection).Label(msg(c, "depth_ladder.last") + " " + text) + mid.DrawOver(func(p *ui.Painter, rect ui.Rect) { + internal.Frame(p, rect, 2, 4, k.AccentText) + }) + } + mid.Children(func() { + if current { + ui.Box(c).Size(8, 8).Draw(func(p *ui.Painter, rect ui.Rect) { + p.FillPath(internal.Diamond(rect.X+4, rect.Y+4, 8), k.AccentText) + }) + } + t := ui.Text(c, text).FontFeatures("tnum").SingleLine() + if current { + t.FontWeight(700) + } + }) + cell(SideSell, s.cache.asks[t]) + }) +} + +// depthLadderRefresh indexes sizes by tick when the book changed. +func depthLadderRefresh(s *DepthLadderState, book OrderBookData, scale float64, tick int64) { + key := bookKeyOf(book, float64(tick)/scale) + if s.cache.bids != nil && s.cache.key == key { + return + } + index := func(ls []BookLevel) map[int64]float64 { + m := make(map[int64]float64, len(ls)) + for _, l := range ls { + m[int64(math.Round(l.Price*scale/float64(tick)))*tick] += l.Size + } + return m + } + s.cache = depthLadderCache{key: key, bids: index(book.Bids), asks: index(book.Asks)} +} diff --git a/depth_ladder_test.go b/depth_ladder_test.go new file mode 100644 index 0000000..6af2c74 --- /dev/null +++ b/depth_ladder_test.go @@ -0,0 +1,113 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func depthLadderBook() OrderBookData { + return OrderBookData{Bids: []BookLevel{{100.00, 5}, {99.99, 3}}, Asks: []BookLevel{{100.01, 2}, {100.03, 7}}} +} + +func TestDepthLadderCentersAndOrders(t *testing.T) { + var s DepthLadderState + var price float64 + var side OrderSide + tt := tradingTester(GreenUp, 400, 600, func(c *ui.Context) { + if p, sd, ok := DepthLadder(c, &s, 100.004, depthLadderBook(), DepthLadderOptions{TickSize: 0.01, Rows: 7}).Clicked(); ok { + price, side = p, sd + } + }) + top, _ := tt.Find("100.03") + mid, _ := tt.Find("Last price 100.00") + bottom, _ := tt.Find("99.97") + if !(top.Y < mid.Y && mid.Y < bottom.Y) || tt.HasText("100.04") { + t.Fatalf("not centered: %v %v %v %q", top, mid, bottom, tt.Texts()) + } + if err := tt.Click("Sell at 100.03"); err != nil { + t.Fatal(err) + } + if price != 100.03 || side != SideSell { + t.Fatalf("clicked %v %v", price, side) + } + tt.Key(0, ui.KeyLeft) + tt.Key(0, ui.KeyEnter) + if price != 100.03 || side != SideBuy { + t.Fatalf("keyboard %v %v", price, side) + } + if !tt.HasText("7") || !tt.HasText("5") { + t.Fatalf("sizes: %q", tt.Texts()) + } +} + +func TestDepthLadderScrollsAndRecenters(t *testing.T) { + var s DepthLadderState + tt := tradingTester(GreenUp, 400, 600, func(c *ui.Context) { + DepthLadder(c, &s, 100, depthLadderBook(), DepthLadderOptions{TickSize: 0.01, Rows: 7}) + }) + _ = tt.Click("Buy at 100.00") + tt.Key(0, ui.KeyPageUp) + if s.Offset != 3 || !tt.HasText("100.06") { + t.Fatalf("page up: offset %d %q", s.Offset, tt.Texts()) + } + tt.Scroll(100, 200, 0, 40) + if s.Offset != 2 { + t.Fatalf("wheel: offset %d", s.Offset) + } + if err := tt.Click("Center on last price"); err != nil { + t.Fatal(err) + } + if s.Offset != 0 || tt.HasText("Center on last price") { + t.Fatalf("recenter: %d", s.Offset) + } +} + +// Only the visible rows are built, whatever the book's size. +func TestDepthLadderLargeBook(t *testing.T) { + var s DepthLadderState + book := OrderBookData{} + for i := range 100_000 { + book.Bids = append(book.Bids, BookLevel{Price: 100 - float64(i)/100, Size: 1}) + } + tt := tradingTester(GreenUp, 400, 600, func(c *ui.Context) { + DepthLadder(c, &s, 100, book, DepthLadderOptions{TickSize: 0.01, Rows: 9}) + }) + if n := len(tt.Texts()); n > 60 { + t.Fatalf("built %d texts", n) + } + // A sentinel survives only if the index is kept. + s.cache.bids[-1] = 42 + tt.Frame() + if s.cache.bids[-1] != 42 { + t.Fatal("index rebuilt without a change") + } +} + +func TestDepthLadderDisabledAndBadTick(t *testing.T) { + var s DepthLadderState + clicked := false + tt := tradingTester(GreenUp, 400, 600, func(c *ui.Context) { + _, _, clicked = DepthLadder(c, &s, 100, depthLadderBook(), DepthLadderOptions{TickSize: 0.01, Disabled: true}).Clicked() + }) + _ = tt.Click("Buy at 100.00") + tt.Scroll(100, 200, 0, 40) + if clicked || s.Offset != 0 { + t.Fatal("disabled ladder acted") + } + defer func() { + if recover() == nil { + t.Fatal("zero tick accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { DepthLadder(c, &s, 100, depthLadderBook(), DepthLadderOptions{}) }) +} + +func TestDepthLadderSnapshot(t *testing.T) { + snapshot(t, "depth_ladder", 340, 340, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + s := ui.Local(c.Root(), "snap", func() DepthLadderState { return DepthLadderState{} }) + DepthLadder(c, s, 100, depthLadderBook(), DepthLadderOptions{TickSize: 0.01, Rows: 7}) + }) + }) +} diff --git a/docs/components/161-ticker-tape.md b/docs/components/161-ticker-tape.md new file mode 100644 index 0000000..e97ec6a --- /dev/null +++ b/docs/components/161-ticker-tape.md @@ -0,0 +1,46 @@ +# 161 TickerTape + +行情滚动条。 + +## 用途 + +横向循环滚动的行情条,显示代码、价格与涨跌幅。指针悬停或键盘聚焦时暂停;减少动画时改为静态分页。 + +## 最小示例 + +```go +items := []mujica.TickerItem{{Symbol: "MUJC", Price: 412.08, ChangePercent: -1.35}, {Symbol: "AVE", Price: 88.2, ChangePercent: 2.1}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TickerTape(c, items, mujica.TickerTapeOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `items` | `[]TickerItem` | 必填 | 代码、价格、涨跌幅(%)。 | +| `Decimals` | `int` | 2 | 价格小数位,0 表示 2,负数 panic。 | +| `Speed` | `float32` | 40 | 每秒滚动的 DIP。 | +| `PerPage` | `int` | 4 | 减少动画时每页条数。 | +| `Label` | `string` | 内置“Market ticker” | 无障碍名称。 | + +## 状态 + +滚动、暂停(悬停或聚焦)、静态分页(减少动画)、空列表。 + +## 事件 + +无业务事件。 + +## 键盘操作 + +Tab 聚焦滚动条即暂停;减少动画时 ←/→ 翻页,也可用上一页、下一页按钮。 + +## 限制 + +- 滚动以四分之一 DIP 取整,暂停时停止请求重绘。 +- 第二份副本用于无缝循环,屏幕阅读器可能读到重复内容。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/162-quote-card.md b/docs/components/162-quote-card.md new file mode 100644 index 0000000..6df9188 --- /dev/null +++ b/docs/components/162-quote-card.md @@ -0,0 +1,43 @@ +# 162 QuoteCard + +报价卡片。 + +## 用途 + +显示代码、名称、现价、涨跌额与涨跌幅,并提供迷你图插槽。 + +## 最小示例 + +```go +quote := mujica.Quote{Symbol: "MUJC", Name: "Ave Mujica Holdings", Price: 412.08, Change: -5.62, ChangePercent: -1.35} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.QuoteCard(c, quote, mujica.QuoteCardOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `q` | `Quote` | 必填 | Symbol 必填,空值 panic;Name、Price、Change、ChangePercent。 | +| `Decimals` | `int` | 2 | 价格与涨跌额小数位。 | +| `Chart` | `func()` | nil | 迷你图插槽,高 40 DIP,例如 Sparkline。 | + +## 状态 + +默认;涨、跌、平三种方向。 + +## 事件 + +无。 + +## 键盘操作 + +卡片本身不获取焦点;插槽内控件自行处理键盘。 + +## 限制 + +- 不计算涨跌,数值由调用方提供。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/163-price-text.md b/docs/components/163-price-text.md new file mode 100644 index 0000000..a13c7a7 --- /dev/null +++ b/docs/components/163-price-text.md @@ -0,0 +1,46 @@ +# 163 PriceText + +价格文本。 + +## 用途 + +按固定小数位与千分位显示价格;可与参考价比较着色并加箭头;价格变化时闪烁一次。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.UseTrend(c, mujica.RedUp) + mujica.PriceText(c, 18234.5, mujica.PriceTextOptions{Compare: true, Reference: 18000}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `value` | `float64` | 必填 | 价格。 | +| `Decimals` | `int` | 2 | 小数位,0 表示 2,负数 panic。 | +| `NoGrouping` | `bool` | false | 不显示千分位。 | +| `Compare / Reference` | `bool / float64` | false / 0 | 按相对 Reference 的方向着色并加箭头。 | +| `NoFlash` | `bool` | false | 变化时不闪烁。 | +| `Size` | `float32` | 正文字号 | 字号(DIP),随系统文字缩放。 | + +## 状态 + +默认;上涨、下跌、持平;变化闪烁(360 ms 淡出)。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点。 + +## 限制 + +- 闪烁由帧间比较值得出:同一元素的值改变才会闪烁。减少动画时不闪烁,结束后不再请求重绘。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/164-price-change-badge.md b/docs/components/164-price-change-badge.md new file mode 100644 index 0000000..af8f3d3 --- /dev/null +++ b/docs/components/164-price-change-badge.md @@ -0,0 +1,42 @@ +# 164 PriceChangeBadge + +涨跌徽标。 + +## 用途 + +显示涨跌额与涨跌幅,带箭头、正负号与语义底色。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PriceChangeBadge(c, -5.62, -1.35, mujica.PriceChangeBadgeOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `change` | `float64` | 必填 | 涨跌额。 | +| `percent` | `float64` | 必填 | 涨跌幅(%),固定 2 位小数。 | +| `Decimals` | `int` | 2 | 涨跌额小数位。 | +| `HidePercent` | `bool` | false | 只显示涨跌额。 | + +## 状态 + +上涨、下跌、持平。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;无障碍名称含方向词与数值。 + +## 限制 + +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/165-order-book.md b/docs/components/165-order-book.md new file mode 100644 index 0000000..a06c386 --- /dev/null +++ b/docs/components/165-order-book.md @@ -0,0 +1,52 @@ +# 165 OrderBook + +盘口。 + +## 用途 + +按价格显示卖档(上)与买档(下),带累计深度条与价差;可按价格步长合并档位;点击档位回传价格。 + +## 最小示例 + +```go +var state mujica.OrderBookState +book := mujica.OrderBookData{ + Bids: []mujica.BookLevel{{Price: 100.00, Size: 5}, {Price: 99.99, Size: 3}}, + Asks: []mujica.BookLevel{{Price: 100.01, Size: 1}, {Price: 100.02, Size: 2}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.OrderBook(c, &state, book, mujica.OrderBookOptions{Groups: []float64{0.01, 0.05}}).Clicked(); ok { + fmt.Println("order at", price, side) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*OrderBookState` | 必填 | Group 为合并步长,0 取 Groups 第一项;不在 Groups 中 panic。 | +| `book` | `OrderBookData` | 必填 | Bids、Asks 与 Version(原地修改时递增)。 | +| `Decimals / SizeDecimals` | `int` | 2 / 0 | 价格与数量小数位。 | +| `Depth` | `int` | 8 | 每侧档数。 | +| `Groups` | `[]float64` | nil | 可选合并步长,须为价格精度的整数倍,否则 panic。 | +| `Disabled` | `bool` | false | 禁用点击与合并选择。 | + +## 状态 + +默认、悬停、聚焦、禁用;空盘口时只显示表头。 + +## 事件 + +`OrderBookResult.Clicked()` 返回被点击档位的价格与方向。 + +## 键盘操作 + +Tab 进入档位列表,↑/↓ 在档位间移动,Enter/Space 选中价格。 + +## 限制 + +- 合并以整数价格单位计算:买档向下取整、卖档向上取整。只在数据或步长变化时重新聚合。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/166-level2-quotes.md b/docs/components/166-level2-quotes.md new file mode 100644 index 0000000..1b4d9bf --- /dev/null +++ b/docs/components/166-level2-quotes.md @@ -0,0 +1,46 @@ +# 166 Level2Quotes + +多档行情。 + +## 用途 + +并排显示买卖各 N 档的价格、数量与委托笔数;档位变化时高亮一次,并以箭头标出数量增减。 + +## 最小示例 + +```go +data := mujica.Level2Data{ + Bids: []mujica.L2Level{{Price: 100.00, Size: 500, Orders: 12}}, + Asks: []mujica.L2Level{{Price: 100.01, Size: 200, Orders: 3}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Level2Quotes(c, data, mujica.Level2QuotesOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `data` | `Level2Data` | 必填 | Bids、Asks,最优价在前。 | +| `Decimals / SizeDecimals` | `int` | 2 / 0 | 价格与数量小数位。 | +| `Levels` | `int` | 5 | 每侧档数;不足的档位显示“—”。 | + +## 状态 + +默认、档位变化高亮(减少动画时只显示箭头)、空档。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;每行有包含档位、价格、数量和笔数的无障碍名称。 + +## 限制 + +- 价格变化视为新档位,不标增减箭头。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/167-time-and-sales.md b/docs/components/167-time-and-sales.md new file mode 100644 index 0000000..d68511f --- /dev/null +++ b/docs/components/167-time-and-sales.md @@ -0,0 +1,48 @@ +# 167 TimeAndSales + +逐笔成交。 + +## 用途 + +逐笔成交列表,最新在上,只构建可见行;大单以菱形与粗体标记;可暂停跟随。 + +## 最小示例 + +```go +var state mujica.TimeAndSalesState +trades := []mujica.TradePrint{{ID: "1", Time: time.Now(), Price: 100.01, Size: 300, Side: mujica.SideBuy}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TimeAndSales(c, &state, trades, mujica.TimeAndSalesOptions{LargeSize: 1000}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*TimeAndSalesState` | 必填 | Paused 暂停跟随。 | +| `trades` | `[]TradePrint` | 必填 | 按时间先后追加;ID 唯一。 | +| `Decimals / SizeDecimals` | `int` | 2 / 0 | 价格与数量小数位。 | +| `LargeSize` | `float64` | 0 | 数量达到即标记为大单。 | +| `Height` | `float32` | 320 | 高度(DIP)。 | +| `Status / Error` | `DataStatus / string` | Ready | 加载、失败等状态。 | + +## 状态 + +跟随、暂停(显示新成交数量)、加载、失败、空列表。 + +## 事件 + +`ChoiceResult.Changed()` 在暂停或继续时为 true。 + +## 键盘操作 + +Tab 到达暂停按钮(Enter/Space 切换)与列表;列表内 ↑/↓ 移动。 + +## 限制 + +- 基于 List 虚拟化,100,000 条成交只构建可见行。 +- 暂停时冻结显示的条数,新成交不打断阅读。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/168-depth-ladder.md b/docs/components/168-depth-ladder.md new file mode 100644 index 0000000..2421ee9 --- /dev/null +++ b/docs/components/168-depth-ladder.md @@ -0,0 +1,50 @@ +# 168 DepthLadder + +价格阶梯。 + +## 用途 + +按最小变动价位排列的价格阶梯(DOM):买量、价格、卖量三列,最新价居中并加框;点击买量或卖量单元格回调下单。 + +## 最小示例 + +```go +var state mujica.DepthLadderState +book := mujica.OrderBookData{Bids: []mujica.BookLevel{{Price: 100, Size: 5}}, Asks: []mujica.BookLevel{{Price: 100.01, Size: 2}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.DepthLadder(c, &state, 100, book, mujica.DepthLadderOptions{TickSize: 0.01}).Clicked(); ok { + fmt.Println("place", side, "at", price) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*DepthLadderState` | 必填 | Offset 为相对最新价滚动的档数。 | +| `last` | `float64` | 必填 | 最新价。 | +| `book` | `OrderBookData` | 必填 | 盘口数据。 | +| `TickSize` | `float64` | 必填 | 最小变动价位,须为价格精度的整数倍,否则 panic。 | +| `Decimals / SizeDecimals` | `int` | 2 / 0 | 小数位。 | +| `Rows` | `int` | 15 | 显示的行数。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +默认、悬停、聚焦、最新价行(底色、框线与菱形)、已滚动(显示回到最新价按钮)、禁用。 + +## 事件 + +`DepthLadderResult.Clicked()` 返回价格与方向(买量列为买入,卖量列为卖出)。 + +## 键盘操作 + +Tab 进入阶梯,方向键在单元格间移动,Enter/Space 下单;PageUp/PageDown 滚动半屏;滚轮逐档滚动。 + +## 限制 + +- 只构建可见行;按价位建立的数量索引只在数据变化时重建。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/169-spread-indicator.md b/docs/components/169-spread-indicator.md new file mode 100644 index 0000000..f071535 --- /dev/null +++ b/docs/components/169-spread-indicator.md @@ -0,0 +1,41 @@ +# 169 SpreadIndicator + +价差指示。 + +## 用途 + +显示卖一减买一的价差与占中间价的百分比;超过阈值或买卖倒挂时给出带图标的文字提示。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SpreadIndicator(c, 99.95, 100.05, mujica.SpreadIndicatorOptions{WarnPercent: 0.5}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `bid / ask` | `float64` | 必填 | 买一价与卖一价。 | +| `Decimals` | `int` | 2 | 价差小数位。 | +| `WarnPercent` | `float64` | 0 | 价差百分比达到即提示;0 不提示,负数 panic。 | + +## 状态 + +正常、价差过大、倒挂。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;以状态角色读出。 + +## 限制 + +- 无。 diff --git a/docs/components/170-bid-ask-bar.md b/docs/components/170-bid-ask-bar.md new file mode 100644 index 0000000..6ef8828 --- /dev/null +++ b/docs/components/170-bid-ask-bar.md @@ -0,0 +1,41 @@ +# 170 BidAskBar + +买卖力量条。 + +## 用途 + +以分段条对比买卖成交量,两端标出占比与数量。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BidAskBar(c, 6234, 3820, mujica.BidAskBarOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `bid / ask` | `float64` | 必填 | 买量与卖量,负数或 NaN panic。 | +| `Decimals` | `int` | 0 | 数量小数位。 | +| `Label` | `string` | 内置“Bid and ask volume” | 无障碍名称。 | + +## 状态 + +默认;两者都为 0 时显示中性灰条与 50%。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;以计量角色读出买卖占比。 + +## 限制 + +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/171-order-entry.md b/docs/components/171-order-entry.md new file mode 100644 index 0000000..fdbceb3 --- /dev/null +++ b/docs/components/171-order-entry.md @@ -0,0 +1,52 @@ +# 171 OrderEntry + +下单面板。 + +## 用途 + +限价、市价、止损与条件限价单的录入:方向、类型、数量、价格、触发价与有效期;同步与调用方异步校验;预估金额;提交防重入。建立在 Form 之上。 + +## 最小示例 + +```go +var state mujica.OrderEntryState +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if order, ok := mujica.OrderEntry(c, &state, mujica.OrderEntryOptions{Symbol: "MUJC", Last: 100.2}).Submitted(); ok { + fmt.Println("place", order.Quantity) + state.EndSubmit("") + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*OrderEntryState` | 必填 | Draft 为当前订单,Form 为表单状态。 | +| `Symbol` | `string` | 必填 | 代码,空值 panic。 | +| `Last` | `float64` | 0 | 最新价,用于市价预估和止损方向检查。 | +| `TickSize / LotSize` | `float64` | 0.01 / 1 | 价格与数量步长。 | +| `MaxQuantity` | `float64` | 0 | 数量上限,0 不限。 | +| `Initial` | `OrderDraft` | 买入限价 | 重置恢复的订单。 | +| `Validate` | `func(OrderDraft) string` | nil | 调用方同步规则。 | +| `Check` | `func(OrderDraft, uint64)` | nil | 异步检查(如可用资金),以 `s.Resolve(version, msg)` 回传;旧版本结果被丢弃。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +默认、字段错误(失焦或提交后)、异步检查中、提交中(按钮加载)、表单错误、禁用。 + +## 事件 + +`OrderEntryResult.Submitted()` 返回通过全部校验的订单;处理完毕后调用 `s.EndSubmit(err)`。 + +## 键盘操作 + +Tab 依次经过方向、类型、各字段与按钮;数量与价格字段 ↑/↓ 按步长调整;提交失败聚焦第一个错误字段。 + +## 限制 + +- 止损单检查:买入触发价须高于最新价,卖出须低于。 +- 数量字段的异步检查覆盖整张订单:任一字段变化都会让旧结果失效。 diff --git a/docs/components/172-quick-trade-buttons.md b/docs/components/172-quick-trade-buttons.md new file mode 100644 index 0000000..a5e2a07 --- /dev/null +++ b/docs/components/172-quick-trade-buttons.md @@ -0,0 +1,47 @@ +# 172 QuickTradeButtons + +快速交易按钮。 + +## 用途 + +以预设数量一键市价买入或卖出;可配置在发送前就近确认。 + +## 最小示例 + +```go +quantity := 10.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if side, q, ok := mujica.QuickTradeButtons(c, &quantity, mujica.QuickTradeButtonsOptions{Symbol: "MUJC", Confirm: true}).Traded(); ok { + fmt.Println(side, q) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `quantity` | `*float64` | 必填 | 当前数量,须为 Presets 之一,0 取第一项。 | +| `Symbol` | `string` | 必填 | 代码。 | +| `Presets` | `[]float64` | 1, 10, 100 | 数量预设。 | +| `Decimals` | `int` | 0 | 数量小数位。 | +| `Confirm` | `bool` | false | 发送前弹出确认,默认聚焦取消。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +默认、悬停、按下、聚焦、确认中、禁用。 + +## 事件 + +`QuickTradeResult.Traded()` 返回方向与数量。 + +## 键盘操作 + +Tab 到达数量分段与买卖按钮;Enter/Space 触发;确认浮层中 Enter 默认取消,Escape 关闭。 + +## 限制 + +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/173-position-table.md b/docs/components/173-position-table.md new file mode 100644 index 0000000..95443d8 --- /dev/null +++ b/docs/components/173-position-table.md @@ -0,0 +1,49 @@ +# 173 PositionTable + +持仓表。 + +## 用途 + +持仓列表:数量、成本、现价、市值、浮动盈亏与比例,每行提供平仓操作。基于 DataTable,以稳定行 ID 保存选择与排序。 + +## 最小示例 + +```go +var state mujica.DataTableState[string] +rows := []mujica.PositionRow{{ID: "p1", Symbol: "MUJC", Quantity: 100, AvgCost: 400, Price: 412.08}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.PositionTable(c, &state, rows, mujica.PositionTableOptions{}).Acted(); ok { + fmt.Println("close", id) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*DataTableState[string]` | 必填 | 表格状态。 | +| `rows` | `[]PositionRow` | 必填 | ID 必须稳定。 | +| `Decimals` | `int` | 2 | 小数位。 | +| `Version` | `int` | 0 | 原地修改行时递增。 | +| `Status / Error` | `DataStatus / string` | Ready | 加载与失败状态。 | +| `Disabled` | `bool` | false | 禁用平仓。 | + +## 状态 + +默认、排序、选中、加载、失败、空、禁用。 + +## 事件 + +`TableActionResult.Acted()` 返回要平仓的行 ID;`Table` 为 DataTable 事件。 + +## 键盘操作 + +沿用 DataTable 的键盘操作;Tab 到达各行的平仓按钮。 + +## 限制 + +- 只构建可见行。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/174-order-table.md b/docs/components/174-order-table.md new file mode 100644 index 0000000..aa1d93d --- /dev/null +++ b/docs/components/174-order-table.md @@ -0,0 +1,48 @@ +# 174 OrderTable + +委托表。 + +## 用途 + +委托列表:方向、类型、价格、成交进度与状态,按状态筛选;进行中的委托提供撤单。基于 DataTable。 + +## 最小示例 + +```go +var state mujica.OrderTableState +rows := []mujica.OrderRow{{ID: "o1", Symbol: "MUJC", Side: mujica.SideBuy, Price: 99.5, Quantity: 100, Filled: 40, Status: mujica.OrderPartial}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.OrderTable(c, &state, rows, mujica.OrderTableOptions{}).Acted(); ok { + fmt.Println("cancel", id) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*OrderTableState` | 必填 | Filter 为状态筛选,Table 为表格状态。 | +| `rows` | `[]OrderRow` | 必填 | Filled 不得超过 Quantity,否则 panic。 | +| `Decimals / QuantityDecimals` | `int` | 2 / 0 | 小数位。 | +| `Version` | `int` | 0 | 原地修改行时递增。 | +| `Status / Error` | `DataStatus / string` | Ready | 加载与失败状态。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +全部、进行中、已成交、已关闭四种筛选;部分成交进度条;禁用。 + +## 事件 + +`TableActionResult.Acted()` 返回要撤销的委托 ID。 + +## 键盘操作 + +筛选分段用方向键切换;表格沿用 DataTable 键盘操作;Tab 到达撤单按钮。 + +## 限制 + +- 筛选只在数据或条件变化时执行。 diff --git a/docs/components/175-trade-history-table.md b/docs/components/175-trade-history-table.md new file mode 100644 index 0000000..429704f --- /dev/null +++ b/docs/components/175-trade-history-table.md @@ -0,0 +1,49 @@ +# 175 TradeHistoryTable + +成交记录表。 + +## 用途 + +成交记录:时间、代码、方向、价格、数量与手续费;按日期范围筛选;导出当前范围的记录交给调用方。 + +## 最小示例 + +```go +var state mujica.TradeHistoryTableState +rows := []mujica.FillRow{{ID: "f1", Time: time.Now(), Symbol: "MUJC", Side: mujica.SideBuy, Price: 400, Quantity: 10, Fee: 1.2}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if fills, ok := mujica.TradeHistoryTable(c, &state, rows, mujica.TradeHistoryTableOptions{}).Exported(); ok { + fmt.Println("export", len(fills)) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `s` | `*TradeHistoryTableState` | 必填 | Range 为日期范围,零值不筛选。 | +| `rows` | `[]FillRow` | 必填 | 成交记录。 | +| `Decimals / QuantityDecimals` | `int` | 2 / 0 | 小数位。 | +| `Version` | `int` | 0 | 原地修改行时递增。 | +| `Status / Error` | `DataStatus / string` | Ready | 加载与失败状态。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +全部日期、指定范围、空范围、加载、失败、禁用。 + +## 事件 + +`TradeHistoryResult.Exported()` 返回导出请求时当前范围内的记录。 + +## 键盘操作 + +日期范围选择器与按钮按 Tab 顺序;表格沿用 DataTable 键盘操作。 + +## 限制 + +- 只回传数据,不生成文件:导出格式与写入由调用方负责。 +- 日期按每条记录自身时区的日期比较。 diff --git a/docs/components/176-pnl-display.md b/docs/components/176-pnl-display.md new file mode 100644 index 0000000..947e0b6 --- /dev/null +++ b/docs/components/176-pnl-display.md @@ -0,0 +1,44 @@ +# 176 PnLDisplay + +盈亏显示。 + +## 用途 + +并列显示已实现、未实现与当日盈亏,带正负号、箭头与语义色;可切换隐私遮蔽。 + +## 最小示例 + +```go +hidden := false +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PnLDisplay(c, mujica.PnL{Realized: 1200.5, Unrealized: -340.2, Today: 88}, &hidden, mujica.PnLDisplayOptions{Currency: "$"}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `pnl` | `PnL` | 必填 | Realized、Unrealized、Today。 | +| `hidden` | `*bool` | 必填 | 为 true 时以“••••”遮蔽。 | +| `Decimals` | `int` | 2 | 小数位。 | +| `Currency` | `string` | "" | 金额前缀,例如 "$"。 | + +## 状态 + +正、负、零;已遮蔽。 + +## 事件 + +`ChoiceResult.Changed()` 在遮蔽切换时为 true。 + +## 键盘操作 + +Tab 到达遮蔽按钮,Enter/Space 切换。 + +## 限制 + +- 遮蔽时无障碍名称只读出“已隐藏”,不读出金额。 +- 涨跌颜色由 `UseTrend(c, GreenUp|RedUp)` 按窗口设置,默认绿涨红跌;方向同时用箭头与正负号表达,不只靠颜色。 diff --git a/docs/components/177-leverage-slider.md b/docs/components/177-leverage-slider.md new file mode 100644 index 0000000..31ecb1e --- /dev/null +++ b/docs/components/177-leverage-slider.md @@ -0,0 +1,46 @@ +# 177 LeverageSlider + +杠杆滑块。 + +## 用途 + +在预设杠杆档位间选择草稿值,显示高风险与极高风险区间提示,按“确认”后才写入值。 + +## 最小示例 + +```go +leverage := 5.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if mujica.LeverageSlider(c, &leverage, mujica.LeverageSliderOptions{Warning: 10, Danger: 50}).Changed() { + fmt.Println("leverage", leverage) + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `value` | `*float64` | 必填 | 当前杠杆,须为 Levels 之一。 | +| `Levels` | `[]float64` | 1–100 八档 | 递增档位,至少两档。 | +| `Warning / Danger` | `float64` | 0 | 高风险与极高风险起点;Danger 须大于 Warning。 | +| `Label` | `string` | 内置“Leverage” | 名称。 | +| `Disabled` | `bool` | false | 禁用。 | + +## 状态 + +默认、聚焦、拖动、高风险、极高风险、草稿未确认、禁用。 + +## 事件 + +`ChoiceResult.Changed()` 在确认写入时为 true。 + +## 键盘操作 + +Tab 聚焦滑块:←/↓ 与 →/↑ 逐档、Home/End 到两端;Tab 到达确认按钮。 + +## 限制 + +- 滑块命中区高 44 DIP;风险区间以色带、图标和文字共同表达。 diff --git a/docs/components/178-margin-indicator.md b/docs/components/178-margin-indicator.md new file mode 100644 index 0000000..e3d3332 --- /dev/null +++ b/docs/components/178-margin-indicator.md @@ -0,0 +1,41 @@ +# 178 MarginIndicator + +保证金率指示。 + +## 用途 + +显示保证金率(维持保证金 / 权益)及其与警戒线、强平线的关系。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.MarginIndicator(c, 0.86, mujica.MarginIndicatorOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `ratio` | `float64` | 必填 | 保证金率,0 以上。 | +| `Warning / Liquidation` | `float64` | 0.8 / 1 | 警戒与强平线;须 0 < Warning < Liquidation。 | +| `Label` | `string` | 内置“Margin ratio” | 名称。 | + +## 状态 + +安全、追加保证金、强制平仓。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;以计量角色读出比率、状态与两条线。 + +## 限制 + +- 状态同时用图标、文字与颜色表达;两条线粗细不同,并在下方以文字标注。 diff --git a/docs/components/179-risk-meter.md b/docs/components/179-risk-meter.md new file mode 100644 index 0000000..208b797 --- /dev/null +++ b/docs/components/179-risk-meter.md @@ -0,0 +1,41 @@ +# 179 RiskMeter + +风险等级。 + +## 用途 + +分段刻度显示风险等级,当前段上方有菱形标记,并显示等级名称与说明。 + +## 最小示例 + +```go +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RiskMeter(c, 4, mujica.RiskMeterOptions{}) +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `level` | `int` | 必填 | 从 1 开始,超出范围 panic。 | +| `Levels` | `[]RiskLevel` | 内置五级 | 各级名称与说明,至少两级。 | +| `Label` | `string` | 内置“Risk level” | 名称。 | + +## 状态 + +各等级。 + +## 事件 + +无。 + +## 键盘操作 + +不获取焦点;以计量角色读出“第 n 级,共 N 级”和名称。 + +## 限制 + +- 颜色只辅助:位置标记与等级文字同时表达等级。 diff --git a/docs/components/180-order-confirm-dialog.md b/docs/components/180-order-confirm-dialog.md new file mode 100644 index 0000000..00225c1 --- /dev/null +++ b/docs/components/180-order-confirm-dialog.md @@ -0,0 +1,52 @@ +# 180 OrderConfirmDialog + +下单确认对话框。 + +## 用途 + +以模态对话框展示下单摘要与风险提示,默认聚焦取消;可要求勾选确认后才能下单。 + +## 最小示例 + +```go +open := true +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + r := mujica.OrderConfirmDialog(c, &open, mujica.OrderConfirmDialogOptions{ + Lines: []mujica.OrderSummaryLine{{Label: "Symbol", Value: "MUJC"}, {Label: "Quantity", Value: "100"}}, + Risk: "Leveraged products can lose more than the deposit.", + Acknowledge: "I understand the risk", + }) + if r.Confirmed { + fmt.Println("send order") + } +} +ui.Render(view, 400, 300, 1) +``` + +## 参数 + +| 字段 | 类型 | 默认值 | 含义 | +| --- | --- | --- | --- | +| `open` | `*bool` | 必填 | 是否显示。 | +| `Lines` | `[]OrderSummaryLine` | 必填 | 摘要行,空值 panic。 | +| `Title` | `string` | 内置“Confirm order” | 标题。 | +| `Risk` | `string` | "" | 风险提示。 | +| `Acknowledge` | `string` | "" | 二次确认复选框文字;设置后须勾选才能下单。 | +| `ConfirmLabel` | `string` | 内置“Place order” | 确认按钮文字。 | + +## 状态 + +打开、未勾选(下单按钮禁用)、已勾选。 + +## 事件 + +`AlertDialogResult.Confirmed` / `Canceled`;Escape 视为取消。 + +## 键盘操作 + +打开时焦点在取消上;Tab 在复选框与按钮间移动;Escape 取消。点击遮罩不关闭。 + +## 限制 + +- 每次打开都需重新勾选。 diff --git a/example_trading_test.go b/example_trading_test.go new file mode 100644 index 0000000..6c32d4f --- /dev/null +++ b/example_trading_test.go @@ -0,0 +1,221 @@ +package mujica_test + +import ( + "fmt" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +func ExampleTickerTape() { + items := []mujica.TickerItem{{Symbol: "MUJC", Price: 412.08, ChangePercent: -1.35}, {Symbol: "AVE", Price: 88.2, ChangePercent: 2.1}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TickerTape(c, items, mujica.TickerTapeOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleQuoteCard() { + quote := mujica.Quote{Symbol: "MUJC", Name: "Ave Mujica Holdings", Price: 412.08, Change: -5.62, ChangePercent: -1.35} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.QuoteCard(c, quote, mujica.QuoteCardOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExamplePriceText() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.UseTrend(c, mujica.RedUp) + mujica.PriceText(c, 18234.5, mujica.PriceTextOptions{Compare: true, Reference: 18000}) + } + ui.Render(view, 400, 300, 1) +} + +func ExamplePriceChangeBadge() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PriceChangeBadge(c, -5.62, -1.35, mujica.PriceChangeBadgeOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleOrderBook() { + var state mujica.OrderBookState + book := mujica.OrderBookData{ + Bids: []mujica.BookLevel{{Price: 100.00, Size: 5}, {Price: 99.99, Size: 3}}, + Asks: []mujica.BookLevel{{Price: 100.01, Size: 1}, {Price: 100.02, Size: 2}}, + } + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.OrderBook(c, &state, book, mujica.OrderBookOptions{Groups: []float64{0.01, 0.05}}).Clicked(); ok { + fmt.Println("order at", price, side) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleLevel2Quotes() { + data := mujica.Level2Data{ + Bids: []mujica.L2Level{{Price: 100.00, Size: 500, Orders: 12}}, + Asks: []mujica.L2Level{{Price: 100.01, Size: 200, Orders: 3}}, + } + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Level2Quotes(c, data, mujica.Level2QuotesOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleTimeAndSales() { + var state mujica.TimeAndSalesState + trades := []mujica.TradePrint{{ID: "1", Time: time.Now(), Price: 100.01, Size: 300, Side: mujica.SideBuy}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TimeAndSales(c, &state, trades, mujica.TimeAndSalesOptions{LargeSize: 1000}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleDepthLadder() { + var state mujica.DepthLadderState + book := mujica.OrderBookData{Bids: []mujica.BookLevel{{Price: 100, Size: 5}}, Asks: []mujica.BookLevel{{Price: 100.01, Size: 2}}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.DepthLadder(c, &state, 100, book, mujica.DepthLadderOptions{TickSize: 0.01}).Clicked(); ok { + fmt.Println("place", side, "at", price) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleSpreadIndicator() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SpreadIndicator(c, 99.95, 100.05, mujica.SpreadIndicatorOptions{WarnPercent: 0.5}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleBidAskBar() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BidAskBar(c, 6234, 3820, mujica.BidAskBarOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleOrderEntry() { + var state mujica.OrderEntryState + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if order, ok := mujica.OrderEntry(c, &state, mujica.OrderEntryOptions{Symbol: "MUJC", Last: 100.2}).Submitted(); ok { + fmt.Println("place", order.Quantity) + state.EndSubmit("") + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleQuickTradeButtons() { + quantity := 10.0 + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if side, q, ok := mujica.QuickTradeButtons(c, &quantity, mujica.QuickTradeButtonsOptions{Symbol: "MUJC", Confirm: true}).Traded(); ok { + fmt.Println(side, q) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExamplePositionTable() { + var state mujica.DataTableState[string] + rows := []mujica.PositionRow{{ID: "p1", Symbol: "MUJC", Quantity: 100, AvgCost: 400, Price: 412.08}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.PositionTable(c, &state, rows, mujica.PositionTableOptions{}).Acted(); ok { + fmt.Println("close", id) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleOrderTable() { + var state mujica.OrderTableState + rows := []mujica.OrderRow{{ID: "o1", Symbol: "MUJC", Side: mujica.SideBuy, Price: 99.5, Quantity: 100, Filled: 40, Status: mujica.OrderPartial}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.OrderTable(c, &state, rows, mujica.OrderTableOptions{}).Acted(); ok { + fmt.Println("cancel", id) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleTradeHistoryTable() { + var state mujica.TradeHistoryTableState + rows := []mujica.FillRow{{ID: "f1", Time: time.Now(), Symbol: "MUJC", Side: mujica.SideBuy, Price: 400, Quantity: 10, Fee: 1.2}} + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if fills, ok := mujica.TradeHistoryTable(c, &state, rows, mujica.TradeHistoryTableOptions{}).Exported(); ok { + fmt.Println("export", len(fills)) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExamplePnLDisplay() { + hidden := false + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PnLDisplay(c, mujica.PnL{Realized: 1200.5, Unrealized: -340.2, Today: 88}, &hidden, mujica.PnLDisplayOptions{Currency: "$"}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleLeverageSlider() { + leverage := 5.0 + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if mujica.LeverageSlider(c, &leverage, mujica.LeverageSliderOptions{Warning: 10, Danger: 50}).Changed() { + fmt.Println("leverage", leverage) + } + } + ui.Render(view, 400, 300, 1) +} + +func ExampleMarginIndicator() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.MarginIndicator(c, 0.86, mujica.MarginIndicatorOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleRiskMeter() { + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RiskMeter(c, 4, mujica.RiskMeterOptions{}) + } + ui.Render(view, 400, 300, 1) +} + +func ExampleOrderConfirmDialog() { + open := true + view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + r := mujica.OrderConfirmDialog(c, &open, mujica.OrderConfirmDialogOptions{ + Lines: []mujica.OrderSummaryLine{{Label: "Symbol", Value: "MUJC"}, {Label: "Quantity", Value: "100"}}, + Risk: "Leveraged products can lose more than the deposit.", + Acknowledge: "I understand the risk", + }) + if r.Confirmed { + fmt.Println("send order") + } + } + ui.Render(view, 400, 300, 1) +} diff --git a/examples/gallery/pages_trading.go b/examples/gallery/pages_trading.go index e79ef71..5a65056 100644 --- a/examples/gallery/pages_trading.go +++ b/examples/gallery/pages_trading.go @@ -1,3 +1,276 @@ package main -var tradingPages = []page{} +import ( + "fmt" + "math" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +const tradingCategory = "Trading" + +// tradingTrend shows and applies the rise-color switch. +func tradingTrend(c *ui.Context, redUp *bool, log func(string)) { + if mujica.Checkbox(c, redUp, "Red means up (China)", mujica.CheckboxOptions{}).Changed() { + log(fmt.Sprintf("red up %v", *redUp)) + } + t := mujica.GreenUp + if *redUp { + t = mujica.RedUp + } + mujica.UseTrend(c, t) +} + +// tradingAction is a demo button at its natural width. +func tradingAction(c *ui.Context, label string) bool { + clicked := false + ui.Row(c).Children(func() { + clicked = mujica.Button(c, label, mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() + }) + return clicked +} + +// tradingBook is a deterministic book around mid, moved by step. +func tradingBook(mid float64, step int) mujica.OrderBookData { + var b mujica.OrderBookData + for i := range 12 { + w := float64((i*7+step*3)%11 + 1) + b.Bids = append(b.Bids, mujica.BookLevel{Price: math.Round((mid-0.01*float64(i+1))*100) / 100, Size: w * 10}) + b.Asks = append(b.Asks, mujica.BookLevel{Price: math.Round((mid+0.01*float64(i))*100) / 100, Size: float64((i*5+step)%9+1) * 10}) + } + b.Version = step + return b +} + +var tradingPages = []page{ + {ID: "161", Name: "TickerTape", ZhName: "行情滚动条", Category: tradingCategory, Code: tradingCode["TickerTape"], Demo: tradingTickerDemo, + Keys: "Tab focuses the tape, which pauses it. With reduced motion, Left and Right turn pages."}, + {ID: "162", Name: "QuoteCard", ZhName: "报价卡片", Category: tradingCategory, Code: tradingCode["QuoteCard"], Demo: tradingQuoteDemo, + Keys: "The card takes no focus; controls in its chart slot do."}, + {ID: "163", Name: "PriceText", ZhName: "价格文本", Category: tradingCategory, Code: tradingCode["PriceText"], Demo: tradingPriceDemo, + Keys: "Display only."}, + {ID: "164", Name: "PriceChangeBadge", ZhName: "涨跌徽标", Category: tradingCategory, Code: tradingCode["PriceChangeBadge"], Demo: tradingBadgeDemo, + Keys: "Display only; the name reads the direction and values."}, + {ID: "165", Name: "OrderBook", ZhName: "盘口", Category: tradingCategory, Code: tradingCode["OrderBook"], Demo: tradingBookDemo, + Keys: "Tab into the levels, Up and Down move, Enter picks a price."}, + {ID: "166", Name: "Level2Quotes", ZhName: "多档行情", Category: tradingCategory, Code: tradingCode["Level2Quotes"], Demo: tradingLevel2Demo, + Keys: "Display only; each row reads its level, price, size and orders."}, + {ID: "167", Name: "TimeAndSales", ZhName: "逐笔成交", Category: tradingCategory, Code: tradingCode["TimeAndSales"], Demo: tradingTapeDemo, + Keys: "Tab to Pause and the list; Up and Down move in the list."}, + {ID: "168", Name: "DepthLadder", ZhName: "价格阶梯", Category: tradingCategory, Code: tradingCode["DepthLadder"], Demo: tradingLadderDemo, + Keys: "Arrows move between cells, Enter orders, Page Up and Page Down scroll, the wheel steps a tick."}, + {ID: "169", Name: "SpreadIndicator", ZhName: "价差指示", Category: tradingCategory, Code: tradingCode["SpreadIndicator"], Demo: tradingSpreadDemo, + Keys: "Display only."}, + {ID: "170", Name: "BidAskBar", ZhName: "买卖力量条", Category: tradingCategory, Code: tradingCode["BidAskBar"], Demo: tradingBarDemo, + Keys: "Display only; read as a meter."}, + {ID: "171", Name: "OrderEntry", ZhName: "下单面板", Category: tradingCategory, Code: tradingCode["OrderEntry"], Demo: tradingEntryDemo, + Keys: "Tab through side, type and fields; Up and Down step numbers; a failed submit focuses the first error."}, + {ID: "172", Name: "QuickTradeButtons", ZhName: "快速交易按钮", Category: tradingCategory, Code: tradingCode["QuickTradeButtons"], Demo: tradingQuickDemo, + Keys: "Enter or Space trades; with Confirm, Enter in the popup cancels and Escape closes it."}, + {ID: "173", Name: "PositionTable", ZhName: "持仓表", Category: tradingCategory, Code: tradingCode["PositionTable"], Demo: tradingPositionsDemo, + Keys: "DataTable keys; Tab reaches each Close button."}, + {ID: "174", Name: "OrderTable", ZhName: "委托表", Category: tradingCategory, Code: tradingCode["OrderTable"], Demo: tradingOrdersDemo, + Keys: "Arrows switch the status filter; DataTable keys; Tab reaches Cancel."}, + {ID: "175", Name: "TradeHistoryTable", ZhName: "成交记录表", Category: tradingCategory, Code: tradingCode["TradeHistoryTable"], Demo: tradingHistoryDemo, + Keys: "Tab to the range picker, Export and the table."}, + {ID: "176", Name: "PnLDisplay", ZhName: "盈亏显示", Category: tradingCategory, Code: tradingCode["PnLDisplay"], Demo: tradingPnLDemo, + Keys: "Tab to the eye button; Enter or Space masks the amounts."}, + {ID: "177", Name: "LeverageSlider", ZhName: "杠杆滑块", Category: tradingCategory, Code: tradingCode["LeverageSlider"], Demo: tradingLeverageDemo, + Keys: "Arrows step levels, Home and End jump; Apply sets the value."}, + {ID: "178", Name: "MarginIndicator", ZhName: "保证金率指示", Category: tradingCategory, Code: tradingCode["MarginIndicator"], Demo: tradingMarginDemo, + Keys: "Display only; read as a meter with its lines."}, + {ID: "179", Name: "RiskMeter", ZhName: "风险等级", Category: tradingCategory, Code: tradingCode["RiskMeter"], Demo: tradingRiskDemo, + Keys: "Display only."}, + {ID: "180", Name: "OrderConfirmDialog", ZhName: "下单确认对话框", Category: tradingCategory, Code: tradingCode["OrderConfirmDialog"], Demo: tradingConfirmDemo, + Keys: "Cancel has the focus; Escape cancels; the backdrop does not close it."}, +} + +type tradingTickerState struct { + redUp bool + items []mujica.TickerItem +} + +func tradingTickerDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "161", func() tradingTickerState { + return tradingTickerState{items: []mujica.TickerItem{{Symbol: "MUJC", Price: 412.08, ChangePercent: -1.35}, {Symbol: "AVE", Price: 88.2, ChangePercent: 2.1}, {Symbol: "OBLV", Price: 1204.5, ChangePercent: 0.4}, + {Symbol: "DOLO", Price: 7.25, ChangePercent: -0.8}, {Symbol: "MORT", Price: 33.1, ChangePercent: 1.2}, {Symbol: "TIMR", Price: 61.9, ChangePercent: -2.3}}} + }) + tradingTrend(c, &d.redUp, log) + if tradingAction(c, "Move prices") { + for i := range d.items { + d.items[i].ChangePercent = -d.items[i].ChangePercent + } + log("prices moved") + } + ui.Box(c).Width(560).Children(func() { mujica.TickerTape(c, d.items, mujica.TickerTapeOptions{}) }) + formStates(c, func() { + ui.Box(c).Width(280).Children(func() { mujica.TickerTape(c, d.items[:2], mujica.TickerTapeOptions{Speed: 15}) }) + }) +} + +type tradingQuoteState struct { + redUp bool + price float64 +} + +func tradingQuoteDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "162", func() tradingQuoteState { return tradingQuoteState{price: 412.08} }) + tradingTrend(c, &d.redUp, log) + if mujica.Slider(c, &d.price, mujica.SliderOptions{Min: 380, Max: 440, Step: 0.01, Label: "Price", ShowValue: true}).Changed() { + log(fmt.Sprintf("price %.2f", d.price)) + } + change := d.price - 417.7 + ui.Row(c).Gap(16).Wrap().Children(func() { + mujica.QuoteCard(c, mujica.Quote{Symbol: "MUJC", Name: "Ave Mujica Holdings", Price: d.price, Change: change, ChangePercent: change / 417.7 * 100}, + mujica.QuoteCardOptions{Chart: func() { + k := mujica.Tokens(c) + ui.Box(c).Fill().Draw(func(p *ui.Painter, r ui.Rect) { + p.Line(r.X, r.Y+r.H*0.7, r.X+r.W/2, r.Y+r.H*0.3, 1.5, k.Info) + p.Line(r.X+r.W/2, r.Y+r.H*0.3, r.X+r.W, r.Y+r.H*(0.5-float32(change)/40), 1.5, k.Info) + }) + }}) + mujica.QuoteCard(c, mujica.Quote{Symbol: "AVE", Price: 88.2}, mujica.QuoteCardOptions{}) + }) +} + +type tradingPriceState struct { + redUp, noFlash, grouping bool + price float64 +} + +func tradingPriceDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "163", func() tradingPriceState { return tradingPriceState{price: 18234.5, grouping: true} }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Thousands separators", "No flash"}, &d.grouping, &d.noFlash) + ui.Row(c).Gap(8).Children(func() { + if mujica.Button(c, "Tick up", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() { + d.price += 12.5 + log(fmt.Sprintf("price %.2f", d.price)) + } + if mujica.Button(c, "Tick down", mujica.ButtonOptions{Variant: mujica.Secondary}).Clicked() { + d.price -= 12.5 + log(fmt.Sprintf("price %.2f", d.price)) + } + }) + mujica.PriceText(c, d.price, mujica.PriceTextOptions{Size: 28, Compare: true, Reference: 18234.5, NoFlash: d.noFlash, NoGrouping: !d.grouping}) + formStates(c, func() { + mujica.PriceText(c, 0.004521, mujica.PriceTextOptions{Decimals: 6}) + mujica.PriceText(c, 100, mujica.PriceTextOptions{Compare: true, Reference: 100}) + }) +} + +type tradingBadgeState struct { + redUp, hidePercent bool + change float64 +} + +func tradingBadgeDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "164", func() tradingBadgeState { return tradingBadgeState{change: 1.25} }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Hide percent"}, &d.hidePercent) + if mujica.Slider(c, &d.change, mujica.SliderOptions{Min: -5, Max: 5, Step: 0.05, Label: "Change", ShowValue: true}).Changed() { + log(fmt.Sprintf("change %.2f", d.change)) + } + mujica.PriceChangeBadge(c, d.change, d.change/1.47, mujica.PriceChangeBadgeOptions{HidePercent: d.hidePercent}) + formStates(c, func() { + mujica.PriceChangeBadge(c, 2.4, 1.2, mujica.PriceChangeBadgeOptions{}) + mujica.PriceChangeBadge(c, -2.4, -1.2, mujica.PriceChangeBadgeOptions{}) + mujica.PriceChangeBadge(c, 0, 0, mujica.PriceChangeBadgeOptions{}) + }) +} + +type tradingBookState struct { + redUp, disabled bool + step int + book mujica.OrderBookState +} + +func tradingBookDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "165", func() tradingBookState { return tradingBookState{} }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Disabled"}, &d.disabled) + if tradingAction(c, "Next update") { + d.step++ + log(fmt.Sprintf("book update %d", d.step)) + } + ui.Box(c).Width(320).Children(func() { + r := mujica.OrderBook(c, &d.book, tradingBook(100, d.step), mujica.OrderBookOptions{Depth: 6, Groups: []float64{0.01, 0.05, 0.1}, Disabled: d.disabled}) + if price, side, ok := r.Clicked(); ok { + log(fmt.Sprintf("level %v at %.2f", side, price)) + } + }) +} + +type tradingLevel2State struct { + redUp bool + step int +} + +func tradingLevel2Demo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "166", func() tradingLevel2State { return tradingLevel2State{} }) + tradingTrend(c, &d.redUp, log) + if tradingAction(c, "Next update") { + d.step++ + log(fmt.Sprintf("level 2 update %d", d.step)) + } + book := tradingBook(100, d.step) + var data mujica.Level2Data + for i := range 5 { + data.Bids = append(data.Bids, mujica.L2Level{Price: book.Bids[i].Price, Size: book.Bids[i].Size, Orders: int(book.Bids[i].Size / 10)}) + data.Asks = append(data.Asks, mujica.L2Level{Price: book.Asks[i].Price, Size: book.Asks[i].Size, Orders: int(book.Asks[i].Size / 10)}) + } + ui.Box(c).Width(620).Children(func() { mujica.Level2Quotes(c, data, mujica.Level2QuotesOptions{}) }) +} + +type tradingTapeState struct { + redUp bool + trades []mujica.TradePrint + tape mujica.TimeAndSalesState +} + +func tradingTapeDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "167", func() tradingTapeState { return tradingTapeState{} }) + tradingTrend(c, &d.redUp, log) + if tradingAction(c, "Add 20 trades") { + at := time.Date(2026, 10, 5, 9, 30, 0, 0, time.Local) + for range 20 { + n := len(d.trades) + side := mujica.SideBuy + if n%3 == 1 { + side = mujica.SideSell + } + d.trades = append(d.trades, mujica.TradePrint{ID: fmt.Sprint(n), Time: at.Add(time.Duration(n) * time.Second), + Price: 100 + float64(n%17)/100, Size: float64((n*37)%1500 + 1), Side: side}) + } + log(fmt.Sprintf("%d trades", len(d.trades))) + } + ui.Box(c).Width(460).Children(func() { + if mujica.TimeAndSales(c, &d.tape, d.trades, mujica.TimeAndSalesOptions{LargeSize: 1000}).Changed() { + log(fmt.Sprintf("paused %v", d.tape.Paused)) + } + }) +} + +type tradingLadderState struct { + redUp, disabled bool + last float64 + ladder mujica.DepthLadderState +} + +func tradingLadderDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "168", func() tradingLadderState { return tradingLadderState{last: 100} }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Disabled"}, &d.disabled) + if mujica.Slider(c, &d.last, mujica.SliderOptions{Min: 99.9, Max: 100.1, Step: 0.01, Label: "Last price", ShowValue: true}).Changed() { + log(fmt.Sprintf("last %.2f", d.last)) + } + ui.Box(c).Width(360).Children(func() { + r := mujica.DepthLadder(c, &d.ladder, d.last, tradingBook(100, 0), mujica.DepthLadderOptions{TickSize: 0.01, Rows: 11, Disabled: d.disabled}) + if price, side, ok := r.Clicked(); ok { + log(fmt.Sprintf("order %v at %.2f", side, price)) + } + }) +} diff --git a/examples/gallery/pages_trading_code.go b/examples/gallery/pages_trading_code.go new file mode 100644 index 0000000..b5fdbc7 --- /dev/null +++ b/examples/gallery/pages_trading_code.go @@ -0,0 +1,156 @@ +package main + +// tradingCode holds each page's copyable snippet, the same as its doc and Example. +var tradingCode = map[string]string{ + "TickerTape": `items := []mujica.TickerItem{{Symbol: "MUJC", Price: 412.08, ChangePercent: -1.35}, {Symbol: "AVE", Price: 88.2, ChangePercent: 2.1}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TickerTape(c, items, mujica.TickerTapeOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "QuoteCard": `quote := mujica.Quote{Symbol: "MUJC", Name: "Ave Mujica Holdings", Price: 412.08, Change: -5.62, ChangePercent: -1.35} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.QuoteCard(c, quote, mujica.QuoteCardOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "PriceText": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.UseTrend(c, mujica.RedUp) + mujica.PriceText(c, 18234.5, mujica.PriceTextOptions{Compare: true, Reference: 18000}) +} +ui.Render(view, 400, 300, 1)`, + "PriceChangeBadge": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PriceChangeBadge(c, -5.62, -1.35, mujica.PriceChangeBadgeOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "OrderBook": `var state mujica.OrderBookState +book := mujica.OrderBookData{ + Bids: []mujica.BookLevel{{Price: 100.00, Size: 5}, {Price: 99.99, Size: 3}}, + Asks: []mujica.BookLevel{{Price: 100.01, Size: 1}, {Price: 100.02, Size: 2}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.OrderBook(c, &state, book, mujica.OrderBookOptions{Groups: []float64{0.01, 0.05}}).Clicked(); ok { + fmt.Println("order at", price, side) + } +} +ui.Render(view, 400, 300, 1)`, + "Level2Quotes": `data := mujica.Level2Data{ + Bids: []mujica.L2Level{{Price: 100.00, Size: 500, Orders: 12}}, + Asks: []mujica.L2Level{{Price: 100.01, Size: 200, Orders: 3}}, +} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.Level2Quotes(c, data, mujica.Level2QuotesOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "TimeAndSales": `var state mujica.TimeAndSalesState +trades := []mujica.TradePrint{{ID: "1", Time: time.Now(), Price: 100.01, Size: 300, Side: mujica.SideBuy}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.TimeAndSales(c, &state, trades, mujica.TimeAndSalesOptions{LargeSize: 1000}) +} +ui.Render(view, 400, 300, 1)`, + "DepthLadder": `var state mujica.DepthLadderState +book := mujica.OrderBookData{Bids: []mujica.BookLevel{{Price: 100, Size: 5}}, Asks: []mujica.BookLevel{{Price: 100.01, Size: 2}}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if price, side, ok := mujica.DepthLadder(c, &state, 100, book, mujica.DepthLadderOptions{TickSize: 0.01}).Clicked(); ok { + fmt.Println("place", side, "at", price) + } +} +ui.Render(view, 400, 300, 1)`, + "SpreadIndicator": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.SpreadIndicator(c, 99.95, 100.05, mujica.SpreadIndicatorOptions{WarnPercent: 0.5}) +} +ui.Render(view, 400, 300, 1)`, + "BidAskBar": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.BidAskBar(c, 6234, 3820, mujica.BidAskBarOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "OrderEntry": `var state mujica.OrderEntryState +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if order, ok := mujica.OrderEntry(c, &state, mujica.OrderEntryOptions{Symbol: "MUJC", Last: 100.2}).Submitted(); ok { + fmt.Println("place", order.Quantity) + state.EndSubmit("") + } +} +ui.Render(view, 400, 300, 1)`, + "QuickTradeButtons": `quantity := 10.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if side, q, ok := mujica.QuickTradeButtons(c, &quantity, mujica.QuickTradeButtonsOptions{Symbol: "MUJC", Confirm: true}).Traded(); ok { + fmt.Println(side, q) + } +} +ui.Render(view, 400, 300, 1)`, + "PositionTable": `var state mujica.DataTableState[string] +rows := []mujica.PositionRow{{ID: "p1", Symbol: "MUJC", Quantity: 100, AvgCost: 400, Price: 412.08}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.PositionTable(c, &state, rows, mujica.PositionTableOptions{}).Acted(); ok { + fmt.Println("close", id) + } +} +ui.Render(view, 400, 300, 1)`, + "OrderTable": `var state mujica.OrderTableState +rows := []mujica.OrderRow{{ID: "o1", Symbol: "MUJC", Side: mujica.SideBuy, Price: 99.5, Quantity: 100, Filled: 40, Status: mujica.OrderPartial}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if id, ok := mujica.OrderTable(c, &state, rows, mujica.OrderTableOptions{}).Acted(); ok { + fmt.Println("cancel", id) + } +} +ui.Render(view, 400, 300, 1)`, + "TradeHistoryTable": `var state mujica.TradeHistoryTableState +rows := []mujica.FillRow{{ID: "f1", Time: time.Now(), Symbol: "MUJC", Side: mujica.SideBuy, Price: 400, Quantity: 10, Fee: 1.2}} +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if fills, ok := mujica.TradeHistoryTable(c, &state, rows, mujica.TradeHistoryTableOptions{}).Exported(); ok { + fmt.Println("export", len(fills)) + } +} +ui.Render(view, 400, 300, 1)`, + "PnLDisplay": `hidden := false +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.PnLDisplay(c, mujica.PnL{Realized: 1200.5, Unrealized: -340.2, Today: 88}, &hidden, mujica.PnLDisplayOptions{Currency: "$"}) +} +ui.Render(view, 400, 300, 1)`, + "LeverageSlider": `leverage := 5.0 +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + if mujica.LeverageSlider(c, &leverage, mujica.LeverageSliderOptions{Warning: 10, Danger: 50}).Changed() { + fmt.Println("leverage", leverage) + } +} +ui.Render(view, 400, 300, 1)`, + "MarginIndicator": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.MarginIndicator(c, 0.86, mujica.MarginIndicatorOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "RiskMeter": `view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + mujica.RiskMeter(c, 4, mujica.RiskMeterOptions{}) +} +ui.Render(view, 400, 300, 1)`, + "OrderConfirmDialog": `open := true +view := func(c *ui.Context) { + mujica.Use(c, mujica.Settings{}) + r := mujica.OrderConfirmDialog(c, &open, mujica.OrderConfirmDialogOptions{ + Lines: []mujica.OrderSummaryLine{{Label: "Symbol", Value: "MUJC"}, {Label: "Quantity", Value: "100"}}, + Risk: "Leveraged products can lose more than the deposit.", + Acknowledge: "I understand the risk", + }) + if r.Confirmed { + fmt.Println("send order") + } +} +ui.Render(view, 400, 300, 1)`, +} diff --git a/examples/gallery/pages_trading_orders.go b/examples/gallery/pages_trading_orders.go new file mode 100644 index 0000000..cecdc50 --- /dev/null +++ b/examples/gallery/pages_trading_orders.go @@ -0,0 +1,286 @@ +package main + +import ( + "fmt" + "time" + + "github.com/egoist/mygo/ui" + + mujica "mujicaui" +) + +type tradingSpreadState struct { + ask, warn float64 +} + +func tradingSpreadDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "169", func() tradingSpreadState { return tradingSpreadState{ask: 100.05, warn: 0.5} }) + if mujica.Slider(c, &d.ask, mujica.SliderOptions{Min: 99.5, Max: 101, Step: 0.01, Label: "Ask (bid 99.95)", ShowValue: true}).Changed() { + log(fmt.Sprintf("ask %.2f", d.ask)) + } + if mujica.Slider(c, &d.warn, mujica.SliderOptions{Min: 0, Max: 2, Step: 0.1, Label: "Warn at percent", ShowValue: true}).Changed() { + log(fmt.Sprintf("warn %.1f%%", d.warn)) + } + mujica.SpreadIndicator(c, 99.95, d.ask, mujica.SpreadIndicatorOptions{WarnPercent: d.warn}) + formStates(c, func() { + mujica.SpreadIndicator(c, 99.95, 100.05, mujica.SpreadIndicatorOptions{}) + mujica.SpreadIndicator(c, 99, 101, mujica.SpreadIndicatorOptions{WarnPercent: 0.5}) + mujica.SpreadIndicator(c, 100.1, 100, mujica.SpreadIndicatorOptions{}) + }) +} + +type tradingBarState struct { + redUp bool + bid, ask float64 +} + +func tradingBarDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "170", func() tradingBarState { return tradingBarState{bid: 6234, ask: 3820} }) + tradingTrend(c, &d.redUp, log) + for _, v := range []struct { + name string + p *float64 + }{{"Bid volume", &d.bid}, {"Ask volume", &d.ask}} { + if mujica.Slider(c, v.p, mujica.SliderOptions{Min: 0, Max: 10000, Step: 1, Label: v.name, ShowValue: true}).Changed() { + log(fmt.Sprintf("%s %.0f", v.name, *v.p)) + } + } + ui.Box(c).Width(360).Children(func() { mujica.BidAskBar(c, d.bid, d.ask, mujica.BidAskBarOptions{}) }) +} + +type tradingEntryState struct { + redUp, disabled, reject bool + entry mujica.OrderEntryState +} + +func tradingEntryDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "171", func() tradingEntryState { return tradingEntryState{} }) + checks := *ui.Local(c.Root(), "171.checks", func() chan [2]any { return make(chan [2]any, 8) }) + placed := *ui.Local(c.Root(), "171.placed", func() chan string { return make(chan string, 1) }) + for drained := false; !drained; { + select { + case r := <-checks: + v, msg := r[0].(uint64), r[1].(string) + log(fmt.Sprintf("buying power check v%d: %q, kept %v", v, msg, d.entry.Resolve(v, msg))) + case e := <-placed: + d.entry.EndSubmit(e) + log(fmt.Sprintf("order placed, error %q", e)) + default: + drained = true + } + } + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Disabled", "Broker rejects"}, &d.disabled, &d.reject) + r := mujica.OrderEntry(c, &d.entry, mujica.OrderEntryOptions{Symbol: "MUJC", Last: 100.2, MaxQuantity: 5000, Disabled: d.disabled, + Check: func(o mujica.OrderDraft, v uint64) { + log(fmt.Sprintf("check started v%d", v)) + go func() { + time.Sleep(600 * time.Millisecond) + msg := "" + if o.Quantity*100 > 250000 { + msg = "Not enough buying power." + } + checks <- [2]any{v, msg} + c.Invalidate() + }() + }}) + if o, ok := r.Submitted(); ok { + log(fmt.Sprintf("submitted %+v", o)) + fail := "" + if d.reject { + fail = "The broker rejected the order. Your entry is kept." + } + go func() { + time.Sleep(800 * time.Millisecond) + placed <- fail + c.Invalidate() + }() + } +} + +type tradingQuickState struct { + redUp, confirm, disabled bool + qty float64 +} + +func tradingQuickDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "172", func() tradingQuickState { return tradingQuickState{confirm: true, qty: 10} }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Confirm first", "Disabled"}, &d.confirm, &d.disabled) + ui.Box(c).Width(400).Children(func() { + if side, q, ok := mujica.QuickTradeButtons(c, &d.qty, mujica.QuickTradeButtonsOptions{Symbol: "MUJC", Confirm: d.confirm, Disabled: d.disabled}).Traded(); ok { + log(fmt.Sprintf("trade %v %v", side, q)) + } + }) +} + +type tradingPositionsState struct { + redUp, disabled bool + rows []mujica.PositionRow + table mujica.DataTableState[string] +} + +func tradingPositionsDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "173", func() tradingPositionsState { + return tradingPositionsState{rows: []mujica.PositionRow{ + {ID: "p1", Symbol: "MUJC", Quantity: 100, AvgCost: 400, Price: 412.08}, + {ID: "p2", Symbol: "AVE", Quantity: 50, AvgCost: 90, Price: 88.2}, + {ID: "p3", Symbol: "OBLV", Quantity: 8, AvgCost: 1180, Price: 1204.5}, + }} + }) + tradingTrend(c, &d.redUp, log) + formToggles(c, []string{"Disabled"}, &d.disabled) + ui.Box(c).Width(1000).Height(260).Children(func() { + r := mujica.PositionTable(c, &d.table, d.rows, mujica.PositionTableOptions{Disabled: d.disabled}) + if id, ok := r.Acted(); ok { + for i, p := range d.rows { + if p.ID == id { + d.rows = append(d.rows[:i:i], d.rows[i+1:]...) + break + } + } + log("close " + id) + } + if r.Table.Changed() { + id, _ := d.table.Selected() + log("select " + id) + } + }) +} + +type tradingOrdersState struct { + disabled bool + rows []mujica.OrderRow + table mujica.OrderTableState + version int +} + +func tradingOrdersDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "174", func() tradingOrdersState { + return tradingOrdersState{rows: []mujica.OrderRow{ + {ID: "o1", Symbol: "MUJC", Side: mujica.SideBuy, Type: mujica.OrderLimit, Price: 99.5, Quantity: 100, Filled: 40, Status: mujica.OrderPartial}, + {ID: "o2", Symbol: "AVE", Side: mujica.SideSell, Type: mujica.OrderMarket, Quantity: 10, Filled: 10, Status: mujica.OrderFilled}, + {ID: "o3", Symbol: "OBLV", Side: mujica.SideBuy, Type: mujica.OrderStop, Price: 12, Quantity: 5, Status: mujica.OrderCanceled}, + {ID: "o4", Symbol: "DOLO", Side: mujica.SideSell, Type: mujica.OrderLimit, Price: 7.25, Quantity: 30, Status: mujica.OrderOpen}, + }} + }) + formToggles(c, []string{"Disabled"}, &d.disabled) + ui.Box(c).Width(1000).Height(300).Children(func() { + if id, ok := mujica.OrderTable(c, &d.table, d.rows, mujica.OrderTableOptions{Disabled: d.disabled, Version: d.version}).Acted(); ok { + for i := range d.rows { + if d.rows[i].ID == id { + d.rows[i].Status = mujica.OrderCanceled + } + } + d.version++ + log("cancel " + id) + } + }) +} + +type tradingHistoryState struct { + disabled bool + rows []mujica.FillRow + table mujica.TradeHistoryTableState +} + +func tradingHistoryDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "175", func() tradingHistoryState { + var rows []mujica.FillRow + for i := range 30 { + side := mujica.SideBuy + if i%3 == 0 { + side = mujica.SideSell + } + rows = append(rows, mujica.FillRow{ID: fmt.Sprint(i), Time: time.Date(2026, 9, 10+i/2, 9+i%6, 0, 0, 0, time.Local), + Symbol: []string{"MUJC", "AVE", "OBLV"}[i%3], Side: side, Price: 100 + float64(i), Quantity: float64(i%5+1) * 10, Fee: 0.5}) + } + return tradingHistoryState{rows: rows} + }) + formToggles(c, []string{"Disabled"}, &d.disabled) + ui.Box(c).Width(1000).Height(360).Children(func() { + if fills, ok := mujica.TradeHistoryTable(c, &d.table, d.rows, mujica.TradeHistoryTableOptions{Disabled: d.disabled}).Exported(); ok { + log(fmt.Sprintf("export %d fills", len(fills))) + } + }) +} + +type tradingPnLState struct { + redUp, hidden bool +} + +func tradingPnLDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "176", func() tradingPnLState { return tradingPnLState{} }) + tradingTrend(c, &d.redUp, log) + if mujica.PnLDisplay(c, mujica.PnL{Realized: 1200.5, Unrealized: -340.2, Today: 88}, &d.hidden, mujica.PnLDisplayOptions{Currency: "$"}).Changed() { + log(fmt.Sprintf("hidden %v", d.hidden)) + } +} + +type tradingLeverageState struct { + disabled bool + value float64 +} + +func tradingLeverageDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "177", func() tradingLeverageState { return tradingLeverageState{value: 5} }) + formToggles(c, []string{"Disabled"}, &d.disabled) + ui.Box(c).Width(380).Children(func() { + if mujica.LeverageSlider(c, &d.value, mujica.LeverageSliderOptions{Warning: 10, Danger: 50, Disabled: d.disabled}).Changed() { + log(fmt.Sprintf("leverage applied %v×", d.value)) + } + }) +} + +type tradingMarginState struct{ ratio float64 } + +func tradingMarginDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "178", func() tradingMarginState { return tradingMarginState{ratio: 0.55} }) + if mujica.Slider(c, &d.ratio, mujica.SliderOptions{Min: 0, Max: 1.4, Step: 0.01, Label: "Margin ratio", ShowValue: true}).Changed() { + log(fmt.Sprintf("ratio %.2f", d.ratio)) + } + ui.Box(c).Width(360).Children(func() { mujica.MarginIndicator(c, d.ratio, mujica.MarginIndicatorOptions{}) }) + formStates(c, func() { + for _, r := range []float64{0.3, 0.85, 1.1} { + ui.Box(c).Width(260).Children(func() { mujica.MarginIndicator(c, r, mujica.MarginIndicatorOptions{}) }) + } + }) +} + +type tradingRiskState struct{ level float64 } + +func tradingRiskDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "179", func() tradingRiskState { return tradingRiskState{level: 3} }) + if mujica.Slider(c, &d.level, mujica.SliderOptions{Min: 1, Max: 5, Step: 1, Label: "Level", ShowValue: true}).Changed() { + log(fmt.Sprintf("level %.0f", d.level)) + } + ui.Box(c).Width(360).Children(func() { mujica.RiskMeter(c, int(d.level), mujica.RiskMeterOptions{}) }) +} + +type tradingConfirmState struct { + open, acknowledge bool +} + +func tradingConfirmDemo(c *ui.Context, log func(string)) { + d := ui.Local(c.Root(), "180", func() tradingConfirmState { return tradingConfirmState{acknowledge: true} }) + formToggles(c, []string{"Require acknowledgement"}, &d.acknowledge) + if tradingAction(c, "Review order") { + d.open = true + log("open") + } + ack := "" + if d.acknowledge { + ack = "I understand leveraged products can lose more than the deposit" + } + r := mujica.OrderConfirmDialog(c, &d.open, mujica.OrderConfirmDialogOptions{ + Lines: []mujica.OrderSummaryLine{{Label: "Symbol", Value: "MUJC"}, {Label: "Side", Value: "Buy"}, {Label: "Type", Value: "Limit 100.20"}, + {Label: "Quantity", Value: "100"}, {Label: "Estimated amount", Value: "10,020.00"}}, + Risk: "5× leverage: a 20% move against you wipes out the margin.", Acknowledge: ack, + }) + if r.Confirmed { + log("confirmed") + } + if r.Canceled { + log("canceled") + } +} diff --git a/level2_quotes.go b/level2_quotes.go new file mode 100644 index 0000000..0df1966 --- /dev/null +++ b/level2_quotes.go @@ -0,0 +1,123 @@ +package mujica + +import ( + "fmt" + "log/slog" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// L2Level is a level's price, size and order count. +type L2Level struct { + Price, Size float64 + Orders int +} + +// Level2Data holds the bid and ask levels, best first. +type Level2Data struct { + Bids, Asks []L2Level +} + +// Level2QuotesOptions configure a Level2Quotes. +type Level2QuotesOptions struct { + // Decimals of prices and sizes; zero means 2 and 0. + Decimals, SizeDecimals int + // Levels shown each side; zero means 5. + Levels int +} + +// level2Mark is a level's last values and size move. +type level2Mark struct { + price, size float64 + dir int + at time.Time + seen bool +} + +// Level2Quotes lists bid and ask levels; changes flash and mark. +func Level2Quotes(c *ui.Context, data Level2Data, opts Level2QuotesOptions) *ui.Element { + dec := priceDecimals("Level2Quotes", opts.Decimals) + if opts.SizeDecimals < 0 || opts.Levels < 0 { + panic("mujica: Level2Quotes SizeDecimals and Levels cannot be negative") + } + n := opts.Levels + if n == 0 { + n = 5 + } + u := Density(c).Unit() + e := ui.Row(c).Gap(u * 3).AlignItems(ui.Start).Role(ui.RoleTable).Label(msg(c, "level2_quotes.label")) + marks := ui.Local(e, "marks", func() map[string]*level2Mark { return map[string]*level2Mark{} }) + e.Children(func() { + for _, side := range []OrderSide{SideBuy, SideSell} { + levels := data.Bids + if side == SideSell { + levels = data.Asks + } + ui.Column(c).Grow(1).Basis(0).MinWidth(0).Children(func() { + for i := range n { + var l *L2Level + if i < len(levels) { + l = &levels[i] + } + level2Row(c, *marks, side, i, l, dec, opts.SizeDecimals) + } + }) + } + }) + return e +} + +// level2Row is one level with its move mark. +func level2Row(c *ui.Context, marks map[string]*level2Mark, side OrderSide, i int, l *L2Level, dec, sizeDec int) { + k := Tokens(c) + d := Density(c) + name := fmt.Sprintf(msg(c, fmt.Sprintf("level2_quotes.side%d", side)), i+1) + key := fmt.Sprint(side, i) + m := marks[key] + if m == nil { + m = &level2Mark{} + marks[key] = m + } + row := ui.Row(c).Gap(d.Unit()*2).AlignItems(ui.Center).MinHeight(d.ControlHeight()).Padding(0, d.Unit()*2). + Radius(theme.ControlRadius).BorderWidth(0, 0, theme.BorderWidth, 0).BorderColor(k.Border) + if l == nil { + row.Children(func() { + ui.Text(c, name).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).Width(28) + ui.Text(c, "—").TextColor(k.TextMuted) + }) + return + } + if m.seen && (l.Price != m.price || l.Size != m.size) { + // A new price is a new level, not a move. + m.dir, m.at = 0, c.Now() + if l.Price == m.price { + m.dir = trendSign(l.Size - m.size) + } + slog.Debug("mujica: level2_quotes level changed", "level", name) + } + m.price, m.size, m.seen = l.Price, l.Size, true + if dur := Motion(c, priceTextFlash); dur > 0 && !m.at.IsZero() { + if t := c.Now().Sub(m.at); t < dur { + row.Background(k.Selection.Alpha(1 - float32(float64(t)/float64(dur)))) + c.AnimationFrame() + } + } + col := trendColor(c, side.sign()) + sizeText := statisticFormat(l.Size, sizeDec) + orders := fmt.Sprintf(msg(c, "level2_quotes.orders"), l.Orders) + row.Role(ui.RoleRow).Label(name + " " + statisticFormat(l.Price, dec) + " " + sizeText + " " + orders) + row.Children(func() { + ui.Text(c, name).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).Width(28) + ui.Text(c, statisticFormat(l.Price, dec)).TextColor(col).FontFeatures("tnum").FontWeight(600).Grow(1).Basis(0).SingleLine() + ui.Row(c).Gap(2).AlignItems(ui.Center).Justify(ui.End).Grow(1).Basis(0).Children(func() { + if m.dir != 0 { + ui.Icon(c, trendIcon(m.dir)).Size(12, 12).TextColor(trendColor(c, m.dir)) + } + ui.Text(c, sizeText).FontFeatures("tnum").SingleLine() + }) + ui.Text(c, fmt.Sprint(l.Orders)).TextColor(k.TextMuted).FontFeatures("tnum").TextAlign(ui.End).Width(36).SingleLine() + }) +} diff --git a/level2_quotes_test.go b/level2_quotes_test.go new file mode 100644 index 0000000..492b5fe --- /dev/null +++ b/level2_quotes_test.go @@ -0,0 +1,63 @@ +package mujica + +import ( + "bytes" + "testing" + + "github.com/egoist/mygo/ui" +) + +func level2Sample() Level2Data { + return Level2Data{ + Bids: []L2Level{{100.00, 500, 12}, {99.99, 300, 4}}, + Asks: []L2Level{{100.01, 200, 3}, {100.02, 900, 21}, {100.03, 50, 1}}, + } +} + +func TestLevel2QuotesLevels(t *testing.T) { + tt := tradingTester(GreenUp, 600, 300, func(c *ui.Context) { + ui.Box(c).Width(560).Children(func() { Level2Quotes(c, level2Sample(), Level2QuotesOptions{Levels: 3}) }) + }) + for _, name := range []string{"B1 100.00 500 12 orders", "S2 100.02 900 21 orders"} { + if _, ok := tt.Find(name); !ok { + t.Fatalf("no row %q in %q", name, tt.Texts()) + } + } + if !tt.HasText("B3") || !tt.HasText("—") { + t.Fatal("missing third bid not shown as empty") + } +} + +// A changed level marks its size move and flashes. +func TestLevel2QuotesHighlightsChangedLevel(t *testing.T) { + data := level2Sample() + var marks *map[string]*level2Mark + tt := tradingTester(GreenUp, 600, 300, func(c *ui.Context) { + e := Level2Quotes(c, data, Level2QuotesOptions{Levels: 2}) + marks = ui.Local(e, "marks", func() map[string]*level2Mark { return nil }) + }) + before := bytes.Clone(tt.Image().Pix) + data.Bids = []L2Level{{100.00, 650, 13}, {99.99, 300, 4}} + tt.Frame() + m := (*marks)["1 0"] + if m.dir != 1 || m.at.IsZero() { + t.Fatalf("bid 1 mark %+v", m) + } + if (*marks)["1 1"].dir != 0 || !(*marks)["1 1"].at.IsZero() { + t.Fatal("unchanged level marked") + } + if bytes.Equal(before, tt.Image().Pix) { + t.Fatal("nothing drawn for the change") + } + data.Bids = []L2Level{{100.01, 650, 13}, {99.99, 300, 4}} + tt.Frame() + if (*marks)["1 0"].dir != 0 { + t.Fatal("new price read as a size move") + } +} + +func TestLevel2QuotesSnapshot(t *testing.T) { + snapshot(t, "level2_quotes", 600, 230, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { Level2Quotes(c, level2Sample(), Level2QuotesOptions{}) }) + }) +} diff --git a/leverage_slider.go b/leverage_slider.go new file mode 100644 index 0000000..dd2e101 --- /dev/null +++ b/leverage_slider.go @@ -0,0 +1,159 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/internal" + "mujicaui/theme" +) + +// LeverageSliderOptions configure a LeverageSlider. +type LeverageSliderOptions struct { + // Levels are the rising leverages; nil means 1× to 100×. + Levels []float64 + // Warning and Danger start the risk zones; zero omits one. + Warning, Danger float64 + // Label names the slider; empty uses the built-in "Leverage". + Label string + Disabled bool +} + +type leverageSliderState struct { + draft float64 + seen float64 +} + +// LeverageSlider drafts a leverage; Apply sets *value. +func LeverageSlider(c *ui.Context, value *float64, opts LeverageSliderOptions) ChoiceResult { + levels := opts.Levels + if levels == nil { + levels = []float64{1, 2, 3, 5, 10, 20, 50, 100} + } + if len(levels) < 2 || !slices.IsSorted(levels) || slices.Index(levels, *value) < 0 { + panic(fmt.Sprintf("mujica: LeverageSlider value %v must be one of at least two rising Levels", *value)) + } + if opts.Warning < 0 || opts.Danger < 0 || opts.Danger != 0 && opts.Danger <= opts.Warning { + panic("mujica: LeverageSlider Danger must be above Warning") + } + k := Tokens(c) + d := Density(c) + label := opts.Label + if label == "" { + label = msg(c, "leverage_slider.label") + } + var r ChoiceResult + r.Element = ui.Column(c).Gap(d.Unit() * 2).MinWidth(260).Disabled(opts.Disabled) + st := ui.Local(r.Element, "lev", func() leverageSliderState { return leverageSliderState{draft: *value, seen: *value} }) + if *value != st.seen { + st.draft, st.seen = *value, *value + } + disabled := r.Element.IsDisabled() + if disabled { + st.draft = *value + } + zone := func(v float64) (string, ui.Color, string) { + switch { + case opts.Danger > 0 && v >= opts.Danger: + return msg(c, "leverage_slider.danger"), k.Danger, "circle-alert" + case opts.Warning > 0 && v >= opts.Warning: + return msg(c, "leverage_slider.warning"), k.Warning, "triangle-alert" + } + return "", k.TextMuted, "" + } + r.Element.Children(func() { + note, col, icon := zone(st.draft) + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, label).TextColor(k.TextMuted).Grow(1) + ui.Text(c, leverageText(st.draft)).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).FontFeatures("tnum") + }) + leverageTrack(c, st, levels, disabled, zone) + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).MinHeight(d.ControlHeight()).Children(func() { + ui.Row(c).Gap(d.Unit()).AlignItems(ui.Center).TextColor(col).Grow(1).Children(func() { + if icon != "" { + ui.Icon(c, icons.Must(icon)).Size(14, 14) + ui.Text(c, note).FontSize(FontSize(c, theme.CaptionSize)).FontWeight(600).Role(ui.RoleStatus) + } + }) + if Button(c, msg(c, "leverage_slider.apply"), ButtonOptions{Disabled: disabled || st.draft == *value}).Clicked() && !disabled { + *value, st.seen, r.changed = st.draft, st.draft, true + slog.Debug("mujica: leverage_slider applied", "leverage", *value) + } + }) + }) + return r +} + +func leverageText(v float64) string { return statisticFormat(v, 0) + "×" } + +// leverageTrack is the slider with zones, ticks and thumb. +func leverageTrack(c *ui.Context, st *leverageSliderState, levels []float64, disabled bool, zone func(float64) (string, ui.Color, string)) { + k := Tokens(c) + n := len(levels) + at := slices.Index(levels, st.draft) + set := func(i int) { + i = max(0, min(n-1, i)) + if levels[i] != st.draft && !disabled { + st.draft = levels[i] + slog.Debug("mujica: leverage_slider draft", "leverage", st.draft) + } + } + const pad = 10 + t := ui.Box(c).Height(theme.MinHitSize+16).FillWidth().Padding(0, pad).Focusable().Role(ui.RoleSlider). + Label(msg(c, "leverage_slider.label")).Description(leverageText(st.draft)) + t.FocusRing(false) + if !disabled { + switch { + case t.Shortcut(0, ui.KeyRight), t.Shortcut(0, ui.KeyUp): + set(at + 1) + case t.Shortcut(0, ui.KeyLeft), t.Shortcut(0, ui.KeyDown): + set(at - 1) + case t.Shortcut(0, ui.KeyHome): + set(0) + case t.Shortcut(0, ui.KeyEnd): + set(n - 1) + } + if _, _, ok := t.Dragged(); ok { + x, _, _ := t.PointerPosition() + if w := t.Bounds().W - 2*pad; w > 0 { + set(int(math.Round(float64((x - pad) / w * float32(n-1))))) + } + } + } + at = slices.Index(levels, st.draft) + t.Draw(func(p *ui.Painter, r ui.Rect) { + x0, w := r.X+pad, r.W-2*pad + y := r.Y + 14 + xs := func(i int) float32 { return internal.Snap(p, x0+w*float32(i)/float32(n-1)) } + // Zone bands run under the track. + for i := 0; i < n-1; i++ { + _, col, icon := zone(levels[i+1]) + if icon != "" { + p.Fill(ui.Rect{X: xs(i), Y: y + 4, W: xs(i+1) - xs(i), H: 3}, col, 0) + } + } + p.Line(x0, y, x0+w, y, 2, k.ControlBorder) + p.Line(x0, y, xs(at), y, 2, k.AccentText) + size := FontSize(c, theme.CaptionSize) + widest, _ := p.MeasureText(0, ui.Span{Text: leverageText(levels[n-1]), Size: size}) + // Crowded labels skip levels, counted back from the last. + every := max(1, int(math.Ceil(float64((widest+8)/(w/float32(n-1)))))) + for i, v := range levels { + p.Line(xs(i), y+4, xs(i), y+8, 1, k.TextMuted) + if (n-1-i)%every == 0 { + tw, _ := p.MeasureText(0, ui.Span{Text: leverageText(v), Size: size}) + p.Text(xs(i)-tw/2, y+11, leverageText(v), size, k.TextMuted) + } + } + p.FillPath(internal.Diamond(xs(at), y, 16), k.Surface) + p.FillPath(internal.Diamond(xs(at), y, 13), k.AccentText) + if t.FocusVisible() { + internal.FocusRing(p, ui.Rect{X: xs(at) - 8, Y: y - 8, W: 16, H: 16}, theme.ControlRadius, k.Focus) + } + }) +} diff --git a/leverage_slider_test.go b/leverage_slider_test.go new file mode 100644 index 0000000..fbbf4ce --- /dev/null +++ b/leverage_slider_test.go @@ -0,0 +1,94 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +type leverageProbe struct { + value float64 + opts LeverageSliderOptions + applied int +} + +func (p *leverageProbe) tester(density theme.Density) *ui.Tester { + return ui.NewTester(func(c *ui.Context) { + Use(c, Settings{Density: density}) + ui.Column(c).Padding(10).Children(func() { + if LeverageSlider(c, &p.value, p.opts).Changed() { + p.applied++ + } + }) + }, 420, 200) +} + +func TestLeverageSliderAppliesOnlyOnConfirm(t *testing.T) { + p := &leverageProbe{value: 5, opts: LeverageSliderOptions{Warning: 10, Danger: 50}} + tt := p.tester(theme.Default) + tt.Key(0, ui.KeyTab) + if !tt.Focused("Leverage") { + t.Fatal("slider not focusable") + } + tt.Key(0, ui.KeyRight) + if p.value != 5 || !tt.HasText("10×") || !tt.HasText("High risk") { + t.Fatalf("draft: value %v texts %q", p.value, tt.Texts()) + } + tt.Key(0, ui.KeyEnd) + if !tt.HasText("Very high risk") { + t.Fatalf("danger zone: %q", tt.Texts()) + } + if err := tt.Click("Apply"); err != nil { + t.Fatal(err) + } + if p.value != 100 || p.applied != 1 { + t.Fatalf("apply: %v %d", p.value, p.applied) + } + tt.Key(ui.Shift, ui.KeyTab) + tt.Key(0, ui.KeyHome) + if p.value != 100 || !tt.HasText("1×") { + t.Fatalf("home moved value: %v", p.value) + } +} + +func TestLeverageSliderPointerAndHitArea(t *testing.T) { + p := &leverageProbe{value: 1, opts: LeverageSliderOptions{Levels: []float64{1, 2, 3}}} + tt := p.tester(theme.Compact) + // The track is at least 28 DIPs tall, even Compact. + tt.ClickAt(10+400-10, 70) + if !tt.HasText("3×") { + t.Fatalf("pointer: %q", tt.Texts()) + } + tt.ClickAt(30, 70) + if !tt.HasText("1×") || p.applied != 0 { + t.Fatalf("pointer back: %q", tt.Texts()) + } +} + +func TestLeverageSliderDisabledAndBadValue(t *testing.T) { + p := &leverageProbe{value: 2, opts: LeverageSliderOptions{Disabled: true}} + tt := p.tester(theme.Default) + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyRight) + _ = tt.Click("Apply") + if p.value != 2 || tt.HasText("3×") || !tt.HasText("2×") { + t.Fatal("disabled slider moved") + } + defer func() { + if recover() == nil { + t.Fatal("value outside Levels accepted") + } + }() + (&leverageProbe{value: 4}).tester(theme.Default) +} + +func TestLeverageSliderSnapshot(t *testing.T) { + v := 20.0 + snapshot(t, "leverage_slider", 360, 160, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { + LeverageSlider(c, &v, LeverageSliderOptions{Warning: 10, Danger: 50}) + }) + }) +} diff --git a/margin_indicator.go b/margin_indicator.go new file mode 100644 index 0000000..4c59696 --- /dev/null +++ b/margin_indicator.go @@ -0,0 +1,71 @@ +package mujica + +import ( + "fmt" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// MarginIndicatorOptions configure a MarginIndicator. Zero lines mean 80% and 100%. +type MarginIndicatorOptions struct { + // Warning and Liquidation are margin ratios, Warning below Liquidation. + Warning, Liquidation float64 + // Label names the indicator; empty uses the built-in "Margin ratio". + Label string +} + +// MarginIndicator shows maintenance over equity against its two lines. +func MarginIndicator(c *ui.Context, ratio float64, opts MarginIndicatorOptions) *ui.Element { + warn, liq := opts.Warning, opts.Liquidation + if warn == 0 && liq == 0 { + warn, liq = 0.8, 1 + } + if !(warn > 0 && warn < liq) || ratio < 0 || math.IsNaN(ratio) { + panic(fmt.Sprintf("mujica: MarginIndicator ratio %v, lines %v and %v: need 0 < Warning < Liquidation", ratio, warn, liq)) + } + k := Tokens(c) + u := Density(c).Unit() + label := opts.Label + if label == "" { + label = msg(c, "margin_indicator.label") + } + status, col, icon := msg(c, "margin_indicator.safe"), k.Success, "circle-check" + switch { + case ratio >= liq: + status, col, icon = msg(c, "margin_indicator.liquidation"), k.Danger, "circle-x" + case ratio >= warn: + status, col, icon = msg(c, "margin_indicator.warning"), k.Warning, "triangle-alert" + } + pct := func(v float64) string { return statisticFormat(v*100, 1) + "%" } + top := math.Max(liq*1.25, ratio) + e := ui.Column(c).Gap(u * 2).MinWidth(220).Role(ui.RoleMeter).Label(label). + Description(fmt.Sprintf(msg(c, "margin_indicator.spoken"), pct(ratio), status, pct(warn), pct(liq))) + e.Children(func() { + ui.Row(c).Gap(u * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, pct(ratio)).FontSize(FontSize(c, theme.H3Size)).FontFeatures("tnum").FontWeight(600).SingleLine() + ui.Row(c).Gap(u / 2).AlignItems(ui.Center).TextColor(col).Children(func() { + ui.Icon(c, icons.Must(icon)).Size(14, 14) + ui.Text(c, status).FontSize(FontSize(c, theme.CaptionSize)).FontWeight(600).SingleLine() + }) + }) + ui.Box(c).Height(14).FillWidth().Draw(func(p *ui.Painter, r ui.Rect) { + bar := ui.Rect{X: r.X, Y: r.Y + 3, W: r.W, H: 8} + p.Fill(bar, k.SurfaceHover, theme.ControlRadius) + p.Fill(ui.Rect{X: bar.X, Y: bar.Y, W: bar.W * float32(ratio/top), H: bar.H}, col, theme.ControlRadius) + // The liquidation line is drawn heavier than the warning line. + for i, line := range []float64{warn, liq} { + x := bar.X + bar.W*float32(line/top) + p.Line(x, r.Y, x, r.Y+r.H, 1.5+float32(i)*1.5, k.Text) + } + }) + ui.Row(c).Gap(u * 4).Wrap().Children(func() { + ui.Text(c, msg(c, "margin_indicator.warning_line")+" "+pct(warn)).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted) + ui.Text(c, msg(c, "margin_indicator.liquidation_line")+" "+pct(liq)).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted) + }) + }) + return e +} diff --git a/margin_indicator_test.go b/margin_indicator_test.go new file mode 100644 index 0000000..0eefd39 --- /dev/null +++ b/margin_indicator_test.go @@ -0,0 +1,39 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestMarginIndicatorStates(t *testing.T) { + ratio := 0.42 + tt := tradingTester(GreenUp, 400, 160, func(c *ui.Context) { + ui.Box(c).Width(300).Children(func() { MarginIndicator(c, ratio, MarginIndicatorOptions{}) }) + }) + for _, tc := range []struct { + ratio float64 + want string + }{{0.42, "Safe"}, {0.8, "Margin call"}, {1.2, "Liquidation"}} { + ratio = tc.ratio + tt.Frame() + if !tt.HasText(tc.want) { + t.Fatalf("%v: %q", tc.ratio, tt.Texts()) + } + } + if !tt.HasText("Warning line 80.0%") || !tt.HasText("Liquidation line 100.0%") || !tt.HasText("120.0%") { + t.Fatalf("lines: %q", tt.Texts()) + } + defer func() { + if recover() == nil { + t.Fatal("warning above liquidation accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { MarginIndicator(c, 1, MarginIndicatorOptions{Warning: 2, Liquidation: 1}) }) +} + +func TestMarginIndicatorSnapshot(t *testing.T) { + snapshot(t, "margin_indicator", 340, 120, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { MarginIndicator(c, 0.86, MarginIndicatorOptions{}) }) + }) +} diff --git a/messages_trading.go b/messages_trading.go new file mode 100644 index 0000000..8f72fe7 --- /dev/null +++ b/messages_trading.go @@ -0,0 +1,161 @@ +package mujica + +func init() { + addMessages(map[string][2]string{ + "price_text.up": {"up", "上涨"}, + "price_text.down": {"down", "下跌"}, + "price_text.flat": {"unchanged", "平"}, + + "ticker_tape.label": {"Market ticker", "行情滚动条"}, + "ticker_tape.pause_hint": {"Pauses under the pointer or keyboard focus", "指针悬停或键盘聚焦时暂停"}, + "ticker_tape.previous": {"Previous page", "上一页"}, + "ticker_tape.next": {"Next page", "下一页"}, + + "spread_indicator.title": {"Spread", "价差"}, + "spread_indicator.value": {"%s (%s%%)", "%s(%s%%)"}, + "spread_indicator.wide": {"Wide spread", "价差过大"}, + "spread_indicator.crossed": {"Crossed market", "买卖价倒挂"}, + + "bid_ask_bar.label": {"Bid and ask volume", "买卖力量"}, + "bid_ask_bar.buy": {"Buy %s%% · %s", "买 %s%% · %s"}, + "bid_ask_bar.sell": {"%s · Sell %s%%", "%s · 卖 %s%%"}, + + "risk_meter.label": {"Risk level", "风险等级"}, + "risk_meter.value": {"Level %d of %d, %s.", "第 %d 级,共 %d 级,%s。"}, + "risk_meter.level1": {"Low", "低"}, + "risk_meter.level2": {"Moderately low", "中低"}, + "risk_meter.level3": {"Medium", "中"}, + "risk_meter.level4": {"Moderately high", "中高"}, + "risk_meter.level5": {"High", "高"}, + + "margin_indicator.label": {"Margin ratio", "保证金率"}, + "margin_indicator.safe": {"Safe", "安全"}, + "margin_indicator.warning": {"Margin call", "追加保证金"}, + "margin_indicator.liquidation": {"Liquidation", "强制平仓"}, + "margin_indicator.warning_line": {"Warning line", "警戒线"}, + "margin_indicator.liquidation_line": {"Liquidation line", "强平线"}, + "margin_indicator.spoken": {"%s, %s. Warning at %s, liquidation at %s.", "%s,%s。警戒线 %s,强平线 %s。"}, + + "pnl_display.label": {"Profit and loss", "盈亏"}, + "pnl_display.realized": {"Realized", "已实现"}, + "pnl_display.unrealized": {"Unrealized", "未实现"}, + "pnl_display.today": {"Today", "当日"}, + "pnl_display.masked": {"hidden", "已隐藏"}, + "pnl_display.hide": {"Hide amounts", "隐藏金额"}, + "pnl_display.show": {"Show amounts", "显示金额"}, + + "order_book.label": {"Order book", "盘口"}, + "order_book.group": {"Group", "合并档位"}, + "order_book.price": {"Price", "价格"}, + "order_book.size": {"Size", "数量"}, + "order_book.total": {"Total", "累计"}, + "order_book.side1": {"Bid", "买"}, + "order_book.side2": {"Ask", "卖"}, + "order_book.level": {"%s %s, size %s", "%s %s,数量 %s"}, + + "level2_quotes.label": {"Level 2 quotes", "多档行情"}, + "level2_quotes.side1": {"B%d", "买%d"}, + "level2_quotes.side2": {"S%d", "卖%d"}, + "level2_quotes.orders": {"%d orders", "%d 笔委托"}, + + "time_and_sales.title": {"Time and sales", "逐笔成交"}, + "time_and_sales.pause": {"Pause", "暂停跟随"}, + "time_and_sales.resume": {"Resume", "继续跟随"}, + "time_and_sales.resume_count": {"Resume (%d new)", "继续跟随(%d 笔新成交)"}, + "time_and_sales.time": {"Time", "时间"}, + "time_and_sales.price": {"Price", "价格"}, + "time_and_sales.size": {"Size", "数量"}, + "time_and_sales.large": {"large trade", "大单"}, + "time_and_sales.empty": {"No trades yet", "暂无成交"}, + + "depth_ladder.label": {"Price ladder", "价格阶梯"}, + "depth_ladder.bid": {"Bid", "买量"}, + "depth_ladder.price": {"Price", "价格"}, + "depth_ladder.ask": {"Ask", "卖量"}, + "depth_ladder.last": {"Last price", "最新价"}, + "depth_ladder.order1": {"Buy at %s", "以 %s 买入"}, + "depth_ladder.order2": {"Sell at %s", "以 %s 卖出"}, + "depth_ladder.recenter": {"Center on last price", "回到最新价"}, + + "order_entry.label": {"Order entry", "下单"}, + "order_entry.side": {"Side", "方向"}, + "order_entry.buy": {"Buy", "买入"}, + "order_entry.sell": {"Sell", "卖出"}, + "order_entry.side1": {"Buy", "买入"}, + "order_entry.side2": {"Sell", "卖出"}, + "order_entry.type": {"Order type", "订单类型"}, + "order_entry.type0": {"Limit", "限价"}, + "order_entry.type1": {"Market", "市价"}, + "order_entry.type2": {"Stop", "止损"}, + "order_entry.type3": {"Stop limit", "条件限价"}, + "order_entry.quantity": {"Quantity", "数量"}, + "order_entry.price": {"Limit price", "限价"}, + "order_entry.trigger": {"Trigger price", "触发价"}, + "order_entry.tif": {"Time in force", "有效期"}, + "order_entry.tif0": {"Day", "当日有效"}, + "order_entry.tif1": {"Good till canceled", "撤销前有效"}, + "order_entry.tif2": {"Immediate or cancel", "立即成交剩余撤销"}, + "order_entry.tif3": {"Fill or kill", "全部成交否则撤销"}, + "order_entry.estimate": {"Estimated amount", "预估金额"}, + "order_entry.submit1": {"Buy %s", "买入 %s"}, + "order_entry.submit2": {"Sell %s", "卖出 %s"}, + "order_entry.quantity_positive": {"Enter a quantity above zero.", "请输入大于零的数量。"}, + "order_entry.quantity_max": {"At most %s.", "最多 %s。"}, + "order_entry.price_positive": {"Enter a price above zero.", "请输入大于零的价格。"}, + "order_entry.trigger_positive": {"Enter a trigger price above zero.", "请输入大于零的触发价。"}, + "order_entry.trigger_above": {"A buy stop triggers above the last price.", "买入止损的触发价须高于最新价。"}, + "order_entry.trigger_below": {"A sell stop triggers below the last price.", "卖出止损的触发价须低于最新价。"}, + + "quick_trade_buttons.label": {"Quick trade", "快速交易"}, + "quick_trade_buttons.quantity": {"Quantity", "数量"}, + "quick_trade_buttons.side1": {"Buy %s", "买入 %s"}, + "quick_trade_buttons.side2": {"Sell %s", "卖出 %s"}, + "quick_trade_buttons.confirm1": {"Buy %s %s?", "买入 %s %s?"}, + "quick_trade_buttons.confirm2": {"Sell %s %s?", "卖出 %s %s?"}, + "quick_trade_buttons.market": {"The order fills at the market price.", "订单将以市价成交。"}, + + "position_table.symbol": {"Symbol", "代码"}, + "position_table.quantity": {"Quantity", "数量"}, + "position_table.cost": {"Avg cost", "成本价"}, + "position_table.price": {"Price", "现价"}, + "position_table.value": {"Market value", "市值"}, + "position_table.pnl": {"Unrealized P/L", "浮动盈亏"}, + "position_table.pnl_percent": {"P/L %", "盈亏比例"}, + "position_table.action": {"Action", "操作"}, + "position_table.close": {"Close", "平仓"}, + "position_table.empty": {"No positions", "暂无持仓"}, + + "order_table.side": {"Side", "方向"}, + "order_table.market": {"Market", "市价"}, + "order_table.filled": {"Filled", "成交"}, + "order_table.status": {"Status", "状态"}, + "order_table.status0": {"Open", "未成交"}, + "order_table.status1": {"Partly filled", "部分成交"}, + "order_table.status2": {"Filled", "已成交"}, + "order_table.status3": {"Canceled", "已撤销"}, + "order_table.status4": {"Rejected", "已拒绝"}, + "order_table.filter": {"Order status", "委托状态"}, + "order_table.filter0": {"All", "全部"}, + "order_table.filter1": {"Working", "进行中"}, + "order_table.filter2": {"Filled", "已成交"}, + "order_table.filter3": {"Closed", "已关闭"}, + "order_table.cancel": {"Cancel", "撤单"}, + "order_table.empty": {"No orders", "暂无委托"}, + + "trade_history_table.time": {"Time", "时间"}, + "trade_history_table.fee": {"Fee", "手续费"}, + "trade_history_table.range": {"Date range", "日期范围"}, + "trade_history_table.all": {"All dates", "全部日期"}, + "trade_history_table.export": {"Export", "导出"}, + "trade_history_table.empty": {"No trades in this range", "该范围内无成交"}, + + "leverage_slider.label": {"Leverage", "杠杆"}, + "leverage_slider.warning": {"High risk", "高风险"}, + "leverage_slider.danger": {"Very high risk", "极高风险"}, + "leverage_slider.apply": {"Apply", "确认"}, + + "order_confirm_dialog.title": {"Confirm order", "确认下单"}, + "order_confirm_dialog.confirm": {"Place order", "确认下单"}, + "order_confirm_dialog.cancel": {"Cancel", "取消"}, + }) +} diff --git a/order_book.go b/order_book.go new file mode 100644 index 0000000..dbf2871 --- /dev/null +++ b/order_book.go @@ -0,0 +1,260 @@ +package mujica + +import ( + "cmp" + "fmt" + "log/slog" + "math" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// OrderSide is the buy or sell side. +type OrderSide int + +const ( + SideBuy OrderSide = iota + 1 + SideSell +) + +// sign is +1 for buying and -1 for selling. +func (s OrderSide) sign() int { + switch s { + case SideBuy: + return 1 + case SideSell: + return -1 + } + panic(fmt.Sprintf("mujica: unknown OrderSide %d", s)) +} + +// BookLevel is a price and the size resting there. +type BookLevel struct { + Price, Size float64 +} + +// OrderBookData is the book; bump Version on in-place changes. +type OrderBookData struct { + Bids, Asks []BookLevel + Version int +} + +// OrderBookOptions configure an OrderBook. +type OrderBookOptions struct { + // Decimals of prices and sizes; zero means 2 and 0. + Decimals, SizeDecimals int + // Depth is the levels shown each side; zero means 8. + Depth int + // Groups are the offered aggregation steps; nil shows raw levels. + Groups []float64 + Disabled bool +} + +// OrderBookState is an OrderBook's chosen grouping and its aggregated view. +type OrderBookState struct { + // Group is the aggregation step; zero takes Groups[0]. + Group float64 + cache orderBookCache +} + +type orderBookCache struct { + key bookKey + valid bool + bids, asks []BookLevel +} + +// bookKey tells when a book or its grouping changed. +type bookKey struct { + bid, ask *BookLevel + nb, na int + version int + group float64 +} + +func bookKeyOf(book OrderBookData, group float64) bookKey { + first := func(ls []BookLevel) *BookLevel { + if len(ls) == 0 { + return nil + } + return &ls[0] + } + return bookKey{first(book.Bids), first(book.Asks), len(book.Bids), len(book.Asks), book.Version, group} +} + +// OrderBookResult is a built OrderBook and its clicked level. +type OrderBookResult struct { + Element *ui.Element + price float64 + side OrderSide +} + +// Clicked returns the clicked level's price and side. +func (r OrderBookResult) Clicked() (price float64, side OrderSide, ok bool) { + return r.price, r.side, r.side != 0 +} + +// OrderBook shows clickable asks over bids with depth bars. +func OrderBook(c *ui.Context, s *OrderBookState, book OrderBookData, opts OrderBookOptions) OrderBookResult { + dec := priceDecimals("OrderBook", opts.Decimals) + if opts.SizeDecimals < 0 || opts.Depth < 0 { + panic("mujica: OrderBook SizeDecimals and Depth cannot be negative") + } + depth := opts.Depth + if depth == 0 { + depth = 8 + } + if len(opts.Groups) > 0 && s.Group == 0 { + s.Group = opts.Groups[0] + } + if s.Group != 0 && !slices.Contains(opts.Groups, s.Group) { + panic(fmt.Sprintf("mujica: OrderBook Group %v is not one of Groups", s.Group)) + } + orderBookRefresh(s, book, dec) + k := Tokens(c) + d := Density(c) + var r OrderBookResult + r.Element = ui.Column(c).Gap(d.Unit()).MinWidth(240).Disabled(opts.Disabled).Role(ui.RoleTable).Label(msg(c, "order_book.label")) + r.Element.Children(func() { + if len(opts.Groups) > 0 { + var choices []SelectOption[float64] + for _, g := range opts.Groups { + choices = append(choices, SelectOption[float64]{Value: g, Label: statisticFormat(g, dec)}) + } + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, msg(c, "order_book.group")).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)) + if Select(c, &s.Group, choices, SelectOptions{Label: msg(c, "order_book.group"), Disabled: opts.Disabled}).Changed() { + slog.Debug("mujica: order_book group", "step", s.Group) + } + }) + } + asks := s.cache.asks[:min(depth, len(s.cache.asks))] + bids := s.cache.bids[:min(depth, len(s.cache.bids))] + total := max(orderBookSum(asks), orderBookSum(bids)) + orderBookHeader(c) + list := ui.Column(c).FocusGroup(ui.Vertical) + list.Children(func() { + cum := orderBookSum(asks) + for i := len(asks) - 1; i >= 0; i-- { + orderBookRow(c, &r, asks[i], cum, total, SideSell, dec, opts.SizeDecimals) + cum -= asks[i].Size + } + if len(asks) > 0 && len(bids) > 0 { + ui.Row(c).Padding(d.Unit(), d.Unit()*2).BorderWidth(theme.BorderWidth, 0).BorderColor(k.Border).Children(func() { + SpreadIndicator(c, bids[0].Price, asks[0].Price, SpreadIndicatorOptions{Decimals: dec}) + }) + } + cum = 0 + for _, l := range bids { + cum += l.Size + orderBookRow(c, &r, l, cum, total, SideBuy, dec, opts.SizeDecimals) + } + }) + }) + if r.side != 0 { + slog.Debug("mujica: order_book clicked", "side", r.side) + } + return r +} + +func orderBookSum(ls []BookLevel) float64 { + var t float64 + for _, l := range ls { + t += l.Size + } + return t +} + +// orderBookHeader names the columns. +func orderBookHeader(c *ui.Context) { + k := Tokens(c) + d := Density(c) + ui.Row(c).Padding(0, d.Unit()*2).Children(func() { + for i, key := range []string{"order_book.price", "order_book.size", "order_book.total"} { + t := ui.Text(c, msg(c, key)).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted).Grow(1).Basis(0) + if i > 0 { + t.TextAlign(ui.End) + } + } + }) +} + +// orderBookRow is one clickable level with its depth bar. +func orderBookRow(c *ui.Context, r *OrderBookResult, l BookLevel, cum, total float64, side OrderSide, dec, sizeDec int) { + k := Tokens(c) + d := Density(c) + col := trendColor(c, side.sign()) + price := statisticFormat(l.Price, dec) + b := ui.ButtonBase(c).Key(fmt.Sprint(side, price)).MinHeight(d.ControlHeight()). + Padding(0, d.Unit()*2).Radius(theme.ControlRadius). + Label(fmt.Sprintf(msg(c, "order_book.level"), msg(c, fmt.Sprintf("order_book.side%d", side)), price, statisticFormat(l.Size, sizeDec))) + internal.Ring(b, k.Focus, theme.ControlRadius) + if b.Hovered() { + b.Background(k.SurfaceHover) + } + share := float32(0) + if total > 0 { + share = float32(cum / total) + } + b.Draw(func(p *ui.Painter, rect ui.Rect) { + w := rect.W * share + p.Fill(ui.Rect{X: rect.X + rect.W - w, Y: rect.Y + 2, W: w, H: rect.H - 4}, col.Alpha(0.14), 0) + }) + b.Children(func() { + ui.Text(c, price).TextColor(col).FontFeatures("tnum").FontWeight(600).Grow(1).Basis(0).SingleLine() + ui.Text(c, statisticFormat(l.Size, sizeDec)).FontFeatures("tnum").TextAlign(ui.End).Grow(1).Basis(0).SingleLine() + ui.Text(c, statisticFormat(cum, sizeDec)).FontFeatures("tnum").TextColor(k.TextMuted).TextAlign(ui.End).Grow(1).Basis(0).SingleLine() + }) + if b.Clicked() && !b.IsDisabled() { + r.price, r.side = l.Price, side + } +} + +// orderBookRefresh regroups only when book or grouping changed. +func orderBookRefresh(s *OrderBookState, book OrderBookData, dec int) { + key := bookKeyOf(book, s.Group) + if s.cache.valid && s.cache.key == key { + return + } + s.cache = orderBookCache{key: key, valid: true, + bids: orderBookGroup(book.Bids, s.Group, dec, false), asks: orderBookGroup(book.Asks, s.Group, dec, true)} +} + +// orderBookGroup merges levels into group steps, best first. +func orderBookGroup(ls []BookLevel, group float64, dec int, up bool) []BookLevel { + scale := math.Pow(10, float64(dec)) + step := int64(1) + if group != 0 { + step = int64(math.Round(group * scale)) + if step < 1 || math.Abs(group*scale-float64(step)) > 1e-6 { + panic(fmt.Sprintf("mujica: OrderBook group %v is not a whole number of %d-decimal ticks", group, dec)) + } + } + sizes := map[int64]float64{} + for _, l := range ls { + if l.Price < 0 || l.Size < 0 { + panic("mujica: OrderBook levels need prices and sizes of zero or more") + } + t := int64(math.Round(l.Price * scale)) + // Bids round down, asks up: groups never beat real prices. + b := t / step * step + if up && b < t { + b += step + } + sizes[b] += l.Size + } + out := make([]BookLevel, 0, len(sizes)) + for t, sz := range sizes { + out = append(out, BookLevel{Price: float64(t) / scale, Size: sz}) + } + slices.SortFunc(out, func(a, b BookLevel) int { + if up { + return cmp.Compare(a.Price, b.Price) + } + return cmp.Compare(b.Price, a.Price) + }) + return out +} diff --git a/order_book_test.go b/order_book_test.go new file mode 100644 index 0000000..b0d6485 --- /dev/null +++ b/order_book_test.go @@ -0,0 +1,123 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func orderBookSample() OrderBookData { + return OrderBookData{ + Bids: []BookLevel{{100.00, 5}, {99.99, 3}, {99.94, 2}, {99.90, 4}}, + Asks: []BookLevel{{100.01, 1}, {100.02, 2}, {100.07, 6}}, + } +} + +func TestOrderBookClickReportsPrice(t *testing.T) { + var s OrderBookState + var price float64 + var side OrderSide + tt := tradingTester(GreenUp, 400, 500, func(c *ui.Context) { + if p, sd, ok := OrderBook(c, &s, orderBookSample(), OrderBookOptions{}).Clicked(); ok { + price, side = p, sd + } + }) + if err := tt.Click("Ask 100.02, size 2"); err != nil { + t.Fatal(err) + } + if price != 100.02 || side != SideSell { + t.Fatalf("clicked %v %v", price, side) + } + tt.Key(0, ui.KeyDown) + tt.Key(0, ui.KeyEnter) + if price != 100.01 || side != SideSell { + t.Fatalf("keyboard %v %v", price, side) + } + if !tt.HasText("0.01 (0.010%)") { + t.Fatalf("spread missing: %q", tt.Texts()) + } +} + +func TestOrderBookGroupsLevelsByTicks(t *testing.T) { + s := OrderBookState{Group: 0.05} + tt := tradingTester(GreenUp, 400, 500, func(c *ui.Context) { + OrderBook(c, &s, orderBookSample(), OrderBookOptions{Groups: []float64{0.01, 0.05, 0.1}}) + }) + // Bids round down, asks round up. + want := []BookLevel{{100.00, 5}, {99.95, 3}, {99.90, 6}} + for i, l := range want { + if s.cache.bids[i] != l { + t.Fatalf("bids %v", s.cache.bids) + } + } + if s.cache.asks[0] != (BookLevel{100.05, 3}) || s.cache.asks[1] != (BookLevel{100.10, 6}) { + t.Fatalf("asks %v", s.cache.asks) + } + if !tt.HasText("99.95") { + t.Fatalf("texts %q", tt.Texts()) + } +} + +func TestOrderBookAggregatesOnlyOnChange(t *testing.T) { + var s OrderBookState + book := orderBookSample() + tt := tradingTester(GreenUp, 400, 500, func(c *ui.Context) { OrderBook(c, &s, book, OrderBookOptions{}) }) + first := &s.cache.bids[0] + tt.Frame() + if &s.cache.bids[0] != first { + t.Fatal("regrouped without a change") + } + book.Bids[0].Size = 9 + book.Version++ + tt.Frame() + if s.cache.bids[0].Size != 9 { + t.Fatal("version change ignored") + } +} + +func TestOrderBookDisabledAndBadGroup(t *testing.T) { + var s OrderBookState + clicked := false + tt := tradingTester(GreenUp, 400, 500, func(c *ui.Context) { + _, _, clicked = OrderBook(c, &s, orderBookSample(), OrderBookOptions{Disabled: true}).Clicked() + }) + _ = tt.Click("Bid 100.00, size 5") + if clicked { + t.Fatal("disabled book clicked") + } + defer func() { + if recover() == nil { + t.Fatal("off-tick group accepted") + } + }() + bad := OrderBookState{Group: 0.015} + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { + OrderBook(c, &bad, orderBookSample(), OrderBookOptions{Groups: []float64{0.015}}) + }) +} + +func TestOrderBookSnapshot(t *testing.T) { + snapshot(t, "order_book", 320, 420, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + s := ui.Local(c.Root(), "snap", func() OrderBookState { return OrderBookState{} }) + OrderBook(c, s, orderBookSample(), OrderBookOptions{Depth: 4, Groups: []float64{0.01, 0.05}}) + }) + }) +} + +// A 100,000-level book builds only the shown depth. +func TestOrderBookLargeBook(t *testing.T) { + var s OrderBookState + book := OrderBookData{} + for i := range 100_000 { + book.Bids = append(book.Bids, BookLevel{Price: 1000 - float64(i)/100, Size: 1}) + book.Asks = append(book.Asks, BookLevel{Price: 1000.01 + float64(i)/100, Size: 1}) + } + tt := tradingTester(GreenUp, 400, 900, func(c *ui.Context) { OrderBook(c, &s, book, OrderBookOptions{}) }) + if n := len(tt.Texts()); n > 80 { + t.Fatalf("built %d texts", n) + } + if len(s.cache.bids) != 100_000 || s.cache.bids[0].Price != 1000 { + t.Fatalf("bids %d", len(s.cache.bids)) + } +} diff --git a/order_confirm_dialog.go b/order_confirm_dialog.go new file mode 100644 index 0000000..357b5b0 --- /dev/null +++ b/order_confirm_dialog.go @@ -0,0 +1,88 @@ +package mujica + +import ( + "log/slog" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// OrderSummaryLine is one labeled value of an order summary. +type OrderSummaryLine struct { + Label, Value string +} + +// OrderConfirmDialogOptions configure an OrderConfirmDialog. Lines are required. +type OrderConfirmDialogOptions struct { + // Title is "Confirm order" when empty. + Title string + Lines []OrderSummaryLine + // Risk is a warning shown above the actions. + Risk string + // Acknowledge, when set, must be ticked before confirming. + Acknowledge string + // ConfirmLabel is "Place order" when empty. + ConfirmLabel string +} + +type orderConfirmState struct{ ack bool } + +// OrderConfirmDialog summarizes an order; Cancel has the focus. +func OrderConfirmDialog(c *ui.Context, open *bool, opts OrderConfirmDialogOptions) AlertDialogResult { + if len(opts.Lines) == 0 { + panic("mujica: OrderConfirmDialog needs summary Lines") + } + var res AlertDialogResult + k := Tokens(c) + u := Density(c).Unit() + title, confirm := opts.Title, opts.ConfirmLabel + if title == "" { + title = msg(c, "order_confirm_dialog.title") + } + if confirm == "" { + confirm = msg(c, "order_confirm_dialog.confirm") + } + was := *open + var st *orderConfirmState + Dialog(c, open, DialogOptions{Title: title, KeepOnBackdrop: true, HideClose: true, Actions: func() { + if Button(c, msg(c, "order_confirm_dialog.cancel"), ButtonOptions{Variant: Secondary}).AutoFocus().Clicked() { + res.Canceled = true + } + locked := opts.Acknowledge != "" && !st.ack + if Button(c, confirm, ButtonOptions{Disabled: locked}).Clicked() && !locked { + res.Confirmed = true + } + }}, func() { + list := ui.Column(c) + // The tick lives with the open dialog only. + st = ui.Local(list, "ack", func() orderConfirmState { return orderConfirmState{} }) + list.Children(func() { + for _, l := range opts.Lines { + ui.Row(c).Gap(u*4).MinHeight(Density(c).ControlHeight()).AlignItems(ui.Center). + BorderWidth(0, 0, theme.BorderWidth, 0).BorderColor(k.Border).Children(func() { + ui.Text(c, l.Label).TextColor(k.TextMuted).Grow(1) + ui.Text(c, l.Value).FontFeatures("tnum").FontWeight(600) + }) + } + }) + if opts.Risk != "" { + ui.Row(c).Gap(u * 2).AlignItems(ui.Start).Padding(u * 3).Radius(theme.ControlRadius).Background(k.Warning.Alpha(0.12)).Children(func() { + ui.Icon(c, icons.Must("triangle-alert")).Size(16, 16).TextColor(k.Warning).Shrink(0) + ui.Text(c, opts.Risk).Grow(1) + }) + } + if opts.Acknowledge != "" { + Checkbox(c, &st.ack, opts.Acknowledge, CheckboxOptions{}) + } + }) + if was && !*open && !res.Confirmed { + res.Canceled = true + } + if res.Confirmed || res.Canceled { + *open = false + slog.Debug("mujica: order_confirm_dialog close", "confirmed", res.Confirmed) + } + return res +} diff --git a/order_confirm_dialog_test.go b/order_confirm_dialog_test.go new file mode 100644 index 0000000..68d48f2 --- /dev/null +++ b/order_confirm_dialog_test.go @@ -0,0 +1,78 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func orderConfirmTester(open *bool, opts OrderConfirmDialogOptions, res *AlertDialogResult) *ui.Tester { + return tradingTester(GreenUp, 600, 500, func(c *ui.Context) { + if r := OrderConfirmDialog(c, open, opts); r.Confirmed || r.Canceled { + *res = r + } + }) +} + +var orderConfirmLines = []OrderSummaryLine{{"Symbol", "MUJC"}, {"Side", "Buy"}, {"Quantity", "100"}, {"Est. amount", "10,020.00"}} + +func TestOrderConfirmDialogFocusesCancel(t *testing.T) { + open := true + var res AlertDialogResult + tt := orderConfirmTester(&open, OrderConfirmDialogOptions{Lines: orderConfirmLines, Risk: "Leveraged products can lose more than the deposit."}, &res) + if !tt.Focused("Cancel") || !tt.HasText("10,020.00") || !tt.HasText("Leveraged products can lose more than the deposit.") { + t.Fatalf("texts %q", tt.Texts()) + } + tt.Key(0, ui.KeyEnter) + if !res.Canceled || open { + t.Fatalf("Enter on Cancel: %+v open %v", res, open) + } + open, res = true, AlertDialogResult{} + tt.Frame() + if err := tt.Click("Place order"); err != nil { + t.Fatal(err) + } + if !res.Confirmed || open { + t.Fatalf("confirm: %+v", res) + } +} + +func TestOrderConfirmDialogAcknowledgeAndEscape(t *testing.T) { + open := true + var res AlertDialogResult + tt := orderConfirmTester(&open, OrderConfirmDialogOptions{Lines: orderConfirmLines, Acknowledge: "I understand the risk"}, &res) + _ = tt.Click("Place order") + if res.Confirmed || !open { + t.Fatal("confirmed before acknowledging") + } + _ = tt.Click("I understand the risk") + _ = tt.Click("Place order") + if !res.Confirmed { + t.Fatal("acknowledged confirm refused") + } + open, res = true, AlertDialogResult{} + tt.Frame() + _ = tt.Click("Place order") + if res.Confirmed { + t.Fatal("acknowledgement survived reopening") + } + tt.Key(0, ui.KeyEscape) + if !res.Canceled || open { + t.Fatalf("escape: %+v", res) + } + defer func() { + if recover() == nil { + t.Fatal("empty summary accepted") + } + }() + open = true + orderConfirmTester(&open, OrderConfirmDialogOptions{}, &res) +} + +func TestOrderConfirmDialogSnapshot(t *testing.T) { + open := true + snapshot(t, "order_confirm_dialog", 560, 480, func(c *ui.Context) { + OrderConfirmDialog(c, &open, OrderConfirmDialogOptions{Lines: orderConfirmLines, + Risk: "Leveraged products can lose more than the deposit.", Acknowledge: "I understand the risk"}) + }) +} diff --git a/order_entry.go b/order_entry.go new file mode 100644 index 0000000..0c95398 --- /dev/null +++ b/order_entry.go @@ -0,0 +1,222 @@ +package mujica + +import ( + "fmt" + "log/slog" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// OrderType is limit, market, stop or stop limit. +type OrderType int + +const ( + OrderLimit OrderType = iota + OrderMarket + OrderStop + OrderStopLimit +) + +// TimeInForce is how long an order rests. +type TimeInForce int + +const ( + TIFDay TimeInForce = iota + TIFGoodTillCanceled + TIFImmediateOrCancel + TIFFillOrKill +) + +// OrderDraft is an order as entered. +type OrderDraft struct { + Side OrderSide + Type OrderType + Quantity float64 + Price float64 + Trigger float64 + TIF TimeInForce +} + +// OrderEntryOptions configure an OrderEntry. Symbol is required. +type OrderEntryOptions struct { + Symbol string + // Last is the last price; zero means unknown. + Last float64 + // TickSize and LotSize step prices and quantities; zero: 0.01, 1. + TickSize, LotSize float64 + // MaxQuantity caps the quantity; zero means no cap. + MaxQuantity float64 + // Initial is what Reset restores; a zero Side means buy. + Initial OrderDraft + // Validate adds the caller's rules, returning a message or "". + Validate func(o OrderDraft) string + // Check starts an async check, finished with OrderEntryState.Resolve. + Check func(o OrderDraft, version uint64) + Disabled bool +} + +// OrderEntryState holds the draft and its form state. +type OrderEntryState struct { + Draft OrderDraft + Form FormState + started bool +} + +// Resolve delivers Check's result; stale versions return false. +func (s *OrderEntryState) Resolve(version uint64, err string) bool { + return s.Form.Resolve("quantity", version, err) +} + +// EndSubmit finishes a submit; a formError shows, keeping the draft. +func (s *OrderEntryState) EndSubmit(formError string) { s.Form.EndSubmit(formError) } + +// OrderEntryResult is a built OrderEntry and its submitted order. +type OrderEntryResult struct { + Element *ui.Element + order OrderDraft + submitted bool +} + +// Submitted returns the checked order; call EndSubmit once placed. +func (r OrderEntryResult) Submitted() (OrderDraft, bool) { return r.order, r.submitted } + +// OrderEntry edits an order and submits it once checked. +func OrderEntry(c *ui.Context, s *OrderEntryState, opts OrderEntryOptions) OrderEntryResult { + if opts.Symbol == "" { + panic("mujica: OrderEntry needs a Symbol") + } + if opts.TickSize < 0 || opts.LotSize < 0 || opts.MaxQuantity < 0 || opts.Last < 0 { + panic("mujica: OrderEntry TickSize, LotSize, MaxQuantity and Last cannot be negative") + } + tick, lot := opts.TickSize, opts.LotSize + if tick == 0 { + tick = 0.01 + } + if lot == 0 { + lot = 1 + } + initial := opts.Initial + if initial.Side == 0 { + initial.Side = SideBuy + } + if !s.started { + s.started, s.Draft = true, initial + } + priceSpec := numberInputResolve(NumberInputOptions{Step: tick}) + k := Tokens(c) + u := Density(c).Unit() + var r OrderEntryResult + r.Element = ui.Column(c).Gap(u * 4).MaxWidth(360).Disabled(opts.Disabled).Role(ui.RoleGroup).Label(msg(c, "order_entry.label")) + disabled := r.Element.IsDisabled() + r.Element.Children(func() { + side := 0 + if s.Draft.Side == SideSell { + side = 1 + } + sides := []Segment{{Label: msg(c, "order_entry.buy")}, {Label: msg(c, "order_entry.sell")}} + SegmentedControl(c, &side, sides, SegmentedControlOptions{Equal: true, Label: msg(c, "order_entry.side"), Disabled: disabled}) + s.Draft.Side = SideBuy + OrderSide(side) + var types []SelectOption[OrderType] + for t := OrderLimit; t <= OrderStopLimit; t++ { + types = append(types, SelectOption[OrderType]{Value: t, Label: msg(c, fmt.Sprintf("order_entry.type%d", t))}) + } + ui.Row(c).Gap(u * 3).AlignItems(ui.Center).Children(func() { + ui.Text(c, opts.Symbol).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).Grow(1) + Select(c, &s.Draft.Type, types, SelectOptions{Label: msg(c, "order_entry.type"), Disabled: disabled}) + }) + submit := fmt.Sprintf(msg(c, fmt.Sprintf("order_entry.submit%d", s.Draft.Side)), opts.Symbol) + res := Form(c, &s.Form, FormOptions{SubmitLabel: submit}, func(f *FormScope) { + orderEntryFields(c, f, s, opts, initial, tick, lot, disabled) + }) + ui.Row(c).Gap(u * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, msg(c, "order_entry.estimate")).TextColor(k.TextMuted) + est := "—" + if p := orderEntryPrice(s.Draft, opts.Last); p > 0 && s.Draft.Quantity > 0 { + est = "≈ " + statisticFormat(p*s.Draft.Quantity, priceSpec.decimals) + } + ui.Text(c, est).FontFeatures("tnum").FontWeight(600) + }) + if res.Submitted() { + r.order, r.submitted = s.Draft, true + slog.Debug("mujica: order_entry submitted", "side", s.Draft.Side, "type", s.Draft.Type) + } + }) + return r +} + +// orderEntryPrice is the expected fill price, or 0 if unknown. +func orderEntryPrice(o OrderDraft, last float64) float64 { + switch o.Type { + case OrderLimit, OrderStopLimit: + return o.Price + case OrderStop: + return o.Trigger + } + return last +} + +// orderEntryFields registers the fields the order type needs. +func orderEntryFields(c *ui.Context, f *FormScope, s *OrderEntryState, opts OrderEntryOptions, initial OrderDraft, tick, lot float64, disabled bool) { + maxQ := opts.MaxQuantity + FormItem(c, f, "quantity", &s.Draft, FormItemOptions[OrderDraft]{Label: msg(c, "order_entry.quantity"), Required: true, Initial: initial, + Validate: func(o OrderDraft) string { return orderEntryCheck(c, o, opts, maxQ) }, + Async: opts.Check, + }, func() *ui.Element { + return NumberInput(c, &s.Draft.Quantity, NumberInputOptions{Step: lot, Disabled: disabled, Error: s.Form.Error("quantity")}).Input + }) + if s.Draft.Type == OrderStop || s.Draft.Type == OrderStopLimit { + FormItem(c, f, "trigger", &s.Draft.Trigger, FormItemOptions[float64]{Label: msg(c, "order_entry.trigger"), Required: true, Initial: initial.Trigger, + Validate: func(v float64) string { return orderEntryTrigger(c, s.Draft, opts.Last) }, + }, func() *ui.Element { + return NumberInput(c, &s.Draft.Trigger, NumberInputOptions{Step: tick, Disabled: disabled, Error: s.Form.Error("trigger")}).Input + }) + } + if s.Draft.Type == OrderLimit || s.Draft.Type == OrderStopLimit { + FormItem(c, f, "price", &s.Draft.Price, FormItemOptions[float64]{Label: msg(c, "order_entry.price"), Required: true, Initial: initial.Price, + Validate: func(v float64) string { + if v <= 0 { + return msg(c, "order_entry.price_positive") + } + return "" + }, + }, func() *ui.Element { + return NumberInput(c, &s.Draft.Price, NumberInputOptions{Step: tick, Disabled: disabled, Error: s.Form.Error("price")}).Input + }) + } + var tifs []SelectOption[TimeInForce] + for t := TIFDay; t <= TIFFillOrKill; t++ { + tifs = append(tifs, SelectOption[TimeInForce]{Value: t, Label: msg(c, fmt.Sprintf("order_entry.tif%d", t))}) + } + FormItem(c, f, "tif", &s.Draft.TIF, FormItemOptions[TimeInForce]{Label: msg(c, "order_entry.tif"), Initial: initial.TIF}, func() *ui.Element { + return Select(c, &s.Draft.TIF, tifs, SelectOptions{Label: msg(c, "order_entry.tif"), Disabled: disabled}).Element + }) +} + +// orderEntryCheck checks the quantity, then the caller's rules. +func orderEntryCheck(c *ui.Context, o OrderDraft, opts OrderEntryOptions, maxQ float64) string { + switch { + case o.Quantity <= 0: + return msg(c, "order_entry.quantity_positive") + case maxQ > 0 && o.Quantity > maxQ: + return fmt.Sprintf(msg(c, "order_entry.quantity_max"), statisticFormat(maxQ, 0)) + } + if opts.Validate != nil { + return opts.Validate(o) + } + return "" +} + +// orderEntryTrigger checks a stop's side of the last price. +func orderEntryTrigger(c *ui.Context, o OrderDraft, last float64) string { + switch { + case o.Trigger <= 0: + return msg(c, "order_entry.trigger_positive") + case last > 0 && o.Side == SideBuy && o.Trigger <= last: + return msg(c, "order_entry.trigger_above") + case last > 0 && o.Side == SideSell && o.Trigger >= last: + return msg(c, "order_entry.trigger_below") + } + return "" +} diff --git a/order_entry_test.go b/order_entry_test.go new file mode 100644 index 0000000..58e9a19 --- /dev/null +++ b/order_entry_test.go @@ -0,0 +1,137 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +type orderEntryProbe struct { + s OrderEntryState + opts OrderEntryOptions + orders []OrderDraft + checks []uint64 + checked []OrderDraft +} + +func (p *orderEntryProbe) tester() *ui.Tester { + return tradingTester(GreenUp, 520, 700, func(c *ui.Context) { + if o, ok := OrderEntry(c, &p.s, p.opts).Submitted(); ok { + p.orders = append(p.orders, o) + } + }) +} + +func TestOrderEntryLimitSubmitOnce(t *testing.T) { + p := &orderEntryProbe{opts: OrderEntryOptions{Symbol: "MUJC", Last: 100}} + tt := p.tester() + _ = tt.Click("Quantity") + tt.Type("10") + _ = tt.Click("Limit price") + tt.Key(ui.Cmd, ui.KeyA) + tt.Type("99.5") + if !tt.HasText("≈ 995.00") { + t.Fatalf("estimate: %q", tt.Texts()) + } + if err := tt.Click("Buy MUJC"); err != nil { + t.Fatal(err) + } + _ = tt.Click("Buy MUJC") + if len(p.orders) != 1 || p.orders[0] != (OrderDraft{Side: SideBuy, Type: OrderLimit, Quantity: 10, Price: 99.5}) { + t.Fatalf("orders %+v", p.orders) + } + p.s.EndSubmit("") + tt.Frame() + _ = tt.Click("Buy MUJC") + if len(p.orders) != 2 { + t.Fatalf("after EndSubmit: %d orders", len(p.orders)) + } +} + +func TestOrderEntryValidatesByType(t *testing.T) { + p := &orderEntryProbe{opts: OrderEntryOptions{Symbol: "MUJC", Last: 100, MaxQuantity: 50}} + tt := p.tester() + _ = tt.Click("Buy MUJC") + if len(p.orders) != 0 || !tt.HasText("Enter a quantity above zero.") || !tt.HasText("Required") { + t.Fatalf("empty order: %q", tt.Texts()) + } + if !tt.Focused("Quantity") { + t.Fatal("first error not focused") + } + tt.Type("80") + tt.Key(0, ui.KeyTab) + if !tt.HasText("At most 50.") { + t.Fatalf("max: %q", tt.Texts()) + } + p.s.Draft.Type, p.s.Draft.Side, p.s.Draft.Quantity, p.s.Draft.Trigger = OrderStop, SideSell, 5, 101 + tt.Frame() + _ = tt.Click("Sell MUJC") + if len(p.orders) != 0 || !tt.HasText("A sell stop triggers below the last price.") || tt.HasText("Limit price") { + t.Fatalf("stop: %q", tt.Texts()) + } + p.s.Draft.Trigger = 98 + tt.Frame() + _ = tt.Click("Sell MUJC") + if len(p.orders) != 1 || p.orders[0].Type != OrderStop || p.orders[0].Trigger != 98 { + t.Fatalf("orders %+v", p.orders) + } +} + +// An old draft's check cannot clear a newer draft. +func TestOrderEntryAsyncCheckIsVersioned(t *testing.T) { + p := &orderEntryProbe{} + p.opts = OrderEntryOptions{Symbol: "MUJC", Last: 100, Check: func(o OrderDraft, v uint64) { + p.checks, p.checked = append(p.checks, v), append(p.checked, o) + }} + p.s.started, p.s.Draft = true, OrderDraft{Side: SideBuy, Type: OrderMarket, Quantity: 10} + tt := p.tester() + _ = tt.Click("Buy MUJC") + if len(p.checks) != 1 || len(p.orders) != 0 { + t.Fatalf("checks %v orders %d", p.checks, len(p.orders)) + } + p.s.Draft.Quantity = 20 + tt.Frame() + if p.s.Resolve(p.checks[0], "") { + t.Fatal("stale check accepted") + } + tt.Frame() + if len(p.checks) != 2 || p.checked[1].Quantity != 20 || len(p.orders) != 0 { + t.Fatalf("checks %v orders %d", p.checks, len(p.orders)) + } + p.s.Resolve(p.checks[1], "Not enough buying power.") + tt.Frame() + tt.Frame() + if len(p.orders) != 0 || !tt.HasText("Not enough buying power.") { + t.Fatalf("failed check submitted: %q", tt.Texts()) + } +} + +func TestOrderEntryDisabledAndReset(t *testing.T) { + p := &orderEntryProbe{opts: OrderEntryOptions{Symbol: "MUJC", Disabled: true, Initial: OrderDraft{Quantity: 1, Price: 50}}} + tt := p.tester() + _ = tt.Click("Quantity") + tt.Type("9") + _ = tt.Click("Buy MUJC") + if p.s.Draft.Quantity != 1 || len(p.orders) != 0 { + t.Fatalf("disabled entry changed: %+v", p.s.Draft) + } + p.opts.Disabled = false + p.s.Draft.Quantity, p.s.Draft.Side = 7, SideSell + tt.Frame() + _ = tt.Click("Reset") + if p.s.Draft != (OrderDraft{Side: SideBuy, Quantity: 1, Price: 50}) { + t.Fatalf("reset: %+v", p.s.Draft) + } +} + +func TestOrderEntrySnapshot(t *testing.T) { + snapshot(t, "order_entry", 420, 520, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { + s := ui.Local(c.Root(), "snap", func() OrderEntryState { return OrderEntryState{} }) + if !s.started { + s.started, s.Draft = true, OrderDraft{Side: SideBuy, Type: OrderStopLimit, Quantity: 25, Price: 101.5, Trigger: 101} + } + OrderEntry(c, s, OrderEntryOptions{Symbol: "MUJC", Last: 100.2}) + }) + }) +} diff --git a/order_table.go b/order_table.go new file mode 100644 index 0000000..7e558ff --- /dev/null +++ b/order_table.go @@ -0,0 +1,194 @@ +package mujica + +import ( + "cmp" + "fmt" + "log/slog" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// OrderStatus is where an order stands. +type OrderStatus int + +const ( + OrderOpen OrderStatus = iota + OrderPartial + OrderFilled + OrderCanceled + OrderRejected +) + +// working reports an order that can still fill. +func (s OrderStatus) working() bool { return s == OrderOpen || s == OrderPartial } + +// OrderRow is one order; ID must be stable across updates. +type OrderRow struct { + ID, Symbol string + Side OrderSide + Type OrderType + Price float64 + Quantity float64 + Filled float64 + Status OrderStatus +} + +// OrderFilter picks which orders an OrderTable shows. +type OrderFilter int + +const ( + OrdersAll OrderFilter = iota + OrdersWorking + OrdersFilled + OrdersClosed +) + +func (f OrderFilter) keeps(s OrderStatus) bool { + switch f { + case OrdersWorking: + return s.working() + case OrdersFilled: + return s == OrderFilled + case OrdersClosed: + return s == OrderCanceled || s == OrderRejected + } + return true +} + +// OrderTableOptions configure an OrderTable. +type OrderTableOptions struct { + // Decimals of prices and quantities; zero means 2 and 0. + Decimals, QuantityDecimals int + // Version must change when rows change in place. + Version int + Status DataStatus + Error string + Disabled bool +} + +// OrderTableState is the status filter and table state. +type OrderTableState struct { + Filter OrderFilter + Table DataTableState[string] + cache tradingRows[OrderRow] +} + +// OrderTable lists orders with filter, progress and Cancel. +func OrderTable(c *ui.Context, s *OrderTableState, rows []OrderRow, opts OrderTableOptions) TableActionResult { + dec := priceDecimals("OrderTable", opts.Decimals) + if opts.QuantityDecimals < 0 { + panic("mujica: OrderTable with negative QuantityDecimals") + } + qd := opts.QuantityDecimals + shown := s.cache.view(rows, opts.Version, s.Filter, func(o OrderRow) bool { + if o.Quantity <= 0 || o.Filled < 0 || o.Filled > o.Quantity { + panic(fmt.Sprintf("mujica: OrderTable order %s fills %v of %v", o.ID, o.Filled, o.Quantity)) + } + return s.Filter.keeps(o.Status) + }) + var r TableActionResult + text := func(id, key string, t func(OrderRow) string) DataColumn[OrderRow] { + return DataColumn[OrderRow]{ID: id, Title: msg(c, key), Sortable: true, Text: t, + Compare: func(a, b OrderRow) int { return cmp.Compare(t(a), t(b)) }} + } + cols := []DataColumn[OrderRow]{ + text("symbol", "position_table.symbol", func(o OrderRow) string { return o.Symbol }), + {ID: "side", Title: msg(c, "order_table.side"), Text: func(o OrderRow) string { return msg(c, fmt.Sprintf("order_entry.side%d", o.Side)) }, + Cell: func(o OrderRow) { tradingSide(c, o.Side) }}, + text("type", "order_entry.type", func(o OrderRow) string { return msg(c, fmt.Sprintf("order_entry.type%d", o.Type)) }), + {ID: "price", Title: msg(c, "order_book.price"), Align: ui.End, Sortable: true, + Compare: func(a, b OrderRow) int { return cmp.Compare(a.Price, b.Price) }, + Text: func(o OrderRow) string { + if o.Type == OrderMarket { + return msg(c, "order_table.market") + } + return statisticFormat(o.Price, dec) + }}, + {ID: "filled", Title: msg(c, "order_table.filled"), Width: 140, + Text: func(o OrderRow) string { + return statisticFormat(o.Filled, qd) + " / " + statisticFormat(o.Quantity, qd) + }, + Cell: func(o OrderRow) { orderTableProgress(c, o, qd) }}, + text("status", "order_table.status", func(o OrderRow) string { return msg(c, fmt.Sprintf("order_table.status%d", o.Status)) }), + {ID: "action", Title: msg(c, "position_table.action"), Width: 96, Text: func(OrderRow) string { return "" }, + Cell: func(o OrderRow) { + if o.Status.working() && Button(c, msg(c, "order_table.cancel"), ButtonOptions{Variant: Secondary}). + Label(msg(c, "order_table.cancel")+" "+o.Symbol).Clicked() { + r.id = o.ID + } + }}, + } + d := Density(c) + r.Element = ui.Column(c).Gap(d.Unit() * 2).Disabled(opts.Disabled).Grow(1).FillWidth().MinHeight(0) + r.Element.Children(func() { + var segs []Segment + for f := OrdersAll; f <= OrdersClosed; f++ { + segs = append(segs, Segment{Label: msg(c, fmt.Sprintf("order_table.filter%d", f))}) + } + at := int(s.Filter) + if SegmentedControl(c, &at, segs, SegmentedControlOptions{Label: msg(c, "order_table.filter"), Disabled: opts.Disabled}).Changed() { + s.Filter = OrderFilter(at) + slog.Debug("mujica: order_table filter", "filter", s.Filter) + } + r.Table = DataTable(c, &s.Table, shown, DataTableOptions[OrderRow, string]{Columns: cols, Key: func(o OrderRow) string { return o.ID }, + Status: opts.Status, Error: opts.Error, Empty: msg(c, "order_table.empty")}) + r.Table.Element.Grow(1) + }) + if r.Element.IsDisabled() { + r.id = "" + } + if r.id != "" { + slog.Debug("mujica: order_table cancel") + } + return r +} + +// orderTableProgress shows the filled share as bar and count. +func orderTableProgress(c *ui.Context, o OrderRow, qd int) { + k := Tokens(c) + share := float32(o.Filled / o.Quantity) + ui.Row(c).Gap(Density(c).Unit() * 2).AlignItems(ui.Center).FillWidth().Children(func() { + ui.Box(c).Size(48, 6).Shrink(0).Role(ui.RoleNone).Draw(func(p *ui.Painter, r ui.Rect) { + p.Fill(r, k.SurfaceHover, theme.ControlRadius) + p.Fill(ui.Rect{X: r.X, Y: r.Y, W: r.W * share, H: r.H}, k.AccentText, theme.ControlRadius) + }) + ui.Text(c, statisticFormat(o.Filled, qd)+" / "+statisticFormat(o.Quantity, qd)).FontFeatures("tnum").FontSize(FontSize(c, theme.CaptionSize)).SingleLine() + }) +} + +// tradingSide names a side with its arrow and trend color. +func tradingSide(c *ui.Context, side OrderSide) { + ui.Row(c).Gap(2).AlignItems(ui.Center).TextColor(trendColor(c, side.sign())).Children(func() { + ui.Icon(c, trendIcon(side.sign())).Size(12, 12) + ui.Text(c, msg(c, fmt.Sprintf("order_entry.side%d", side))).FontWeight(600).SingleLine() + }) +} + +// tradingRows is a filtered view, rebuilt only on change. +type tradingRows[R any] struct { + first *R + n, ver int + filter any + valid bool + visible []R +} + +func (t *tradingRows[R]) view(rows []R, version int, filter any, keep func(R) bool) []R { + var first *R + if len(rows) > 0 { + first = &rows[0] + } + if t.valid && t.first == first && t.n == len(rows) && t.ver == version && t.filter == filter { + return t.visible + } + t.first, t.n, t.ver, t.filter, t.valid = first, len(rows), version, filter, true + t.visible = make([]R, 0, len(rows)) + for _, r := range rows { + if keep(r) { + t.visible = append(t.visible, r) + } + } + return t.visible +} diff --git a/order_table_test.go b/order_table_test.go new file mode 100644 index 0000000..be31cfa --- /dev/null +++ b/order_table_test.go @@ -0,0 +1,118 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +func orderTableSample() []OrderRow { + return []OrderRow{ + {ID: "o1", Symbol: "MUJC", Side: SideBuy, Type: OrderLimit, Price: 99.5, Quantity: 100, Filled: 40, Status: OrderPartial}, + {ID: "o2", Symbol: "AVE", Side: SideSell, Type: OrderMarket, Quantity: 10, Filled: 10, Status: OrderFilled}, + {ID: "o3", Symbol: "OBLV", Side: SideBuy, Type: OrderStop, Price: 12, Quantity: 5, Status: OrderCanceled}, + {ID: "o4", Symbol: "DOLO", Side: SideSell, Type: OrderLimit, Price: 7.25, Quantity: 30, Status: OrderOpen}, + } +} + +func orderTableTester(s *OrderTableState, rows *[]OrderRow, opts *OrderTableOptions, acted *string) *ui.Tester { + return tradingTester(GreenUp, 1000, 400, func(c *ui.Context) { + ui.Box(c).Width(960).Height(320).Children(func() { + if id, ok := OrderTable(c, s, *rows, *opts).Acted(); ok { + *acted = id + } + }) + }) +} + +func TestOrderTableFilterProgressAndCancel(t *testing.T) { + var s OrderTableState + rows, opts, acted := orderTableSample(), OrderTableOptions{}, "" + tt := orderTableTester(&s, &rows, &opts, &acted) + if !tt.HasText("40 / 100") || !tt.HasText("Partly filled") || !tt.HasText("Market") { + t.Fatalf("texts %q", tt.Texts()) + } + if err := tt.Click("Working"); err != nil { + t.Fatal(err) + } + if tt.HasText("AVE") || tt.HasText("OBLV") || !tt.HasText("DOLO") { + t.Fatalf("working filter: %q", tt.Texts()) + } + if _, ok := tt.Find("Cancel AVE"); ok { + t.Fatal("filled order offers cancel") + } + if err := tt.Click("Cancel DOLO"); err != nil { + t.Fatal(err) + } + if acted != "o4" { + t.Fatalf("acted %q", acted) + } + _ = tt.Click("Closed") + if !tt.HasText("OBLV") || tt.HasText("MUJC") { + t.Fatalf("closed filter: %q", tt.Texts()) + } +} + +func TestOrderTableFiltersOnlyOnChange(t *testing.T) { + var s OrderTableState + rows, opts, acted := orderTableSample(), OrderTableOptions{}, "" + tt := orderTableTester(&s, &rows, &opts, &acted) + view := s.cache.visible + tt.Frame() + if &s.cache.visible[0] != &view[0] { + t.Fatal("refiltered without a change") + } + rows[0].Status = OrderFilled + opts.Version++ + _ = tt.Click("Working") + if len(s.cache.visible) != 1 { + t.Fatalf("version change ignored: %d rows", len(s.cache.visible)) + } +} + +func TestOrderTableDisabledAndBadFill(t *testing.T) { + var s OrderTableState + rows, opts, acted := orderTableSample(), OrderTableOptions{Disabled: true}, "" + tt := orderTableTester(&s, &rows, &opts, &acted) + _ = tt.Click("Cancel DOLO") + _ = tt.Click("Working") + if acted != "" || s.Filter != OrdersAll { + t.Fatal("disabled table acted") + } + defer func() { + if recover() == nil { + t.Fatal("overfilled order accepted") + } + }() + var s2 OrderTableState + bad := []OrderRow{{ID: "x", Quantity: 1, Filled: 2}} + orderTableTester(&s2, &bad, &OrderTableOptions{}, &acted) +} + +func TestOrderTableSnapshot(t *testing.T) { + snapshot(t, "order_table", 960, 300, func(c *ui.Context) { + ui.Column(c).Padding(16).Height(280).Width(940).Children(func() { + s := ui.Local(c.Root(), "snap", func() OrderTableState { return OrderTableState{} }) + OrderTable(c, s, orderTableSample(), OrderTableOptions{}) + }) + }) +} + +// 100,000 orders filter once and build only visible rows. +func TestOrderTableLargeData(t *testing.T) { + var s OrderTableState + rows := make([]OrderRow, 100_000) + for i := range rows { + rows[i] = OrderRow{ID: fmt.Sprint(i), Symbol: fmt.Sprintf("S%05d", i), Side: SideBuy, Price: 1, Quantity: 10, Status: OrderStatus(i % 5)} + } + opts, acted := OrderTableOptions{}, "" + tt := orderTableTester(&s, &rows, &opts, &acted) + _ = tt.Click("Working") + if len(s.cache.visible) != 40_000 { + t.Fatalf("working rows %d", len(s.cache.visible)) + } + if n := len(tt.Texts()); n > 400 { + t.Fatalf("built %d texts", n) + } +} diff --git a/pnl_display.go b/pnl_display.go new file mode 100644 index 0000000..605745d --- /dev/null +++ b/pnl_display.go @@ -0,0 +1,82 @@ +package mujica + +import ( + "log/slog" + "math" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// PnL is profit and loss: realized, unrealized and today's. +type PnL struct { + Realized, Unrealized, Today float64 +} + +// PnLDisplayOptions configure a PnLDisplay. +type PnLDisplayOptions struct { + // Decimals of the amounts; zero means 2. + Decimals int + // Currency prefixes each amount, as "$". + Currency string +} + +// PnLDisplay shows three profits signed; *hidden masks them. +func PnLDisplay(c *ui.Context, pnl PnL, hidden *bool, opts PnLDisplayOptions) ChoiceResult { + dec := priceDecimals("PnLDisplay", opts.Decimals) + k := Tokens(c) + u := Density(c).Unit() + var r ChoiceResult + r.Element = ui.Row(c).Gap(u * 6).AlignItems(ui.Start).Wrap().Role(ui.RoleGroup).Label(msg(c, "pnl_display.label")) + r.Element.Children(func() { + for _, item := range []struct { + key string + v float64 + }{{"pnl_display.realized", pnl.Realized}, {"pnl_display.unrealized", pnl.Unrealized}, {"pnl_display.today", pnl.Today}} { + title := msg(c, item.key) + sign := trendSign(item.v) + text := statisticSigned(item.v, dec) + if opts.Currency != "" { + text = pnlDisplaySign(sign) + opts.Currency + statisticFormat(math.Abs(item.v), dec) + } + col := trendColor(c, sign) + spoken := title + ", " + trendWord(c, sign) + " " + text + if *hidden { + text, col, spoken = "••••", k.TextMuted, title+", "+msg(c, "pnl_display.masked") + } + ui.Column(c).Gap(u).Label(spoken).Role(ui.RoleText).Children(func() { + ui.Text(c, title).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted).Role(ui.RoleNone) + ui.Row(c).Gap(u).AlignItems(ui.Center).TextColor(col).Role(ui.RoleNone).Children(func() { + if !*hidden { + ui.Icon(c, trendIcon(sign)).Size(16, 16) + } + ui.Text(c, text).FontSize(FontSize(c, theme.H3Size)).FontFeatures("tnum").FontWeight(600).SingleLine() + }) + }) + } + name := msg(c, "pnl_display.hide") + icon := icons.Must("eye-off") + if *hidden { + name, icon = msg(c, "pnl_display.show"), icons.Must("eye") + } + b := iconAction(c, icon, name) + if b.Clicked() && !b.IsDisabled() { + *hidden = !*hidden + r.changed = true + slog.Debug("mujica: pnl_display mask", "hidden", *hidden) + } + }) + return r +} + +func pnlDisplaySign(sign int) string { + switch { + case sign > 0: + return "+" + case sign < 0: + return "−" + } + return "" +} diff --git a/pnl_display_test.go b/pnl_display_test.go new file mode 100644 index 0000000..b258102 --- /dev/null +++ b/pnl_display_test.go @@ -0,0 +1,43 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestPnLDisplaySignsAndMask(t *testing.T) { + hidden, n := false, 0 + tt := tradingTester(GreenUp, 520, 160, func(c *ui.Context) { + if PnLDisplay(c, PnL{Realized: 1200.5, Unrealized: -340, Today: 0}, &hidden, PnLDisplayOptions{Currency: "$"}).Changed() { + n++ + } + }) + for _, want := range []string{"+$1,200.50", "−$340.00", "$0.00"} { + if !tt.HasText(want) { + t.Fatalf("missing %q in %q", want, tt.Texts()) + } + } + if err := tt.Click("Hide amounts"); err != nil { + t.Fatal(err) + } + if !hidden || n != 1 || tt.HasText("+$1,200.50") { + t.Fatalf("mask: hidden %v changes %d texts %q", hidden, n, tt.Texts()) + } + if _, ok := tt.Find("Realized, hidden"); !ok { + t.Fatal("masked amount still spoken") + } + tt.Key(0, ui.KeySpace) + if hidden || n != 2 { + t.Fatalf("keyboard toggle: hidden %v", hidden) + } +} + +func TestPnLDisplaySnapshot(t *testing.T) { + hidden := false + snapshot(t, "pnl_display", 460, 100, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { + PnLDisplay(c, PnL{Realized: 1200.5, Unrealized: -340.2, Today: 88}, &hidden, PnLDisplayOptions{Currency: "$"}) + }) + }) +} diff --git a/position_table.go b/position_table.go new file mode 100644 index 0000000..d868894 --- /dev/null +++ b/position_table.go @@ -0,0 +1,107 @@ +package mujica + +import ( + "cmp" + "log/slog" + + "github.com/egoist/mygo/ui" +) + +// PositionRow is one holding; ID must be stable across updates. +type PositionRow struct { + ID, Symbol string + Quantity float64 + AvgCost float64 + Price float64 +} + +// MarketValue is the quantity at the last price. +func (p PositionRow) MarketValue() float64 { return p.Quantity * p.Price } + +// Unrealized is the floating profit against the average cost. +func (p PositionRow) Unrealized() float64 { return (p.Price - p.AvgCost) * p.Quantity } + +// UnrealizedPercent is the floating profit as a percent of cost. +func (p PositionRow) UnrealizedPercent() float64 { + if p.AvgCost == 0 { + return 0 + } + return (p.Price - p.AvgCost) / p.AvgCost * 100 +} + +// PositionTableOptions configure a PositionTable. +type PositionTableOptions struct { + // Decimals of prices and amounts; zero means 2. + Decimals int + // Version must change when rows change in place. + Version int + Status DataStatus + Error string + Disabled bool +} + +// TableActionResult is a trading table and its acted row. +type TableActionResult struct { + Element *ui.Element + Table DataTableView + id string +} + +// Acted returns the ID of the row acted on. +func (r TableActionResult) Acted() (string, bool) { return r.id, r.id != "" } + +// PositionTable lists holdings with floating profit and Close. +func PositionTable(c *ui.Context, s *DataTableState[string], rows []PositionRow, opts PositionTableOptions) TableActionResult { + dec := priceDecimals("PositionTable", opts.Decimals) + var r TableActionResult + num := func(id, key string, v func(PositionRow) float64) DataColumn[PositionRow] { + return DataColumn[PositionRow]{ID: id, Title: msg(c, key), Align: ui.End, Sortable: true, + Compare: func(a, b PositionRow) int { return cmp.Compare(v(a), v(b)) }, + Text: func(p PositionRow) string { return statisticFormat(v(p), dec) }} + } + pnl := num("pnl", "position_table.pnl", PositionRow.Unrealized) + pnl.Cell = func(p PositionRow) { tradingSigned(c, p.Unrealized(), statisticSigned(p.Unrealized(), dec)) } + pct := num("pct", "position_table.pnl_percent", PositionRow.UnrealizedPercent) + pct.Cell = func(p PositionRow) { + tradingSigned(c, p.UnrealizedPercent(), statisticSigned(p.UnrealizedPercent(), 2)+"%") + } + cols := []DataColumn[PositionRow]{ + {ID: "symbol", Title: msg(c, "position_table.symbol"), Sortable: true, + Compare: func(a, b PositionRow) int { return cmp.Compare(a.Symbol, b.Symbol) }, + Text: func(p PositionRow) string { return p.Symbol }}, + num("qty", "position_table.quantity", func(p PositionRow) float64 { return p.Quantity }), + num("cost", "position_table.cost", func(p PositionRow) float64 { return p.AvgCost }), + num("price", "position_table.price", func(p PositionRow) float64 { return p.Price }), + num("value", "position_table.value", PositionRow.MarketValue), + pnl, pct, + {ID: "action", Title: msg(c, "position_table.action"), Width: 96, + Text: func(PositionRow) string { return "" }, + Cell: func(p PositionRow) { + if Button(c, msg(c, "position_table.close"), ButtonOptions{Variant: Secondary}).Label(msg(c, "position_table.close") + " " + p.Symbol).Clicked() { + r.id = p.ID + } + }}, + } + r.Element = ui.Column(c).Disabled(opts.Disabled).Grow(1).FillWidth().MinHeight(0) + r.Element.Children(func() { + r.Table = DataTable(c, s, rows, DataTableOptions[PositionRow, string]{Columns: cols, Key: func(p PositionRow) string { return p.ID }, + Version: opts.Version, Status: opts.Status, Error: opts.Error, Empty: msg(c, "position_table.empty")}) + r.Table.Element.Grow(1) + }) + if r.Element.IsDisabled() { + r.id = "" + } + if r.id != "" { + slog.Debug("mujica: position_table close") + } + return r +} + +// tradingSigned shows a signed amount with its arrow. +func tradingSigned(c *ui.Context, v float64, text string) { + sign := trendSign(v) + ui.Row(c).Gap(2).AlignItems(ui.Center).Justify(ui.End).FillWidth().TextColor(trendColor(c, sign)).Children(func() { + ui.Icon(c, trendIcon(sign)).Size(12, 12) + ui.Text(c, text).FontFeatures("tnum").FontWeight(600).SingleLine() + }) +} diff --git a/position_table_test.go b/position_table_test.go new file mode 100644 index 0000000..95e4a40 --- /dev/null +++ b/position_table_test.go @@ -0,0 +1,84 @@ +package mujica + +import ( + "fmt" + "testing" + + "github.com/egoist/mygo/ui" +) + +func positionSample() []PositionRow { + return []PositionRow{ + {ID: "p1", Symbol: "MUJC", Quantity: 100, AvgCost: 400, Price: 412.08}, + {ID: "p2", Symbol: "AVE", Quantity: 50, AvgCost: 90, Price: 88.2}, + } +} + +func TestPositionTableValuesAndClose(t *testing.T) { + var s DataTableState[string] + rows := positionSample() + closed := "" + tt := tradingTester(GreenUp, 1000, 400, func(c *ui.Context) { + ui.Box(c).Width(960).Height(300).Children(func() { + if id, ok := PositionTable(c, &s, rows, PositionTableOptions{}).Acted(); ok { + closed = id + } + }) + }) + for _, want := range []string{"41,208.00", "+1,208.00", "+3.02%", "−90.00", "−2.00%"} { + if !tt.HasText(want) { + t.Fatalf("missing %q in %q", want, tt.Texts()) + } + } + if err := tt.Click("Close AVE"); err != nil { + t.Fatal(err) + } + if closed != "p2" { + t.Fatalf("closed %q", closed) + } +} + +// Selection follows the row ID when rows reorder and change. +func TestPositionTableStableIDs(t *testing.T) { + var s DataTableState[string] + rows := positionSample() + tt := tradingTester(GreenUp, 1000, 400, func(c *ui.Context) { + ui.Box(c).Width(960).Height(300).Children(func() { PositionTable(c, &s, rows, PositionTableOptions{}) }) + }) + _ = tt.Click("AVE") + rows = []PositionRow{{ID: "p3", Symbol: "OBLV", Quantity: 1, AvgCost: 1, Price: 1}, {ID: "p2", Symbol: "AVE", Quantity: 60, AvgCost: 90, Price: 91}, rows[0]} + tt.Frame() + if id, ok := s.Selected(); !ok || id != "p2" { + t.Fatalf("selection %q %v", id, ok) + } +} + +func TestPositionTableDisabledAndLargeData(t *testing.T) { + var s DataTableState[string] + rows := make([]PositionRow, 100_000) + for i := range rows { + rows[i] = PositionRow{ID: fmt.Sprint(i), Symbol: fmt.Sprintf("S%05d", i), Quantity: 1, AvgCost: 1, Price: 2} + } + closed := false + tt := tradingTester(GreenUp, 1000, 400, func(c *ui.Context) { + ui.Box(c).Width(960).Height(300).Children(func() { + _, closed = PositionTable(c, &s, rows, PositionTableOptions{Disabled: true}).Acted() + }) + }) + _ = tt.Click("Close S00000") + if closed { + t.Fatal("disabled table closed a position") + } + if n := len(tt.Texts()); n > 400 { + t.Fatalf("built %d texts for 100,000 rows", n) + } +} + +func TestPositionTableSnapshot(t *testing.T) { + snapshot(t, "position_table", 1040, 220, func(c *ui.Context) { + ui.Column(c).Padding(16).Height(200).Width(1010).Children(func() { + s := ui.Local(c.Root(), "snap", func() DataTableState[string] { return DataTableState[string]{} }) + PositionTable(c, s, positionSample(), PositionTableOptions{}) + }) + }) +} diff --git a/price_change_badge.go b/price_change_badge.go new file mode 100644 index 0000000..5989747 --- /dev/null +++ b/price_change_badge.go @@ -0,0 +1,37 @@ +package mujica + +import ( + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// PriceChangeBadgeOptions configure a PriceChangeBadge. +type PriceChangeBadgeOptions struct { + // Decimals of the amount, zero meaning 2; percents show 2. + Decimals int + // HidePercent shows only the amount. + HidePercent bool +} + +// PriceChangeBadge shows a signed change and percent with an arrow. +func PriceChangeBadge(c *ui.Context, change, percent float64, opts PriceChangeBadgeOptions) *ui.Element { + dec := priceDecimals("PriceChangeBadge", opts.Decimals) + sign := trendSign(change) + if sign == 0 { + sign = trendSign(percent) + } + col := trendColor(c, sign) + u := Density(c).Unit() + text := statisticSigned(change, dec) + if !opts.HidePercent { + text += " (" + statisticSigned(percent, 2) + "%)" + } + e := ui.Row(c).Gap(u).AlignItems(ui.Center).Padding(u/2, u*2).Radius(theme.ControlRadius).Shrink(0). + Background(col.Alpha(0.12)).TextColor(col).Role(ui.RoleText).Label(trendWord(c, sign) + " " + text) + e.Children(func() { + ui.Icon(c, trendIcon(sign)).Size(14, 14) + ui.Text(c, text).FontSize(FontSize(c, theme.CaptionSize)).FontFeatures("tnum").FontWeight(600).SingleLine() + }) + return e +} diff --git a/price_change_badge_test.go b/price_change_badge_test.go new file mode 100644 index 0000000..42a6a1d --- /dev/null +++ b/price_change_badge_test.go @@ -0,0 +1,35 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestPriceChangeBadgeSignsAndWords(t *testing.T) { + tt := tradingTester(GreenUp, 400, 160, func(c *ui.Context) { + PriceChangeBadge(c, 1.25, 0.85, PriceChangeBadgeOptions{}) + PriceChangeBadge(c, -3, -1.5, PriceChangeBadgeOptions{Decimals: 1}) + PriceChangeBadge(c, 0, 0, PriceChangeBadgeOptions{HidePercent: true}) + }) + for _, want := range []string{"+1.25 (+0.85%)", "−3.0 (−1.50%)", "0.00"} { + if !tt.HasText(want) { + t.Fatalf("missing %q in %q", want, tt.Texts()) + } + } + for _, name := range []string{"up +1.25 (+0.85%)", "down −3.0 (−1.50%)", "unchanged 0.00"} { + if _, ok := tt.Find(name); !ok { + t.Fatalf("not spoken: %q", name) + } + } +} + +func TestPriceChangeBadgeSnapshot(t *testing.T) { + snapshot(t, "price_change_badge", 360, 80, func(c *ui.Context) { + ui.Row(c).Padding(20).Gap(10).Children(func() { + PriceChangeBadge(c, 1.25, 0.85, PriceChangeBadgeOptions{}) + PriceChangeBadge(c, -3.4, -1.52, PriceChangeBadgeOptions{}) + PriceChangeBadge(c, 0, 0, PriceChangeBadgeOptions{}) + }) + }) +} diff --git a/price_text.go b/price_text.go new file mode 100644 index 0000000..f415a16 --- /dev/null +++ b/price_text.go @@ -0,0 +1,171 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// Trend picks the rise color: green, or red (China). +type Trend int + +const ( + GreenUp Trend = iota + RedUp +) + +type trendKey struct{} + +// UseTrend sets the window's rise and fall colors. +func UseTrend(c *ui.Context, t Trend) { + if t != GreenUp && t != RedUp { + panic(fmt.Sprintf("mujica: unknown Trend %d", t)) + } + *ui.Local(c.Root(), trendKey{}, func() Trend { return GreenUp }) = t +} + +// trendColor colors a rise (sign > 0), fall or flat. +func trendColor(c *ui.Context, sign int) ui.Color { + k := Tokens(c) + up, down := k.Success, k.Danger + if *ui.Local(c.Root(), trendKey{}, func() Trend { return GreenUp }) == RedUp { + up, down = k.Danger, k.Success + } + switch { + case sign > 0: + return up + case sign < 0: + return down + } + return k.TextMuted +} + +// trendIcon is the arrow that says the direction without color. +func trendIcon(sign int) *ui.SVG { + switch { + case sign > 0: + return icons.Must("arrow-up") + case sign < 0: + return icons.Must("arrow-down") + } + return icons.Must("minus") +} + +// trendWord names the direction for assistive technology. +func trendWord(c *ui.Context, sign int) string { + switch { + case sign > 0: + return msg(c, "price_text.up") + case sign < 0: + return msg(c, "price_text.down") + } + return msg(c, "price_text.flat") +} + +func trendSign(v float64) int { + switch { + case v > 0: + return 1 + case v < 0: + return -1 + } + return 0 +} + +// priceDecimals resolves a Decimals option: zero means 2, negative panics. +func priceDecimals(name string, d int) int { + if d < 0 { + panic("mujica: " + name + " with negative Decimals") + } + if d == 0 { + return 2 + } + return d +} + +// priceTextFlash is the tint's fade, three state steps long. +const priceTextFlash = 3 * theme.StateDuration + +// PriceTextOptions configure a PriceText. +type PriceTextOptions struct { + // Decimals shown; zero means 2. + Decimals int + // NoGrouping drops the thousands separators. + NoGrouping bool + // Compare marks the price's move from Reference. + Compare bool + Reference float64 + // NoFlash keeps the price still when it changes. + NoFlash bool + // Size is the font size; zero is the body size. + Size float32 +} + +type priceTextState struct { + last float64 + seen bool + at time.Time + dir int +} + +// PriceText shows a price; a change tints it once. +func PriceText(c *ui.Context, value float64, opts PriceTextOptions) *ui.Element { + dec := priceDecimals("PriceText", opts.Decimals) + if opts.Size < 0 { + panic("mujica: PriceText with negative Size") + } + size := opts.Size + if size == 0 { + size = theme.BodySize + } + text := statisticFormat(value, dec) + if opts.NoGrouping { + text = priceUngrouped(value, dec) + } + e := ui.Row(c).Gap(Density(c).Unit()).AlignItems(ui.Center).Padding(0, 2).Radius(theme.ControlRadius).Shrink(0) + st := ui.Local(e, "price", func() priceTextState { return priceTextState{} }) + if st.seen && value != st.last { + st.at, st.dir = c.Now(), trendSign(value-st.last) + slog.Debug("mujica: price_text changed", "dir", st.dir) + } + st.last, st.seen = value, true + sign := 0 + if opts.Compare { + sign = trendSign(value - opts.Reference) + } + col := Tokens(c).Text + spoken := text + if opts.Compare { + col = trendColor(c, sign) + spoken += ", " + trendWord(c, sign) + } + if d := Motion(c, priceTextFlash); d > 0 && !opts.NoFlash && !st.at.IsZero() { + if t := c.Now().Sub(st.at); t < d { + e.Background(trendColor(c, st.dir).Alpha(0.2 * float32(1-float64(t)/float64(d)))) + c.AnimationFrame() + } + } + e.Role(ui.RoleText).Label(spoken).TextColor(col) + e.Children(func() { + if opts.Compare { + ui.Icon(c, trendIcon(sign)).Size(size*0.85, size*0.85) + } + ui.Text(c, text).FontSize(FontSize(c, size)).FontFeatures("tnum").FontWeight(500).SingleLine() + }) + return e +} + +// priceUngrouped writes v with dec decimals and no separators. +func priceUngrouped(v float64, dec int) string { + s := fmt.Sprintf("%.*f", dec, math.Abs(v)) + if v < 0 && s != fmt.Sprintf("%.*f", dec, 0.0) { + return "−" + s + } + return s +} diff --git a/price_text_test.go b/price_text_test.go new file mode 100644 index 0000000..bb21a2c --- /dev/null +++ b/price_text_test.go @@ -0,0 +1,106 @@ +package mujica + +import ( + "bytes" + "testing" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// tradingTester runs view in the default theme with trend t. +func tradingTester(t Trend, w, h int, view func(c *ui.Context)) *ui.Tester { + return ui.NewTester(func(c *ui.Context) { + Use(c, Settings{}) + UseTrend(c, t) + ui.Column(c).Padding(10).AlignItems(ui.Start).Children(func() { view(c) }) + }, w, h) +} + +func TestPriceTextFormatAndTrend(t *testing.T) { + price := 12345.678 + tt := tradingTester(GreenUp, 300, 100, func(c *ui.Context) { + PriceText(c, price, PriceTextOptions{Decimals: 2, Compare: true, Reference: 12000}) + }) + if !tt.HasText("12,345.68") { + t.Fatalf("texts %q", tt.Texts()) + } + if _, ok := tt.Find("12,345.68, up"); !ok { + t.Fatal("trend not spoken") + } + price = 11000 + tt.Frame() + if _, ok := tt.Find("11,000.00, down"); !ok { + t.Fatalf("down not spoken: %q", tt.Texts()) + } + tt = tradingTester(GreenUp, 300, 100, func(c *ui.Context) { + PriceText(c, 1234.5, PriceTextOptions{Decimals: 3, NoGrouping: true}) + }) + if !tt.HasText("1234.500") { + t.Fatalf("ungrouped %q", tt.Texts()) + } +} + +func TestTrendColorsFollowUseTrend(t *testing.T) { + var up, down [2]ui.Color + for i, tr := range []Trend{GreenUp, RedUp} { + tradingTester(tr, 100, 100, func(c *ui.Context) { + up[i], down[i] = trendColor(c, 1), trendColor(c, -1) + }) + } + k := theme.Light() + if up[0] != k.Success || down[0] != k.Danger || up[1] != k.Danger || down[1] != k.Success { + t.Fatalf("up %v down %v", up, down) + } + defer func() { + if recover() == nil { + t.Fatal("unknown trend accepted") + } + }() + tradingTester(Trend(7), 100, 100, func(*ui.Context) {}) +} + +// A change tints once; reduced motion never tints. +func TestPriceTextFlashesOnceAndNotUnderReducedMotion(t *testing.T) { + for _, still := range []bool{false, true} { + prefs := ui.Preferences{ReduceMotion: still, TextScale: 1} + price := 10.0 + tt := tradingTester(GreenUp, 200, 60, func(c *ui.Context) { PriceText(c, price, PriceTextOptions{}) }) + tt.SetPreferences(prefs) + price = 10.5 + tt.Frame() + fresh := tradingTester(GreenUp, 200, 60, func(c *ui.Context) { PriceText(c, price, PriceTextOptions{}) }) + fresh.SetPreferences(prefs) + fresh.Frame() + same := bytes.Equal(tt.Image().Pix, fresh.Image().Pix) + if same == !still { + t.Fatalf("reduced motion %v: flashed %v", still, !same) + } + time.Sleep(priceTextFlash + 20*time.Millisecond) + tt.Frame() + if !bytes.Equal(tt.Image().Pix, fresh.Image().Pix) { + t.Fatalf("reduced motion %v: flash did not end", still) + } + } +} + +func TestPriceTextRejectsNegativeDecimals(t *testing.T) { + defer func() { + if recover() == nil { + t.Fatal("negative decimals accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { PriceText(c, 1, PriceTextOptions{Decimals: -1}) }) +} + +func TestPriceTextSnapshot(t *testing.T) { + snapshot(t, "price_text", 320, 150, func(c *ui.Context) { + ui.Column(c).Padding(20).Gap(12).AlignItems(ui.Start).Children(func() { + PriceText(c, 18234.5, PriceTextOptions{Size: theme.H2Size, Compare: true, Reference: 18000}) + PriceText(c, 0.004521, PriceTextOptions{Decimals: 6, Compare: true, Reference: 0.0046}) + PriceText(c, 100, PriceTextOptions{Compare: true, Reference: 100}) + }) + }) +} diff --git a/quick_trade_buttons.go b/quick_trade_buttons.go new file mode 100644 index 0000000..d0926c1 --- /dev/null +++ b/quick_trade_buttons.go @@ -0,0 +1,127 @@ +package mujica + +import ( + "fmt" + "log/slog" + "slices" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// QuickTradeButtonsOptions configure QuickTradeButtons. Symbol is required. +type QuickTradeButtonsOptions struct { + Symbol string + // Presets are the quantities offered; nil means 1, 10, 100. + Presets []float64 + // Decimals of the quantities shown. + Decimals int + // Confirm asks before sending, by the button pressed. + Confirm bool + Disabled bool +} + +// QuickTradeResult is built QuickTradeButtons and their trade. +type QuickTradeResult struct { + Element *ui.Element + side OrderSide + quantity float64 +} + +// Traded returns the side and quantity the user traded. +func (r QuickTradeResult) Traded() (OrderSide, float64, bool) { return r.side, r.quantity, r.side != 0 } + +type quickTradeState struct{ asking OrderSide } + +// QuickTradeButtons trade *quantity at market with one press. +func QuickTradeButtons(c *ui.Context, quantity *float64, opts QuickTradeButtonsOptions) QuickTradeResult { + if opts.Symbol == "" { + panic("mujica: QuickTradeButtons needs a Symbol") + } + if opts.Decimals < 0 { + panic("mujica: QuickTradeButtons with negative Decimals") + } + presets := opts.Presets + if presets == nil { + presets = []float64{1, 10, 100} + } + if *quantity == 0 { + *quantity = presets[0] + } + at := slices.Index(presets, *quantity) + if at < 0 { + panic(fmt.Sprintf("mujica: QuickTradeButtons quantity %v is not one of Presets", *quantity)) + } + u := Density(c).Unit() + var r QuickTradeResult + r.Element = ui.Column(c).Gap(u * 2).Disabled(opts.Disabled).Role(ui.RoleGroup).Label(msg(c, "quick_trade_buttons.label")) + st := ui.Local(r.Element, "quick", func() quickTradeState { return quickTradeState{} }) + disabled := r.Element.IsDisabled() + if disabled { + st.asking = 0 + } + qty := statisticFormat(*quantity, opts.Decimals) + r.Element.Children(func() { + var segs []Segment + for _, p := range presets { + segs = append(segs, Segment{Label: statisticFormat(p, opts.Decimals)}) + } + if SegmentedControl(c, &at, segs, SegmentedControlOptions{Equal: true, Label: msg(c, "quick_trade_buttons.quantity"), Disabled: disabled}).Changed() { + *quantity = presets[at] + qty = statisticFormat(*quantity, opts.Decimals) + } + ui.Row(c).Gap(u * 2).Children(func() { + for _, side := range []OrderSide{SideBuy, SideSell} { + label := fmt.Sprintf(msg(c, fmt.Sprintf("quick_trade_buttons.side%d", side)), qty) + b := quickTradeButton(c, label, side) + if b.Clicked() && !disabled { + if opts.Confirm { + st.asking = side + } else { + r.side, r.quantity = side, *quantity + } + } + open := st.asking == side + res := Popconfirm(c, b, &open, PopconfirmOptions{ + Title: fmt.Sprintf(msg(c, fmt.Sprintf("quick_trade_buttons.confirm%d", side)), qty, opts.Symbol), + Description: msg(c, "quick_trade_buttons.market"), + ConfirmLabel: msg(c, fmt.Sprintf("order_entry.side%d", side)), + Danger: true, + }) + if res.Confirmed && !disabled { + r.side, r.quantity = side, *quantity + } + if !open && st.asking == side { + st.asking = 0 + } + } + }) + }) + if r.side != 0 { + slog.Debug("mujica: quick_trade_buttons traded", "side", r.side) + } + return r +} + +// quickTradeButton is a large button tinted by its side. +func quickTradeButton(c *ui.Context, label string, side OrderSide) *ui.Element { + k := Tokens(c) + d := Density(c) + col := trendColor(c, side.sign()) + b := ui.ButtonBase(c).Grow(1).Basis(0).MinHeight(d.ControlHeight()+d.Unit()*2).Radius(theme.ControlRadius). + Border(theme.BorderWidth*1.5, col).TextColor(col).Background(col.Alpha(0.1)).Label(label) + internal.Ring(b, k.Focus, theme.ControlRadius) + switch { + case b.Pressed(): + b.Background(col.Alpha(0.28)) + case b.Hovered(): + b.Background(col.Alpha(0.18)) + } + b.Children(func() { + ui.Icon(c, trendIcon(side.sign())).Size(16, 16) + ui.Text(c, label).FontWeight(700).SingleLine() + }) + return b +} diff --git a/quick_trade_buttons_test.go b/quick_trade_buttons_test.go new file mode 100644 index 0000000..c764999 --- /dev/null +++ b/quick_trade_buttons_test.go @@ -0,0 +1,86 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +type quickTradeProbe struct { + qty float64 + opts QuickTradeButtonsOptions + trades []OrderSide + sizes []float64 +} + +func (p *quickTradeProbe) tester() *ui.Tester { + return tradingTester(GreenUp, 520, 400, func(c *ui.Context) { + ui.Box(c).Width(400).Children(func() { + if side, q, ok := QuickTradeButtons(c, &p.qty, p.opts).Traded(); ok { + p.trades, p.sizes = append(p.trades, side), append(p.sizes, q) + } + }) + }) +} + +func TestQuickTradeButtonsPresetsAndTrade(t *testing.T) { + p := &quickTradeProbe{opts: QuickTradeButtonsOptions{Symbol: "MUJC"}} + tt := p.tester() + if p.qty != 1 { + t.Fatalf("default preset %v", p.qty) + } + if err := tt.Click("10"); err != nil { + t.Fatal(err) + } + if err := tt.Click("Sell 10"); err != nil { + t.Fatal(err) + } + if len(p.trades) != 1 || p.trades[0] != SideSell || p.sizes[0] != 10 { + t.Fatalf("trades %v %v", p.trades, p.sizes) + } +} + +func TestQuickTradeButtonsConfirmFocusesCancel(t *testing.T) { + p := &quickTradeProbe{qty: 100, opts: QuickTradeButtonsOptions{Symbol: "MUJC", Confirm: true}} + tt := p.tester() + _ = tt.Click("Buy 100") + if len(p.trades) != 0 || !tt.HasText("Buy 100 MUJC?") || !tt.Focused("Cancel") { + t.Fatalf("confirm: %q", tt.Texts()) + } + tt.Key(0, ui.KeyEnter) + if len(p.trades) != 0 || tt.HasText("Buy 100 MUJC?") { + t.Fatal("Enter traded instead of canceling") + } + _ = tt.Click("Buy 100") + if err := tt.Click("Buy"); err != nil { + t.Fatal(err) + } + if len(p.trades) != 1 || p.trades[0] != SideBuy || p.sizes[0] != 100 { + t.Fatalf("trades %v", p.trades) + } +} + +func TestQuickTradeButtonsDisabledAndBadQuantity(t *testing.T) { + p := &quickTradeProbe{opts: QuickTradeButtonsOptions{Symbol: "MUJC", Disabled: true}} + tt := p.tester() + _ = tt.Click("Buy 1") + _ = tt.Click("10") + if len(p.trades) != 0 || p.qty != 1 { + t.Fatal("disabled buttons acted") + } + defer func() { + if recover() == nil { + t.Fatal("quantity outside presets accepted") + } + }() + (&quickTradeProbe{qty: 7, opts: QuickTradeButtonsOptions{Symbol: "MUJC"}}).tester() +} + +func TestQuickTradeButtonsSnapshot(t *testing.T) { + qty := 10.0 + snapshot(t, "quick_trade_buttons", 380, 130, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { + QuickTradeButtons(c, &qty, QuickTradeButtonsOptions{Symbol: "MUJC"}) + }) + }) +} diff --git a/quote_card.go b/quote_card.go new file mode 100644 index 0000000..a35e886 --- /dev/null +++ b/quote_card.go @@ -0,0 +1,52 @@ +package mujica + +import ( + "github.com/egoist/mygo/ui" + + "mujicaui/theme" +) + +// Quote is an instrument's price and change since the close. +type Quote struct { + Symbol, Name string + Price float64 + Change float64 + ChangePercent float64 +} + +// QuoteCardOptions configure a QuoteCard. +type QuoteCardOptions struct { + // Decimals of the price and change; zero means 2. + Decimals int + // Chart builds the mini chart slot; nil leaves it out. + Chart func() +} + +// QuoteCard shows a symbol, name, price, change and mini chart. +func QuoteCard(c *ui.Context, q Quote, opts QuoteCardOptions) *ui.Element { + if q.Symbol == "" { + panic("mujica: QuoteCard needs a Symbol") + } + dec := priceDecimals("QuoteCard", opts.Decimals) + k := Tokens(c) + u := Density(c).Unit() + e := ui.Column(c).Gap(u*2).Padding(u*4).MinWidth(200).Radius(theme.CardRadius). + Background(k.Surface).Border(theme.BorderWidth, k.Border).Role(ui.RoleGroup).Label(q.Symbol) + e.Children(func() { + ui.Row(c).Gap(u * 2).AlignItems(ui.End).Children(func() { + ui.Text(c, q.Symbol).Font(theme.SerifFont).FontSize(FontSize(c, theme.H3Size)).FontWeight(600).SingleLine() + if q.Name != "" { + ui.Text(c, q.Name).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).SingleLine(). + Ellipsis("…").MinWidth(0).Shrink(1) + } + }) + ui.Row(c).Gap(u * 3).AlignItems(ui.Center).Wrap().Children(func() { + PriceText(c, q.Price, PriceTextOptions{Decimals: dec, Size: theme.H2Size}) + PriceChangeBadge(c, q.Change, q.ChangePercent, PriceChangeBadgeOptions{Decimals: dec}) + }) + if opts.Chart != nil { + ui.Box(c).Height(40).FillWidth().Children(opts.Chart) + } + }) + return e +} diff --git a/quote_card_test.go b/quote_card_test.go new file mode 100644 index 0000000..6d53d20 --- /dev/null +++ b/quote_card_test.go @@ -0,0 +1,43 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestQuoteCardShowsQuoteAndChartSlot(t *testing.T) { + charted := false + tt := tradingTester(RedUp, 400, 240, func(c *ui.Context) { + QuoteCard(c, Quote{Symbol: "600519", Name: "Kweichow Moutai", Price: 1688.5, Change: 12.3, ChangePercent: 0.73}, + QuoteCardOptions{Chart: func() { charted = true; ui.Text(c, "chart") }}) + }) + for _, want := range []string{"600519", "Kweichow Moutai", "1,688.50", "+12.30 (+0.73%)", "chart"} { + if !tt.HasText(want) { + t.Fatalf("missing %q in %q", want, tt.Texts()) + } + } + if !charted { + t.Fatal("chart slot not built") + } + defer func() { + if recover() == nil { + t.Fatal("empty symbol accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { QuoteCard(c, Quote{}, QuoteCardOptions{}) }) +} + +func TestQuoteCardSnapshot(t *testing.T) { + snapshot(t, "quote_card", 300, 190, func(c *ui.Context) { + ui.Column(c).Padding(20).AlignItems(ui.Start).Children(func() { + QuoteCard(c, Quote{Symbol: "MUJC", Name: "Ave Mujica Holdings", Price: 412.08, Change: -5.62, ChangePercent: -1.35}, + QuoteCardOptions{Chart: func() { + k := Tokens(c) + ui.Box(c).Fill().Draw(func(p *ui.Painter, r ui.Rect) { + p.Line(r.X, r.Y+r.H*0.3, r.X+r.W, r.Y+r.H*0.7, 1.5, k.Info) + }) + }}) + }) + }) +} diff --git a/risk_meter.go b/risk_meter.go new file mode 100644 index 0000000..d0a5685 --- /dev/null +++ b/risk_meter.go @@ -0,0 +1,84 @@ +package mujica + +import ( + "fmt" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// RiskLevel is one step of a RiskMeter's scale. +type RiskLevel struct { + Label string + Description string +} + +// RiskMeterOptions configure a RiskMeter. +type RiskMeterOptions struct { + // Levels rise in risk; nil uses five built-in levels. + Levels []RiskLevel + // Label names the meter; empty uses the built-in "Risk level". + Label string +} + +// RiskMeter shows level, from 1, on a named graded scale. +func RiskMeter(c *ui.Context, level int, opts RiskMeterOptions) *ui.Element { + levels := opts.Levels + if levels == nil { + for i := range 5 { + levels = append(levels, RiskLevel{Label: msg(c, fmt.Sprintf("risk_meter.level%d", i+1))}) + } + } + if len(levels) < 2 || level < 1 || level > len(levels) { + panic(fmt.Sprintf("mujica: RiskMeter level %d outside 1..%d", level, len(levels))) + } + k := Tokens(c) + u := Density(c).Unit() + label := opts.Label + if label == "" { + label = msg(c, "risk_meter.label") + } + cur := levels[level-1] + spoken := fmt.Sprintf(msg(c, "risk_meter.value"), level, len(levels), cur.Label) + col := riskMeterColor(k, level, len(levels)) + e := ui.Column(c).Gap(u * 2).MinWidth(200).Role(ui.RoleMeter).Label(label).Description(spoken + " " + cur.Description) + e.Children(func() { + ui.Row(c).Gap(u * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, cur.Label).TextColor(col).FontWeight(600).SingleLine() + ui.Text(c, fmt.Sprintf("%d / %d", level, len(levels))).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).FontFeatures("tnum") + }) + ui.Box(c).Height(18).FillWidth().Draw(func(p *ui.Painter, r ui.Rect) { + n := len(levels) + const gap = 3 + w := (r.W - gap*float32(n-1)) / float32(n) + for i := range n { + seg := ui.Rect{X: r.X + float32(i)*(w+gap), Y: r.Y + 8, W: w, H: 8} + if i < level { + p.Fill(seg, riskMeterColor(k, i+1, n), theme.ControlRadius) + } else { + p.Stroke(seg, k.ControlBorder, theme.ControlRadius, theme.BorderWidth) + } + if i == level-1 { + p.FillPath(internal.Diamond(seg.X+seg.W/2, r.Y+3, 7), k.Text) + } + } + }) + if cur.Description != "" { + ui.Text(c, cur.Description).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)) + } + }) + return e +} + +// riskMeterColor grades from success through warning to danger. +func riskMeterColor(k theme.Tokens, level, n int) ui.Color { + switch f := float64(level-1) / float64(n-1); { + case f < 0.34: + return k.Success + case f < 0.67: + return k.Warning + } + return k.Danger +} diff --git a/risk_meter_test.go b/risk_meter_test.go new file mode 100644 index 0000000..83058ed --- /dev/null +++ b/risk_meter_test.go @@ -0,0 +1,42 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestRiskMeterLevelsAndText(t *testing.T) { + level := 4 + levels := []RiskLevel{{Label: "Conservative", Description: "Capital first."}, {Label: "Balanced"}, {Label: "Aggressive", Description: "Losses can exceed half."}} + custom := false + tt := tradingTester(GreenUp, 400, 160, func(c *ui.Context) { + if custom { + RiskMeter(c, level, RiskMeterOptions{Levels: levels}) + } else { + RiskMeter(c, level, RiskMeterOptions{}) + } + }) + if !tt.HasText("Moderately high") || !tt.HasText("4 / 5") { + t.Fatalf("default: %q", tt.Texts()) + } + custom, level = true, 3 + tt.Frame() + if !tt.HasText("Aggressive") || !tt.HasText("Losses can exceed half.") || !tt.HasText("3 / 3") { + t.Fatalf("custom: %q", tt.Texts()) + } + defer func() { + if recover() == nil { + t.Fatal("level 0 accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { RiskMeter(c, 0, RiskMeterOptions{}) }) +} + +func TestRiskMeterSnapshot(t *testing.T) { + snapshot(t, "risk_meter", 320, 110, func(c *ui.Context) { + ui.Column(c).Padding(20).Children(func() { + RiskMeter(c, 4, RiskMeterOptions{Levels: []RiskLevel{{Label: "Low"}, {Label: "Medium"}, {Label: "Elevated"}, {Label: "High", Description: "Suited to experienced traders."}, {Label: "Extreme"}}}) + }) + }) +} diff --git a/spread_indicator.go b/spread_indicator.go new file mode 100644 index 0000000..be7c7fa --- /dev/null +++ b/spread_indicator.go @@ -0,0 +1,53 @@ +package mujica + +import ( + "fmt" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// SpreadIndicatorOptions configure a SpreadIndicator. +type SpreadIndicatorOptions struct { + // Decimals of the spread; zero means 2. + Decimals int + // WarnPercent flags spreads this wide, in percent; zero never. + WarnPercent float64 +} + +// SpreadIndicator shows ask minus bid and its percent. +func SpreadIndicator(c *ui.Context, bid, ask float64, opts SpreadIndicatorOptions) *ui.Element { + if opts.WarnPercent < 0 { + panic("mujica: SpreadIndicator with negative WarnPercent") + } + dec := priceDecimals("SpreadIndicator", opts.Decimals) + k := Tokens(c) + u := Density(c).Unit() + spread := ask - bid + pct := 0.0 + if mid := (ask + bid) / 2; mid > 0 { + pct = spread / mid * 100 + } + text := fmt.Sprintf(msg(c, "spread_indicator.value"), statisticFormat(spread, dec), statisticFormat(pct, 3)) + note, col, icon := "", k.TextMuted, "" + switch { + case spread < 0: + note, col, icon = msg(c, "spread_indicator.crossed"), k.Danger, "circle-alert" + case opts.WarnPercent > 0 && pct >= opts.WarnPercent: + note, col, icon = msg(c, "spread_indicator.wide"), k.Warning, "triangle-alert" + } + e := ui.Row(c).Gap(u * 1.5).AlignItems(ui.Center).Shrink(0).Role(ui.RoleStatus).Label(text + " " + note) + e.Children(func() { + ui.Text(c, msg(c, "spread_indicator.title")).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)) + ui.Text(c, text).FontFeatures("tnum").FontWeight(500).SingleLine() + if note != "" { + ui.Row(c).Gap(u / 2).AlignItems(ui.Center).TextColor(col).Children(func() { + ui.Icon(c, icons.Must(icon)).Size(14, 14) + ui.Text(c, note).FontSize(FontSize(c, theme.CaptionSize)).FontWeight(600).SingleLine() + }) + } + }) + return e +} diff --git a/spread_indicator_test.go b/spread_indicator_test.go new file mode 100644 index 0000000..c9835e4 --- /dev/null +++ b/spread_indicator_test.go @@ -0,0 +1,42 @@ +package mujica + +import ( + "testing" + + "github.com/egoist/mygo/ui" +) + +func TestSpreadIndicatorValueAndThreshold(t *testing.T) { + bid, ask := 99.95, 100.05 + tt := tradingTester(GreenUp, 400, 100, func(c *ui.Context) { + SpreadIndicator(c, bid, ask, SpreadIndicatorOptions{WarnPercent: 0.5}) + }) + if !tt.HasText("0.10 (0.100%)") || tt.HasText("Wide spread") { + t.Fatalf("narrow: %q", tt.Texts()) + } + ask = 101 + tt.Frame() + if !tt.HasText("Wide spread") { + t.Fatalf("wide: %q", tt.Texts()) + } + ask = 99 + tt.Frame() + if !tt.HasText("Crossed market") { + t.Fatalf("crossed: %q", tt.Texts()) + } + defer func() { + if recover() == nil { + t.Fatal("negative threshold accepted") + } + }() + tradingTester(GreenUp, 100, 100, func(c *ui.Context) { SpreadIndicator(c, 1, 2, SpreadIndicatorOptions{WarnPercent: -1}) }) +} + +func TestSpreadIndicatorSnapshot(t *testing.T) { + snapshot(t, "spread_indicator", 380, 100, func(c *ui.Context) { + ui.Column(c).Padding(20).Gap(10).Children(func() { + SpreadIndicator(c, 99.95, 100.05, SpreadIndicatorOptions{WarnPercent: 0.5}) + SpreadIndicator(c, 99, 101, SpreadIndicatorOptions{WarnPercent: 0.5}) + }) + }) +} diff --git a/testdata/snapshots/darwin/bid_ask_bar-dark.png b/testdata/snapshots/darwin/bid_ask_bar-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..16712d6a5f1b634a9b33ef673904c99d118f2e4f GIT binary patch literal 5801 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/bid_ask_bar-light.png b/testdata/snapshots/darwin/bid_ask_bar-light.png new file mode 100644 index 0000000000000000000000000000000000000000..a2c9c789743b54bfc8ecc56440558a1c6dd63f30 GIT binary patch literal 5715 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 CLVAS& literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/depth_ladder-dark.png b/testdata/snapshots/darwin/depth_ladder-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c3a5b919fcb8146b27b60a626c3f2e070bfc5f GIT binary patch literal 11744 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 E20=PHy8r+H literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/level2_quotes-dark.png b/testdata/snapshots/darwin/level2_quotes-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..021ce64404b50535adcaccfb8ac758d73a56c150 GIT binary patch literal 15272 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 P1(KCg`cw`y4*Wj=e6h7; literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/leverage_slider-dark.png b/testdata/snapshots/darwin/leverage_slider-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..4657808f0f48052a0d30017577f84e55c4546bb4 GIT binary patch literal 8567 zcmd6NRa6{7w=RJYBm@oa?havaf=iIWg9HoiI!Is$?(P~qxVw9R;I0F~C%6nU$mP#H zFXukqwa&Wtq4(-<_3o-IRlB~b?r=2~xp(L!=m-c1?-b;v)e#V0S-srE@;0PBI)R`!%Px=!?CfKzw{tSvNn>h#56W8=s}s-TuP+RI=@=#Pae>+g4WGq2Ubg!bMUs_FL$# z&cfeoZ-wiTUSA(3Up~+7cQKgMklx2dv>wW>@{Zx=Hp48=UNDurQYJc|Q8w`~B&|!iRUt%J%~IHrF`=QlEXmlw-hHFfbx>TGc6W!v{oDvf ze{2LguX5hbjwdXbi4%PJU5ft5B(&M>sRPARQ_XC z-*2u*?*-z5#qUB_KfvMej>bDJLPExqSvHG7Zo$WAD3sJy!0u&;g({6*=y1kHYacD^ zFRd;T;^Ck7AJ)S>JbKL@x>-d4qx1AaJP(nMU64md5Bi1a<@9WRsXrW0wbHPI->sK- znayd6>WAle^usYaUphWXXFNSslxi4cWev%&R#YOFUo@rZP`=$0i^DFVqiF_K39zra zbq2#@P)%D8kB{MZ)IXDxwHzki9tr37J<9#2EinHgtqGa3<0DyqD?Prb?=F-rL3MUx zwgvDi%XfO-x@stli{oB}K$0?>t$m+tbaX6fy!Sh^S+odsHh4CTiH64d3(DJlMgqM0 zLpuvP3%xtLjs`|<)2u>F^82KSLzu<1Ic{JK`8At8(_hqSTxyyvbqv0!^O6yA=s0T~ zx?Il}I@fNSnaK(XMFcrW)723C>L|1)&$i$X`}r_O%uCj-Mc{-Gvx*p#D-g0(J*H1w zu9?OLfFD{K;l=B+eI*JBTWLW?#UYL!f?+00vt3*nHwy}7JB-ZiR_|A5@KMtfoa!4K8zg(>HGO0V1xKh*_?|TL>7;~k0FlE09{64wg4tO>lHaTf(XiE3y z0|0J!G+3Lu(o@s0hhgDO9i5M0oo&wVQswg>nj2tOu&(Y)yjg_1QS-g}^s9rzQ)x|@q5pCW(H8x6%fiwxeA0->L=FGy$u1-rO22zSoONC^ z8)+*p_}@k7cJlP$NO-V}+>xDq$tQVU7L)h6x+hXWJ@FrWthl7sGSW6uD63V~ zz|ne_Om+43S}geq+uL8&t+(=MjgIanz6H&eLNn4b z47|=~o@iji_yyCR(BFcTcL#;HEuOo&6uCDiF@~vSWyE4&y`h2nWWq9A8)Y8?nAhr3 zZNzykw@dosVT597=nni5#mCz_Hdn;Gvq-CaJ|$O3L)%ZiG>naf-S+gLx1F7BmgE>% znVD72LtTtk=ax%J@HTI@P%@8>kE3L_p;?PYdfA*fkpY2-S=qA1CG^Kn7y6ajp#IPe zZ_gJ#;q%NGI=n3iSSp9lc?WI{*>*=X`YY$^jlWw{@2%PV5p|X1i-MI~^|OHhm0&!V z6rZ5&;Beo^8}87_7NDz_m7N`v{LQC-(@Byh0R;smoJrhqcdnhmrC(~~bGr#V29X9A zUG8}8skk|He^jg5SN&}MjAd_Qc{WlhRvdQAE0itMcP=onF~MPZR|n+as5~a0P@%0v z4(OATYdU6WF(C<9`{L~82GG99zUz%9&7VD_87hWeA3dv}pun&1$`f%zF~zREA17i# z`xWaw%QV*me!S)EVzom0XlL|7tN;oH?^ZHE?z zWhWLWA3e}$sp_Hz=z-h}Bn;@XeJmt6gS{9T=B8w^8OH*2LpbDv{CLyx1%D1&29TRK z(Zkprm?HgwKk}B_^4bq~K^etq2mXn~0@4ncz5c#keS7;#c*z*WAE}4it>;|B=4t^!c**1+ zmhL$}okQ@b8UFVUlfN024T7+)DN3ZH3#&Xtx;j9Djio#P+xT};R?9({QgoM0k#_a3 zrz+qytbHVpEZ|3ZXr0*lt$;Uvv6+bwL9yBMtQ%XHeQ&$j)_Sef%Qe}hc__TzqVA`k zca;B^YUmX=W|;Fsn;Drb=v(MxndRW{W#V6V*(o1w)I|&O;?bQv|w+ z3bu&CU#L9nR*vngS$8hKlSFB}glnMp{Nm`7w>x%HayoYy5*2D+fB)lE1? z3`t&pPRn%m+vNp|@`8y%K8Fvwg&Ud>S(uqy_wCN$cj5x)HYwhU#WG^+cA$#ZnV=7K zVfNRYEtdSwdb*!ZY!#G?nVpwSDAH}a zHR{=qjIX9cEZjYauixz7BtXcIPnA-q?%9PS6h{wmBlG1ys!LW>$KK?2-Il?&V($ev z<9?)l=4DE-vq^D)blxmvyLjvG;lJO^O~N*_uqm6iQOyy|^*yUmDXGVegy`Q^Mb;-u zmWueEg!+cYOl9)2VTLZn*QRh#N6YeZx~Fe7$0cFok&ww_OW!??x@R_XpI~r$c`+~! zF>95@YWqG#Q7rQ!^KSMyf4iH}+&76qFG?VaVk95vB+r{YoJpzX5fFe|DU4n%GMtVJ zN(mXabB1RK3E7tB*&|d>$o*_mbJUpNvwes0(&4Tdl z;h0Bzr=f-HnUsZwq{5|UONZ5K(7hDKL3B;{bUZKJ_)J$x1jZb#PqFcyI`XhH;;{JL z(PVUjMSl@`>X@>Uf=k0`r^3#0^9C6uiKOF1hu+Exj8bfcE_q>2l&!kLrKVm6HMm=h z{wVqUr`$%)N#q{=f5Od?n&~6PX=|jCsOi1G@yJlBDGx-Y*0C&^D{Li;c{<2Q&*0F{ zva>f=0Ed~x(|y*`(7!pD4r~jZZ*(_A55{3LcC__r{Bcko1s1Ixfh@{ZE*y;uu2IDw zjfzR2z5YVsz$O@|CXY{$N+Ia1$8ai=3Q{PUec@=jX_?PMtG3U11z41#Vws@Blg@{uS*V81z7lA#A91_4w7vUlT= zKEp$!7c-5BL2;6$SLZNAl_-HNm**O*uE5T0#iD%iff}ao#`j4I!aNHO_xEE5zle!K zhPJIM7-A1S??bRHk6Q3R36mwUUrbSsWhRm+ey*srb2jXU{2& ze&q5i&)rBpA+}^I;RTa=jg>=3M}2umor~PU7jG%;oxj`UU1`GKM7LWMJy^55*m!_7O>p}_N3jSB zU#m}{i7za@yJ(bb%V0MlYBE+?1 zfg6F1p=SRl&%M{6I95~e(!h4twy)JHq$p# z%hc*+>wYirQhOmCuAu&fY@!e^AMXPJo3+88&Ni!;$?AC&EcpzSomWvq!{R-wPfV99AxVcI63pTA0?kIlCy?+5)YYeMV08KG*So zw6ZiKr{o{wqSe*7IrDZt{FUkrZgy186dDEXg!Aqft9YBQ5jEwDNJd~>-R!z}m(by( z(>Gh*k6RHOX!x2H1a`9LPV&B145nM2VltT|zWugQ2jNT_5ni-(5HJWM&hI;^;t2U! z6Pl?cRS;BUw)NrLEh-kMzxF`8eBLIy_vku0As163Ppzr3xgLt~2m{116P=?s`ThPT zcKSFMJZRqBbi8t@HDuwa8XIJ~G3R3fj{CXL5>5!9^`e#ZX zSIlwMFlT3vmuXqJb1{L&85^F?pGbrJMC&Uli?Y_LWAf?kRcXsnib_djc$T%TJvk*l zv%NKYx6w!fFE$`2gKu(Zg=ha4w~sz4D0Pd5dVYCX%jMEzAkz`UwFb+_y(6@Itmr{9 zB?kH9CXg3Q__9QyzXtO5dx<2r->~9Hre404l8r@2KLfcs=X@}~*nL23%FcuQ*R*u< zI4X-xS?|#I+dKn4(rO{ft~0S}lwUuiyf_c~wHuwl;4Kw$JrBhX=}~oDswnkZj+p0| zP*E(paF!~djypL#8J%e$lVoyAGBUlgqn5F0T+s)O37oFYQzu?}b)?FAZZLIPFEP+@ zZQe)Yrc@Ei!tY)d&Ghv27tM$KKffL8`ADLj*{BH67Qw9+gZtpB(pktb4hb2NfN;Qj z)Qlo_{q9xQ_6G{3iOrpZv%%aa`P8eiT8-9alxJ&ZTz12X?ozoT^=yEvA2?Q^&Y8`L zEH;yz+p7;iHjIyMzR;CL$ze1vK-FNZVrS)q{c&>_Ukmc!u9Pa-dyBAvnhCJ(Yr)d? z6H<%4hiBgNzLf4)*4Lkk=k?Pv%iG#>#SNajOZO=h%bQ|6f+g>y1E+(xTatC@tW%(F zZGIWibzw4+=^eAE!;<3GlE9avgB3<*V+)H>YQRtjj`I(SWiDj@Km{j%iEiAjBR|m> z7W?0r)c*)X3JmN&S?os~!`36aBbfM>Acqa;a|;wnc?J?m>J@5O&ACU!P~z7yu53mj zO#n8d0;72`EyYF{0ZW`IB=;yuG(ptAlQxAeM;J*E{t$#et^`C66Dn$4EdjX4+c*D_pe)7;>r>Kuf@=WmU9ig_@|5?FZ8MT z=}gzOLjdw!f{Hd0J57J;?<75j6y%%8y1Erh&1Ptfi;%|?$NGhlymWe(z`l99!Sd7` z_&z!~eI%)tf+&Q)*<;3iQr&dm0LNjW`9xp}U)4&orhJSGI38Q+hKzc})|vslf`S>d zs0NxA03q(;khca>eOH_<4yiobwODN{2lKt{nqKx3^Z(~fjx1LTv z-4w9qEc|KVEl1|5k|t0kyiuzW`_obe!k z-Jn8W+Gb5Y>)8NB(zeERlRGhF3-{TY6O7y7Lm4u-7LpS_~I*^??uNKH!J6YY#cdm!S% zNGxF(M&C~F`Au1N)^gN{f9C@;+LLp_mIRABnH!q-wvJ_Qd=#JkN`%qxME15L<9APA zAP!l(r&jxYG?>Wy_|te26|>DXDSQOw24(gYRS*rW6MGaMJ*sIwnKs-+=jG9OOa(tL#q4i+5K^O{6W5A=)B7S}40Yotb@z-1NM6L zvW_Do2@ak&RyFwQil$u;oBN8^cD@BBm$|C%T0&>LCz~o=yxuS;jOMVHdb&Oflcos0 z=^%xOQ?PH^-zz(BhzQC68{f5Ii3{%&o$(0gA-kG8K6?P$CobUP#^m-j@NnriLPxL(%X%h$U9sb5Xz{baR4PUrTRO#szr zz(k*O02N4Et6MXNHY)O~Ui8ajPQx?;y_rP35FSE>d@8*j8B}|p@(M1w=`{;Fd1#3e z4}CbI3eh8t(|N!SMdIvN3Z`Ev-M0@v42|x3U)+ZvFvpdrw z%`$DGl}03w5*uykLjqzDcIfby-1+{_{?c!4DLI{dzS5eCAkqmln3Q&+APtY{Pu6h7 ziP%5-$`-|bAz#V5%YSvdXn+sfFsXN7_W|6Ru9biF5>4!7o)%)C`}xRZEF#WgtJ%$( zhHweVbMh2h{Mz^DD~Gv)j+eVwcx8TR=D&5%Xch;=mqk_IpCLDj#GuW#bUvjDP!Of7 zQ3aXiBR-#YGVCvBz&hosFk245meQ~H3&chCZxXA!ZzeaMD4*ZPBWyY_@y@;Yuxtgj zInKJ7OO&)$&+Q5=m2QOO@IrmKF!XO9cs?t-Jc1f~xu8~U8eonZhYuMp5tjpsrF$Me zKM<*NK{fgXc&z3}HC)}3j2f(+4yx4?J#K<{JTVn~(=&+I!&>v--vxC6GzIuXmVsKG z6-@3PHZ-#y?-w)L7aau2^tuG+2ZF2)`6StuJsdNT8AnEnC&LE@}~wEq$(i99IV-`f@VM_TUX(!ha)qZx?V~yr%eIiu))3 zkLeLXrY!)r&X*!qUx z(bOM8OSZICtqz|y6w3K^nbF5{X?IU?UZoZnOQOQ|BYLW&ttv3*`*JY4(C*%XiA6wRwxXzMbtpZCY3wodo_ zxE-=X_1B-c+D~+mXrJDf*q+%bXR4E2URRA)gR~-o18UhBMoubOCp0_rlLi{x(wNZS z710r7!n4Ust~+5yA_C1^a=m;g{?-Wn+%kG~>vp28r}9>u`9RvOD;0?_wLgRP?5gwJ*AUgNTYz6di8pGq76?Wf#jS^nt7}~61i`ui9;8N}O z&~W4kK)l$bSwSC;B*WOx(8iy}iW1TC7{82DWYpcbT7sL7#a8ERekL10xj*Cmo81_nXqghd}Yn={0j6bra0l33I=kl=;bZr#{ zbTEGXWK3p5;?@rPLgvMz8mHQnQvZ4Bq}s;I0Je9n)Yqpw`E>8-7eH2W7^L(S5Gt88 zc1((o>>plB=jS45eewr!zG80Mh}=UkWPkl_E;A0Rxtut}=;|l|)h}p_n<^=SDS_vj z$W}G`rcD%Dah3H)L|Lg_gr3-POC@vL+ug8PHq>Nklpmk{ow9&!b;#cOn09qo6mHfn zT!3R3VfK*@uv%@deOe7TVV-24SZXLv8$;WXc8GO^Gd_#D)<&1U_DAXYI(Yv4xuJtE z3eRJ2vm0Q5DFf{Kc<)VsJ3QhmXP`nDI(FW&W_E+Y(edl7j!-8py7+Qfg|`;Y7{mNd z>%{u*2Gl&c(4df*uaGc9Qlasi|A&N^)z}Zv!!)-7HmF{9@1d1=`7_&x^1D%Yh7Y_( zF71T3Xft-M`bQ3)c4QQ!;LX@*)m{2#=X3Zs0<-R8AIA!u*IO`~`98`I*t*I!kN5&=QP!XF?(Mumxu z5{5MJ>JNhRe}iege|n1ZV&!&p|LF`%4}PSvA@Rwa9!C79%D{q&wbgCAZsx)EuL-mK zKL-~8k)T}3x!>gV#;CwB7rZWx*zNC~J8uwrw$U&d-(~SR&3rm3eD&Wu`ak;ppMvM| ek=tM-1hdC10zx%n)|VeD5ENuoq^l&21O68ash#ft literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/leverage_slider-light.png b/testdata/snapshots/darwin/leverage_slider-light.png new file mode 100644 index 0000000000000000000000000000000000000000..155c31238825989d1d523a0e79fce81b54ef3de6 GIT binary patch literal 8234 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

gk%(*3}PpMXwPcUOQ$GcR3vF zFCO3Xv`ByzHalaEdxRaoKUURIpUq%5`^V1j6R=?97s}#)AI~e$EHxo1uC;e>aF`K8 zW+^W_dL9cic4-BOFLC(Z0gt_xWQTxf&0D^7ivcK=(LKiSUng=1St_SZ_HpInQ-&*o z$nZmi*3aBc`ir@LGSY&@LzY(#!=UC2HR!NfoZh49Gm;*{JpUY>v3Kuud2hXz%KpS;uI3u^bzC1=+IV#sD1Kz*P?!r5@B)r-!oc+O{Tq`ZDbhx_?d4Y-v)nHb zh4A5MqZGxv?B5-9ySrmFV~?Ma$eF?Pbcj-kQk~wsoRG2(b4rtkvTJbfqZVMx1;Ypu z;>cC|g}-|iA#=#scI(;-v(GIHcpxQ?U+8!@TuLBUE}iC-!@B2-K=wv?u?2Z;zZT|K z9KYTqw-ocb-?Qp1jv3%VuTPd5t&A0s=Z6>*LX|2#}5HtT=0mt_?N1 zmO2#3P7$3pjV={8yL2PozlmyH^q3AEKAW#MAUkY6J+EB^h-*g-asHx0rp%N^LDYI0 zDaJTld2AGYaho)D0j2Q6*?WJB@<1%Syg{cmGIF(S5^A%-uv!n9MV{f1`TDzZqQu2a z8Tq?Lm`TG1>o06-3L1?+-Chhdt4>{@5o||H!V3H-eO|A0GsZyV7QxdyZYsG_-}ZZJ z(1Bb=zxY}A;Pj1i~1Xj*&tRDEOun zEdqB-z2bdL<0U|GPU7m_ad)1InXu8XoKZiVyB(QHx7wIIqA{VV9%+SUEsz^h7B^L?EBpnEi2Zs>7eafVBBw>3Dmp0yC^TnEKDB;)vxd*j>iocXC zY09T8e^KukgdJ1JA*R^T$sr!Y`w<2uDsK1d&$E)+M2*`^eYRDG7mx4A63KY$poFdQ?5otnvv%7*84+NmNV1bubWon;1wFk>Kx5|X51 zMj9vyF`})4@0yUC+xdS@Zo4wW!PVjbkV4<~!f(Ji`0%`IMmwyA{}}N_{b$UN625P)J3=)C7@)<)Niuy#50KCnu#W KStao`;C}!$J*I8| literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/margin_indicator-dark.png b/testdata/snapshots/darwin/margin_indicator-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..f77e26e53d28070cfb8c7813c44d9ce245cf5c33 GIT binary patch literal 8169 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%0Aq7BzQ5L zj##}Qy|WV9T`ie(or17!L*D#O_ZBduvw_#meF1_ya52uxLMg;jygNMJ=eZ#>tR ze{7x5Zcjz0VsshqOf+h+bHpzcoN3lweKc}6;KB?p$a?W`TJt-uL)hf#9*2>LRoB-P zf|DOB3Lr(LShA+WybNL6^PJ5YKm799rkUB0myg}bPiJ?g8o;l!DPR3LZNkTYv{rik zIVN;?TS>cB0{_9A5k6NRJtA2cil1eXZD@eLdnC0yQtjS4sv3aO#*sc@Jbi*e)(-^x z4)b`op$uf^5aj`O^@&Bs%==Y{2>()Hqs_PUo0O8C7Mx0CQbtIzI^Spu$n0KcFK2T z4IgN&v_yi7QLR{PkCVV@{H;(_TcS|1xUxiEYR&3nANruUn)hf9&{9-zdb0s}*WVnU zmr%#sj^hsOU%6&w1&9!T`^yjfTV;y=k1qZvFk+;`R;T`Q*GdqJN$A*GU#zv!L2M-T zIW1swk{vdG!v;Z%Q>HISssaRBNHMPPh0b|4NQA+=9U+?q7w$sXHnr=V_a}?+hZr9g zX!v4t3wW$k-(DmELLmZZ$Y`PQju8JLq)g}&24>`c!{M`UXxW*rQbKbI zOV{|WfUOu7mNeL0J-qh>pNcT3QuTHfqGanPF_)h0^QyWVmR+?GXh5JYTE*7h`5~1P zZR<8#yL#g85#hJHYw)4r6Me7VN^~_|RP;H)c4lIgj1o!s`^k9(e)}Q|&>QoL?cv2Y zv5sh@LuF~Fj;Zh@)!UCIkSCAnGvQKq9NWQpah_jEYu2zwJHx5>BS=~gFx(NOzuB^~q{YK^Bh#|LAl24koH$O-?SnGc`I;R6W&E1XP2 z@&R}l+82?k?mld^PeY1mAFk`ah?`R6E9(3I)hZmOHsBEHdT16WlG-1 zV(xt?X{``43%+^%1n*L0a>A*~ zu{hU22^P_Z#Klg>3r4CfF<4UBg3b*2B@sBI9_MLMjMr)vg*iFba_gtfbv^UY9GUB z3uf~Bx%AX>Jxzg3l@~P#Wv=)K;e653`<-Q$wJC$c)5%>lNs0SH$c+rAJVEP-A(q=q zg^S?9_@G~E6{p)>DDe<&UXs|=Rc%dOo3b|THO7|7%A?Hv#m~YL<|yFf+?+!*Y9nE8 ztvw1MT6;BkuHZ(58gO}je64n3K#Qr#=vse7v$jJm$x^M>aK!jt-%bLZF-;OkH#l<8 zO~Ibv=ZngZ3}tB{m-8#unUQ5LK*?dXpD#cW26iklN+-M5^VI?40|8v& z@LV3ahzEROAC+Uee;YJW+KeT$DhhGXo~Ldh+DA~ze0*?VasH0;mo<38Kz>g3v4 z=12{a1Xjt6`C_#6&(l1ERl26Ns(Wb<(=ZoRypFhh6LijD;~W>zIu|p?v7vAzpx3+x zjxY=fcVg1bQF&C-DOoIGtWn}13I3**>7-1mb7pzpF|)E%YAmHJkfP^{tL@QhRBo@V z@XD=WR(`Cz)?~bt37T3|=64?HWPrY@YjfMw)U~WqOAByxG$O?+9eoSi$YWN)3@jUUC5%<_9ziI_4atx*26<^)IB zc)q3J@cCY`6Ly`v$?xFPsD*4!3oB-0I?Gx$bB**v5;BvbLO8;RRE`h}8N4z+G@>!D zi>^tndd%JLb@JpV@o+75XR9}nt(2u@=6tW)bLU%L9AcG_TdUs{jIB3Yg}q3laA;1B zPvFj+wtc}r=Su9u*?n)eWW_|`;=!Nl%l5M&WkcHMrAh`;A!@Nsw_{QV<}(#szHExO z&U{g7F^BlLE$tTVysOExV}ZVF6{}@A&&!9juaVQA5;T^plbb=X!u^JKy^$Ju_V(&e zhkH~rt#ocIUh{LKDwqQ{K5%|7nrc>BI&WQveA^++IiY4`cbqT=W#Ii3#=t6Ew9c6Lj_@B9qrp|P zj^HOEy8r#hAmYFH*MHgU|4)AaBKnW+(|^&S?NG?q2e93GeU$bIRZFnXO-xu?s8T@J G|9=1=LDlX6 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/order_confirm_dialog-dark.png b/testdata/snapshots/darwin/order_confirm_dialog-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..e36eea50be456bfc396cca7b08f028d8cc0cbbd9 GIT binary patch literal 27098 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/order_confirm_dialog-light.png b/testdata/snapshots/darwin/order_confirm_dialog-light.png new file mode 100644 index 0000000000000000000000000000000000000000..4d91420fbc13186e439e9c412177241af7f1bd86 GIT binary patch literal 27676 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 C>!RWS literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/order_entry-dark.png b/testdata/snapshots/darwin/order_entry-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..45148b8e741a1fd935c8e61f17bdcc400fb7191d GIT binary patch literal 25738 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 g%hO*01h>ZBr{DMe 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/order_table-light.png b/testdata/snapshots/darwin/order_table-light.png new file mode 100644 index 0000000000000000000000000000000000000000..442feec9232ceebed9d520484b7881b56988f6d8 GIT binary patch literal 31963 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 IkunSYKNmSjUH||9 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/position_table-light.png b/testdata/snapshots/darwin/position_table-light.png new file mode 100644 index 0000000000000000000000000000000000000000..860ce9fa1e68efb2b400f3f983390ba6b13a8237 GIT binary patch literal 27071 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 WYD;c;9v1%kGqRFO5>;X*!T$kuHQVq2 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/price_change_badge-dark.png b/testdata/snapshots/darwin/price_change_badge-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..735c54849893dc87a739afc70e86abae2121cd7e GIT binary patch literal 5715 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/price_change_badge-light.png b/testdata/snapshots/darwin/price_change_badge-light.png new file mode 100644 index 0000000000000000000000000000000000000000..2008a6cb87d02dd91c41b4af6a472a950071db3c GIT binary patch literal 5632 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 X{>|Wn=1YCd&n}>@qN7}^Xc_)LvJP$L literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/price_text-dark.png b/testdata/snapshots/darwin/price_text-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..9c9c10145681844f8fd48a70998c155ffe0fe5df GIT binary patch literal 6387 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/price_text-light.png b/testdata/snapshots/darwin/price_text-light.png new file mode 100644 index 0000000000000000000000000000000000000000..c891bbf1769f9f012c7d100dfdfa7f87f51b0aa3 GIT binary patch literal 6279 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 IV*U2t02e+il>h($ literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/quick_trade_buttons-light.png b/testdata/snapshots/darwin/quick_trade_buttons-light.png new file mode 100644 index 0000000000000000000000000000000000000000..34f5b42173aa438695b1b8e1b6706d16aedb63ae GIT binary patch literal 5097 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 MqWijD>CMOg28vA!w*UYD literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/risk_meter-dark.png b/testdata/snapshots/darwin/risk_meter-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..805964c394614c1ee839ec6a7cc29927232ad859 GIT binary patch literal 5465 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/risk_meter-light.png b/testdata/snapshots/darwin/risk_meter-light.png new file mode 100644 index 0000000000000000000000000000000000000000..2ac5c3f1dbccee7a94300a33e0083fba949270b1 GIT binary patch literal 5229 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

  • J=`iE(l>3p>7iiTNs}NkBBrlR}O6lbRz69Ep_5`;$+aA2FF}Z zjpVe;q_EADN+aK58r55DEIpgKV>L`A4HSoEZS@RvIi5PE1R;V}2(o+DHvW(zjXIF0IDS$y6c`)Oct|$g!k}tqrP|7)XJm;TtXa2l+$`2Ub*SK<2C9IQeKSh zBpSHvQlw)M3keQ|Eq*Wj#s;{Kyz}SXRvJPv*nCq0jI3W*8-pSf7XF-)gyY($#ulLN zFJ~R5;yenk0{s2r45*NnQEbZhXjBW>3o?Jot7@%0VP#{R^m9>Ln9?U#n3MNby58*$ zbP1e9&vaq&_Zj)D1mQH&e1oCe)Hoyp>CTz!DYq)lzJ|LEM@9Krro?#}Mpoxgv)?XirV|H5-L!?ok|$#pFeeu{fXNxdy+E0H5c;&`!;&D(1im_vuu7oCPYpku-xrgI+CsF4L9 zDEeDqFsWK|)uqWhn#`Lu6PsdG*n^tE?6W0rrQpH`ix@2?GuY-EhMo^RtwPg&ZtfOU zXxEu4~?ENQS&Mzz!M(3aGi^$?7| zWh+|>VO&L8S6mOJwUw1L0vWy4cNNsrlbJ}J+%@jvuZRk!GlrR7><`(T9{xU~T$7QK z)K1kgWGK|JDbxc+OYIAS2o>by*awsX&c?xzKDGM}{w6k`cvJFM_0)sj3_^ zs?62lmP2Ut4|p}abp+u@MM0i!(r;mDq0c|D@q6NDf)B0gb@X+;j`_e2BU_IyN(8#s zz{w>hJGx!-mW!%$qj+K&_l7Z9U4gr<$gFnyb=YfhS=kErm%FDI9~G_wLnM{TDGh6_ zkP_}Xf9mG#8%2d435hdPZCY;TRbl#p1 z*xjWCv&9P2%Aq{io9xIhH#y5sTR1%3Jm9aqH@Na{<-TRB2=1lCAtBzWXbG*M&Z@_Q z8z}|%D@<%rQAPQgR-ZthB4rmHBoYy7wr*37~&FV4S9} zO)OCv{|;KrJ;CD4DZS=tx9e$=DZw{qZtvOogJVWWAN@0_FrU*Eg}~j>x;=3?J4^0& zI5`)+xKc5!)MKP4l#1lth-{I`NNv3(Eu_l|<@)omqOszOGvX#lIgyingETpxAtzEc z^5SA{F>Fi!*I@qgEpN7m(oFipy3ezF7Omoeugi8X+!t4yrF~`d$y;+qt2e^49d!wK z*<^;B^yl*P^VJr(2k2jLy{>p$Ra}%(hHSfbIwm`gD-+b2fZb|ifUhrnEmjt}fIdQP zl|n&MIePpt4{vjx?^%QN>f$+izuJt5l8Q-s?_@r8YoROfQri6;@N@CbK2ixeC+#tC z{*cnhvCiks0^W*8`+kQQ>61D>ID1{5U=laE&mZBOGzKGjuoyENDVzK~>92wmJ-9Ti zrxbQFa7STQzYXmD;oYSgxD3$F*r2 z`RM$7j?pG4tr(TBN-daHE7H$FFOyv-VYrVy5A*SlK6CtsFsOX}ZGOPP?6ofYhpIyi zj#b{~J9{BLciG%>QhVp{*}cQxeNk?0>sS6>Ym=0l*+ZP^13k*4uAHfVR4U+Ba3(nEwE6O6Z9I literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/spread_indicator-dark.png b/testdata/snapshots/darwin/spread_indicator-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..df230e2e9c30195bfa4619dee896807ad2dff3f9 GIT binary patch literal 7438 zcmd^^^;cBUyZ;YJONk;O2#V53Ne$B7HFQc044nc)sR)P&h=}Bn(!x+f!=RLO$IMXD zjda7E&v$*-{TJ@K>+XHl+2{Ol*4bH`2?Fz(u( z1Rr-M^Jkg|0Hz5wMLBRl#`bI=*ua<(__rtb@O>2_K1o%Q$Tq%ujRTaHPSMMn$ltsu z-|VNkoJ(iz0#k_}7g!R^kUy+#SzxeJe5{Ln%FP+WT0}^Y!1v6RhV?SzUjP|>kvL&g z=3dkJ(#l-&Ue{8f%x=iusuYIa&Y%s~=*x$*MX8w;iAUso|Mv}!fbUB`<=BGSTe82a zy%d?!rp4fcbNmwR5PF8H28$q~@R89`&@_1gdsoo?Hw-?X4-R4?bF7hCz99J8mYbcO z>5#{lo@KCzCwyB%ITBxv4X7|NizZ&$adj)7uUA6a*)%U_>pkLsOdwZ5anxz6maeKe zL7_Ih;Y($__Ir`0(nNkjih?~cArm&;iN4pkICnkTslf&UNfw`233B*$ovd?O!beb6 zjg2q7w`_zJJYM+;6I ztVLzU4F=tFp`aiy`eaqahmiRR6;6b%ANGI%~Mr`-NJR8;0lbt#gdrT$dCbT(^Yvb~SZ?m&+I>Lh?RE#=k(5 z9b3hB(p`;moom$K{oYSOF*y!Cq{`?x?CI~Fs}Ed@aYzwDQvspUVO~X-%-KCN!Q_Cw z<66QY`@znt)}D!J+_jVc`-;kFbp#{v#Kd9uWx(dfhQ6P8%kPbek8rD0dLO5k13Xji zB;GvNA z@eg@r1KckftdEO`0Ozf<&gZAyfsJt@Vx_@nA2FqpxpTJy!aUg7f%8rwO?nwh;Nb43 z$VTgE#Zha6i9BauVZS*&-5kg+DT!R$Vy^X_Lub9nxLtXg)YSA~=0)bi2kR>vZ}tx+ zIFd{%nt$ewc=Y*nSD2ne*MNnt(XXy0rKr#1Kb{3tn zsWHn}{0{)DB`p%T;IaB-tVgTN(w1=f5M2Px@3Qw3>xYbat!uP=0N*oU%aNc!(Jc)?#;Wa!+iSpF9V!+d|iZ5@e&fPcO|T%6oDH&N99YhusSc?%`KIUZ1x_Nfpu1x)DV=jQKQB$IQA zvbTA(en-~8r!QOj82?)R+1H!2Z|W;ed!3r}d!#^}x5wVcIVT9@;zZJXZ3y1rU|=5- zqM+(YEhp=Y;R2j?8#R?f-Eaw&0loeu93G-(4HZnadhCAaI5b1udIIMY1pZaHTp<|G zjg5ur$!l-M?id~$PYr+3E<~7A*>rv-w4~LwG%p;mjX;q3_^*ySag(`hg2N`XVq@>d zXn=!`{+zpVZ87?r_`)%))^<&`Jr`@yYeTYD9Jymq?}lL2%jY8-{0(64mbCmdkBiIw zhc8n6Hv1c5k`d)r$R9tOZCAG)7}ijyL9r^i3Wd-&3D-weAZ>&vOhmuX_zhy3mz?4W zNv;9!U~lVryUv=QuX3WXqj=-d?c5j*fD#gLpb1 zTarG^7s2+r46ujqbddy+1ETbsp~TwS4=pX>I{qqCllx02Osw-{5nAf``qR@t3Jb@i zUT$5KEKe!>Qo|Es*$wdqX9P>k6gQdPvoR7+UVco{q%uMdZ*F_NeR6^{-7*B>( z?D&SEgQ4FhN}HdYf;3f>5IDnsZF^AZ&a2+{+c*+hZ9>Ij$f72J2dGEL=YaKDB0848 z9shNajzh~+D_XrCL7*%rY=v;sZORk#|J1ocOLgoE*2oVVthaX%6t$i3*3ydIo(aC| zQ=O>>>na{|gfqFW4Zs`hN0<_dr1-9VFX|kND%I{s*^Of^QZUAbs>D4Fqb!hh({g*O zEL<8|+DX{oO3K;wf6EU1+doO66%xTcHHqBaf<=9ei(}bqV1wBC`MHfIJOFG2)_2_p zpXyyEc8=lF){OjTLDBqLYXOq?3-ndb^`XMZa+%ksQFJe?2J16=Y@x_#%;omHFugB` znjr9Cu?NFasW|Frub4OTQbc6@h2pLOJ$YkNl9Gc%lH$|+O<4tnaOJUWQ{icHsrEl# zLb#S{Dk?XQxejT`It7j-Wyh)`SV^R$W+9tLro-Rf@>6zP2ka&fnA;Uw{;M-S!sslVUS!KZy$%moEZ05SSK?0O%3|o_%tV)=o+k4!K1yFcaKHN} zS-*JO;6Ja-Ysm}mu_q$ZEGaJI=W384zos1iQS1BW&8@YQlhd<~z45WJS!!g<(A&HJ zsfwbYkj0CEnW_V_2Kk(V9ezDBvfYmuNoSWWmRA9)6W20Ci9Pfp&R}Ou4>qC`%>4gk zcu;6ek849LjA8PW|8r;-h+Ze}f#0zw!&~;D)Mqb0z7A#V zNR)h6{r@@aNOLKR!51{!KG9H7ueigE!A*rpL)ym8ZRD8J*?DWKnKu9AP3~Sr{-$uF!JM@EWQP2nThNn#?+iwhHs?kU## zz8tk$)XCZ9KETS4azgj2eicA??anjlG=JI0Mi%XqSb^)xA0lE*QvLWiBsr)6;HGab zwN1p!@9vfM2|!AH!n@5%U{Cj+C+nlp!+SGI_mG|W?q&L=wYAd^vCeMDvNDZ{r?lps zMrHGbJB1ICMQ_P^bDv())K+kO`Ox1yFTn7f+HL+aNxJoPSK|Cybr+ryq_BFkmf=H8 z2@Ku7V`U9&e;N1W4(p$$NAkvdSETJ$zE_9#GbXP;cI=lL_%|)zxs`YXP}3|Ijbw}Y z@U$&V-nt2{R|6Oh-&SvF53p?)FrJBPyyE&+xTpio? z|8=!Mj`oj(3*o~92t;Ka9USEu*vXS#Zi(uwtAzO-dsq3$;&-2yYk%HbUk~O89Eu*_ zL-S6~#lK<1aRKmE6t(%}@gXb1rf+h2Cg|MG0$$hB@Gf}%t+)gR_0rDy^+@7&1~Hq| z?qQ>%{LQl3S38c;(~uJ+BEB$+p8xqDNTswUdSq@cwb_MVf>-=z2MV;6x*Taj>$S7i zxhqy%o0qyfnAcp-*~hvh6Q%BW!)|j+Ijjrx_FWeOWSYzijmykS__mQAK^IQ zP8%K0`sbkYuxAiu-mzQG$LA*bCiE=GXfTQ;j1u^FmvK&%J%`69oLAxZ48?W^m$b0b@oMMmlvLNSC>VV7OEnpMkFRYE;P%| zzD>YJxK$#tNmTo{{rbgkLY*zNW?D>(1kg4gu9L%xmx+Ica${>7>#QnPnq%F%SX|zT zcrGO-NYl%8gqZ|NOBo4MEM1K)_bodoDZfooUm{IPc+~G<;N2}?O7Hm zTJgcDkzeJ*o0aeInu^Y#ep<{{RMoAOMQ6phu+VKo{45#SHwA#eb3!($a`k+em9d|7 zaX@rOR*{FHr6mXHLA?2c%R`y4mV>_ICwK0Axvg+gHu;z}G`*FIN_2xgbN{ZBEFXB| zydN1b<0J6}CJAZmUgX?cVo*4cYlwGlFZ{gki{yUccC^(VTiwDi^|41-R6xicvbvBn zmaDo~q8D+wB(eeW26s&F3~c@$gqZh9uA zT^$yvpIt}NUeRc93Pt~ z(a5oA*vYV}7JR*^q&Fw}FoPR|Aerd7Bwnu)3Pe|aOC(GFMc)rl%IlR{8Km0WQV#zz^Vz%^e&QuxEqO2z;we*n_VlR&iZ2*9hvKDs_Li*?1)1k9z z4_m)(;)=L^yK3y^`*IBCVqU14W|7Vn^W}_nPtVYAXZN&DOsuXs>i~K+dY-k7b0s58 zPoabWCts(Wje8CsDZ;p{|MMc`oaszdBTugQ0a=p#h|}NBQ@!Qs;|0_9}w&xE(A529iOIong(l7hRe~Kc+H!#ICBWJSnG=Y8XBAdyKLt7 zly4;y@xaD!dxN?6@9l&LXS|Gek^ebAZd1r3mNoaMI7M_0YWkBUQ?h!Q02b3R`2Cb@ zYbJwtE=;O_JY~Rs^z3^^s)2=M<2R~LKVSnOZ0hqCA=A8Hp;yR1zsDC^w8rRtH?KSq z5%;V(KS}Yq#HH@a#gR+F_4YQ3CN^iYLIuO#fL+07&Fg<~GWQrAWl8=#K`-=m z!Za$J2QGqoE)ibdXg_rO0 z5d5(fjPA;8{UDgw$wVS{k?HTh#r`$0fE{={S$mT3IGHoJr0#Beh2Nt(;u8s@(_NWh z7pzNg>+vSiqdz)Y6?5gRpkQDhK>z-2jR6Ay@)%dPBCG5|6z?P;A6<)aZPLww4B8V)79P@V! z%`rIZPn{N8=OJe;OhWNSUU0ju&eW1DNidm~al4~#aZ<#Irvtagz}v{x@-6?~(LtFn zJT-@Ur@5tbH^s$Dt*_B%xYf6_EWBBqhH9E^!e1*#FL{ZZ8iX-#`TZO=95?0Q_!sRfU== zL9^DL(oBvb14cWCo1O3tol;hw1Ra_Mf^vM$nZT6KqJY6BZ ztI@~(6vEd4Tj~E1O@j~eWsD2|h1~=#{J&<~& zIy}Qu6ia$PO3O3Bzx3c!J{6hEwG<)eC&LM(2$CHA>w(!)^p7Z=O*~*lq>R}TGr&un z!$l}Z$*z(}j4#=$CgUqq{(uM;J=vv(J9oB0AT78BLVIGJ>&X?!cs&?=oKs=3tslGA05NRvdfX~wX(0-v3qty z31lyuN@V()2&C6fIJmn$0~So7N-8Rj28sQH+RsQ2I8HKgJ{5zNOiTBx(@S?a;}dw5 zxuF_==~&RQ;w?Rm)H0h_4Yq%g%$A6>rDu16iioa$857vaI`NdFuHbqt-^Cx%K}G8cULBF)J1{D9mO^dk{K) z;A258|ND$)QYf2ZciRM)!0aXql*-g&P19>_>|lfK?>bEN)Rwl9(5(uB zZ2b25I&)=Hsd9K)YHDbuOg@639x}EH=lql@6#{0hP_w9he%Q5R*R3;aaZN@0(|GD%qBF6Y4Q47?N^NVr)xwp^DFuoNU zG+^&WMnEpGnl9Xs9M2a|dMJLXk@H67X9Z2q0l`Rg83_wqek-nRRGv?r)!Uw-GFAH&ISAZaemd$+}@P%ES+S;4TOWHT-^ls z1*U3mEt=r!moiaI8Ogj_jy{*ct>C?|SpLv&;(h53We*>&GBd*i#@XGbPmFpefB5O$ z8`FEx;(z-$9V^pz;R?yPL=Q}GiL%@Ny+V68EP^i@j>crZt`aY=mPrc#mdC$pL0C0O zj4rhXsN>zt=_QQm#)8b z26FX^zir%yV?mMj2v=TY+*hvT*s$+Lgy=gMP>_15{oosj|AE&GE}`dZ!6#QUE+hO1 z+;y+)@W?yWxznhE(~-9BvcH*bn{A;QL1Oy}D9Nnuy5$dAo}{GS+uwNn6Y;*C82o_j zSkR>%_1Xh%V+X4^ZVTW6{3w_;K_b#!b;y>>h2kc^Shym@EZkX#v<1R%#Y0Kz{V{Em zea|S#untylf9!puyMA3ww)AqnqvV7VObXpn6*=xA=9Qop!8V;|u;596U8GqYPkH_A`B_J<^KI2|zlBzaH& z$Orr9$aK1f%X(XBG^s&bEhHmsp4x}G3;E@E9Ud&9!7K}Psm5ch zj_peYC&B*o5aGyYXXDE~kx6k^(!V1VpITGI6*H8iCqCsir3ZspTUtP2MMv}ZA1E1e zTY{*?P~>z;>X!QY%B`bp16AKW;tCPkpW{=RGre{ls{#qSuiLpOjL6$Bq7`y#<;k; z*EwLlx|L|?l~ z)YUtSwS2wry#K@d&b)JH?%aESI`=&1Jm)!cV)S%gQIIi_0RR9Bjn`@*0N`HG-PwkO z;BF`LWmy6MSoAg2R1N&{b{8N9U#B~X4;8zI|7B5d&Boe8%)YxYu z#+cBTk=f%S71E@9spZ28B$QLZED-@4HR01vTWy_Wh&o$tTd?mG9&B{2bXgVonXiZi*{-ZAIMZE*C9;S^fm0LaQjp0$z?G=olUp-6+o9p_c)57dVXSNqz1o^$TMzL| zJbFwP>2=8Qs%G{ec0m%Kz17sz)Nr7a_&vB;AlM?bYpDrdvwe2e;5MON#G$Ljq}zXB z69O8_T}~nIc4$D6uJ&KxbPwJVL3Ntf8^44Cx=P;Aou0KqDW1h!;-kRmMdYc4=eM{R zyp7{uf}I-t0`Qq;qzC3zN{~`biPX_?DmUMneNn|heXJXhwVq)W|$cV>L zHW#02u~UPLjM-SWO{%q&2;Z?b)|YV5&e@eaO}~4KS)m?717~?>bv~8H;bb^SdMk3} z!BD_@){!-xi0Lr>;Yr;|wOMD;v_s8@4muz+Sb{03gjGP`Da~Bm+UMgzU2UF-HOz+n zP1f8La!qOi>^Lw{SX3C1JegfqA2K4vlyIyf`=JG*#WR^u;S_Q^qn)hs>)UltL_AG) zK*!AucsyUR*6LL>3e~#!ZeVnfHzJ-5Gd;U=?AJaTW%g3$=<@nHtjO}*CxS{^8uq*} zK3GK9rZ@GeKF>G`&Zr!$sH)S8VkO$C}k#Z~STeFM5J-BO>}W+P~@OvWg0n zgM^$$)FkD~uHduWkr4BmBA_p)k5_?6pnjow;lGp1(a}`ak?r2r59CLF?cRj~N*AI^ z*YM4C1l=4urf4zFlfjOSjxHxX9skyB#m(Mh>&fxOYIQ_%YXH&S9hKPsDtbX;jNNX1 zYhJ9wqWp*%n0pvPD%tE@h3^dR)GyUx+>;F0kMl%`d^K$)afi&GwaAVcTk=2U_qSYp z0Fs6^*I-{KrDO`5Q_sb4T603KgUr4Q(|pT%?}-3av^NCBV!xJ^DGD(Q`o=8% z(+@p%s=pc;JdeqUn!+e@rC%?6Z%E2RC>xm>wA-yR8Nr-K-DEKj#%P}JM$c8g+nxb6 z*hL>5ei9i_wlFdhp_AuNr)cqyWaV1;IX?qu>1H4#Q0i!srbUUlWZ^ISKpD31UYyq* z0H)}~0pz36)C6Wj<7RQI+Vw*|I{6s^lP(@NhszEMW;An8{Qeh#fGYVLsa+jz{|m4rK5VoO0a=6&z?3v zKcCepc~ZaUV|giQNzARQ|NA#2j8B=3la2Hs^(K|m`Pcn}KHmE}$PGQkZkLBi!!ju? ziVC3OaaYoM1qIHCyQi;XCVC$rx#s9qGT-J$qdI~JLqqd}Xzw&T%Y=3Z{wVw-(%2#bwBQle-Q!uh{xGz*#-Uff+&5|>y4d?TONSGW6V z@Q}9Bs3D$etTsPz6}#OaX9U|hPDgCT%NtX-Ke<%#I7N>OB6I>gCL%Ow81CzTYGS|I zb3m&$6)V1~G{_jUce6NPo^^W?oabOSGHIt(TrWRx>bPi``ywqZ>CX0sdKxh5XTZkr z%nrrN;=!Jref(%vx8r(}kJr29eJSfG-J!y%l@+mU7aNNjbT1Xh_tK3TsCx{vbk*rG zi|w92_mj;jnD_(pfZj>{rl2{_H}o8Lp98_-OcAR#5)H2wWwyKcH+RhYT%-iHX`8}b zqRAO2CRBa;_s(;-uxnGij8Tjd4th9JU&$y-85YWKAs9f>v=bN%Mnl=-Ulz}~bmHnp zt;Djc&GGs?p3Swjg^-L=dj@o1lAj{{FJ06#LZvQ;i5~YD(q|9z&h%#XtjfD*3P9*) z1qGgn`SOZo>iv62%8*&U zd%J2ti_fdHiAML2{36*&Ch(uwOt}9qXetFkubf;-Oxzo0gKf&beXvornLgjw(*-C4 zdDO&29JzG?5ZGfQwx_E(I4Fx&-tm!|ny+$naVa`5u@=il-53kk&t1>mtclP0dma9M zJH4QV?pV)_n4LarMp4`Y7Mw^we+36QH=0~k*Ziq-G1f3f1E;HN1#$a{Nc(FH+^kVn zMd^0raDdY7}-#j>Zpb2*Ybb%OIzz6J|85%&k+_-CCvoNC8VGfJ@c zZtnyMC~5T`(~^Ny)KXOK^u`N5i@qk|NS5V2kk_D0`+UBrbiIi^55eGujB&e-x-`e~ z&NcP6372e*SADwQuw-%(L5m4J9V+lX`5VPXcPFxmB!1fPMvcZj$35sqRN%$9T8bHJ zNiU$jt(Z|-C86d^$gPX~%}Gd6RBIHCJ1?0l?VT1;cJbTX-q$Q1zoB{6^+GIrcXRet zxW$7~5bP&duZ#vnJ!U@tlf&s`!$A(}!@bIrt#ypeO~me;=Ao~aUwxa{Y*4&K%1)zK zkJFhY8!6te9T0_fSrSvns0v;m>%v)6A#!dSakV#dg{n{niuK~ zlacKx`+-btYo&9kJ3@lM*6VtOjkIz3*_y6L@(%PebPS; z2zAu&5WdMfDyXA7V3}%kHikg(OAwrTXz7}(Kn?yn^0Y5nJD=6{=~I}Y;c$3u8_dAz zV}XUYHpD}78#O?C=OD5N2j^#JA|?#yWE((uWk<1op&sFX7unCW?g510;Ej#=y!o(Q zi(qXT@2@YJ1^-w&4xVCjGt$$s%}};3Gdt_@uO5zX`;L;kTvIi!?g2R5T-%|K4#b4M zsM=;_KQ6lnbwu~ADaDSwWccTn^;V@`pD40hY}G?)ncqcKb-nz z5<()^@y9${Yh!uuGdoGbOVbt~?yk6pfY%Dy16K7;mCi&#pWDiCvC{$rkB{*yIPIj| zCsw4Gr@ZGo?@K`0DLHQ~^xdrN#H3yJ8yF`6fV&pQziaI*<_ej(`|fRJy!H>AjitHe z(VkTaNLJcKSgD@1cbAELj-S8c?PG6G?>>s~l~4IxBrBL`ZDK&ymhznsy(lr+ZD05@57r@Ity6 z`Zlwl|4S)veAL;gbde|LAJCdPU*mUu0c&e};5u16G5>^r0ck&jCfa&+4^X&_u5>L+ zU*{nfitW?=ZSEp{TQ|RUzF|Txmn1+HF|cY-`PBpV{t0zM8*ZeVUkzhXHPFRy=}0g# zuxtEc5IP)k*8VSm2v3Xs+?XS8#Q#7fh7jn2%|0>gXJE)#QB>hbo4>kr)>!}oNYWtY zfr=|`He^C)IJm?Med+M! zE(BH#FE&C3O73mX|7aO!Q-4!3ktbO7<&!nU+R)Ar8TMnqmkV)_xhkH-tz_}TcgZL! zDr#p2{s$cH6x=5%ZBIUxTsOXEo0HojB&1LRas=DPd?RsjshV;+tH%iaROJo!mCn|h zp=6o$@89H1dCgoj%X-BxZ0Eb1GreqA%45NzU^Oa=uH$YkD7eVw>W|z1`Y-&~6K(LA zaIm!NU#^sbVhL$ki6G)Is<%}P6=bSk?f`t_nR*pq9{~{ZuWMh(3ofSv^T6a=ai7Qq@I$sWpQC)Oqi;*U!R_^RWj>w zc*>|+k{1BLtb|I=h2}yOaZae|yRu+dWo!u!pB|swq|W&EfmtkH zXfJ~9TfB12Sd|3`=7mmN00Ko4At7HJEfaHz)yu|FX!#>9_7tl@9XaUBGHd61*)F2k zr|Fut)tMjz0@Wl~%#lD=re;a}3=!bsFdUm9XkGwxUoaNyYn=n zlhWMWXFU&>2%R#LQAI`sst@;HCdF2>+P95)WreLn1|BbL508syt#6xpNd_;sLM~!L zwMvZT{hB0ao1|w2)+i0Kn>h_q!bt`PB$FCa$+ru-zsE4s( z1^cQ13RMGzdRv7EU#b|J+ShvdzB)XQ-a5AWHd;(+v$IRQ5U(lVo_xXeMePGrz2fuR zo~G5u_giBk_x1$(<$flhIF#x$MooeD0Rx(-+d9)1`f=K|v*lhiCC^byh?9U2!pMRLh#VOoWA4#ArlxVhl{wc<>1=&$SEAA^2y z)%SY9C^Xtf6Is5YOu0B~w~wd=4v<U|QEMujX=&UbE`=f(T!r>N z#8u<}8l;P)Z8p)DPdojN!|>2GNpOh|=dKRe6H&?0(91!A&=K9-`(gK~2;HG8au$-x zTVB+$MaX(IE5{9$(d*(#zV6DM2?q(X^g72A9=cpfy$@K`x$y0wZLG52Qoe0S^QP-N zby`D?Ov{-#w_wIYSrhq-b>GNH-)1*-gF?{J4@$tA2T^3$f+!RUtTnarF~1NK?ENH; zqXT@btG^HUH8@z*Sfj~njm z#LOh>+ec%}FZj3X)l}FwXPjMwx##RFVujnZpy7p+T%z)_bR5+7!@!nm39;^d#g3r- zl8!hK#{rGccsv8LV`#qA;$me%k)HJDSfR1Kr*l6RYrgH`KV|UYlZZeeA6KyZX^3@j zD|(twQ-zA7%lnsXlQ@8_d={+j{&JyX_^&N`-fp;3P)le;Hg4f|xa!BIRtY=x;2&Yu zeZclRl5uO?!X0yGhIE>}HThgrZpIU$cm6Biwg%tyb^htr?&f1`+)41Drw6NXV5SPY zjIK{-I^+#!%9j9jQeJ9)guuF(Y>ZmnN0U?RS>}Sk zMQs^RVadH5C^SK{M9!aoYYq1Ot0xSFYHPEi9EMmwO`5HSk+k>B^j*EbhBcfH7rQGj zc0$~?OdrfKorC9Cgwhbcy(|Mmqi9-B6~PRbg*x{hK>)y%+4-@0Ztl0PF#nK~)QJi4 zH~U6CefvC)1dR5)(L)ue4LetF?T(D^fKXoDA3#2-rmNMSjlR@GOu~!$-Y6bAFPaC} zB!pcpg=x4S6?{NxfIJ4KMy-w#@j4{wAz;G-(lrZ{HFzAU8(!qX)1;q2q5aMVZ_D&w z9cC?IF_k3%u#^&>leX>OrXqWtTT?E^CUF@ETdN?d0lBt=)0=fr%z&jPAV!Tte=A3| zzyg_`-q2MlQ!I00@g(*$Edt1PukTakU#-}p3gN}HsEOPhntO;|BVpPlnG^rL1?R}j z)lbBt6WNC;i7k=-7Zr!`4e<>R9Qk5ROpL1`Ztzm#pE~Y}k9?o=r=aS0XRA!ZlNb!t zY}Agk*N}>}e6d$r*rVg4RDreilJ(j^E7*Sq^hWfBRBg&Q;w#T@o=LZ3?vfRhIkXW; zGsRXTHy>GR@b9l36Yjl#FWT_1omR6%Gt%}>Q{8C-;)nZ*iWdu?MLIdCW9pw1_&}Q8 zVfV<6m+EBYWG^SGv+kFc@~{OTF7D0+*yTwIu&e?O>yBPX;&?ME6eT5QJ#hh#xolfM{ds)9k4(Y-qxPqt-ADE(lL$a8f8L3E`63y?c zG}r~6`ZQzma1(#Owj4q`ysV?%O9;wW&%*nMiS8PZX7LpYa&0iMy}|#8v8HD0pOjMY z;m%|ZXU#wEY4xr9?krWdH@xMx)rOUAmkS2>D^gPSu^Y$~YmWLCr8w-q+1}DbZr~=sfcin_JTAQM5byVicE~DN%Gr5;*edcAjo=g*)Y-qwOjU$hLy- zjwq`5gK!^X>c1+ZPGnW}TwK&tNq#%VP!F3ff6i0Lz_9WkbjrzKg7-Uf_7?sRq6AM! zAeQ_@u0AC4Q8&L8`l#@!eaFO(Ag*#dte>X;Q6I5|@`E8L1lLirvaXN-(Tcg8w9 zt^E8cv!%Rs>$SMl{{0a+R0a^bw)W;uG43oS^-yp{viGzglz%7nsS^?$i@7)WTpb=d zm7h}nRvLO1Bc6jUOqmLOxf>XfGWv~Y!oTGVd!}FhRhc?V>r)|LPM*i$!ooY8pTi$b zxFK(T$L7{DooH>%3AUj#pPnS;wX_u58F{&KOdpZlkKg|>yA(^VJxqxD`}zOlbs0hl e6!N<91<1`(dISZ{|Gt|t0yNZh)T*C<4ErAg6}7Yg literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/ticker_tape-dark.png b/testdata/snapshots/darwin/ticker_tape-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..d749ec08b4505196a20194ff0d5679ee994c4d8a GIT binary patch literal 8071 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

    3GCFsquN0#ehdNEk2W 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 literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/ticker_tape-light.png b/testdata/snapshots/darwin/ticker_tape-light.png new file mode 100644 index 0000000000000000000000000000000000000000..f3b79a819cd17d08bc1841fcbf7c18f87ed56a70 GIT binary patch literal 7578 zcmc(EWl$VZ*X95T5P}7F4G=82yAE!_Jy?Pbu0eyly9Edk7<6!V3l72EWq`q5cHaH9 zTlH0K)&BUtbGy24b=SRB_wwWi%K^j2KzeqcrWTE365;PyZ`C(MqJV0dbd@Fo?)oQZuQYp6gkn57uY&G880lO60 zN2jUSaR$8okA%F7YY#B}?;Cd+rr6!asM?mpipO+#aQW9Mz0?adXM2mv@T6)chqGIq zruH9s#Zh0*s!nrcdZ$9yUHXwfxr<%7wX9uS`EvE$*4F=g3qM41Q~yoz zgSWHWHSoCnKP$@0TH4#mxt`E#h|qbH7|Y*et-h2tfa`CKY8F`pgKkZ0y*n^$q;NML zom)oC8N^h5p3zQ-(2yC~ z!>xIX#5SbEmONT4yau}Yr+ucJ87v5SP+w&?AOpV8_Mey~iIak_-^e)9M+4iY{EhNN zXWP8K^xWDP#tCHJJ%oy51*Pu0uqn~kikWmXBL`8pDY9pbZf!NXxtXv_#eL`2cRF8w zS(6N}l@xnhb$2S^Irgf^zOXpX%grw0%8tfGRa#hRUVivd3TXzc;{X7>@H;L{c3nMO zXX%Q1UKaOFcDaV!l8kn#Yiq~m2U-s`7_Bh)Pvj!uvRW-nWN#lF*qGUUz;|n_GT6t> zQSoqfruw6V|6j6+PD4q_sEqXU!UF%Oz zAEWKM<2oIz=OwY39%C|Vy_i-quI#Ss?FCWH1X2}sAh<$Zj5kASZrXq{&LmqFhtWSq z_*SY7e9ZT7Kwkk}(4=>bhQ7K+uA^sM(j_xvW5uK->9WBvl+}m3^Q8R1(uf*?l%Vs6pk0i*OC`~(PCS`q}J zq#e#2TM0C0WGVl+xe`c4;^eCRrj&QM!#!`;Q+Eyh`REPqFk{acUw+PReB=mzAP+no znIDkZlz_h>0NP~|A75@sF{bvik+d^E$Zq{x7ikzE>$a2o>wE1w?(TmZ9^;otawPk`N#maruZ zlVX>*u^TmsF{z^09XNd`XTti~&-T0NQEfq5SVTkw4>vmo`a%G4{LZoP`eYaPwlRU# zhR!#JlQ<-xY#a&OZ(vbzaaN{M_O`J9Ukhmesc}Vxy)NcL>n&F8yO}-yi9GJ9i>;86 z^n23r$SfsgmZrQZxDm}Vy&}v#i6J9-8@77~5n48CXm|nFeaV|0_ha`Ui^uWy`QKCq zF-W+F1_wvPx^(pP7>^Fl!_RzmCAyb7Vc0?4@$uM$=yH)UF&@sYC*NUR=wvxDB5Ce? zw0l?QB@<{r`A}qJ$R~z}_dWWQ=3s%O1_sOHd2z}eUJ=qX6?(V}Q-PW(DJkR>1c#Ix zSxH%bn`VXv2Cbdz-p7Jpk8JGsDMzrBl>1?z<~tubl_bsMTh&cJ*5~*}4zoM6`Nh)n zhIi^l_9t=fWIKItVoXp`+J*D**sLqeF#0){bKx!k)p#@?<4RzN}s*WG>yp zEU0Ysk+aWS$vHXm)6ftc?#V^Kp{2 z+h_sM0{%vp!Oe?7g>z!4&G$gfLZZ8OsNLU`@Et+W@CuHLZm>8uHFiTE89@&+ebnOg z)HZ0c?j9!fv0!x82;V023h z^Z>;6I!IR)Yb+(|K$zpVwbxH;%jaNRM|0$jI2gh~Bs4+cl4T>L0Hg$OgfYVpp!v^< zAgbPOajV`|$J*9*wIk)I+0N3yV4~LC*0!Gd)1>Xa#)l6HO-;euQzg}8F9-8$YXpG! zq$JfsCz|{?O0ksGwxqr>V4k9Ip5xb%xnIZGbs_KfPgaOu4%9dKa`5@;8yh{`r)g+=ad0OJ28)%U z$hwzo2*{kx)XZF@LP+xRI@M|GRS?L9Vp`?jk&%9e>@{q>CijyvC|}~v4zfv;V{>ye zF>`-aUEPoU@f4l)fM{vfy0q zl$sid2vF;Yw{+u{EXTyGfn#_^G(n*Umhx?f}I$jDeeHB0O1ExMd@7&L&cu+BvCh-}R` z_xhuBhWRwAHBA5hlNS{=?(T**+DXV>!PQYi=2r>^#}IR6Dik>j;R`lYH{?=({=C3L zNFZ7d$#vpm)q^$W!*kK~wFMvFycW34($Z3CkVG}p;`|7IFzh2e{g|7JlZ%VGme%>D ziM^d&vg`R@xIyY*?8pMT{#hp}50Vsy<*rQz{(DjkkT5omm8PMiGul>4 zc~xmY1epp6*;-oCjdw=HC(E_q<)srbGckDrmKWuhah*&P9ubj(;2E*7Q$5ML(;#swcHFZ{~fuYqLG!>_7m1|$BAytuwF~cyJLZ zWWk)ZkW#TYmfyp0gIsUV^4tA;4focAgCxqo%-Pvw)lmM#rc{m)JO`8y8vhh65pCm1qk}2`GwoxNt zVPm8>Rx{L8doq+#4+&tv)9Fwhl3P67WTvONn|k~pxe6W4;Dty3ApwAynVDi5t1R+G z)w*dB0Q@8NWwrHozJ&o?QC?y$fVeX$($GPEDY4uR27{~54*#f!V|}gB)zYF2`|5`TV7FUv__L0ETHZv%#~mISxz?T~I_T8_ zh8Dn;^u3C}__7KSnS-Ndv6kG~<#IA4?YE-NyEko7&|?P^M(&j44kUo%y9kP*U1} zbA@+Bmt$4hDXeSXeF2ih%EZ0U+lO#xz)ycTQv$+VJ2e&CKg$=>sknfL=x8GbaV#_n zx{n_p?yG39QN!~p9{v;*L|fA2{9YcSbaAuyu5_V}yrM9% z`1&$3j4k_pMo>LSq1MbBa#IM}t>OB$^87&Cj2YK^-^{W`LFz_xzm>W8-ukL?vgtb( zbnz&XiLmz6aHwTfb~i8a`GfZ(fgb17{CqEZz>kNPCKPmP>U=n!j>Y_ZXiZ#eC4fqq zvADdvaefya%|Z}0`|s*{v6coWg4-!kAoVqmiN?po+VgiJG(eHexzvhJXJU~(yq;rEha^U?X49!Y^LgHtfp(MMkJ3# ze6agABwv<=Ql52J>vkU0JI>#;>8Qe3!!O*CruF^7KDV$eHs+ijFuw3}BLa>pxwy4$UL2|NC2C?3OiB-=PwD<$oZM$bPfMMZMeGx|c6>^z=Dmd9HV7 zqHbz`Z_vV)~Lf( zS=nArQ4zc>Oz3J)@SZXLTYXXUTdsh)RPD<4P8nqa`h>bV?nf0G4B^rt#wH~Q zGTih&D;yigNKOU=Z`%#lc6|0YVnV^(rN{k{2^fQFY?%Ox&v71#RhdWCCN7%2c__iuF-W6BL6=f490N~>e3aRHaP|=6&CEA{~D%0mXN=Xprtko28 zUDcQwXJ7fOLGnN>ui<#N6i}I5-Kc&Zb7)Y8va)E&D12b^ysmgpV)aMf#}vGwiTn8- z|6tInWCOL{vaU*QG|K=YAeKxtH7RL*Wkrc50bZ3D=qe43vGV&NE=q44m@+gGqnk1YlQSA1pqwyn_qSz{7bsK#y5f5p99NiCS>_F7NRfqU#FMiqV1H%Lu*XA- zSm0`YpyjqnrlyGN%*wnuNLUVjw+#Tq#3-w)%RO0eTj6P!0rAjwp*j`@XfVv-4oH3N zQZv^R$i~~;JP87sUZ|nh9lr&am#?fl1VusZ#9n99G2~mM+@`0w+EdwNI+U1r`1saA z#baGLT6T6m1MTH-w4Yttc`AbWoqyV7tdoq0jO?VR_m+pp*QnW9z~nnGD7!Q=@&X?8 z2}W<(xkyd)_1$0nVt@bsU4)OrV{2`_vx{GTbxz8&bf&Gq1aWI@Ee%CiUxk;4{_E5e zmZGWJGnSSXptUyTB8^o-Hf$p9la+e={mNWoB3$z*H|P@q+vaG+Z5o^px;+)x*s)-v zr%%m$1pt0gv5DC=`572IYG64udVPLRIQ~UjJCkqy+VhH$oSd9Sor&|}S95=`)3y=< zfXhlLD)t4sGd#mPmwIh+ak~1Ws3>B4FzcfIecl-jO)V_Dcl<@@A^WlEKyLIm5;f=2 z5n3S-FHi85Q&44a3Q~J+JC#6Wt;}Q1Y7v-xl{KD~E=|nJ)6Wr_cPjQrVT=U#AZ8Zf zfIK;D87tZt%2*i0aw~6J%9p0)&dcNP^&}~qRSUS2!WE3$+1|Fa=<~WT>GVs2moqs+ zLm;s?$gwxg&2LliwWLD-kYq)7S8jje=aY_%8!T=a_XwdM93XPF6YDU|KNeCe@mas#KiV4bAOop4q9scSAK*5Pwe&5dy4`l&bmwOlXhm4 zdVh6E+;~Hui{_}OVW{P|?{qqFZ>&q7h-o5HLZzs05z$wrfs+VNy{ZaPGN^Be8Moq! z5dq@z@=nVQ%K7;}e6-7RcDm-GeBqTgx2e*503El#f_=Dh|;<{vo(-r?Yf)fZE#b7dsJpdPAQTe*7>HJ;Gwg$8T?Qd8~wGra&N^ zaMKrMo# z$7dEU#XG9E9iFeEe#C%psQp-pin{Ttmo2{O*nXPd=}LVL=e%2-Xm^nt5XJ`vjwZ}e zN;Pd{Wbj)sJ^-qnwp%h)^L(}MAi8$6h3cD|Lak$69%Bk5G44k@he(fDxTtp@kZEz) z`mP(VPr@PIsCT|Ri0!NRqWou{c9Vi8m3p7Mad7LZNJ!g zqm;1;N%us*1*3fXLI9~ck4w^!N)BtD*c8s7r_~ybt}+KU zjh_Blua~D>*o|276;(mVCJ|yBA@sPQNLaefVCU_4I1T`NZ`Z-zMgnyIP}9+nauGxM z7dR6Xfc@Xp2B<^6#p#OGxJ=Y4V`yDc98XBPRq$L_;N`M*l2HKF#N>G+OvI5Kw#zP z2R1h|!=ex_D=Wik5qc9tAHolYw@oZ%v|MicgpO=_dT7jFV*5882L@yZ3$R=mCXqER z0U@?@X_w2Mi67Nt*RM>JHJR$$+9aij;$Wn@mmyc&J zzGj>mKKZI&W^@E|K0A^ZRGvnam$Sh7dL{_7hWoBNzA`ndCx4=w-mg3$|97KW4{6Et zoN|c6Z&_OE57z*M;l|&->OJ!i=crUwF@Vd;&fFV1awNi;n9Gv2l3yEhHYqC*H0S4; z5_XU|iDzX>Y7q!cw11(%n%&d!<8!)EEbxdju2p6;{D(B=Q# zH`9ibGpbpr7%3&BLnr{I6F3*L(i|z70+Ls*41GPCdrZZcVts Qd#(U^85QYDNzF(G4eLX!IZ2BNt9fOg<{+x6YCiqB06jG%qBA2RW(C`YAcz3Ol{tPQAm~&_!|2>M|EQ_< zbq4Dof#VlH+St2C+vmKgmzgN1M`IU}28+OcN^79~O!lEa`9%?fm_}T(v>N{MS%3O! z{kiP|6f;8N>1`YB8E>%k)@DUAxt&huI)x&8)Wt02Uy#Esz+p}TC@M6@fu`>dufDgLB9Rm zmJp!5(#M8fQqL4eG%=@zn#G+i7lE!)xv;11uE!B$1^Ca|)wZ8DH4v~hE(r!0hTOzK zb#Mr~J1pWr_g{QEtsIZrbGl_hrm#`WSNl=?wsEq^0P59lbAfdJNQ>s0V|+L_slSB>f=Xf2xO5%Zzj0XmkM-rBmBX z7JBH0FCxXD$&`VN5#_cu!iJqSbU@(c9gi6khK02t)*I0G>x|@lxkG_v;sco&RZ7%8 z(Bi$+`MIF*!7oJk#fv9(shtV8tr-$o6RqQa5g;xqYN`o=BoWQV9|cT3m_Jrb>TYWD zzQ&P;{@pyNF>2Jls-Hm^P{`wUWbfzWywFfrr=Kb9RnpVTbh)CAY80)#0~YU2t;bH- zfxZkx!2xj9mJ^y@UmDS(GO2LbZ@>_gtOB?v%KdNVrLQ+{xr(|vI#HP=FUkHp6DwxK zih|5XBZEaGQTrQzt>#-=?#>e!NK?j$h=>Nq7_8WAEK4gI8&j+f;~cok)mk7n7pyX# zGpKv>KbkYG4hhz2ib@WK7FLK_Y>AH|If4!;zz-`enMs;33;@ zQ>bLBMTDqXlP2HZ5;3?|mXt;r>F73I``)bcQ$jvcyL))#O3Q7$z6GowZ%}SV$zq4C zY9%ODDhqF&rN7o|_wHf<`;*C@*Xt%do8Dt&*HCNk6inH z1`H1uR8(Y+qVT#nu8AOM>ts4^VsL|1Ge!EkGFm)3`AWnLAf80eKhv6s;a0s!Q4y_EV4n1#>E-)2q%D~%ngjGim(^W8dn#zFGMp0Q?+y7rhc|}w#Sjp7A_at~aw`aGB`cgkC#0t8I;D6On)g3Woi6RCt87Wn& z|492Rn)$8DlcPEr&TDTEtE5D~xq-*vs8&nsCQ8#{Y=7zE`l^&I8|nxVYb;;-=Mfx+;a zHF`IhT&ULNfwvC_v3C0I110yLKgaO#4X5MAfC4N1e9ts^c~35S`J>U3xp?(J9X)<4 zx(NBd7BzGUWbx%$?FXGZVnBzimMKwb4Gnn=mQGxD=9MZmxD~qJS=rfpez|w^%Ippk z!NQ7rcyLT96uQ~Ex?1$+mySpv_~%^u3mebu-A-Jc*9@MV_5G~_RY-2%zdD_7ZyZkB z*qr2I)pwM{AC`Xi2yDE|KCB_S8}H^H;T+rJBVH2UwxZ;if4yNe`08M8?R>l`ZBkD* zg9v!yMJBXt)HX?CVxttI*){A+jYsFn%g*#8ljjt&wMv~t$uqX2Blo!-9+qeXeIfAV zW9(&O{ysE0S>9aio}MwbT%R18QhF~zB7&f%l7AS0r8H{x)5vON{TW_h&a1Ai&60F+zG$@D*;S@4@OC4|Q|7`t z6a5(CChO}vohA+L{>sW~dWNTVX`6KCskUirKZc`nFr8IgI>PbwGj#%<*xJyfHCQwh1Eal(<>5J|jZ5 zx$4^0I7h>h!4|k-2LrPaBUV*aLB>HY_0H!d<{Fw9GdLr@o$kv2zROwa-^I_zzmCUs z&KwY%mNt|E2Okt5Yoa2ftXz&?4jMl{*uy!#TZ|`;uV><7^#B=v7MB@B$GmN{N9eO{r2#gA7*_CvIAwE|}e0 zws@W`QKNmlf4s{)CI1{Ux;UIHci!$vKmdXyff$NQBElFu6R$}oFO?Q=vm<>5?XMr< z9yyWR-x^x*>+c873@}IRS24V~IEKOFCRhEvs^zKdCoT3Xcfv~#YKvlnpMnA=(<-$M z^Im$PmRxJTcPwXVVPj|P;IV%irfm#rIeU=eq&W&u>H~vCT9+)1nPby$)5${%-s%Nu zD7WWeB)JIhmYEgA#WTOGLDqCT3rsx3hX}bI#E%1OuyKI=H|{Uqi4d*RQhWmdaYB~& z-iy;&4rwUWqZ|`EvrN0&Y_#_q;k4gAFNKVKx5Jg0b(k+%J z>}_p=V-*iCybAh?^c6mHPVi(DzEkM|;J;Kwgyxyh_nuN`SoeJ#8EiSgXw{%7pxUuBIX@ zYpe9THZ2V{Lk=|y>zLfx&f5C*c(8oIk#VibIE*+VZtkc@08=h@Xr$-qZfW&f&jzu8 zz>YJ|`k+|XUQVlJH=YXv_t{J#9QhOyv&ZcwgXKD@4dW*&jN3wWSC$Mr8ym60*>Mo9 zj*hQjU5PF@h4!nvJKB*On2B{Re0UfPet$D3=ThJ#anR6KrvTE9n$2G1^_wgvt z%#Q!__SCmhj4uYMqmOfisDu zbS-g^<|vFDH4Sgl|NF<4BU8-5J{A?;tLO1*67uo$R~ne&GPMc;RdXoP2o$uOtvQ6M zO8_H6M>nmOD?jo!!Usw+kkS9wSPvt0r$XAX_GTixQy){6YO&9T;(rpU&Lw#d6qfd= zNWpZo2;=l}slTKtXrl>U9|8Xu$qy`&5;`$~lZ0%Wp-bf|?4!HfoH4l%R9)|u7v~`b zTo+tHf}pbvXGSN+YnSYy=)-gkgQ3vu2QZnmHP$6;Y#Fo0pqhMzM{)+Z>BucxhuS`; zJd@Kovf!aVrYwm|<(mzYh+48y?6{FweCtj;Z0b&Y=Y~hyPJWcBVhuJg@#e)v-m2xj zM|RF;z?y%2=a8rA)w-4+r^jF*CpNoQ0N0Fj!H(GdD<;wM2VNui(;%Wc7>_@w{{@Xs z<3R>828mLXVp)Xi%|S!*j2gvMsX;fu6%X=2>}(m93pWvIp}X-Fv$ETmC(CKCPXn9l zn`@)R-{PNL?cOKHK%j=fi{Esg2v0caCdkd-a~@`L>qXq&T)p|Ej^kODQX^|}%jqx5mtEhCjG}3s^d9q7ROXQ(u~#lg=`_~Y zv|K)Y;UzS&YPD;9G%pL*WPm?#(Cl> zPe_6XDU704)U*RX*jQ@bhmInMs)9B|#U05ZziX)NVU?_n}&=mh$HT~$vmlgY8(nB){2 z(;!FIOl(Fu>QFu+l2$L_r?6vLc-eS`s04jB#<+6;o;D(~(ydN)2#TtK^ZDUODc7%s zGWDuR6a*zZy_6j{9?!FtO$V0RKy&pVk@)?qHNNouU+0~kOM6vP^46azH7Gr=l z=pwr;8ME%39{YOc4gtar0exwVwrS%+qOLI_44aoAyR6B(zKz!^sU~N6R8aKco5V}n zy3#R;<+P@T{~H8Cz?yO!R!p*B@GL=U_DZ{gJRld9@c8r;7k!f!if%7;$%^Rwj3j&b zj81|!($H9PG-To|V%MZVpyPKMYMY)K=u%Vlf=p(1$yyVYv}49{w7I#tZdyM-Z;-||1?8U!Uzb^nDXahBsovZ$NvIzBBPnMtUT6%t>h4(iJ zBER?DRcEb}AR`9cqwAzTTS382n6+6+&N2f2& z1mEIoE_y$G@Gvks$e$qcQl7STt=*%^vHk005wz^jJpJ~@TO1Pw&TYg*Ya+WSF552 z)SD$K5M(BC9NgE|YQn+&_U7YESl<9y#W^T0SFgyBemc|Tj0oprPGIo$)AR_Yb&KMH?K^s!7DoS6 z%5>S!f9`YU=IB?kU8O*f+)W4CG&Hf}?7lY^SpTrS(_U)~XIp37Ge;ksaj?14ZD~FH za`ZH4Q0ab=PoB~a^B;E~K7Q665yO~N7VANnnMmY}*+xdzfk4H1Bjfig>u}@6D!q+f zb~5;ASu?uZl9e2h>SYblu%<0AXUn3^lNA zbAYBaTf)Ja1|bJJ2mO(YG6$88lODJb>z1+vYp8PJ3=Z^1gmj zD7wq;LG$%9gcAF|Dr)_|$3SAd&cJ$4DkJ$E>&-wH1*srPA&rleRb+H+#50;Zquc9E5hCxdF4)@n7 zk{KD|*qCPyB|O<;q(bG{#7(a&glF30VE*|M}2}a8qrzglW>Rc9@R}~$rbkS?~%_1^ovPvABM{2xbdcU!bqiDR6c%-Tw9zuqYQV| zn)prnPBN@w-Gm$de7#-#I(G#=KKT!)LU?$b$iY@Ou*VRo@_{N{Rt_++!6B`n zZWa}`ccA*?{L1k9Gpdh{kg{=K^fk-H^zO>(oqgv$hheuu>`jyyc^WV+6?^h7HE7K4 z@fKvi&f;w}y@Q20WcWVY!30MHU@~d62WzZ=7e4^JAVUWf-h>4}#X!Gj{xk{M)ZgdT z>W{F1ApJNLv9R7{x8V~c9B3kHgYM+9cG3`i!N|RD;{7`Viik2m2q^Qoy+0ixDRFs% zAug!b?V&>+&}Zb}sjj-yDcM6&RUq|7JzZlub5)mV-?FK$$>Fwb{AvZcaVC7PV|cyf zZ--7+p#RwN>*u|_cZ1HSBXa~1ojRvDm2xT_($nEShpnz{w)#V%v-L3KLshUV(-j(vm-xd5NX?SotcvI~O0hquX1sRjMP$03q%SQX#Pw`U7h zHs|vMo%ab@$zQ@2Xf^2#ySCl~zW#B=4e9AHu?Dr;TM{tBC5w=a2b(`g>3L3!kbWjJQ0 z$q1pf0?ZdCj`zNj2~wYe1?lvzpT%VZ8hxn&|BAVX<}kzw6p48kef-y}Ml=-yPcvUM z^lg!tzjA)gcmeKtX&FA+G%gswZ|;HKn#>+m^Zd#y)-#_qcLn+Mp_q) zRXamFE*x*KXQ825A;yto$kY|aQ|Iy7`h9HHx{^ytrkiDK;2ia52%KqO6CproKUJ-D zwcFb=O{MyXM9prsn=?{wYC7d3U^|rgsC-P1g8=Z)rQIeWucCsxYT<~t)3?*d+zy+y z&XOmGN*XgJ1;a_RKG-T?_iezP6U^&tcAc}pj?ANv=QE)R|cLW_*VMPSHJ+XpthQw#ei6>bU9sTcNBJB zBVXE^bkY>a-Db#brk9>08hf*niYrXcc)hdZ9=D!D?|7J$%DGIjY^87nC%ac?|85FYXV5iH#=M8!MpX1keA zM`&uD73(!5dYm8rqc0plOVZAPb4rmRB8(HyFVGG*90euIOOJyYA@JL`LGz+g!silV zg%c{lYFhND&2laFVP2N#9@Y8^AxbK+e?we6Mg%6MS$*0LHf_MO?+Pm$N@%6-@8eCVfPZd0lNLzIPtwQ6 zyQilf@PMG>cK)lLvajQZWpiQ1)%Is`z?$6yivu%h^iO#8EA-eWm-;FerBk_%7pDqX zG1m>Oh5^Qt&jg&XmwpF`N@c0_?0P@aOd5F|?g2*9+T~+*0^a*I-#x56!6bKnuL?sI zoRtp0p^{h5ds$E?gP`fSf*Fx0VXuJdqwD6{ANSeZo2kj!gF6i{UQ~sLUG0sS+o2DH zeT_}y7Ec{e;}sPZ>AKhkrItpCM_oxKG{+HCf7M~Ufl{T?(TYwfM- zc?!O_QuRub^XSzPP7Pq=<^}vIrlm)$@5g&=_nxgXPO-l45rz582P&MkYCWy;@$r7F zWE42?=!8ZBs2O{CTA=+s?dDaq~qeL zzrDcCSg<)+H~Q0l*6dIWZF+(*W}g|GQj7cgz??oD;U06h6HBFK|e;N`dNr7{kb zs=ar6P*+e9He-pHRH_ylz#N#r(-nC_n+&N&}xDplZ>vh-21P3GjCB%8O z_XC)sS&Ku`l0*CS&A2#m>?4(I$wF)%YXQP`D`2RERq0c^t1Z%eZ#@gfP+T>TTJ2TJ z!o&3WU)Lj-pfPTVn(fPvURBY762v`U@4LCWv9D!#V2XxL{}|Ag+nv>X07^g+3?TMw zJ_L?Fhz#wb`nPZh+}R9XDAE59kM#st4>U-7Js$(F0ZrS=3cp?EC6gUo&M$OoG4!HN zP2zvtE5^t^Rit1Oq9YO|Xh=`F;xj-9rlkI+6g+BAv_2Iz5E2}$l9HnI^(YC_X9;?9 zn*L=jQJ;faD$TiNy*U5(UmIPLa=t3)t5}ZW7e5Zc?>ZY`TcQqIEolUDsTc~?;N5Ee zni)jnZ>qtesu<{Bl|3N3v7QjXS*}FB((K%j*cf%?5O`)qG?nxeVL6}XX?%LIBuX3r zXkGO`w%a-PhwrYV{XwUtYykB|002j)|LS@7q-HJVjvslF)SmgbV(~`)Z$>P-0PT#1MxA>z6$hJl6m3X2y%_uGcUl@PZk%t00Dyg7#qlJ) z2M8fx(CbohS&AXzfOEr9+lO1JNylmIU98r*auTS zC8=^l1IL8!#P2VECL8GoxyqhZ8))7@)9(_ge#a*SdR@2P1-F>!n@K*F2)AzCgHme4Df0t>4YU5renPnxl|X6g4D`*jA|}%qHma zzSTi+21S#PQ^)vlISkT@9{>~SxwehG9QLd9DfhJM$Gw3)d#{Q;xb-WMm=T{T8IJ&f zvjg4L>DG^c@x@vpB{x23PycsBn6uWFw`JA_uji zBHHH?0ASWqKF#pL0qi;a`)|&g+h`F{CX4S6=Bd)rBHWfB&zkFp>R%4xmYZXYXkpWsQn%m`W}Ks@b-@-f;0&=jS*GQrP7x#bzkBp3 zAlewlXsz$-n`eUC$$FCL`q!?0nsz^g1pDy%opkHt13z8B!1n)13RDm9>9J}5lM_@I z#>i34iHOdsB(u)VW!CDWoq8+fKkX3^NZ374bLWk~0^Ho5uaWfmS&#=F^tzI#cka-B z>|;$&O{I&FCpk2Ep7VRnJ9wfWpkhhg7-~mL9*0y|?}crIG(c#f_H}y+uP%nOhJT;y z0+x)LwP!9|hAVcU%UTQ+{iU5f61$C?#-sD;RYyOCGi#sF{YU3B1*U1FvjB79j;TK`%avuT!Rl9Jq_pVeEB7VmH84#xlXxd6(|E zvXD9oqmi3GAR{&mtUpGC$rduBG~g8q+V7d_^}Az4h8LpBO$A-Zy($9(eBD7nH&Y!b zcZfY|2Luskbh%9b{F9r*0CXR`m!8_IyQB(XWQ;dn{#zF{GBo`oc_cq9d>GM`LEk!m zPQ-Hm0P5j3Uk_Q42M~Zto@u8#n!5fVtz1;scGN(nG>vrWrsvz7qMItgx+eeD3px1? zW4L35DlZ>yfVMsJQG(#Yn313F^Y_@f zTd{WYK_1YmLMZrHmmwFYad3B7InICKxaM{{cvO)&;Mo2AfjhEF#rBFD2dJu{B32lN z5hAo1RPg^yI{<(*IM31l3+*Uaz>~9R1iAr&Xz9H?^l&ldA3~l!n5!N3b8U$shB{vX z@V<7CHGgn5HeN%Nmq;U)(|cm_VF@x_ry*1OK|h#_-1%YI6 z7-{fM^73M8ePfAe_}9P6u;)m`kUC_W7CZs~%^LSX@0IW64Z3z7Apg>L2n_gAN+VV4 zQ2xCX%c5N(X8=FjO(M-8oAJs)+PH22*81w{!{qXCNB!1@vgrW7z?DNsfIJOF>eO{u z8YV$hqdMY%PoOa*MJ$=;;3{}PQeo80UyLY7SMjAaH=TYlmmylz2#R!>9A>i&xbI6U5w*Z3N^B*e|5~kNb&Ajkg{~BP%A3C5nxC~XPUU&Vyc;-RN zp1Hz$J*OfzOs49h(htoPoQg}QSI*nd z<}_98q>jCiM)D=S$oZoDjo^W9)uKUWUy6cU+hIcgK@KqlGvM~(xoY57q|{;u+TvU~ z@=7zqNnIEwL55D^mRoFti5D!Ec(}0r>l9Dxsy*(!IrhPj1*J}GN&0--%JfvDt{sFo zzAt;dH@VUGM6owIcK79plR%E@rU>q3v?Z61av9}^I$2*|`|QMv-uH~ybKcwO#TE}h z(2&i-@omDMG*ZbyQM9-}OmuZ;#Uyr&=Yf;2Wx~MEQllq$EQL~9#Y}cn9|sAaXqD=> z-57hS#&1EE$OAl`zV1FD2d~1Ct#r%+9u@%xzbN&~7ai8s&t6MHhfLHf*ydbIvE@Kx z*~ujf1OiWfCznhw7(-~+-=e=aHZqr1R=;IBLe|cikdHBnw_^(k4fuK+k0f620)1MK zj-D2v5J2W9Ww+B08LGTWzKxR=dO~~!5X}@jvXw8xj&DD_!$vd)5>(vM?d4GEtd~A_ z+jep^stcCMXJv4kdw7^Aj3O2k4lE9c^>x#%8MKr|k zJw`yrB!i2ibR~9c*rYK+4%za>hcjL%`57_Rt)lqQL%Z)E7QuXq8Zl{+S7a%OWXh!U zl^HkUB`Kjmj{|h>w6^jIf<72)q8q!<>-mx#GHT3MVywg~P=yfvAph6uiyKC8I%FUK zlkJl@1$hQ)*3J}FSzgC~r!P^n31}Wl(8p#BF?6NO^ykOVpFbZbA@!sF-;Q(mkag%v zyxgBmp8J<~7Z<6Il%J9T#)u+8b!-ixzoph|u|ZSi(=CW)uB?yuzd6Bs4&&!|iHQe~Sbku}USG)KTv9q_E z8l}Hf_}m@~1Tts&+fe1|WBwd}5fLs#ewUD=lT_Ph(y9%-DhhnWVnjC^9L}-V%yf7w z|HDM*DML<+F1T9b7AI9nX`-fM&j7SAx-P{U_=x^l2*KOGAZFzAh;s&=eDyg8{_|nO ziA=JbF%vF*^_g3rdsx^NWz-dr!O*!q{IG%dFNG_#JT`BUFdvDE;uIHonB;A9;AqzD z2MT-XiN`6wP_gkwRWLj#8s_6DGI#bAJ?|YGn|@L44J|3@?hl2XToJcF5|9V9~TtYw_MA zEJD7$d$U`g79!UgP*&!k#GI`RoCoeoVvwNyZ1MK)8~qUvIaDc2<7RhX5$??6+I7t6 z#eQgDj&c`1{L;rWr`q@aFUo8t;kPHF1yeuN42_t9E1A7Jum(%Du-yKXV64o^5Cfzz zPwu)YJnZUD!(sPI&5FyZ=l#x?CkMDE*&jBv~udx*6Y@GLT!zAXQ}2%rEsI= zUT@vgn3pr1NLi=k&Bk+9CEC&hD-A;6%{1fQzJ&>{MdJ#ZzrWoXF9AZo?7fdIKTB(3 z@OteKFC1s6t7KP9Oza{A@2GKA{ipzz^?Fy`kYq)tJ#W%tI+IzxaN*vnNjge3*Y6=8 zq^TpY+_dMm-X8kU#_f3kE&1)UXa&ux0_nA@&X3r2s~T?SBgSPD@^~7LVu<2!7%dei zrR0;ctN3{prt|ftc4&e1S`$+>xk7}2cSn*dc8ii(y?n~LdB2iVsi!Lhmk!<9AB?-a z8RqMhG`r$8%-)dg-UGN#Gx%|92DDpvp7Dqj-MB|W%zM4~^OcapH_9Y) z{I}-uOK-}2Ow`Urtq)uJkdN~!Fl}?`Ksq_P#Db{nFZ7qi_%<3|f<4iQmi?~9)J;Xz zO$TN`IL}oneATvZO*&MvH$(;d`-^j%{)$U_OBGmqiu~=tLnb!OPydWO4hro>suStdfqJR>!3+lTM)SF+*;CMrA4@z*FPJaKRxv9aPAE26~Hw!S}B-N6+%D8BeTd3j_=7A#*x zzHwjsn6H*#j_}5XbE2KjA>RUbcW0L#cWRcoq|N4iCDE3?>jo-$_P84f3Wl<(%9NyC z_=Yagu4eM6&)Xu?P#aFV)VaX`v zlc1NS?9L2e_4Ns3$21q6CT%CDNvM*f;5|H;g2p0Nki|U~^(hq%eM`Nr#w%bVzKA3U zG{g>>%=m9I964yPNQc+kanPoM_ya1YJj27+&f^u_gSp}f^9leeJ=$o!o9WHtxcJ?-sj=Wia;_qLOp@}Z3}w|$kh?@zZ*hVKADK4eQK zomHsHqMt8JnKSx?g|WK^>uLl48@P&~su@BduJ7aN+ znD3KuUHVW@K7c(&Gnrnn(vDSY0_xs-Apgu1P72W&M;UZP^Zb6GkR;i`VX*lg#6X%5 z5xzzo+&1sme6DBOLr%>p8*ZGwzSX2-AHu2aQ_1bWZ&S%4pP3Czd7RjxUGi_U&dv?= zfsw;@U2dq?l8d+i3&-qjCusI8w>ug+p_4Va93^*_(t72u{S;=!Ux7W8@NvJNYQ_RB zY0x>&*`SNq(vFf%S9W^NLRu3i_mEBCW-TL$r1od_-N1TgHo+fjOW7mG+}hXAXRINd zH|i+&MmNO^X7$-N?bj9y0^J#MCz-R~ie17ILG0<&#yW)s(4rhVNrcyt4(L>dU2A{- ze9PmAe-6AVhiUb-YQr8mk_6U9lOiOH>=3&o^o(x~pWVg!C**zFTMw`~7pUfD=>vVm z+&aCLz!XOJ3&7P6`n0v>6OyDyaPK3y+2gw&k=65fH(2uu|Ne6B!-u|fJerYHhG2XZ z>`g}2cPlQnzV3VX5;om>0bQK4vyo9T3pL8lb%rzDdf|>zl@hF7NFn;%|2nyBr{Sc8 z4q=EB)C&mQIrw^nE;29T>pQ#g|&gxtsC4#hIpr(|ahfdF)C4NO#coHCS^D-%-RrUAxZ`+=J(@CIa;3Ky< zPw3wySu>rv0%}VgoORxWA(Jnk>TS#)hZEj;)PE^h6gf?SISuo(9*XUH_YEy#W2gcj z>x0q{X&UsrCr=s175Scg9b#_$#cbHv_J-Ce0lgDZl6;#dmkH?n6cA^Wc3>h zoK(6l$=vUv2>dN3M< zLebRbV=FKs&ujiPcf+XQg2)X?xoZFqck0i1q#Hs$YPUfA^z_#e)zTqtZid#*&e~~F zbeoiVrC-u3o(Ie3mv=G~A(RNIS}|P87up$CEvAWgy_MEv|sgg8oYdPKO<52&fIxMXFQp#_cPfxBT7O7v?=L%;u&INZNKJu@x z9G$Nd_i+rsm`Rg$e*G^vm}hS7DkA!XTefIzn}~T| z(*bR1biQhLlqnUmp4L2pPaq~AmaFjQN+M0+;U|yEzst&CXUe_8S0v1GqINVR)Ozab zpS5)8Z0~n!mD7MGZ_o!X7gIdC9h?;$aw*HFZRkOhx}>0&wtZcjcbVRG4XSC(8`w`< z{ykPnkt4c|mcTKaFE_C2)9=i|1Ujo=lLj3Xv4VnfZPfcjO7iQB$FLtETY_lMa~)#L z^!!wdR?LcuGTtpt#*TsSfkb)P)@O%Gnk3~b-S_B_`y+q?UW11|Vv-@*9NQ923Pb$6)ZbDpj~g*ITkgzf!_1#qD7AdszU$KW-i`VwVL#_%*FgA{^y}m?1Npo z%7HC5T)BZ-*f3WUQ!xnSptnXK9{oq)Z!QXbpJTPxql;1ha?P5i`jx7|K`#RuAZcVt z38=QK<5z>PMT~m6T5+i?Y_JpINN0!7X2AVx_>ExV#m~PP9pSf4W=S+GG?Dhr;5&8y zn?A|BnO3Jx8Jd$>_tKRh1sOfcow*flgM~?KY)9ONTGEJOe+CwThIC znpZ|1b(xQckoI`=86pO_OO7r06O?IyAR{CHR~XZzX`=^+KO9qrS;8+D;$1>kP3hHB z_15OwUV2=H=6@4zW08>w8Uf$_IpN`!5D;c*WcNiLAU&P6IKP4IW=DQabF8J2`8z-| zRZFL5%@GEeqRgTV9E&_MVwLS;5nw;Ld2Rx}=`l!BMjsw3CA@@y48>Ky&34EhNMgN~ z7{Pz|z})A&z3f26>U91BpQCW#b@n!M%W4#nzytGBC`Aev+v!@ZTW6hrOzQsTqY-=^ z%(A@B@|RH0N!yFRmhVep@@u-nLPA0>J|Cc8eK-Yp0CGZYl&8M67z{dRHMx}B002B0 z!?1Htn6uC=s|AG=R~Qx{ApRfHu9F4%av=$#`!gU>>ls zr!7*56ac8=Sbd8gm;}~tk9dodqDRMk{(OVeCi};T?QEm7R}y?7c%$)8kwM!oX0;_NN9$InG|J9MjnGU?V zU%kYzAUS)x-QhR)I{JVf^+oL7`BC$epj`Rfzv6Nm$aQeLcJgsb>3Bsv+^0{wlR5O7 zW#N0#%jt)u9D;sl5mO0wr-Dn%Y!p9CgdIHQiZvRC$Q5KBhQR7D11upklnOFlZDx>+ zMigIxTB~*+dg!7nnZbkpE39Br2J#bTR)BD!@-uwIceCq8-9S8aq1En-n81ZR#n^<& z*kJ{JPh0U_9t+)vI*V#HKzpFj1vghPMuSRFo0b< zt?X=|hN1VypG$1gCT*1%fXUCjHFEDwYC9<+6 zTzq=xE_jixKV>KFYk41~YWektyY?PXCr7~Yjt(GnJRt@IHP=?D)Tp7Lg6=d4OA^Oc zv@uR`Fu3`-nR7?>J_67`aX-rI@6F&hORO%;Ev-}Uxh%g?%pD1DQzp@Hz#(B_ePKX& zZ78|(k<_eh>a9Aa2~ohIrv8_QYPX>kTwnzmQ*DE>k-1Jp1^k`)yEyX~4nX7Mz@H?B zugC)s+MP(xk0;1;cvqtC+=K2LWyEqPZ|+R6f=gRE)~U&Lh|f!rL;U>_kbF>jZ+O=3 zw9A_#=jt=<9O7fPAMEzRRV!jz>Pqpj2@G`Ikx8hs{RfrkT)Hqb-jx?W&BKBXPV^!P zUkLB-fG&|XyEGl&N0-&*lRo@`4eDjsPk+;qB`iJjIzK@Ratz;vXaqkIT9udeDvsrh{r0B9UK##6Zx;nGT*;$@64I2yQB=JSonZXrTt0%zjX`l!GePbBxV7s)M@QwlAl88T{@;C8qu5Ttuv$HS6}V({ z)AJkYe3P+WtY3xYeF{gUOO&sPzbCq*=n1Yyb4EN#Z@UB+7LpefmMkrChDAj5yv#P9 z$ZGscbNczw@ONGNfs&Qlk8=RqkA*EKavJdB#?113a!v*_t-Ks12E9hsm>F@7nQ+Uw zo~WdzVgU^UEd}I=nxp%sl|O)7@dcoU?{0?zlql3$AHk-}B$@bc-F;H6Fj)P6WoIZ2r?nTZLq55`a~U)Hv_<5QOP$ZC?N&1@S^Kw_cD5ogG?6;f#arh^8htH&-pHm0yMr}rV)k#v+RLE}oVK4rX zHH@*$b6KO;S`!B;WTV)9eS_Z?hYeB~on|8Ii4$%YbvJUJD@B>8zRDC1>C!eQ6g6bg=R`MhktwjSvwWQp^-$d$t(h=nu1o8C~LgyRXZM-3ok&e_f`e~B47-qXAOk;T2M->RFCA2}q~Ajk;dwZ^FRwVRdvPCPm*LWd-8QsXF^TDwF^LINN7qD5Lo8?+=p%UAvZ_r+>`-Ip20dc-hQ-rc z5HXv#ij|bl_c15cXdHY3yk%h2c*BOM6N%%ILvx%vDyELmWh|tcC>2wz8ijr%JkE_| z45uAQ&M`n#3U05xO>&4fo=LRvl=jBaGKPM26q!OV zwPIIF%wpn6%+kEHj` z;SgC@zangh8iT4lD(|{XmUH-+Gaay2eea;pwk@9ZHE=^KaQuo``)GTgHuz%t?5v35 zFUD)n1?-scyEwOIBNcIw?uAVbx&0Zx3-KpheYVJ2}Q6r7VQO(3wqe^4j7wf$!VSY~Z5nS2N>+O`lM5_5dS{QdZ zt(o$PeW7de@A?FWUzRfd(w4{k?2rBzQO5GJpvxMQ3d0-B5b*;F(&uaOx!x68;ZGj3 zd&f~Nx^5iH>yLh8H2s>vRmOky%%J@@suGEv@y9bb_%QDPzwi|U`Aaj09S)aAKco-rt|x7S>~p%3eD zI=xKs1fqA?pWepv4)_P-JJV>)eu97Zj|L5TZuN~F6{yY%F3kgBYByza^v9=YXT-YPxkWRh)ODN2e?@6ZRNQwCYt?=M z1~IgG7*nC4hX~ZJ+w=G({_Oav-8-&GQIjS67WEl32 zMGrzi>XLb9y{cV8_&*4vop@34p$g?3D>E z=(+BG-=|u-^A$Xfi$g|u4eGLkomL5~2HY_R<>(^3{?%0SlQTG^6#-pl=B)j}zu@Va zCUN1Kv)kRUk&}pUiB0GD$J3tUDdd?(Quz}J%pC+mB0hGFs%rA+S7g!UP*QSAzkRmb z7-%99&f-2_P()>-#RmN}qzbm%5R+xYKWU>)UJv%Ta-j11{gYjHFQUIQr%Bmh2aHG| z(hwmzFl|?7@S>(|ys@Wz+(3tzz3)3y#+_*_Q2jCt`VYSG%tJ=_ZQ|9Dl}trWoC0MH zBK7VuJ83dI8UC!8BIP>Ap!#$%_9;P`E$;GnJF(8kimJW>x= z-wsCAzN;Vzm zxNQ&!5I6M}y_2Hedg?rXxO!-nm3f!VpYGGO&%jkzNro{IUF?iWJ(`^t$M#a^~X{ zpA+NwAm)lggS?^m;@)U_owrx6fTzqajSTIe(z!!-tBKd3f^j7vZh07H-cy*{tab?Q zGegbHfzZ7INy)0Hs>JWRHiJM25-LHOy1sQX&?&E*Yfrd*Gik%ipod?QfIMw%LN{1i zIvfq$Sy9@)J~hX3%2EDt_~%UD5DG9D)>uCG^){>?u-t7zf)a?~W(~r;Yax`u!bWrD zT3RM{qN@R}uC+eIX|bQkxM}zOTi}n!N}V!K{WTnWH1}ylu)jNPeC~eXNfh^6{PhVU zpLE~eZwPyR!;#8m_&t3jmE68DcY0rDC0E?;k$>*i$sc!OHF;UWZl5?qtj!{ zoaM|v$wMr%=G7}6`Y_i&4m3KTE`WW0gE1N%-xW!+D3Br!S|r3LiE4S-i!l9CUMlhl z9+*F5`4$A&tI^vFfJ#4YL*!8|N{8gfpt?`832O?xKxY!89-pevHqOUc9hk;`UbcI^AD8~a%cP0z9E z^^^)ha)ylY5`lB&^0h+;5>mMz)qL)}mItze!F?Bn!}CNGb~GAni7TqU@GpDTdN24$tQ>CLzwV1*-xCip`_R ze=C|8N8yn@sHUl|l4BDDo{mGph);I1K9pey{nvHY0I>L_+?v)D5RG5QVzEjj8v$76 zcWgfYOc^23kSe~W9PNNWwTxSJ-LPz%t+bk!Baf7ubI}c4x?D%G8t2cj_)D(pe?_j1 zbB}E&zRfVPbxl4_&iIE-POsmb^Hx3S(>7;YG5gZ_8f5PoLh~F?$$;4mqqA*&zCKzJ zGS0-pv*pT^P3W&l-+`VP^{h{@9C7f-s$lrv$0$G3{0Gr5H(BwN%~`>5h?ccZ(j<{y zfrJ$Ku~87HL#kmOJKx=ztr}Kdm*Tb|yk^u39p%ejYQH6xYtF0^XP!Ir_~@)$-ni6s zf}~dR$JG`pu<>{JSL{*x9|VcT$|y5~;;i|YJhj1<+>J7|lG`ASuMegZXI>&gX)ol@Q(X#W5-LdxBGli%c1w!=Ft)+434dF($?mw%s0hIicPv z$5ME#pD?koyl(6sW(@h?fWm(>;-}U;-9aD3s)%2N?m5nv%tVB6rPJ(`t^Amm+IznI zPdu*x693=8^TI2d)yZ+-h|_U2)Jq(F0h+R=5*Hv5RCBwOx!5wWNYbov$iVfy^y`cg z<9v{oI#a5RW%?E9UaJiGJp(V-uqLa*NVO1zeEOXYuVP>64>qP>tn(E_9|D;R;os=| zRF_5Z(kt>joDD>r3(l;B<{bqdPsZvL=JZB3Z6*GhM79WF#Ym+NvEs^9F$LKuUr2_k z8LLg!&6T4H8u6`aowSxN+Hg&bjBiJn&U~ONPltu+KXjDv5GK%4UrbH&UetU5GAcB5 zzMr>J%$oC#4p1^i3g?c;@D+Rd@LSi&#q;;ZhvJbjU`wX}p?^CMoIR#<=)|YLs~(0W zk#sed!D|5Nwuwh3u#}$$3V?k7(&=}n(X0_za$hjAcZoyva-!yqdE`cBQz15~m$-hY z$nqmC;^)D|NQSV9L6t%?vxQDNr;arj-o!97X7O|W*@~4d1xVca1A$^KwV)BM=TnhO z^Oruq8<)a)%lKWF^5CmZ;kU4ka!q@#el&y#CR?3i$-y15cAru$Xiy`*;xP}gV?C`V zEi!EJH1or6M@3X+ua(LwGlO$#=nfPH^WI>wu1nuHiZ46GHg-N?g^2mfu zI9mR2?7?#Qss$z9um-|HQ8YE9k6}`@%(Bj@^O$dY%o|nX(QkHcUQX7~)U%oMyVcgk}<*a%ydwXw& z<8g<6Xso;uPFPrSNeNamCYE#_H8b_Ocjp1Yby(19hlpqEL&K!H6vKu3%@ao2k^fnH z6g^TfeBE7zKy{!TTw1X+UyrD*iua$oOd*$$Z?auyu1ad+l$e7!7^X;zue`pH{lB~B!OhH;Iw7UphISiz^9}x-NCEvCZp`Jv#YxjyFqW#4k^qrOP@dZ zk3)7==q!ei#HkNayqBs4196C%(t_jq#S4KOP6>Ha)2LjCrPSHB{hif@zQ6yCZX2l> zRk-&{h&Mj>tqq%UqN44MjKu1*7WJ9m+(rA7UN@!m5-1VZ&CaKQi;V+1yEz>eOwN-= z0779z{bPVHiS6^&RvDDS;B;F z1ASazmG} z#nbOJxdNOOw;5szx^iJ_%WJbsew#d=(`&RvbdGm7x8DV74cAl_4#fgQ{Q@Z$p?E9v z>>FA{CpxXZw+EeMJgUl?`x4|InV3>G&eu{ilZh9>VPQ0_LARA=%W|htLPAI5PBZ5d#=45LQ zUac=)4u{JCLLuDCHhzDEl)iG$T~>Ve4cXkFzzeq^C$G%1gUdAb#(`9tvDJ(IayCZ-;9}LzrX@yD>^N+pDo;&k z(#tQCoE27Z9lnfH_=6@I7m|?wQ;=9a_c!#<AI}nH@;~oHGFK6tKNiI;zo4%!i4=Wkjom9-f9}?_?wnR7!I%p+YtUm! z&!7(fHgfqC^dcK|QntSfyZvRx1DwFDK zYGdhQsg=}a(zds#_Z7^Z`q?^Jxv-c%F115o$)nZT)W_p-GTCBvQBPWe9LyL(vBA&j zaiWzv=5*dXBgVs(o=*L1op<*Yib53TQL9J!`7~R&+SnPC2R)mE49w`LKd-g17-I6+ zo%hKl^IMe$c2kwDNto^Qu#_y8oxE#RRI;E~$~Igb%_hI`Zt`XqM>g10vg(8NvMui#mU`88P-@%>N8Y zItz~L22gV+v{8Ho zt6O5;p(~13BRsPx(S`^u%}y_`Z@B=Bz4oUtpn3d9z@NUq$BeeC+v?1|UMo}n(kBKG zyX2p0&Ti#HR(;x3lZ_ zd-c0-c81z-cv~Bt7VGzR*Zqz#YduIE`__!@j-CEthe%taV$3P8lWXf_T+qenKw@wx zR@S7}n`y#bI4Vi9lv0Y+_9K30By}>Rwp)a-6&#YlaS%*WqA^=$f_79M5+=V>MnPzm zr!Z92|6`5wb0KkK>86_3uYw0|p*#k&cMT)6DqUZHtKfExnAdCI?M{AIDE(=%*!B0I zrEIRsIp}akjMtR#*3a?Xog(P~8fir6bi`GUu8Dp#I02KGoUH2M@!vMvj%cp?cm&vw zKB<+Jd-p9+?PhdzSqd!CTfI5XZxUw)Q{jW;A5mfq+Q3bnR}%gTkZoN-Rt-6-v@{+h zn~Oa{?xGNOde;~%dEL0?pgl&@mc%6k{Jm2xAvji=TgqH_&rTPc#j>1 zP9zQG7(@X9NBvH6Xrt;k15B&Nky! zSNlI(w!4%%n=+cDYwF}Zt^l6oJn@0R_HM=b zOSh$utFQ-Q>Xv~(cjH|lLE6afy9DddEAphmf?{5`!N|XN9iMzVeT;tC{8{UWvywq# zX=kssr}nxN_UXOOWpE*c40W~ta!LR`nRsVChf!Ww=u04KKYy#L=9wfr(b{8q31i^|!f2okiky_$G(UHhse%H7E)FMzS9`4=pg^nvOg$1)RQ zFFg}CZ{1=UOB1}>*(G}u0aVj z9hd7$#8_vp)f*+`6Z-cl^s{GQtfxIQhjE8r5n|=bM)yr{OkWu<%Kp2;i*QRZgSw(6 zTeK}2pWgy@7~3d2P(N-1fg7`T@u16aS9YN#C^}#2kl6$UzLrk8qKUy0Fp>9q5rGbg z?&gfAjE0TvV}YZNh*kK5TAFYBtkGHrK1fJlhIiX&5U?DE{IU-U$YEtrw5QB9*{#hv zU1|8P^asa;uQ8{Sabm=bi*UJXII(OFkE2r$s=EbG6

    EuF^6sb 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 YB~^LcRjh8n@^>J4X%(qTuxaT30HN~B5C8xG literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/time_and_sales-light.png b/testdata/snapshots/darwin/time_and_sales-light.png new file mode 100644 index 0000000000000000000000000000000000000000..813e949b628d32fd622438c5cce4fc655f1e1fa1 GIT binary patch literal 27613 zcmdqJbx>Tv_b)gJ1a}DT65QP-XmEE3P9V5@aEIXT46cJSxVyUscX!|UefMp>s#m-F z&wEuXx98rP+kI!IkAJ$)sR>t7kU~blM*si-$THI6DgeNzLdaNPZXP#!ltEn!w4hqMMq{71+nEm~%^DWe^Kh0`dqpj&!wf1KN0t$^yR#%xz$y}*V zO5~w_@{a}$gfOI(+T4K8Y&2nGaA7u7Y(aRG;pU{h!@4p&JZe6PtM{LLJI8gh+nw&0 z#rIO$Czt&!UnlrP(4g^-l!l-ZiAGS&LP6h`^G=mqY54yiyIsGa;>Y*+LplVvYpZVN zp-h&u`W?*?WaIuFID;#1Cxo=HCyuJ8JUqTjkYE6oD$>8R^1dIo!0>1D?&@*CDJ&h^6z-vgjt-abPG?qI5X5@8~FZM=^4 zZo5Ad)=*K&D=+`vNH!EEMwfJNQD@1qLc%sMWjH{Gg}^+C8jsPN!mL|pFc6Z75*3Tc z$<3`!gJr$YJej&xZ}PIAXU+%6wf;4p$(vMxOw5-hYZK7q;;{e5vy#Q{75|$U2_abQ`}e>KsYgmWfLs5QyU8WSb@>~|uf6!S9hIOuAAzwxYj>MTbJUWVRpl)U~#3Fdu zd5&HU{+uU56A>Yxs^dz%EmqNbT(?ZmAW)Px%k~SjGu`X8v#qM4GFz%v7W$%+Gj1^Q z4lpxwQ}82LSzczu2p?G1I$L`R&pP9|z8-O;V!Sa{`7jrpjXT zl*DXR<6>&6WT0rj>0n}|!>4Xf%L!mk={4eF5H#lc>&A8?Sf$r-+Kv+=eeeER6b*-YfV#L4-BFANW8BHZdhlM})6>(<+Ak(Xp`xlq3eAz? zJLCwo3xFC@fMYAHt@D{3KB@*>PVh4|Gze2s0V}k@KPWN2z`WB_^DB~~@$s#Yyj(}t znlM%wjK3}p|GO<0E_?1?t~(eVrJKk^hWV44+Kh;Nl%Mn%BC%#5;6uJ;0AWntgwsopd2oh}2{9vv|*Zw=yvB zPbm(C306^2+3IjC$jj>%Tl63z(l7ol#+!-VaMZ^AGC#K#87GTXqf4U02shv&Up|5#3{-&4LaMFx zrJ!Za?B|FHmq!qIM;1lXZS+l!Pk%4n91OoQQZ176d_E%`ViEh6Qhu@a#qZ5V%samL zz{;?*a(tYzgWnbEj|i!y)%M?m&nctU*4D6pX5z1zUt?QZI|!V&NhBphNS=OUhW7z3 z_iF#79`d-MHo2TE78P5ZuAV5m5*f3DHL;M9kzu`bK}8IWjXs^yqnm!*y+fBjbTpKe zm;1s|2)Mn6_O1#{;sLpZg*`nzr>AaP(4tZJW-4lG0|&yN|5TlaLNp~Lm=A3z!>t*g7r$jJCC#p`^?9ujA?bv84a!X6<@2lzL$XFWb%3HZ0) zm|6wg`*%6kv}m}p!aw(6ZgA4XXn4O-OYyP`eHDQ|>^qY0Nf8dnEiX^VN~q2j*k7l? ziu7vHBL)x(VKkc#_dIAar14Dqp9YckLNTRy(Q;N+)W0S$W_GRa=zy-(! zmL6UBsWF^WP5NYm-K%*b>I6%x(V@kPKFKXk7O@R1*4y=Sb8F?L zErUOCvjiNRNhv;eLAeHsxthGy9%z7#bHRjV6!_1UrZECTT)S(Aq11tvxA$Pu>i!v*Z>imGeL_3ZPQL8Ch$jH z6y8lr6-3miUK$lj3f%w^25jq6lsUs?-X~vvVc0*-emNJXrxPP1sv8c4$}fuUMtFjr ziN}g)a6w2R=*zDHPuzB}u&`=sYG(SKaXE&4d)GY_#!s(vE3{_^V@agY#63KyJf1PQN(oN?R$WIW;l@-}=nV!qn7myT?H^LGW&{|9F+AK5o!wW%+SMA0Mh2oT&VC zx-xDAM)wCBMn-u69Aa#obfJrj4~}wm;tOqc37-SG>F{>&rZ-WI(VG=us&LwXHQzHM zTkac$TKT$m84=@`rXLs>%<#|wnQPv$sBOHN3*SSb7#YT1QP25aZ2n#|28yZ5-VB$( zu?3~^FM1r!^vfo$dgI6&Qmf3m6D?49%CWgmR-^kL(t3E8caMbWQ=}#mbuaiPT zisocBk&$j6PFJiRM&>!N89KdanVPo*KI}|wL~d{GDJV?V*4O36<%YS;@>ELWaPqyp zs4&0rXsD~hzEVijU_Cwlo|~PGj*8m4c{E{Ubab-I{tz1L3u>@xkQzF=XtY^9`e#{P zUF}D~+*wmIG-+2}dX&1_6sfAhv>H_h(INj20f;Mep0`5PU&lGUa+jbTYT??cY#Ltq zGxg7HA#U*F0}Xn5ZDxV~yrI5+>Uo|rj1-Ow?BCDE#brKZ3JQTi2{h_6#!IN~#41(O zG2ApY=aQ6?${-Chynw?&kZ^9r&iN=QC>R}CiLU~3hN1TxJD8}}Wmi?Tv|M+F=`p29 z7h*+7nwZqFCK&ZRvwu5=yCy7-^=o(;f(LPtE}g>qeXN2~Q|*gORfigdW@g!6QHi&% z9vQHmjzCnxL6V7y`vmy--ad4@FBg7jkzSRRm8Yj0zpb_@sRpmzUnfxsA-*JebZ=lF zN+0a4>3b;zxO8vR2jAnYGhs)1jgODV5b{1YjuJWs`C~X+E-nb>2ru$vnud}NU5t{N zJ{;#O(X@g|*wO|PEl3uIP1zctheL!4RgMazV$;SBis3NA#c8nEa09*J_~Dk3lVGvn z0+0|nI5_0wv`o+7Iq=UGi&Qt>7v^3YjuQDb>+7?9Kl2unDE;gX_%g~u_dm710B?Td zr%PJM86#np$Wu}(<@j%F6)$prn1toWe?r;>@H7za-ZLY8I{{k!4ET(Rm7430jER+y zWo}wDaMLUZP4=N!&B=j~^uvTjJ0T0QHh>&mA0W3TR+}|9!mf||?Uj8(0%2A*s1VWx zjr8yK{!HrOZE=kioMfp;(q#JKO68W@5=V2a@~Q^))dTgV%H^eJ>0+h*lB7W@D&2p> zlIu;s5Q=$d*$Xrz8g-@q%${)LI)ESJtk=~iL_oiMdpDqT`xwQ1I_iD9nE23LM1B0t zAVd&3IdHx^Ik25hRJFYIUzf88Yu7H6rBD1nVNd@M)j<6(xv>#)z4u$TQ{3EdLff_7 zet5E5vSnaoJS*{=PqtWKm!0M4lvq_ipqh=1?!J>g%NcZo=h8{pV65%!8A(Tg74<1_T~&9OC{dnkDHk;cWt$1SU_ ze3&ta*)iTW&VKKo{gDJ}Dt4>!t2ymwdoLl1mp8l%(uXJ8UCWt-c&)-hAetCW1OoJD zL$3lJgoegvyW1v?hQxNQ{fCz`?lYW8!!h3MglBs?;ST(mohfOzMQPv8kG;)~%qQ{v zf+8urkkZPkuj|x&9>=EkE^_`NT_j=b;Jd74pQjDGJS7_JNHaF=%l6F$w+dJl6hdiU zr8f;1HRm~z%`ON=Q{`2Z2Nw%J4@zN4?7a(cANf;?NiQ~3(Wg{TMb?uo|Fs$3@c4io z;+7yq6IVhH`Wre!(#q?6vv65C7phvmS+-!w8Tb}h`@D3zc3S7hqx+uWSgUnP=+vn9 z8}G?mynNnV7qs&*Sl}VXJy~IqY?KP?cblt3llTMpB=K}k%S~4JlCzEiF34@py$jUP zZHgAoOpQ%LhDGkKzQLg|JlwhC9dw#Yufdsa({!2apqdyTXGOw%mD#-OXv6ftD~dw& z1OI!Cy=gHNDps8GTY4oU>oam|+q~?comF!O*<1cR^t0$2VhXnyzznjpwXIrQ$S|AW zi+2gy;hBu0MuV$icsV!RNTS~b7R%nf+^O4XJZX`nQ#;?3%$1cKmXvXq3w2!AdW|ry z($7*K!jmEOj!jNtilLYh(s^_g?ml76q9-h#%=aIAS5)tx;U`I|d$y{PC$+hq3%+wh zxo$?SuLw9k#s$5>hx&P@?lg~4v$@o^-hMx_eYoaM^Y8FCH34nqk}(NQB>uubCfW8w z2i^3toffy}thD}KpgTDnDj{1I(TF!1VIkzOtjB*BVdG=_!93#;?BQ_buy3-z_NtdN z8M^Rk|J27nHOv-l%z>v;*fL-#Vw`QWG2`W&~oz8?VdWkE7pB z_8zU>86@nDksVK|P+z!?aP+n3ylc3Vd7%E%Sy<(O(=MG;%F~M)PrI0?0^Du-v)*Kc zLmnY5F`&qnE$~d)3AHStEKX&-eafat0NM z7~E3`8&7QL*#;3r%+BN0-f`Q?QM!H7o7LS!g;;5rnxsZ%>AykvqS`HalkaNAD#nx4 zf)lLNgAO)~HZBW%zR;rQ;yA@OFKz zCr_b+g8b;mQq7%XcsF@oU`9dsl|`3nV*mB4l;q_3k7^Dk`X;)v8RB%cSXwlA!Ta#* z0(1={DnEZ&Sz0|>Lk&8t(AZ4ZNm%E+b-LcAFP`|E#a4gGd7B)clz(y1fsDxC$&cft zOFV>w#K%$PmN>3K^Lvh8V_d;_AFp} z#wANrt)3`npZOC7kPg96tP%Uk|F3k!pTNjJaqh(ch;_uVUNeK9Q2rwBh@T*yU@k@^%ezrGD=Us%XgG``ia@Uy=^**7l*3r6478c4$)krEYx zrDhm&R+Sxrv3J)Q86iaG)v4{q_Yun{3zG)iD9TGq5Z5>7%J9FGg#XLPWP=Na1k`;8 zc_M3)oFEY{jChgzn!rEJbJ3r-7p%~~9xv!LR9Wh;tnM{J&iO_iFFTy_J1hONeD(4G zgpx3I`p@~GFhsb|Od@|6(2|2hhO{>(WgN8vzSK62wohE}`i%*&-+1R^c3AB5ChT@% zxtiB$Ya2|zfwk=kH5cbf%B(%#SFi~OPwI6Frlt8jV}BP9goNl+CRd<`7~w{cy5cOu z-H~92kn%*tH=uAPu5oh<8|x^mW>l3R4SJ?6VB2Knfzlxl7tokXo-%>ZkGbJ{S?ZSM z7T$|Hli$J_uPnVaJVQzwl6vPd)+2Yu&p+Km=4&N2Snf zC&yS~9?RdhFaYJt9R(9)G1|x#lN;nE=N`yosD>9 z5R@(zdsQH|*e(TJ-bi@bJZ0c_U0GY}vEM`0Y3Z`tr-aN#=j51O)30h6jBKAta){Hh z<%46W28Q+``$$sr*(>hrc|kR{%Siqg-*sSmll*7r#h(k`@{9-CC8^{%YKAJ zU}(6NPlzs_8cj`|?%{0h>z%Qjw7Zt7$xgSRL+JK>rTal8F?ohu(JVCv)bj%>F$Y?2 zO*0W#Cu)FOvpSz0SLW&p+~oVQ@!=zG!D2q{)zARkp;w%p$m!Hn`C-8#4LfI2S~)C& zO+uz`B(r}!8K;4%N<-=sbTpczP2#fvDs|Bbo>?YCq5_sM@%N+ zd-usqjnRWb;r{QXo~!uCP}Fas7$GK0d-DWip1ncsn^Rg9uhIOon@`T$in>J0V}D~e zPutWOgzUu<+(zU2$%&MFG-PE*!G0fu{gEl3p`hlhkdH!Emuy#;#_DDB(9!b>$RV47 zYI5~W)pi=5Fo1uOw#30=S)3p0+<8jm2@?j*T|ZfN_1j?pCG%D{Rr>6Q;hp3NU&i#? zXdFjOJ4F5+ovky|C~4}hI+;4@uHKyznn`>Ch!m)#the)E#Ts8GLbN#=^{_YR4?~vqHvDJREFQDm5XY^TiULW2U@3D*b#5cj(&=^48x^ zuYjDINzIedq~lX>0H8W2)_w?Z(tqbzJv@ROlO^xsNEs@2r|sg>TJ+6F#j&UD$w`_d zNS}LYi^rgRdI-yL=2Ia;izE;RP_y(KNn+K>1~&#hoELE@Bsj?XYW-UEK;ik%f0G)Wj$T#l2IPU^bO^yo(2K9_44hrgm{T518Wt8`Px*Ft$L{?+5RU$MV$fn; zL%}}Wo*YQ=k)9HN0efblh@uhaDDnXeNlWI@=#4sk-_W3CWaN4r2qmTqAECEd#eATa zYa`<^W7?ap@6Ix~Q1Mv3dkRakDcq7Z3LNrh)3RJyz5PX28+6+h+<4Dac6WzkVlLl5 znjb#WM|soA7n*KRzW*IlKe1*y_i))eulY|wKA zQ!FU}5E5a9pRm<;G*ktm6a!O#9p_Ak$hW(C+##1gPN<|<&9Bcly4w`v7m+H#5uj*6 zqqV>E@-`J0Gb`Qu`iCb>ME(R}OwVlKP7f8ot8(8GtABSlu)kmX=!hl)qPe-DLs^iI zlbf@L7^#&ZpMO)OFR(Ud;(RJZjK$%j3vd>>tGZ-<2A_dqr}jTAf@}}dAGtDH?3+uk#+MD# z8j&VT+v!g>^;C_U(lOCs$pZU^14l*@`zX2dR+r#+zW4OfjnX^2xTx?t&`|CeuXGD~ zMIs`60u(D!o^RX>;vq?!s$hvCdHSHn&C|`lX9*Wlena=^!$1gjWd8^O;?U61uw;y5 z$a0?~Ig-oJV51`XG_FIPv5t@MBZ;y=A7LJa?Upuyt4iuy29gET4Temcud|x_8WT_U zs@m++^sX8fO!rzJmq?_y-Dv^ADo>G>x-RA@R#rQnZqDEa&X^tGW%{eY(Vv>YnwK{t zZq{$lzS_$zv$Q%5-?pZ<8XFrAzIBMK4YV-fs7$`s+jUk|Rb4Ke6~Lmvz&xNHZju04 z$Zwa!S*JTby;Z=T*y>LTCnQ#=Tc4*SX9>89(O`%7Z4;A6_HEP77RBHRXG`1Nco-E( zX7RhUHrHHkwZF(*!M_E3_IY{2tVa4Xa($h#Sgq*ETI7>}Sg9xpoHh`+*@?99Jw5q6 z;--Vuo0QXj4jy>fdr0v0wLk93O}eQ>Eb*t`|7C}T{eGFykx%!KqZ_B8I@OaB=5!RY zKet?+GLS>==uOVuiKiS4MwvI=g9OWjPKT7;WwLxDD4PTQ^F)ozNy2(#-}FKrB?p+UP^U|&1(uV3>i^cm%0gC~GLWETuJRVu~p@2oL9wop*t7dpNVz%(_U z?Z7^I%Hc{t%+FOhz5Ze7+T_USsxo)WWLRf2DBrSDk|G{0;|CZu*K*zpC1upOj=wEd z#pF9w!mxAxtc(@w2^QnZU8P_S_TIjpg1f)z%WLz|37RG zYCRLbx#&mf?Fp%gxVCtzs!EmB7oF{n8UD{uu#0k~WI@%@-WQRV=#X5Rh& z$152jZ*0tO)<=IN~wW=%B6B?LQtkhA})!QZiER?5#;U%UG&)!nzNFFGb!=-lW zX4vH_D+!t0X68~arwb~DI7+08kuCX<8qcoo9Iuf)VR$qdOurd|19w}==Lp^CDqPk_rW0TT4d z9-dwaJGq`X0r~90J_LZjHLjSItIS%fzV(}Hjr@B{-H64K$b|QkKtH<&i?xYW+|KG& zg&lDxLT*aa@wTKh^bUUCe|>w10}I%n2F;ceQ;H=86j6@q?)!px<)ajU*m|g48V;Q&z-)1jWle+95Km%q*{D-kRwX!$Yyprwr zk@1{$+RjO%+F+*FtKOc9)nEkqab4X`TtWB8kR>;mmoLOJ{Hm*SXbT^B0FhT3F{#9G-?#6cpo7$g5## zwXp^wmJxAqkwV(a7sGsj8X0b9>7sT3fD+Bm^KFSZ)o(XnJ}cT?_=@_suB>EJWUQ`K zSsc*N(*XeZNv)^n>v&G)FOM(7>tCw}m=;Rrsrvf?f2`9|^xc`N8B&>5ht`97mXhd& zv>s@)6sQe()D%JSD1ghJnoFFJU?_mlT08tvBX}6XWp;P**A=_f6#a#h-xFqBflu%B zvb(nVwSiI$={#@Z`yMCBH|_&1sh19{TRVN;i@*d6l-n!CHt#&2+&el=O+)7Pn~l*( zm=~DmQNhItzjiUz1YH$40FTFBK0)lq*4m=C88HI)Rf_DU;OiAP17Cp;L%k4Qv?KwS zxAcp;y88OmRI~A(3W&(oWY~rwW~Tvv9HKdKD5UB`qZh(}|Axic&Hg(UM?!?JZT6ST z`%8<(6GLHMSW!rMaope#$9zk;oYt$|d1bvyt_S=K7}|9_AfDj$VJ$%`; zPxBpJ8k)ovfJzLU|EQhp*fZu^b!xlhOVuaw2_#&hec56ILd{IaiyV>TJT8;Kx>jA| z!GliwiRI9Pe zcd#Bdm+JDgzgSHYKuQ}fGtFLPf}4z$BO)MKVn+(WypBD!h7<2d09;=4TZl;tN}d1K zi5>`7umEWl2D*RJiG~5>s+UKP56ok`RFhSh6?7q5QP60qSNVD8@n%R_QQxb)iKr&GFb4jesBzlOD(fME}yy8} zR78NEUAg{!+xcyoQLuOXBlehY*ehn@`qfmJ&%7cYeudS^!2mU6bKQ9n^RrwCpWe~lW%%I zi*KLXY$kO75&tHE-j}=hfTmrka<=*O{f9Bev=jqmgOB^hZiyHL8!L6(JRF#z#xy&> z&`61lRTgkZ<*M>>Sj4-g=$y*V)g)u z?%TG@OFAK!X}|BM{-Q&|lDU)a4`a422jZOSs#0FxN1BBGsEF_*GPaEIZ^UH5A+4A0 zNZ$%-^R9k)wvOo=O%Y(AyiuyskQWqd{iN=6eiw5As%&lLsh6YnpPAGyClt#Am1trg zEks_v68t+8?pn>Mcq^OOH=Q9QT#3zol>S;=4a5;*K(v48&`a&4zI)7=HAKF?Bs*99 z+|+KN$TMSErMJUUrmnoSx1X+>~?$!vI;;5A2(-XVm4 z!2A#voo*C<>PvYhr>*Ys2kaJH65O(|MJl3w$`Cv^Xq02X&}c> zZwo#qTj_tm(mPR)AQ;FL%N~@Y0WFcFlT@s=;Gv_8=fYx5<%$O0AK(WO{SR&Z0tWnHaUqwR-g+(U z3+4Y88G{sBTB}!Mu~k`w;W(^BUDxJdZoTZzuCj7LS+8g`isG0@qgcb{%L!kE%~xow z2=a(9f=K!wT4u;-t{50%*BdW6DVOBA0nSC1M;9+%)YK1dIGe+xFZ)gxK7{_KfBrw; z49q~YRtwgE(+WX>Dy|Q3zcF;_MM0 zF;9#tXYNO>eO62tOWCb>w1>n>vW1?8+^j~9s>nYmRW^5x8aeV8j&0ul)R~S=omQlKYc`iX}QaXkt|u z5B(%QrmwMYIoys?wCNeKK~h-zdzjEUPauUCXY(^ z_BVbH3kyhHcw3`{jZrVj^_5ucLy=Nec1c4Onaw)3#{!f%nm0-8pURU;N+#)Q)dGv3 z_{j5UyfIfqU~UMZioZD0n~KID3I6YJmD*sdWe}B`Jaup=iGb^^xV$`Lmcqls!<*-U z@Y7snVv>i&Y*D4kFD9{}Syj+gb)LWfrx4vzAdt%W%urRe8d9)y_0*|U6qbhvfKNY5Pm=sJ0++<{rF zF#XHrAb;}omQl+ojrXXkkwKHusxd(RHrGFX~DkiOZv*?d)*K7~OS%!fxOE ztC?8q@sOntD_Nl%gEqpCm+>&W97mwZ^B7AbkdRvIg1V?qNywXc`~${+XK}%1o-VOF z)NMw)f*(w-qG^}z?3ja>QEH=Xgde@RuT+%)wTwmPM9(x|y=nEp{qjS0bZl&_UWd_h zf`R(m{^>-u8+#h|MH~Cs``c-`W_9(e^LShVdQnl)*RP+k@CN!}IPEPG6 zTiUO?`r-w7Es;3Eaz2rEHfP)W`*-PzJ~lQF6xORNw#62SDaqtPyXx~_T3Rk9($3D0 z$Q&^ybwOGN`dQRT_DlSH&U`LYevD6Nu-guwX17uBYDev{sP(u^ z>ZE)+A}Cz#@r6DA&G3FH-a$@ScvU^1WT%!fmor{QgkjEM#(mZ?nqwY_2`Ol4uHd`b z2t&?+3qjuY0>9X47t_#ID|7~;Syfg_!G#YzB7`8b5o(-gy&t{fxLs@rJ0GTk!K;b1 zWNPPlD_{#@vBQGco(cF@d zO*V?qSc)KG!T4{~#i{A(gpWp>_h&}d--W-!`MjJx%#}d+T(Eif=H19V7DF1Q)3T<_ zkdHAW$`G%qPQZdN$g-nDpzv?ECv#&+^6}aB<({Axkr(KK6)E-ff)1T$GrMmpJl5)A zt@g+7fx@YItw!H46vFJb<+8FNQSq~JhRTX1!kE0Y{Ll?@APL5e|JI?u_@jg!!L zOxUTz)`c4pwCL}RS4G0X&R45I-rmd~ZtB+MMQv@L$v9Yd72(M8rfi4)io)du1c(JG z`3gPZ3tTC3;Cn~}P{&*-ssBNXmxk2x4M$=S%4u+Na?UR-D4RU=92q2U-UTmn&Mlre z^Fb0NRA`$ktr|>Ha31a+N6xK5sagS~EJ%@pF6pmm1o)*PSy*m-R%e6s_kML=OC@pL zs^8p%9i`@n_V$rr67F`*cXV|Z4;6D;O5q1<=44Ysq6v=snw~c$>Gn6bXmi#bR66_EVBGAMnBx3p1;e#dX=ox5^waiRRY^M0xa0|vMA8>DLWF2t9kMxmbd1-Q2}(6tk#_7`jBzZglBniu5r_Dg=*l-F5M8f)0HlU!9BI>G+q-q{LBPMpaZ{c4R)@ z$)hE2F7&5A0B%Y`7JK7H+;fYn@bN>Zrz?I`-xPBi&+QC@P07RxhvKh$Xt_#(5<75+8rD2x}viK*-Nx{zhS`xyF} z%;E>m#znfByg^KrwX?b1>?0ylCdCZ&gLsn8`=cBAq;pJ~8t0#}$z$8NkGB&LpnTSJW1}c9ETiLBi>ppjt1c_Ef+EAe7Nk2&_##Tb->Fx8LQzN2 z>3xs#V7K{evt`z@a2YiiWmiZ9JpzqRQK7D8 zD?>MaRz+5`_9sgbq$}<+WLHWxCD7^8#}62<>p?xF03n@q2C2s_S-+Z@-J~#0Gv`mET%e|CYVw0yu)ktS zemo{5_!^gA^jLtFdwryinr2opjJMH5FCSlzM@9}w{LDeA3B`&R=B8X3^2M`Kk5AfH z?$~mXMFT|yrKK?n#y~L-zU#sQEkZV%GT)pOY!b}bqG=u;z7e_+KR(yBiEbgwo}AW9 z;Sz#rIXUnB@!K@+S)MF!14!6p%bV2~3s`9)qO6LY{5CH*)Zjb*Jvlv_2%Xn^{6ib{ zl1)y4j@3``8kLi@d&(+ULnpdDYF- z78{byQJ*PL%P#G-<-m%YEVQYnq=bbl&2+%a%bOJ)+36?za=z|`z6GmJcULIW9f_SV zD?>tZ@%Y#mfuOB211u@Q{iRSle`7Dz|hEDPB^EXZn^Sya_3!cUpMCV7_h&FzU9) zid12u)PJSAQjjcaFW718k7T^9L&eTGJ36z`lB&T(;MJP|-k8=!5pYAhx{~-_*KW|~ z@UulrCb)a(T&?6JC%SuJ?;RNOq}a1Fj%$#nf=$t7H?sy0ZXRE64z`)!<5PXlTH6DA zLvyO!{QUN1_p3dBr0?aw=fgL zk+8c@Zd^Z89M(-PQ1wv{WC`x=?8xs8Su|cd-bffrp&a1dD5brla!Zg)-Ku5jR5H=h z-d$gFoZq!q3=PXU+~J8O83@)vO6+_p(%8)*Km=$YpO5h--q~~NS(}OU>C+WBvO5sg z!}EvdblwNT7z(6S31_Sq`FT%M-Gn9$(>q|3qQTt~ApU3QzlQ(c*3Rd-|FbR8mEJld zMr%vmh(nX z)LlzJ-;;>SPL<3;A#v*ert3vj-Bq$cSw~v}4H`*H94)A=O2OQhgE>l23|e%KK8Y_2 z1;%r7O(OUU&WkUtm^O$Q-7#e-39DyqIgZ0UN1{fvhqe~Dvn#IA%@Yt}pLIQLz zF5F$r0(0Oa1G;2rqV#Yn9Gn6J`P5TW{2oQxs(@br|F+J)-o3vNq2BxH?N`lka1WkE zF?Kqokivy$==KHB#N9xl3RIVsJeu9<5Dsd-U9*Sw`WqE)nDx{g(c^pq#8fOv*MU4u zh1;iVsLw24TU4t%IDXrV;jkdF*`@^E1@hBKctAveTbtDIV`)8lIkyV0MivU4A-Kxf%Z;(2NQ|q*4tZ z>@oVMJFrvtW(P!~fzZEA)cM;A)^P9bMQR(9VBQKKBH!TbcUtw=!KBl$=|0jfx#3s` zbNl`wQ@eVRgx|g7@fjHah}m)AcWXFy&SBCAIrlqaXEa!xxI(z??Uq~FaMpF+zJ3{6 z!ED}BQ~mHasz6)Yr`@6e-b;MT6@0ugrXH!N-*RX<7|1$PhUGH4^Ugc-0W_iK{t!H# zU5h8kh$SH<07$pG?@JFXPZp2MYd3Jd&O4l-oV9yCU=v!P$LwsLE*DNWoW6SZ`&avc zOdL9*-n18iV!wY`>$mt>bH9>#@u`-n8Q0RVI`|FJQ|>kl-oG1$=xaRpcTE>S84}q{ z9w;Iq-re4JB*wu5XhxWGl}auqvUX_D!ZQ2W4^ zoPMu~!vaE^>$7z^ojE$dW8S*ypUvqR)RkqQ0W_x9pqZIpb>^N=&&|z0_Qj=Wcdz-W zs4mz213TX(8$bwI_gqM%cQR*%P=GdGhR1QEZonU@>#EE1GuH2tl$DP_0=J1>v%145 z=8x8{{%Km%p|B^+o>+^w4WVCx$xjzG{}y`#3~{arjlU`S4Ucm3z7P^xCkJoi0 zEyhT;&kjzuJB-hz)FWD7`TJ{#DrCYMK%nQt$~2Zgx3?;^CsY_IM!lh~ZG?o6HR#R_Oe&G7?H!FKkU&NhQdP@s%G(MGzp|*}(MA1t z%ly0DU(6l4lQPk}MFlO)op{Q*DoBLQKzOcfY~hhWg2joLe)A?bC_rLTG9;RIvRfq2 zn-u*VBDNUaX#@Z?q?q%SO0W=ITyFDYerk?CkM2(PP-r>BAZe-5R^MT@DA8io!Fp%v zBTE+ORrbJ(l_kFLxK)`y@_^MxPI4ji21L1oo6`mVSz6dl?yHSh%fS9Ace8u*y&IWv zEBK``X;-=bQJYBjHD&ba989u7$ZfXem7~{ekKRbSab3xe;98=mrr`L6auX?}aQq&pW1=%cVsM3QXZo_)-I7%DYHAzI zSkhQTTvgLI0itMwD8!x~kM?$khD%{{nqQD{L42OdgLDMrBUTU+b3c9m>BSsRXQm(k zd-y5usa1zom1B-TPLkTdV(VX@(_cEXbp+T_m4TYtJr*q%5%a%v!xt=>q+FC|Bm`)W zpjeXM;?J>#DrJyL*QH$B%y$L%x}v9ERBST~!;ompz|XcyQ+T_Yt)g~+KIPh3*Kxv9 zo!eseh$$9lwq?eJ8{ua3#x;W-PKn$93hSjsf zjxA9`T)TVbf_P%U(C~=H&@O9^H_{8apubq4L1+s0bVUU*ijV>WOo4oLDDl+Mu(}#{ z*0cdsqw6oL`6fX`;q@@S>U>YzCyLyT$P_6{AuKEj#Zb)M~We_fUp%4;OF~m zn45)o-yjJ-CtZnd(}&9vYnmK(#(b`ZTjgD5X69JRPh+jae|g_8k`r09E66^5U#!xi zW#MkHZ0KLKgN`B;EzsU53>5iCigru#Ptk&9Mxn5cb0;gC9cOpn)7^uYhYul0fhUHW zn``A}*w~*mOwuJ#ga#T=2rLZK*RxG~VBK}ut*4=;U-g?J#nG%UdqdJ_@Z!?+f3%gS zy8WZ4j|#AN!f;Au;K!C)_^F-z1u!&6r%8=|%i#Dm%z;poi?co@X!lc5$n(8zZK;gV zgl$R$;wQjY5I&%5c=SjVD)h0nxp!Jxu_zd^V2i4zvC;RgL3wykv8OAN>=`LY)!OmPbc(JbOn4o8; zAeh}|vFe(N1o2L(!-eyfoO*163OG;8Qjs51w(7dfZVET zMgF*WS8}Qc4DI9`VW)dv58l`6zt5CR3H@fERw*xb)HtVKcRpz=pBoSt9iIsKV|Zgj zr=Ei_K**_u#lM>StJ^{jn z-L9Y8`R!?DFzNY@-?I2!zoSZ*Tk9Ft2Xt92&rJSv$(bvON6Zw=UDUjKe61_}#X(PB zm9<`KGR!$YkIp*1FTpX=LB#*nu_dE;upM-50*l&`PTja~#z`F5kATbDv$C>c$x%pE z3<#(>xY~7bff$@Q3m#@~kLS>saV_MpENZ$$_`SUN0ypNCoOvmFm(}y8Y@+>#OLSC$!8c!v(`n{PR`Q3@$f(u6%#u>ZDUX?KTlW}2!eGYB61AC z4%l>DqPt7#jV@CPhvDoQ_GKXsVc^U7vKA!$?EZ-a*XtkF?tG*ZB>(Ou2t8;=cYjZ- zQk%nU)8KmFN7;}eCOSxMI2ER{a2Bq)va-@oqfTHLxuT-b` z4#$BDlPX4N5$<<4PfokWOS3uzV-lqYpXl=&M7IZgVqs4{3zi)K7kl&H^BP&{12oU3 zhMW!$;hSo%YC?>=Lcx4q;c*x81#!HGRRliGw^t+-ucvcEg2}5ZE3&ea$qC6(0FD^OiBSe%qfUnL9VG=)Hv@i* z1#@)2g0w1gXFitB=pGq+_Q93bB3V;cZG<4YBi}NirOhgxfl-ntJK~$H%i;|D-*yB1;uo#8<>bxNZWv zFyeSZ;d;y*L3Ny|n6HY8+--MWUOp_Fsd@kTXY089lzQ8Uv^nvO@PhwALBk%dM6j}( z`X)QgrKzh^Rimkq2}U>jC$yTT$?587@mU@mNgUY{+<|)2hv)kw6poh@Me#guCK|2H z#o;Ya29@_1p=W$v#A{4U_dW;g09j-Ncf5BrM8ooHYkz*Ie%Rlm6vwG^azI4z_Yack zehr00K2v75SMg3vc!*eyU98ceNp0^FHc%<UWGj#M{E9|{ZJn}{#d>Y&0$TID4YaB0Sd40W7PDJC zxrGmb%;3;SRz`PG*MnN!{PVdorL0>0NlOsSdA$~%eIdl7xoKm+2vh%DnRrne)8ogn z$NHr=mTQ(bb5?0=F)jkBU-K^I;mBz@vnra@*8q%!ueK)S&22t{sx>wE2G z;S-$vgaiR)*YZ0y?ZBQz|6XDl1-T9%umIR<5WdFD1{o;nJx=7n7LSm3c3O#fSMuOW z3;1uLXKE_B2Hp$~?y^AWJEvZ9v=*i( zv+~x7&}mShuz}7JDj@qlDM!bbwmD=rP~a%T@86q?Rt8R)h-~pV9L&EQ5)XCB;b(RG z3623T%@$@Mti-}`&`p*@NLj98rD$vYa|=q1A@^ao0c%70z>k+=y%rE%Bg&ag(m4ZY@FA)vNDij#4FeiZP4gz|Jq7gGwkmoY`Ih}M^fW&uui z5KGW%rx-hrrkQp@Fp5Ayfq1jyAn8Z6h*b}m04afg(YL=a^ zml`<9;>}7Hdy}!!(w!V!q8`BdM(4N z_-O~Y)v{1tSjv@#m$yF|n{n^=%(dMl5`rusz-6s8Ud-;CxlGE!%4y8pH+0EA7_3?J zb%TbR=2pgMIe?FdBjp9sN?tl<*qESL5}-zo-FZWsW)IGnwtDw=cdg|YiaLTTCwFwd zk~3@Sk59LvH>|U|3$w)Dq*$aV2wJp<9arkZ5ws z>BDbap~$EkY)tJLso@q&;{mB+*5{7iCtNb#uA69k(<%co<71-hQ$@WlUOWrZi{|FV*kI=A-#_m zaU<4^OVudN9Zod|ySvulH~0fm*|qxO;@+b-%OLPmXuIm_r~j&@+q2n$9phudjY+0mkdFCof(^RY`$b2N4o(lLE;3kXu)BGf$VKE_0DiICf2XoYE39K(d73R z>Kvk3IJ3giZh(m(|G!l^@0ej8gC6+6$& zgab3b7epKQu(!DMtG}kwRM*r1WWN}CzN115qEIu{^E>@xfs)R}#abOZ4(HcoOWtE( zHi23zcn(znD%m{Tc_ws*0GPZ~F-V$Q+&keu@7juo=A=a9r*@CfR;X9MNO^h+D52?E z`{P8&(|0VCb&30n2hy_Ou)>w3HDCieVpvd$#1Be@uXMi58~O6hU<(3Vpt#%`jn zeHK!z)t@f+e!B;6Bn2@~?ItW+m`}!1%9ro1=c`Dsq0W1^*B_hQ`2#+-tAvHDhDK0* zmxAmE>AXE@S#@9H2;n3GzCgdJ%Sb2bDV#g3 z`-e#roaf&>-8n?;d8$HX3-&+ZxpCQg(#pJ>eMJZ3CJQSoAL0Il{8hR)l5IhOlOb;5 zktJ4jIjIFTvl0)(ql+ykMV0}s8XGAnV&2?X!uC_^d z!x8rJjO!i%lgJXh)y=p_n$9L-qw1+@Vlzn88}WRH9^oE5!r_0$-IDm*Q}e=n6hPi{ zM4HQ}{cFek^-r@|!=M^$`Ey_%_}O>wIq1V*^hfhQ*wbfE-q<~T(~s$W$xq-RPB@lB z`-vfwQx+o;)o1?_&A!dppp9@8fus7+!hGSketyX=Mg?6w=4;M{G)g zoF<)SV>KuiQks$%v1~(Q1ck#x4E?x$@Ghl%6Z1*UGV904jc&wct<~2CzXJ=E{CkSt zP1bJ{2NY{nn(7P^XbiXhU9Rge5XaC7b#pKn@61YOt>RQ1-6*l8u_)87}3HOYXBf&xW<|w=2sw1zPcb9P+t!QKXwe44~#RC$=4o({=kr zdP3>zgIBY0c=IqCW4L2ZS=D92l%)jU#Yv;Ptj^-1g+u<$>|?&Fp3&pyIw(GQoz~C6 zM52PzFR^t51dg2@OZ@y?7elcsdG_bBcg)P-O}KenlRAp*{wZ2XQ@XZxP@$WtJ#=Tf zCv;jgI1b12?n>FXqv;^*^tCDHQFdV_75qqfccHT-$nNQrUzo>;^Db2gZVr9CD~Hp@ zaJgID)<~HCusL`9HB}_!tHni~K{(E+alT@idV!#76|`)R;(lxGZ>ua|{aa(&p=`7S zk(>Bam`aVN)31e6uD&o}Pqkf)i@~dK;C)_sRr*+q33te1(AEVG!>w$QX_L%?rejxvPPk3U}dg^On_ zs0|z1SERtY(cm$6*xNg3qr@OB%^N>t=cR_Cf(DO*^J#8|zeksu^hPOZknHlh&SK)4 z@xmuUML}Kf@-6AOGF7+#jlkp7yplIgBTIAs`+yWMEVkNnG;dGHVe%38URA|sAu}<0 zhan2CifmVId9DIz%vs@QKOc~m$eDF~tFw0@zqLj9J4_up_|>AYqO3(iJ9T6isI!;8 zL8eB3_llGOg|e=8z+6q<14p)(JwHKWe8Uir%O=Kp3?#VB*E&iiQ2ZY$#wD08>@mpi z>7@=YhvtqdKoZa9Glde$wCN+8WFnlykg1UZ=tbbuoQYW#FE*5+?w`BnP0eHGa`vPO zc6@!YVfl$m9>Q=%dS@3d!ZT`nM`dHZ~`&(RVQ+m|d z*rFiQiq3$ujy5m_HLXjkww~@}9?$9=WOZ4FmxD=zId!e-=OMV^eF%#vGk?s8b>M^l z<3ozG|K(SI=r_q(HgYLOM`!){CC;en1BXhK>Q{iHf=+<+=jp8lqd@k~jxbfTp7COy zmn)4%P~^@kqGVzP9a*<`%VRlT6(@(dvu5xTtvE!S4)&~3AikVEb(^>Jti|BaVc>J8 z1|md-CqM{x)|g(#20B~=f^5nq3i$UrEz*fp^80KXk-CB*j{x?%sv{xXW1-Q_O*cp~ zTRMZBpzsx3Rn%te8mX^L7A$tfT|eMq%%1s9W>Ol}6HiFVNI8*JnQ$!5Ld?lUcFo@K zJI@z>enJ1|7VT8vQI;+v-rMMyKZ0=c#Mni~2Q#*J?=Z;y_br@Zn*wfm!eWa_CW#Js zc4M5RMn;SE7VB=kV-UN=rvO^Kk(&iR;`7ZaPY=o~pOcH0mn<+jbrZV-JUos*_4i4d z?u|EWBG1nfMh@1pz6>v!Daum-n0J2^JHVzC8?G253R+qU$?fMKgx z9u+;KQGUxmG$SLTo-a2fQPWXz@miL}s0HnA)|!=kfJHyLQq5wUk(s1OW*s?g zXUrKy651jffILRWdeSL-o*DyB@DNgo1jW%85Ev9*#Gr4$vi2 z$t8FHd!Q?}iPvB3uP?tfiQn-$9cp}0W7g#9(fcJ#s0Nhu{#+oDdNIh$&p%_|G+$%( zcz=(#{*^qOJm2C$twXhnM)+GxRif=VL3_JuVv0!S^^V%xXyTanRv;PIT4y6t_*I~X ziS$D^dwvyfD@r29Sb&Jw$jtY_GIpGpf!#Cqrv|FCj-7|z!X9hd+1DJVqdjf*3JKkj z$TO%Uv>rw2aoJhwOc@Z7LPEmG8Jke{`R5WY31#ycl6C0U{17Z3$4-hKPU{&G!vPw~ zs{IBFgXjRcch@fkZN~N&@;8zN5|u_hS@N`Ys)dicJDIC3ZV5?wyiM1yXAM@|In@@d zWyOA|Up0%|y_=r?%0M6h3ZC*`#StTxZ{H*@*9X3z3O+0{H1T~r=>0>*yl_Q-79bi# z;Wj8QAsm?+#Cou9K#3{p^|#pxzP^WHVTpp_L+Po#6KE%wozR`kO^Y$$X=7m`p|LaP z5nDMig%qDa`bN^!-`HPO2jC-(p+HcBMy)5uz@Kh2X4%TfHr9w%L>Rp`r180l)niKt zZhkZ9Y$w5oT}164qEbC(NC1H z^Qty0LpN~`UJ;jr)k^bWwX-q@{mqn036&Ur<8lbr}~okKHX-3>}nXxFTB37s71y?@~pqc$+(4WRWwD! z%)jBLW3N%QqT4WZ%w)Qgd)34>m;o<7BWw&Fl+{@#+zqzVR{{Ai_!*VQN|z3T)$$Mn zUTA5@#lNR2G<|DL(Nh}3hw;BmwibMEDR6IF<6-cuBuD_%oc*mnh3DklGbz9^`B|_@ zXBl36Rcw&T?Q?ZfB>O(8(KQnpO5z7%GI(SpJmLHl6zh9m71(TjeSUmJ= zjsYuSrXo2ho~4tWoZa;5>Pi?hBTh%$JhRXK3$j$Iz2lm9)HlVll?IP=K7e?@v39ia z26KAz=q{G%2L1~=fB!im-yw zhq|bM(Asha^x)b7@SI%DPwgPm&U_&fo$U?|q7d$+K5aioP5!!JkCH+lQR3vcW)=`f z;kB=?&My&u3dK7QUzLOc2g7l==54hjOR{7FkmTf=$v0XC@T|PX@nimcTLTnO;^D^X z>}a31Z|ds0cGxWI5ug!gbr$t_;#&%oI{voKU@Dp<~u#6@a3H?sb zeIqULP&X_o`Sr?sQMTK_J#sS0^LlrW@sq;c%G%#5qMj$ai<+-{vu=>^0)`&-FKlo{ z=a3n6cP}66*sM(NB`ftrWcCy-RU~S0s8o4HdVdZsiC<)iA(uiM;B41EX2iKE8Em@x zlv?lN{JmPzHF{-r1#Z3N1IT(~a(ne?R%w4n4Ej{A-ea+#1SCIe^FDc@tU??ZY$Ox_ z*Iz&qNVwkJr(S&5T({sP_V?{pbED>9B#u#_)eQf-d999CAH@CNOMyo~KuknLM4-^y zB}Ct^TdNm@ok9%fk$fB<=QV$Z zELPTqz!GX&7ahr+jNBGhg_{XKG`-VRS8vi&!d16s{*)aT$DRJ>Q(8EtUE4{NbBufg z73|og=i;KUJFF)JHfjjD9`U;fiTHEcyBrQewnLr7$|DyPargbd@kLk!2&B)NX|us=vd`M!QT8qW$xCoxzD^eUT(^{0`>iSA4k6P(JKBCrbkDkR9fPh!P$M|R1Gh5sSNhD%kW4~cnUZYM z$LP5q62FYNDsZJD2`Bo{gHq|W`oP3Pse)4@R`ln_DRV!Mp-w`DVO3SXY(#_tRe*xF zbB-;MXPed=dZ>!3bOtvnYa6cNEd8kCh49nKY$z}VMha^4ciikYy@;p5>MM{*~ z(#7m_eZDf@^;bk3hLxK%_v1W{w(|BwLgWLHnud0r>FEcSte4H8F%R546H+_By(jdp=H0@^IBpyV2z!-a-JO;(v8v`isvhMePFniq zSxFh`<}~;Molm`r6k;J^FVGdI_5cy=6);i?13{tSqw((5GLhwz+55?r4!NBClsZs+ z`Oh0ZBR0eJ8%l6)fF~tHC!@o$L}t^P?UT%n+QB}@*)*q=Hw~5?dAI-8>|HEuf7dp+ ziQjXopu4j2s12>&3AwW=!wjPQozr&vjh^3KP7$?uXeddg9*$Ix%|X5XDReWqBt@U~ zlX1n|p7EG8+Ct@mP)?38+cjE)zWvO0Yea;Zub1B)>@SI+;Abs8=>0e$Na!w5 z*Cs$nN?xamwcW>QqyH`V1zGfQWYa&WL9vomm(h7jC)H9?`rl|zbw4HH{D9^j;cqiC zBF}wwqt$4f4!?6EIq|T0$OXnO#dCQwWrwweg0bdx@vX0O@#Y#ysF&@f_4d}-z~C$2 zzsbt$f5O0z7dnifYq`*yTK_@LR!Oi`YxPW)4s+dsL85$4&Ru^Db~(jTcx)tv5-Weu z?eQHvfSZNjUH<@)M|&Pn0K)?}tHGZ{Y0f)ekuP9HJMS}v=TzftCmJ=}Fp+9Krb;5C zH9nm8!J0-cg+eH>i4X8Fx)-wNnOlyIp`mG<=f!qC^dnoi(141-b>qJ5%%ZAB2JQCt z##$IH-q`pbQur_35pSHpgKj@yK2-tojhqj|ON82GSSzb&j)**tA3n$Z1Xe#fJyQSv zmaPciMitI|K*JKN6L$N<<2QOxk?v5sLeqzZNWvEO1e2$bV+?0ARkj)bIy~y#y4+EU!7JZjubKq7A@MgaWIm~9IXQV;4l{i?T+-a*H;+d&+#@P^AWtkXE}d8XE$*g zyx#(!OH|2{c~WBW$2o7m3{Z7^+K{<7!R09j(WQKPPB|kXxF)J-B-Kp< zb3XEug5$!g-0^Kp$xN*Kc@A!;$;C(d$(_?e$tH*V>e9A_L zdq=c*?#40?{B&Ociib9<(e~&?*$gTgD!&4a3d`RsHczjH68}VPJ_6M&FSiHXonD9V^Agn#Y0i0U9-3x$hIKPCosLh$M02vG zYM;{Zybe*LeeijYyr1qi&xg{f4a~69sJsnb7n&f)#N4Qo1AOpT{bXyve7sqAm3CI2 zV$Z#3ZQc2ArRN*%DTf@Z?vTxD{c#iPtTo}i_vHqjbc(dL_Dwv#huOu$Cr)?bNyJl% zi1noDZ?kD>h3S*<$*IjsB6niHlIJ@3K@ZjbL_;BSJ)M>KW^eE|I z;LtzR8J~@$*R^c?5iF|wY-F+J2Wj5ZSzhg-PAc!it>eBZJGmLb(A`K@vGzTr4M7

    9uxZbm^UpV;#;n+zAbIH~91 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 x=QCHDXE?2Y){3j$df<*uT literal 0 HcmV?d00001 diff --git a/testdata/snapshots/darwin/trade_history_table-light.png b/testdata/snapshots/darwin/trade_history_table-light.png new file mode 100644 index 0000000000000000000000000000000000000000..1b2f118f53eea0278aec364dd2748065ced7be79 GIT binary patch literal 22690 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 literal 0 HcmV?d00001 diff --git a/ticker_tape.go b/ticker_tape.go new file mode 100644 index 0000000..67cc954 --- /dev/null +++ b/ticker_tape.go @@ -0,0 +1,155 @@ +package mujica + +import ( + "fmt" + "log/slog" + "math" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" + "mujicaui/theme" +) + +// TickerItem is one symbol on a TickerTape. +type TickerItem struct { + Symbol string + Price float64 + ChangePercent float64 +} + +// TickerTapeOptions configure a TickerTape. +type TickerTapeOptions struct { + // Decimals of the prices; zero means 2. + Decimals int + // Speed is in DIPs a second; zero means 40. + Speed float32 + // PerPage is items per reduced-motion page; zero means 4. + PerPage int + // Label names the tape; empty uses the built-in "Market ticker". + Label string +} + +type tickerTapeState struct { + offset float32 + last time.Time + page int + paused bool +} + +// TickerTape loops quotes, pausing on hover or focus. +func TickerTape(c *ui.Context, items []TickerItem, opts TickerTapeOptions) *ui.Element { + if opts.Speed < 0 || opts.PerPage < 0 { + panic("mujica: TickerTape Speed and PerPage cannot be negative") + } + dec := priceDecimals("TickerTape", opts.Decimals) + speed, per := opts.Speed, opts.PerPage + if speed == 0 { + speed = 40 + } + if per == 0 { + per = 4 + } + label := opts.Label + if label == "" { + label = msg(c, "ticker_tape.label") + } + k := Tokens(c) + d := Density(c) + e := ui.Row(c).MinHeight(d.ControlHeight()).AlignItems(ui.Center).Background(k.Surface). + BorderWidth(theme.BorderWidth, 0).BorderColor(k.Border).Focusable().Role(ui.RoleGroup).Label(label) + e.FocusRing(false) + st := ui.Local(e, "tape", func() tickerTapeState { return tickerTapeState{} }) + if c.Preferences().ReduceMotion || len(items) == 0 { + tickerTapePages(c, e, st, items, per, dec) + return e + } + paused := e.Hovered() || e.FocusWithin() + if paused != st.paused { + st.paused = paused + slog.Debug("mujica: ticker_tape paused", "paused", paused) + } + now := c.Now() + if !paused && !st.last.IsZero() { + st.offset += float32(now.Sub(st.last).Seconds()) * speed + } + st.last = now + if !paused { + c.AnimationFrame() + } + e.Description(msg(c, "ticker_tape.pause_hint")) + e.ClipX().Children(func() { + strip := ui.Row(c).Absolute().Top(0).Bottom(0).AlignItems(ui.Center) + if w := strip.Bounds().W / 2; w > 0 { + st.offset = float32(math.Mod(float64(st.offset), float64(w))) + } + // Quarter steps keep the moving text on the renderer's grid. + strip.Left(-float32(math.Round(float64(st.offset)*4)) / 4) + strip.Children(func() { + // The second copy fills in as the first scrolls out. + for n := range 2 { + r := ui.Row(c).Key(n).AlignItems(ui.Center).Shrink(0) + if n == 1 { + r.Role(ui.RoleNone) + } + r.Children(func() { + for _, it := range items { + tickerTapeItem(c, it, dec) + } + }) + } + }) + }) + return e +} + +// tickerTapePages shows one page of items, for reduced motion. +func tickerTapePages(c *ui.Context, e *ui.Element, st *tickerTapeState, items []TickerItem, per, dec int) { + pages := max(1, (len(items)+per-1)/per) + st.page = min(st.page, pages-1) + turn := func(by int) { + if !e.IsDisabled() { + st.page = (st.page + by + pages) % pages + slog.Debug("mujica: ticker_tape page", "page", st.page) + } + } + if e.Shortcut(0, ui.KeyRight) { + turn(1) + } + if e.Shortcut(0, ui.KeyLeft) { + turn(-1) + } + k := Tokens(c) + e.Children(func() { + ui.Row(c).Grow(1).MinWidth(0).ClipX().AlignItems(ui.Center).Children(func() { + for _, it := range items[st.page*per : min(len(items), (st.page+1)*per)] { + tickerTapeItem(c, it, dec) + } + }) + if pages < 2 { + return + } + if iconAction(c, icons.Must("chevron-left"), msg(c, "ticker_tape.previous")).Clicked() { + turn(-1) + } + ui.Text(c, fmt.Sprintf("%d / %d", st.page+1, pages)).TextColor(k.TextMuted).FontSize(FontSize(c, theme.CaptionSize)).FontFeatures("tnum") + if iconAction(c, icons.Must("chevron-right"), msg(c, "ticker_tape.next")).Clicked() { + turn(1) + } + }) +} + +// tickerTapeItem is one symbol, price and change. +func tickerTapeItem(c *ui.Context, it TickerItem, dec int) { + u := Density(c).Unit() + sign := trendSign(it.ChangePercent) + ui.Row(c).Gap(u*1.5).AlignItems(ui.Center).Padding(0, u*4).Shrink(0).Children(func() { + ui.Text(c, it.Symbol).FontWeight(600).SingleLine() + ui.Text(c, statisticFormat(it.Price, dec)).FontFeatures("tnum").SingleLine() + ui.Row(c).Gap(u / 2).AlignItems(ui.Center).TextColor(trendColor(c, sign)).Label(trendWord(c, sign) + " " + statisticSigned(it.ChangePercent, 2) + "%").Children(func() { + ui.Icon(c, trendIcon(sign)).Size(12, 12) + ui.Text(c, statisticSigned(it.ChangePercent, 2)+"%").FontFeatures("tnum").SingleLine() + }) + }) +} diff --git a/ticker_tape_test.go b/ticker_tape_test.go new file mode 100644 index 0000000..12073db --- /dev/null +++ b/ticker_tape_test.go @@ -0,0 +1,93 @@ +package mujica + +import ( + "fmt" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +func tickerTapeItems(n int) []TickerItem { + var items []TickerItem + for i := range n { + items = append(items, TickerItem{Symbol: fmt.Sprintf("SYM%d", i), Price: 100 + float64(i), ChangePercent: float64(i%3 - 1)}) + } + return items +} + +func tickerTapeX(t *testing.T, tt *ui.Tester) float32 { + t.Helper() + r, ok := tt.Find("SYM0") + if !ok { + t.Fatalf("no SYM0 in %q", tt.Texts()) + } + return r.X +} + +func TestTickerTapeScrollsAndPausesOnHover(t *testing.T) { + tt := tradingTester(GreenUp, 400, 80, func(c *ui.Context) { + ui.Box(c).Width(380).Children(func() { TickerTape(c, tickerTapeItems(6), TickerTapeOptions{Speed: 200}) }) + }) + x0 := tickerTapeX(t, tt) + time.Sleep(60 * time.Millisecond) + tt.Frame() + x1 := tickerTapeX(t, tt) + if x1 >= x0 { + t.Fatalf("did not scroll: %v -> %v", x0, x1) + } + tt.Move(100, 25) + tt.Frame() + x2 := tickerTapeX(t, tt) + time.Sleep(60 * time.Millisecond) + tt.Frame() + if x3 := tickerTapeX(t, tt); x3 != x2 { + t.Fatalf("moved under the pointer: %v -> %v", x2, x3) + } +} + +func TestTickerTapePausesOnFocus(t *testing.T) { + tt := tradingTester(GreenUp, 400, 80, func(c *ui.Context) { + ui.Box(c).Width(380).Children(func() { TickerTape(c, tickerTapeItems(6), TickerTapeOptions{Speed: 200}) }) + }) + tt.Key(0, ui.KeyTab) + if !tt.Focused("Market ticker") { + t.Fatal("tape not focusable") + } + x0 := tickerTapeX(t, tt) + time.Sleep(60 * time.Millisecond) + tt.Frame() + if x1 := tickerTapeX(t, tt); x1 != x0 { + t.Fatalf("moved while focused: %v -> %v", x0, x1) + } +} + +func TestTickerTapePagesUnderReducedMotion(t *testing.T) { + tt := tradingTester(GreenUp, 500, 80, func(c *ui.Context) { + TickerTape(c, tickerTapeItems(5), TickerTapeOptions{PerPage: 2}) + }) + tt.SetPreferences(ui.Preferences{ReduceMotion: true, TextScale: 1}) + if !tt.HasText("SYM0") || tt.HasText("SYM2") || !tt.HasText("1 / 3") || !tt.HasText("−1.00%") { + t.Fatalf("page 1: %q", tt.Texts()) + } + if err := tt.Click("Next page"); err != nil { + t.Fatal(err) + } + if !tt.HasText("SYM2") || tt.HasText("SYM0") || !tt.HasText("+1.00%") { + t.Fatalf("page 2: %q", tt.Texts()) + } + tt.Key(0, ui.KeyTab) + tt.Key(0, ui.KeyLeft) + tt.Key(0, ui.KeyLeft) + if !tt.HasText("SYM4") || !tt.HasText("3 / 3") { + t.Fatalf("wrap back: %q", tt.Texts()) + } +} + +func TestTickerTapeSnapshot(t *testing.T) { + snapshot(t, "ticker_tape", 520, 60, func(c *ui.Context) { + ui.Column(c).Padding(10).Children(func() { + TickerTape(c, []TickerItem{{"MUJC", 412.08, -1.35}, {"AVE", 88.2, 2.1}, {"OBLV", 1204.5, 0}}, TickerTapeOptions{}) + }) + }) +} diff --git a/time_and_sales.go b/time_and_sales.go new file mode 100644 index 0000000..0a6c186 --- /dev/null +++ b/time_and_sales.go @@ -0,0 +1,137 @@ +package mujica + +import ( + "fmt" + "log/slog" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/internal" + "mujicaui/theme" +) + +// TradePrint is one executed trade on the tape. +type TradePrint struct { + // ID identifies the trade; required and unique. + ID string + Time time.Time + Price float64 + Size float64 + Side OrderSide +} + +// TimeAndSalesOptions configure a TimeAndSales. +type TimeAndSalesOptions struct { + // Decimals of prices and sizes; zero means 2 and 0. + Decimals, SizeDecimals int + // LargeSize marks trades at or above it; zero marks none. + LargeSize float64 + // Height of the list in DIPs; zero means 320. + Height float32 + Status DataStatus + Error string +} + +// TimeAndSalesState is the tape's follow state and list place. +type TimeAndSalesState struct { + // Paused stops new trades from showing until resumed. + Paused bool + frozen int + shown int + list ListState[string] +} + +// TimeAndSales lists trades newest on top; Paused holds the view. +func TimeAndSales(c *ui.Context, s *TimeAndSalesState, trades []TradePrint, opts TimeAndSalesOptions) ChoiceResult { + dec := priceDecimals("TimeAndSales", opts.Decimals) + if opts.SizeDecimals < 0 || opts.LargeSize < 0 || opts.Height < 0 { + panic("mujica: TimeAndSales SizeDecimals, LargeSize and Height cannot be negative") + } + height := opts.Height + if height == 0 { + height = 320 + } + if !s.Paused { + s.frozen = len(trades) + } + s.frozen = min(s.frozen, len(trades)) + n := s.frozen + if !s.Paused && n != s.shown { + s.list.ScrollTo(0) + } + s.shown = n + k := Tokens(c) + d := Density(c) + var r ChoiceResult + r.Element = ui.Column(c).Gap(d.Unit() * 2).Height(height) + r.Element.Children(func() { + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).Children(func() { + ui.Text(c, msg(c, "time_and_sales.title")).Font(theme.SerifFont).FontWeight(600).Grow(1) + label := msg(c, "time_and_sales.pause") + if s.Paused { + label = msg(c, "time_and_sales.resume") + if waiting := len(trades) - n; waiting > 0 { + label = fmt.Sprintf(msg(c, "time_and_sales.resume_count"), waiting) + } + } + if Button(c, label, ButtonOptions{Variant: Secondary}).Clicked() { + s.Paused, r.changed = !s.Paused, true + slog.Debug("mujica: time_and_sales follow", "paused", s.Paused) + } + }) + ui.Row(c).Padding(0, d.Unit()*4).Gap(d.Unit() * 2).Children(func() { + for i, key := range []string{"time_and_sales.time", "time_and_sales.price", "time_and_sales.size"} { + t := ui.Text(c, msg(c, key)).FontSize(FontSize(c, theme.CaptionSize)).TextColor(k.TextMuted).Grow(1).Basis(0) + if i > 0 { + t.TextAlign(ui.End) + } + } + ui.Box(c).Width(16) + }) + at := func(i int) TradePrint { return trades[n-1-i] } + List(c, &s.list, n, ListOptions[string]{ + Key: func(i int) string { return at(i).ID }, + Label: func(i int) string { + t := at(i) + return timeAndSalesSpoken(c, t, dec, opts) + }, + Status: opts.Status, Error: opts.Error, Empty: msg(c, "time_and_sales.empty"), + }, func(i int) { timeAndSalesRow(c, at(i), dec, opts) }).Element.Grow(1) + }) + return r +} + +func timeAndSalesLarge(t TradePrint, opts TimeAndSalesOptions) bool { + return opts.LargeSize > 0 && t.Size >= opts.LargeSize +} + +// timeAndSalesSpoken reads a trade with its side and size. +func timeAndSalesSpoken(c *ui.Context, t TradePrint, dec int, opts TimeAndSalesOptions) string { + s := fmt.Sprintf("%s %s %s %s", t.Time.Format("15:04:05"), msg(c, fmt.Sprintf("order_book.side%d", t.Side)), + statisticFormat(t.Price, dec), statisticFormat(t.Size, opts.SizeDecimals)) + if timeAndSalesLarge(t, opts) { + s += ", " + msg(c, "time_and_sales.large") + } + return s +} + +// timeAndSalesRow is one trade with its side and large mark. +func timeAndSalesRow(c *ui.Context, t TradePrint, dec int, opts TimeAndSalesOptions) { + k := Tokens(c) + large := timeAndSalesLarge(t, opts) + sign := t.Side.sign() + ui.Text(c, t.Time.Format("15:04:05")).FontFeatures("tnum").TextColor(k.TextMuted).Grow(1).Basis(0).SingleLine() + ui.Row(c).Gap(2).Justify(ui.End).AlignItems(ui.Center).Grow(1).Basis(0).TextColor(trendColor(c, sign)).Children(func() { + ui.Icon(c, trendIcon(sign)).Size(12, 12) + ui.Text(c, statisticFormat(t.Price, dec)).FontFeatures("tnum").SingleLine() + }) + size := ui.Text(c, statisticFormat(t.Size, opts.SizeDecimals)).FontFeatures("tnum").TextAlign(ui.End).Grow(1).Basis(0).SingleLine() + mark := ui.Box(c).Size(16, 16).Shrink(0) + if large { + size.FontWeight(700) + mark.Draw(func(p *ui.Painter, r ui.Rect) { + p.FillPath(internal.Diamond(r.X+r.W/2, r.Y+r.H/2, 10), k.AccentText) + }) + } +} diff --git a/time_and_sales_test.go b/time_and_sales_test.go new file mode 100644 index 0000000..5bb8056 --- /dev/null +++ b/time_and_sales_test.go @@ -0,0 +1,90 @@ +package mujica + +import ( + "fmt" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +func timeAndSalesTrades(n int) []TradePrint { + at := time.Date(2026, 10, 5, 9, 30, 0, 0, time.UTC) + out := make([]TradePrint, n) + for i := range out { + side := SideBuy + if i%2 == 1 { + side = SideSell + } + out[i] = TradePrint{ID: fmt.Sprint(i), Time: at.Add(time.Duration(i) * time.Second), Price: 100 + float64(i%50)/100, Size: float64(i%7 + 1), Side: side} + } + return out +} + +func TestTimeAndSalesNewestFirstAndLargeMark(t *testing.T) { + var s TimeAndSalesState + trades := timeAndSalesTrades(3) + trades[1].Size = 5000 + tt := tradingTester(GreenUp, 500, 400, func(c *ui.Context) { + TimeAndSales(c, &s, trades, TimeAndSalesOptions{LargeSize: 1000}) + }) + newest, _ := tt.Find("09:30:02") + oldest, _ := tt.Find("09:30:00") + if newest.Y >= oldest.Y { + t.Fatalf("newest %v not above oldest %v", newest, oldest) + } + if !tt.HasText("5,000") { + t.Fatalf("texts %q", tt.Texts()) + } + if _, ok := tt.Find("09:30:01 Ask 100.01 5,000, large trade"); !ok { + t.Fatal("large trade not spoken") + } +} + +func TestTimeAndSalesPauseHoldsView(t *testing.T) { + var s TimeAndSalesState + trades := timeAndSalesTrades(2) + n := 0 + tt := tradingTester(GreenUp, 500, 400, func(c *ui.Context) { + if TimeAndSales(c, &s, trades, TimeAndSalesOptions{}).Changed() { + n++ + } + }) + if err := tt.Click("Pause"); err != nil { + t.Fatal(err) + } + trades = timeAndSalesTrades(5) + tt.Frame() + if tt.HasText("09:30:04") || !tt.HasText("Resume (3 new)") || !s.Paused || n != 1 { + t.Fatalf("paused view moved: %q", tt.Texts()) + } + tt.Key(0, ui.KeyEnter) + if !tt.HasText("09:30:04") || s.Paused || n != 2 { + t.Fatalf("resume: %q", tt.Texts()) + } +} + +func TestTimeAndSalesBuildsOnlyVisibleRows(t *testing.T) { + var s TimeAndSalesState + trades := timeAndSalesTrades(100_000) + tt := tradingTester(GreenUp, 500, 400, func(c *ui.Context) { + TimeAndSales(c, &s, trades, TimeAndSalesOptions{}) + }) + if !tt.HasText("13:16:39") { + t.Fatalf("newest trade not on top: %q", tt.Texts()[:8]) + } + if got := len(tt.Texts()); got > 120 { + t.Fatalf("built %d texts for 100,000 trades", got) + } +} + +func TestTimeAndSalesSnapshot(t *testing.T) { + trades := timeAndSalesTrades(8) + trades[5].Size = 4000 + snapshot(t, "time_and_sales", 420, 360, func(c *ui.Context) { + ui.Column(c).Padding(16).Children(func() { + s := ui.Local(c.Root(), "snap", func() TimeAndSalesState { return TimeAndSalesState{} }) + TimeAndSales(c, s, trades, TimeAndSalesOptions{LargeSize: 1000, Height: 320}) + }) + }) +} diff --git a/trade_history_table.go b/trade_history_table.go new file mode 100644 index 0000000..2f64054 --- /dev/null +++ b/trade_history_table.go @@ -0,0 +1,110 @@ +package mujica + +import ( + "cmp" + "fmt" + "log/slog" + "time" + + "github.com/egoist/mygo/ui" + + "mujicaui/icons" +) + +// FillRow is one of the account's fills; ID is stable. +type FillRow struct { + ID string + Time time.Time + Symbol string + Side OrderSide + Price float64 + Quantity float64 + Fee float64 +} + +// TradeHistoryTableOptions configure a TradeHistoryTable. +type TradeHistoryTableOptions struct { + // Decimals of prices and quantities; zero means 2 and 0. + Decimals, QuantityDecimals int + // Version must change when rows change in place. + Version int + Status DataStatus + Error string + Disabled bool +} + +// TradeHistoryTableState is the date range and table state. +type TradeHistoryTableState struct { + // Range keeps fills on its days; zero keeps all. + Range DateRange + Table DataTableState[string] + cache tradingRows[FillRow] +} + +// TradeHistoryResult is a built table and its export request. +type TradeHistoryResult struct { + Element *ui.Element + Table DataTableView + exported []FillRow + export bool +} + +// Exported returns the range's fills when export was asked. +func (r TradeHistoryResult) Exported() ([]FillRow, bool) { return r.exported, r.export } + +// TradeHistoryTable lists fills by date range, with export. +func TradeHistoryTable(c *ui.Context, s *TradeHistoryTableState, rows []FillRow, opts TradeHistoryTableOptions) TradeHistoryResult { + dec := priceDecimals("TradeHistoryTable", opts.Decimals) + if opts.QuantityDecimals < 0 { + panic("mujica: TradeHistoryTable with negative QuantityDecimals") + } + rng := s.Range + shown := s.cache.view(rows, opts.Version, rng, func(f FillRow) bool { + if rng.IsZero() { + return true + } + d := DateOf(f.Time) + return d.Compare(rng.Start) >= 0 && d.Compare(rng.End) <= 0 + }) + num := func(id, key string, dp int, v func(FillRow) float64) DataColumn[FillRow] { + return DataColumn[FillRow]{ID: id, Title: msg(c, key), Align: ui.End, Sortable: true, + Compare: func(a, b FillRow) int { return cmp.Compare(v(a), v(b)) }, + Text: func(f FillRow) string { return statisticFormat(v(f), dp) }} + } + cols := []DataColumn[FillRow]{ + {ID: "time", Title: msg(c, "trade_history_table.time"), Sortable: true, Width: 180, + Compare: func(a, b FillRow) int { return a.Time.Compare(b.Time) }, + Text: func(f FillRow) string { return f.Time.Format("2006-01-02 15:04:05") }}, + {ID: "symbol", Title: msg(c, "position_table.symbol"), Sortable: true, + Compare: func(a, b FillRow) int { return cmp.Compare(a.Symbol, b.Symbol) }, + Text: func(f FillRow) string { return f.Symbol }}, + {ID: "side", Title: msg(c, "order_table.side"), Text: func(f FillRow) string { return msg(c, fmt.Sprintf("order_entry.side%d", f.Side)) }, + Cell: func(f FillRow) { tradingSide(c, f.Side) }}, + num("price", "order_book.price", dec, func(f FillRow) float64 { return f.Price }), + num("qty", "order_entry.quantity", opts.QuantityDecimals, func(f FillRow) float64 { return f.Quantity }), + num("fee", "trade_history_table.fee", dec, func(f FillRow) float64 { return f.Fee }), + } + d := Density(c) + var r TradeHistoryResult + r.Element = ui.Column(c).Gap(d.Unit() * 2).Disabled(opts.Disabled).Grow(1).FillWidth().MinHeight(0) + disabled := r.Element.IsDisabled() + r.Element.Children(func() { + ui.Row(c).Gap(d.Unit() * 2).AlignItems(ui.Center).Children(func() { + if DateRangePicker(c, &s.Range, DateRangePickerOptions{Label: msg(c, "trade_history_table.range"), Disabled: disabled}).Changed() { + slog.Debug("mujica: trade_history_table range", "days", s.Range.Days()) + } + if !s.Range.IsZero() && Button(c, msg(c, "trade_history_table.all"), ButtonOptions{Variant: Ghost, Disabled: disabled}).Clicked() && !disabled { + s.Range = DateRange{} + } + ui.Box(c).Grow(1) + if Button(c, msg(c, "trade_history_table.export"), ButtonOptions{Variant: Secondary, Icon: icons.Must("upload"), Disabled: disabled || len(shown) == 0}).Clicked() && !disabled { + r.exported, r.export = shown, true + slog.Debug("mujica: trade_history_table export", "rows", len(shown)) + } + }) + r.Table = DataTable(c, &s.Table, shown, DataTableOptions[FillRow, string]{Columns: cols, Key: func(f FillRow) string { return f.ID }, + Status: opts.Status, Error: opts.Error, Empty: msg(c, "trade_history_table.empty")}) + r.Table.Element.Grow(1) + }) + return r +} diff --git a/trade_history_table_test.go b/trade_history_table_test.go new file mode 100644 index 0000000..c2a07b8 --- /dev/null +++ b/trade_history_table_test.go @@ -0,0 +1,87 @@ +package mujica + +import ( + "fmt" + "testing" + "time" + + "github.com/egoist/mygo/ui" +) + +func tradeHistorySample() []FillRow { + day := func(d, h int) time.Time { return time.Date(2026, 10, d, h, 0, 0, 0, time.UTC) } + return []FillRow{ + {ID: "f1", Time: day(1, 10), Symbol: "MUJC", Side: SideBuy, Price: 400, Quantity: 10, Fee: 1.2}, + {ID: "f2", Time: day(3, 14), Symbol: "AVE", Side: SideSell, Price: 88.2, Quantity: 5, Fee: 0.4}, + {ID: "f3", Time: day(5, 9), Symbol: "OBLV", Side: SideBuy, Price: 12, Quantity: 100, Fee: 0.6}, + } +} + +func TestTradeHistoryTableRangeAndExport(t *testing.T) { + s := TradeHistoryTableState{Range: DateRange{Start: Date{2026, 10, 2}, End: Date{2026, 10, 4}}} + var exported []FillRow + tt := tradingTester(GreenUp, 1000, 600, func(c *ui.Context) { + ui.Box(c).Width(960).Height(400).Children(func() { + if rows, ok := TradeHistoryTable(c, &s, tradeHistorySample(), TradeHistoryTableOptions{}).Exported(); ok { + exported = rows + } + }) + }) + if tt.HasText("MUJC") || !tt.HasText("AVE") || tt.HasText("OBLV") { + t.Fatalf("range: %q", tt.Texts()) + } + if err := tt.Click("Export"); err != nil { + t.Fatal(err) + } + if len(exported) != 1 || exported[0].ID != "f2" { + t.Fatalf("exported %v", exported) + } + if err := tt.Click("All dates"); err != nil { + t.Fatal(err) + } + if !tt.HasText("MUJC") || !tt.HasText("OBLV") || !s.Range.IsZero() { + t.Fatalf("all dates: %q", tt.Texts()) + } + _ = tt.Click("Export") + if len(exported) != 3 { + t.Fatalf("exported %d", len(exported)) + } +} + +func TestTradeHistoryTableDisabled(t *testing.T) { + var s TradeHistoryTableState + exported := false + tt := tradingTester(GreenUp, 1000, 600, func(c *ui.Context) { + ui.Box(c).Width(960).Height(400).Children(func() { + _, exported = TradeHistoryTable(c, &s, tradeHistorySample(), TradeHistoryTableOptions{Disabled: true}).Exported() + }) + }) + _ = tt.Click("Export") + if exported { + t.Fatal("disabled table exported") + } +} + +func TestTradeHistoryTableSnapshot(t *testing.T) { + snapshot(t, "trade_history_table", 900, 260, func(c *ui.Context) { + ui.Column(c).Padding(16).Height(240).Width(880).Children(func() { + s := ui.Local(c.Root(), "snap", func() TradeHistoryTableState { return TradeHistoryTableState{} }) + TradeHistoryTable(c, s, tradeHistorySample(), TradeHistoryTableOptions{}) + }) + }) +} + +// 100,000 fills build only visible rows. +func TestTradeHistoryTableLargeData(t *testing.T) { + var s TradeHistoryTableState + rows := make([]FillRow, 100_000) + for i := range rows { + rows[i] = FillRow{ID: fmt.Sprint(i), Time: time.Date(2026, 1, 1, 0, 0, i, 0, time.UTC), Symbol: "S", Side: SideSell, Price: 1, Quantity: 1} + } + tt := tradingTester(GreenUp, 1000, 600, func(c *ui.Context) { + ui.Box(c).Width(960).Height(400).Children(func() { TradeHistoryTable(c, &s, rows, TradeHistoryTableOptions{}) }) + }) + if n := len(tt.Texts()); n > 400 { + t.Fatalf("built %d texts", n) + } +}