Skip to content

Commit

Permalink
multi: show recently matched orders
Browse files Browse the repository at this point in the history
  • Loading branch information
vctt94 committed Sep 20, 2022
1 parent 0ceb0ff commit f9a565e
Show file tree
Hide file tree
Showing 12 changed files with 290 additions and 21 deletions.
14 changes: 12 additions & 2 deletions client/core/bookie.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,16 @@ func (b *bookie) logEpochReport(note *msgjson.EpochReportNote) error {
return fmt.Errorf("epoch report has zero-valued candle end stamp")
}

marketID := marketName(b.base, b.quote)
b.SetMatchesSummary(note.MatchesSummarySell, note.EndStamp, true)
b.SetMatchesSummary(note.MatchesSummaryBuy, note.EndStamp, false)
if note.MatchesSummaryBuy != nil || note.MatchesSummarySell != nil {
b.send(&BookUpdate{
Action: EpochMatchSummary,
MarketID: marketID,
Payload: b.GetMatchesSummary(),
})
}
for durStr, cache := range b.candleCaches {
c := cache.addCandle(&note.Candle)
if c == nil {
Expand All @@ -200,7 +210,7 @@ func (b *bookie) logEpochReport(note *msgjson.EpochReportNote) error {
b.send(&BookUpdate{
Action: CandleUpdateAction,
Host: b.dc.acct.host,
MarketID: marketName(b.base, b.quote),
MarketID: marketID,
Payload: CandleUpdate{
Dur: durStr,
DurMilliSecs: uint64(dur.Milliseconds()),
Expand Down Expand Up @@ -1053,7 +1063,7 @@ func handleEpochReportMsg(_ *Core, dc *dexConnection, msg *msgjson.Message) erro

// handleEpochOrderMsg is called when an epoch_order notification is
// received.
func handleEpochOrderMsg(c *Core, dc *dexConnection, msg *msgjson.Message) error {
func handleEpochOrderMsg(_ *Core, dc *dexConnection, msg *msgjson.Message) error {
note := new(msgjson.EpochOrderNote)
err := msg.Unmarshal(note)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions client/core/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ const (
UnbookOrderAction = "unbook_order"
UpdateRemainingAction = "update_remaining"
CandleUpdateAction = "candle_update"
EpochMatchSummary = "epoch_match_summary"
)

// BookUpdate is an order book update.
Expand Down
66 changes: 66 additions & 0 deletions client/orderbook/orderbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"fmt"
"sync"
"sync/atomic"
"time"

"decred.org/dcrdex/dex"
"decred.org/dcrdex/dex/msgjson"
Expand Down Expand Up @@ -54,6 +55,13 @@ type rateSell struct {
sell bool
}

type MatchSummary struct {
Rate uint64 `json:"rate"`
Qty uint64 `json:"qty"`
Age time.Time `json:"age"`
Sell bool `json:"sell"`
}

// OrderBook represents a client tracked order book.
type OrderBook struct {
log dex.Logger
Expand All @@ -79,6 +87,9 @@ type OrderBook struct {
proofedEpoch uint64
epochQueues map[uint64]*EpochQueue

matchSummaryMtx sync.Mutex
matchesSummary []*MatchSummary

// feeRates is a separate struct to account for atomic field alignment in
// 32-bit systems. See also https://golang.org/pkg/sync/atomic/#pkg-note-BUG
feeRates struct {
Expand Down Expand Up @@ -604,3 +615,58 @@ func (ob *OrderBook) BestFill(sell bool, qty uint64) ([]*Fill, bool) {
func (ob *OrderBook) BestFillMarketBuy(qty, lotSize uint64) ([]*Fill, bool) {
return ob.sells.bestFill(qty, true, lotSize)
}

// SetMatchesSummary set matches summary. If the matches summary length grows
// bigger than 100, it will slice out the ones first added.
func (ob *OrderBook) SetMatchesSummary(matches map[uint64]uint64, ts uint64, sell bool) {
if matches == nil {
return
}
newMatchesSummary := make([]*MatchSummary, len(matches))
i := 0
for rate, qty := range matches {
newMatchesSummary[i] = &MatchSummary{
Rate: rate,
Qty: qty,
Age: time.UnixMilli(int64(ts)),
Sell: sell,
}
i++
}

ob.matchSummaryMtx.Lock()
defer ob.matchSummaryMtx.Unlock()
if ob.matchesSummary == nil {
ob.matchesSummary = newMatchesSummary
return
}
ob.matchesSummary = append(newMatchesSummary, ob.matchesSummary...)
maxLength := 100
// if ob.matchesSummary length is greater than max length, we slice the array
// to maxLength, removing values first added.
if len(ob.matchesSummary) > maxLength {
ob.matchesSummary = ob.matchesSummary[:maxLength]
}
}

// GetMatchesSummary returns a deep copy of MatchesSummary
func (ob *OrderBook) GetMatchesSummary() []MatchSummary {
ob.matchSummaryMtx.Lock()
defer ob.matchSummaryMtx.Unlock()
matchesSummary := make([]MatchSummary, len(ob.matchesSummary))
for i := 0; i < len(ob.matchesSummary); i++ {
matchesSummary[i] = ob.matchesSummary[i].copy()
}
return matchesSummary
}

// makes a copy of a MatchSummary
func (ob *MatchSummary) copy() MatchSummary {
matchSummary := MatchSummary{
Rate: ob.Rate,
Qty: ob.Qty,
Age: ob.Age,
Sell: ob.Sell,
}
return matchSummary
}
1 change: 1 addition & 0 deletions client/webserver/locales/en-us.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ var EnUS = map[string]string{
"immature": "immature",
"Sell Orders": "Sell Orders",
"Your Orders": "Your Orders",
"Recent Matches": "Recent Matches",
"Type": "Type",
"Side": "Side",
"Age": "Age",
Expand Down
35 changes: 35 additions & 0 deletions client/webserver/site/src/css/market.scss
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,41 @@ div.numorders {
}
}

#recentMatchesTable {
th {
align-items: center;

&:hover {
opacity: 0.7;
}

.ico-arrowdown {
display: inline-block;
visibility: hidden;
vertical-align: middle;
font-size: 10px;
margin-left: 5px;
}

&.sorted-dsc {
.ico-arrowdown {
visibility: visible;
}
}

&.sorted-asc {
.ico-arrowdown {
visibility: visible;
transform: rotate(180deg);
}
}
}

tr {
cursor: pointer;
}
}

#vDetailPane {
max-width: 425px;

Expand Down
28 changes: 28 additions & 0 deletions client/webserver/site/src/html/markets.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,34 @@
</div>
</div>

{{- /* Recently Matched orders */ -}}
<div class="bg0 p-0 col-24 col-xxl-100 d-flex flex-column align-items-stretch">
{{/* <div class="bg0 p-0 col-24 col-xxl-10 d-flex flex-column align-items-stretch"> */}}
<div class="market-header text-center fs14 py-1 brdrleft">
[[[Recent Matches]]]
</div>
<div class=" brdrleft flex-grow-1 bg1 position-relative">
<div class="stylish-overflow">
<table id="recentMatchesTable" class="ordertable">
<thead>
<tr>
<th data-ordercol="stamp">[[[Time]]] <span class="ico-arrowdown"></span></th>
<th data-ordercol="rate">[[[Rate]]] <span class="ico-arrowdown"></span></th>
<th data-ordercol="qty">[[[Quantity]]] <span class="ico-arrowdown"></span></th>
<th class="last"></th>
</tr>
</thead>
<tbody id="recentMatchesLiveList">
<tr id="recentMatchesTemplate">
<td data-tmpl="age"></td>
<td data-tmpl="rate"></td>
<td data-tmpl="qty"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>

{{- /* POP-UP FORMS */ -}}
Expand Down

0 comments on commit f9a565e

Please sign in to comment.