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:
2026-04-26 15:40:00 +07:00
parent 9c39423315
commit c7128ff516
5 changed files with 49 additions and 12 deletions
+1
View File
@@ -4,4 +4,5 @@ const (
LogEnv = "LOG_ENV"
TelegramToken = "TELEGRAM_TOKEN"
AdminChatID = "ADMIN_CHAT_ID"
)
+1
View File
@@ -4,6 +4,7 @@ import "me.thuanle/bbot/internal/data/market"
type IMarket interface {
GetFuturePrice(symbol string) (float64, float64, int64, bool)
GetAllPremiumIndex() (map[string]market.PremiumIndex, error)
GetAllFundRate() (map[string]float64, map[string]int64)
GetSpotPrice(symbol string) (float64, bool)
+31 -8
View File
@@ -36,27 +36,50 @@ func (ms *MarketData) GetFuturePrice(symbol string) (float64, float64, int64, bo
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)
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)
return nil, err
}
rates := make(map[string]float64, len(premiums))
times := make(map[string]int64, len(premiums))
result := make(map[string]PremiumIndex, len(premiums))
for _, p := range premiums {
rate, err := strconv.ParseFloat(p.LastFundingRate, 64)
markPrice, err := strconv.ParseFloat(p.MarkPrice, 64)
if err != nil {
continue
}
rates[p.Symbol] = rate
times[p.Symbol] = p.NextFundingTime
rate, _ := strconv.ParseFloat(p.LastFundingRate, 64)
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
}
+8 -4
View File
@@ -13,15 +13,19 @@ func GetTopPrices() ([]string, []float64, []float64) {
topPrice := 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 {
price, rate, _, ok := data.Market.GetFuturePrice(sym)
p, ok := all[sym]
if !ok {
continue
}
topSym[i] = sym
topPrice[i] = price
topRate[i] = rate
topPrice[i] = p.MarkPrice
topRate[i] = p.FundingRate
}
return topSym, topPrice, topRate
}
@@ -1,7 +1,11 @@
package commands
import (
"os"
"strconv"
"gopkg.in/telebot.v3"
"me.thuanle/bbot/internal/configs/key"
"me.thuanle/bbot/internal/data"
"me.thuanle/bbot/internal/services/controllers"
"me.thuanle/bbot/internal/services/tele/chat"
@@ -19,6 +23,10 @@ func OnGetTopFundingFee(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()
return chat.ReplyMessage(context, "Trading pair cache refreshed")
}