Rewrite price lookup from WebSocket to REST API
Replace unreliable WebSocket connections with on-demand REST API calls for spot and futures prices. Add cached trading pair list (refreshed hourly) for symbol validation, and /refresh command for manual updates. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,64 +1,62 @@
|
||||
package market
|
||||
|
||||
import (
|
||||
"github.com/adshao/go-binance/v2/futures"
|
||||
"github.com/rs/zerolog/log"
|
||||
"context"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (ms *MarketData) GetFuturePrice(symbol string) (float64, float64, int64, bool) {
|
||||
ms.mu.RLock()
|
||||
defer ms.mu.RUnlock()
|
||||
p, ok := ms.futureMarkPrice[symbol]
|
||||
if !ok {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
premiums, err := ms.futuresClient.NewPremiumIndexService().Symbol(symbol).Do(ctx)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Str("symbol", symbol).Msg("Failed to fetch futures premium index")
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
return p, ms.futureFundingRate[symbol], ms.futureNextFundingTime[symbol], true
|
||||
}
|
||||
|
||||
func (ms *MarketData) StartFutureWsMarkPrice() error {
|
||||
_, _, err := futures.WsAllMarkPriceServe(ms.futureWsMarkPriceHandler, ms.futureWsErrHandler)
|
||||
if len(premiums) == 0 {
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
|
||||
p := premiums[0]
|
||||
markPrice, err := strconv.ParseFloat(p.MarkPrice, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ms *MarketData) futureWsMarkPriceHandler(event futures.WsAllMarkPriceEvent) {
|
||||
ms.mu.Lock()
|
||||
defer ms.mu.Unlock()
|
||||
for _, priceEvent := range event {
|
||||
price, err := strconv.ParseFloat(priceEvent.MarkPrice, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
fundingRate, err := strconv.ParseFloat(priceEvent.FundingRate, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
ms.futureMarkPrice[priceEvent.Symbol] = price
|
||||
ms.futureFundingRate[priceEvent.Symbol] = fundingRate
|
||||
ms.futureNextFundingTime[priceEvent.Symbol] = priceEvent.NextFundingTime
|
||||
fundingRate, err := strconv.ParseFloat(p.LastFundingRate, 64)
|
||||
if err != nil {
|
||||
fundingRate = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (ms *MarketData) futureWsErrHandler(err error) {
|
||||
log.Debug().Err(err).Msg("Ws Error. Restart socket")
|
||||
_ = ms.StartFutureWsMarkPrice()
|
||||
return markPrice, fundingRate, p.NextFundingTime, true
|
||||
}
|
||||
|
||||
func (ms *MarketData) GetAllFundRate() (map[string]float64, map[string]int64) {
|
||||
ms.mu.RLock()
|
||||
defer ms.mu.RUnlock()
|
||||
rates := make(map[string]float64, len(ms.futureFundingRate))
|
||||
for k, v := range ms.futureFundingRate {
|
||||
rates[k] = v
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
defer cancel()
|
||||
|
||||
premiums, err := ms.futuresClient.NewPremiumIndexService().Do(ctx)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to fetch all futures premium index")
|
||||
return make(map[string]float64), make(map[string]int64)
|
||||
}
|
||||
times := make(map[string]int64, len(ms.futureNextFundingTime))
|
||||
for k, v := range ms.futureNextFundingTime {
|
||||
times[k] = v
|
||||
|
||||
rates := make(map[string]float64, len(premiums))
|
||||
times := make(map[string]int64, len(premiums))
|
||||
|
||||
for _, p := range premiums {
|
||||
rate, err := strconv.ParseFloat(p.LastFundingRate, 64)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
rates[p.Symbol] = rate
|
||||
times[p.Symbol] = p.NextFundingTime
|
||||
}
|
||||
|
||||
return rates, times
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user