Address PR #15 review: batch API calls and admin-guard /refresh
1. Add GetAllPremiumIndex() to fetch all futures data in one call, used by GetTopPrices instead of per-symbol sequential calls. 2. Add ADMIN_CHAT_ID env check to /refresh command to restrict access to authorized users only. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -4,4 +4,5 @@ const (
|
|||||||
LogEnv = "LOG_ENV"
|
LogEnv = "LOG_ENV"
|
||||||
|
|
||||||
TelegramToken = "TELEGRAM_TOKEN"
|
TelegramToken = "TELEGRAM_TOKEN"
|
||||||
|
AdminChatID = "ADMIN_CHAT_ID"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import "me.thuanle/bbot/internal/data/market"
|
|||||||
|
|
||||||
type IMarket interface {
|
type IMarket interface {
|
||||||
GetFuturePrice(symbol string) (float64, float64, int64, bool)
|
GetFuturePrice(symbol string) (float64, float64, int64, bool)
|
||||||
|
GetAllPremiumIndex() (map[string]market.PremiumIndex, error)
|
||||||
GetAllFundRate() (map[string]float64, map[string]int64)
|
GetAllFundRate() (map[string]float64, map[string]int64)
|
||||||
|
|
||||||
GetSpotPrice(symbol string) (float64, bool)
|
GetSpotPrice(symbol string) (float64, bool)
|
||||||
|
|||||||
@@ -36,27 +36,50 @@ func (ms *MarketData) GetFuturePrice(symbol string) (float64, float64, int64, bo
|
|||||||
return markPrice, fundingRate, p.NextFundingTime, true
|
return markPrice, fundingRate, p.NextFundingTime, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MarketData) GetAllFundRate() (map[string]float64, map[string]int64) {
|
type PremiumIndex struct {
|
||||||
|
MarkPrice float64
|
||||||
|
FundingRate float64
|
||||||
|
NextFundingTime int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) GetAllPremiumIndex() (map[string]PremiumIndex, error) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
premiums, err := ms.futuresClient.NewPremiumIndexService().Do(ctx)
|
premiums, err := ms.futuresClient.NewPremiumIndexService().Do(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("Failed to fetch all futures premium index")
|
log.Error().Err(err).Msg("Failed to fetch all futures premium index")
|
||||||
return make(map[string]float64), make(map[string]int64)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
rates := make(map[string]float64, len(premiums))
|
result := make(map[string]PremiumIndex, len(premiums))
|
||||||
times := make(map[string]int64, len(premiums))
|
|
||||||
|
|
||||||
for _, p := range premiums {
|
for _, p := range premiums {
|
||||||
rate, err := strconv.ParseFloat(p.LastFundingRate, 64)
|
markPrice, err := strconv.ParseFloat(p.MarkPrice, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rates[p.Symbol] = rate
|
rate, _ := strconv.ParseFloat(p.LastFundingRate, 64)
|
||||||
times[p.Symbol] = p.NextFundingTime
|
result[p.Symbol] = PremiumIndex{
|
||||||
|
MarkPrice: markPrice,
|
||||||
|
FundingRate: rate,
|
||||||
|
NextFundingTime: p.NextFundingTime,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) GetAllFundRate() (map[string]float64, map[string]int64) {
|
||||||
|
all, err := ms.GetAllPremiumIndex()
|
||||||
|
if err != nil {
|
||||||
|
return make(map[string]float64), make(map[string]int64)
|
||||||
|
}
|
||||||
|
|
||||||
|
rates := make(map[string]float64, len(all))
|
||||||
|
times := make(map[string]int64, len(all))
|
||||||
|
for sym, p := range all {
|
||||||
|
rates[sym] = p.FundingRate
|
||||||
|
times[sym] = p.NextFundingTime
|
||||||
|
}
|
||||||
return rates, times
|
return rates, times
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,15 +13,19 @@ func GetTopPrices() ([]string, []float64, []float64) {
|
|||||||
topPrice := make([]float64, n)
|
topPrice := make([]float64, n)
|
||||||
topRate := make([]float64, n)
|
topRate := make([]float64, n)
|
||||||
|
|
||||||
|
all, err := data.Market.GetAllPremiumIndex()
|
||||||
|
if err != nil {
|
||||||
|
return topSym, topPrice, topRate
|
||||||
|
}
|
||||||
|
|
||||||
for i, sym := range strategy.TopPriceSymbols {
|
for i, sym := range strategy.TopPriceSymbols {
|
||||||
price, rate, _, ok := data.Market.GetFuturePrice(sym)
|
p, ok := all[sym]
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
topSym[i] = sym
|
topSym[i] = sym
|
||||||
topPrice[i] = price
|
topPrice[i] = p.MarkPrice
|
||||||
topRate[i] = rate
|
topRate[i] = p.FundingRate
|
||||||
|
|
||||||
}
|
}
|
||||||
return topSym, topPrice, topRate
|
return topSym, topPrice, topRate
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
package commands
|
package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"gopkg.in/telebot.v3"
|
"gopkg.in/telebot.v3"
|
||||||
|
"me.thuanle/bbot/internal/configs/key"
|
||||||
"me.thuanle/bbot/internal/data"
|
"me.thuanle/bbot/internal/data"
|
||||||
"me.thuanle/bbot/internal/services/controllers"
|
"me.thuanle/bbot/internal/services/controllers"
|
||||||
"me.thuanle/bbot/internal/services/tele/chat"
|
"me.thuanle/bbot/internal/services/tele/chat"
|
||||||
@@ -19,6 +23,10 @@ func OnGetTopFundingFee(context telebot.Context) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func OnRefreshPairCache(context telebot.Context) error {
|
func OnRefreshPairCache(context telebot.Context) error {
|
||||||
|
adminID, _ := strconv.ParseInt(os.Getenv(key.AdminChatID), 10, 64)
|
||||||
|
if adminID != 0 && context.Sender().ID != adminID {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
data.Market.RefreshTradingPairCache()
|
data.Market.RefreshTradingPairCache()
|
||||||
return chat.ReplyMessage(context, "Trading pair cache refreshed")
|
return chat.ReplyMessage(context, "Trading pair cache refreshed")
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user