Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

multi: add support for DCR-USDT pair on /markets view #2002

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ukane-philemon
Copy link
Collaborator

@ukane-philemon ukane-philemon commented Aug 15, 2024

  • Add Mexc exchange DCR-USDT pair.
  • Add Binance DCR-USDT pair.

Breaking Changes:

1. `ratesproto`: Rate messages are no longer `DCR-BTC` only, a new `currencyPair` field indicates which market rate is sent.
  
`ExchangeSubscription` field changed from `btcIndex` to `index`.
2. `exchanges`: Aggregated chart data has been removed. This is because combining usdt and btc market bids and asks is not
   ideal and serves very little purpose. Each market has its own chart.
3. Renamed three fields on `exchanges.ExchangeBotState`:
     - `btc_index` -> `index`
     - `dcr_btc_exchanges` -> `dcr_exchanges` (this field now returns a nested map of supported markets)
     - `btc_indices` -> `indices` (this field now returns a nested map of supported indices)
4. Affected API Endpoints:
     -  `/exchangerate` (`exchanges.ExchangeRates.Exchanges` json field returns a nested map of support markets)
     -  `/exchanges` (returns modified `exchanges.ExchangeBotState`)
Screenshot 2024-08-15 at 3 05 01 AM

Closes #2001

@ukane-philemon
Copy link
Collaborator Author

ukane-philemon commented Sep 23, 2024

This PR sets the foundation for adding other pairs and exchanges. As per UI, we can always improve on that if there are suggestions. If a redesign is want we want, I can get that sorted.

- Add Mexc exchange `DCR-USDT` pair.
- Add Binance `DCR-USDT` pair.
- Fix minor bugs

Breaking Changes:

    1. `ratesproto`: Rate messages are no longer `DCR-BTC` only, a new `currencyPair` field indicates which market rate is sent.
      
`ExchangeSubscription` field changed from `btcIndex` to `index`.
    2. `exchanges`: Aggregated chart data has been removed. This is because combining usdt and btc market bids and asks is not
       ideal and serves very little purpose. Each market has its own chart.
    3. Renamed three fields on `exchanges.ExchangeBotState`:
         - `btc_index` -> `index`
         - `dcr_btc_exchanges` -> `dcr_exchanges` (this field now returns a nested map of supported markets)
         - `btc_indices` -> `indices` (this field now returns a nested map of supported indices)
    4. Affected API Endpoints:
         -  `/exchangerate` (`exchanges.ExchangeRates.Exchanges` json field returns a nested map of support markets)
         -  `/exchanges` (returns modified `exchanges.ExchangeBotState`)

Signed-off-by: Philemon Ukane <ukanephilemon@gmail.com>
Signed-off-by: Philemon Ukane <ukanephilemon@gmail.com>
@buck54321
Copy link
Member

I can't speak for others, but the aggregate chart is kinda the whole point for me. Can't we just convert all depth to USD?

@ukane-philemon
Copy link
Collaborator Author

I can't speak for others, but the aggregate chart is kinda the whole point for me. Can't we just convert all depth to USD?

I'm expecting a review from @davecgh.

@davecgh what do you think?

Copy link
Member

@davecgh davecgh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright, I finished the review and identified a few minor things

In terms of the overall direction, I agree with @buck54321 in that I very much like the aggregated chart and find it much more useful overall.

However, I don't see any issue with having individual markets as an option as well.

@@ -1814,12 +1814,13 @@ func (c *appContext) getCandlestickChart(w http.ResponseWriter, r *http.Request)
}
token := m.RetrieveExchangeTokenCtx(r)
bin := m.RetrieveStickWidthCtx(r)
if token == "" || bin == "" {
currencyPair, error := m.RetrieveCurrencyPair(r)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like error shold be consistently named err like the rest.

if (this.hasPowConvertedTarget) {
this.powConvertedTarget.textContent = `${humanize.twoDecimals(ex.subsidy.pow / 1e8 * xcRate)} ${btcIndex}`
this.powConvertedTarget.textContent = `${humanize.twoDecimals(ex.subsidy.pow / 1e8 * xcRate)} ${index}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this PR is intended to serve as a foundation for for adding other pairs and exchanges, should be the conversion rate be parameterized instead of hard coded as 1e8?

@@ -34,7 +34,7 @@ type config struct {
LogPath string `long:"logpath" description:"Directory to log output. ([appdir]/logs/)" env:"DCRRATES_LOG_PATH"`
LogLevel string `long:"loglevel" description:"Logging level {trace, debug, info, warn, error, critical}" env:"DCRRATES_LOG_LEVEL"`
DisabledExchanges string `long:"disable-exchange" description:"Exchanges to disable. See /exchanges/exchanges.go for available exchanges. Use a comma to separate multiple exchanges" env:"DCRRATES_DISABLE_EXCHANGES"`
ExchangeCurrency string `long:"exchange-currency" description:"The default bitcoin price index. A 3-letter currency code." env:"DCRRATES_EXCHANGE_INDEX"`
ExchangeCurrency string `long:"exchange-currency" description:"The default {bitcoin, usdt} price index. A 3-letter currency code." env:"DCRRATES_EXCHANGE_INDEX"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure these should be listed inline here. It's not clear to me what it intends to set from the text. If it just said "The default price index. A 3-letter currency code.", it would make more sense imo.


// RetrieveCurrencyPair tries to fetch the currency pair from the request query.
func RetrieveCurrencyPair(r *http.Request) (exchanges.CurrencyPair, error) {
pair := exchanges.CurrencyPair(r.URL.Query().Get("currencyPair"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not super familiar with all of this code, but this does not look like it belongs in the middleware since it's specifically getting a URL query parameter as opposed to a query path parameter.

You can see looking at the other handlers in the middleware that they use chi.URLParam. For example, for BlockHashPathAndIndexCtx, it does hash := chi.URLParam(r, "blockhash") so that it pulls the hash from the query path like /block/{hash}.

Instead, you're aiming to qet the URL query parameter ?currencyPair=FOO.

It looks to me like this instead belongs over in internal/middleware/apimiddleware.go in the appContext handlers just like how e.g. func (c *appContext) ChartTypeData and func (c *appContext) getExchanges get URL query parameters inline.


// Other DCR pairs should also provide an index price for the quote
// asset.
update.Indices[exchanges.BTCIndex.String()] = xcState.BtcPrice
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a personal preference thing, but I'd rather cases like this just cast it directly to string since it makes the performance implications much more clear.

As a case in point, I had to go look up what the String method is doing to see if it was constructing it each invocation and should be cached as a result.

On the other hand update.Indices[string(exchanges.BTCIndex)] = xcState.BtcPrice is abundantly clear.

I understand the thought process is likely to make it so the type could theoretically be changed and the String method updated so the callers are not dependent on the type, but I'm not a big fan of that because it makes it too easy to mindlessly cause massive performance implications. In contrast, casts of primitive types make it obvious exactly what the implications are each call site should the type ultimately be changed.

@@ -809,14 +816,22 @@ func (exp *explorerUI) watchExchanges() {
for {
select {
case update := <-xcChans.Exchange:
sendXcUpdate(false, update.Token, update.State)
sendXcUpdate(false, update.Token, update.CurrencyPair.String(), update.State)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same type of thing here regarding the CurrencyPair. Could just directly cast it.

I won't comment on all the rest of the cases, but the same holds for them too.

}
}
}
if price == 0 {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't really matter since price will be zero when there are no sources due to above logic, but this really should be checking if nSources == 0, because it's the divisor that must be non-zero, not the dividend.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Decred Markets Page: Add Binance USDT Volume
3 participants