Files
crypto-price-bot/internal/data/market/alpha_tokens.go
T
thuanle 87e69ec8d0
Build Docker Image / build (amd64) (push) Successful in 2m21s
Remove Alpha token price caching in spotPrice map
Alpha token prices are now looked up directly from Alpha data instead
of being cached into spotPrice. Remove unused ensureAlphaCacheLoaded
and shouldRefreshAlphaCache functions.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-25 01:14:40 +07:00

153 lines
4.9 KiB
Go

package market
import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/rs/zerolog/log"
)
// AlphaTokenInfo represents the response from Binance Alpha token API
type AlphaTokenInfo struct {
TokenID string `json:"tokenId"`
ChainID string `json:"chainId"`
ChainIconURL string `json:"chainIconUrl"`
ChainName string `json:"chainName"`
ContractAddress string `json:"contractAddress"`
Name string `json:"name"`
Symbol string `json:"symbol"`
IconURL string `json:"iconUrl"`
Price string `json:"price"`
PercentChange24h string `json:"percentChange24h"`
Volume24h string `json:"volume24h"`
MarketCap string `json:"marketCap"`
FDV string `json:"fdv"`
Liquidity string `json:"liquidity"`
TotalSupply string `json:"totalSupply"`
CirculatingSupply string `json:"circulatingSupply"`
Holders string `json:"holders"`
Decimals int `json:"decimals"`
ListingCex bool `json:"listingCex"`
HotTag bool `json:"hotTag"`
CexCoinName string `json:"cexCoinName"`
CanTransfer bool `json:"canTransfer"`
Denomination int `json:"denomination"`
Offline bool `json:"offline"`
TradeDecimal int `json:"tradeDecimal"`
AlphaID string `json:"alphaId"`
Offsell bool `json:"offsell"`
PriceHigh24h string `json:"priceHigh24h"`
PriceLow24h string `json:"priceLow24h"`
Count24h string `json:"count24h"`
OnlineTge bool `json:"onlineTge"`
OnlineAirdrop bool `json:"onlineAirdrop"`
Score int `json:"score"`
CexOffDisplay bool `json:"cexOffDisplay"`
StockState bool `json:"stockState"`
ListingTime int64 `json:"listingTime"`
MulPoint int `json:"mulPoint"`
BnExclusiveState bool `json:"bnExclusiveState"`
}
// AlphaTokenResponse represents the API response structure
type AlphaTokenResponse struct {
Code string `json:"code"`
Message *string `json:"message"`
MessageDetail *string `json:"messageDetail"`
Data []AlphaTokenInfo `json:"data"`
}
// GetPrice returns the price as float64
func (a *AlphaTokenInfo) GetPrice() float64 {
price, err := strconv.ParseFloat(a.Price, 64)
if err != nil {
log.Error().Err(err).Str("symbol", a.Symbol).Msg("Failed to parse Alpha token price")
return 0
}
return price
}
// GetPercentChange24h returns the 24h percentage change as float64
func (a *AlphaTokenInfo) GetPercentChange24h() float64 {
change, err := strconv.ParseFloat(a.PercentChange24h, 64)
if err != nil {
log.Error().Err(err).Str("symbol", a.Symbol).Msg("Failed to parse Alpha token 24h change")
return 0
}
return change
}
// fetchAlphaTokens fetches Alpha tokens from Binance API
func (ms *MarketData) fetchAlphaTokens() ([]AlphaTokenInfo, error) {
const alphaTokenURL = "https://www.binance.com/bapi/defi/v1/public/wallet-direct/buw/wallet/cex/alpha/all/token/list"
client := &http.Client{
Timeout: 10 * time.Second,
}
resp, err := client.Get(alphaTokenURL)
if err != nil {
return nil, fmt.Errorf("failed to fetch Alpha tokens: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("Alpha token API returned status: %d", resp.StatusCode)
}
var tokenResponse AlphaTokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenResponse); err != nil {
return nil, fmt.Errorf("failed to decode Alpha token response: %w", err)
}
if tokenResponse.Code != "000000" {
return nil, fmt.Errorf("Alpha token API returned error code: %s", tokenResponse.Code)
}
return tokenResponse.Data, nil
}
// refreshAlphaTokenCache refreshes the Alpha token cache
func (ms *MarketData) refreshAlphaTokenCache() {
ms.alphaCacheMutex.Lock()
defer ms.alphaCacheMutex.Unlock()
log.Info().Msg("Refreshing Alpha token cache")
tokens, err := ms.fetchAlphaTokens()
if err != nil {
log.Error().Err(err).Msg("Failed to refresh Alpha token cache")
return
}
// Clear existing cache
ms.alphaTokens = make(map[string]AlphaTokenInfo)
// Populate cache with new data
for _, token := range tokens {
symbol := token.Symbol // Already uppercase from API
ms.alphaTokens[symbol] = token
}
ms.lastAlphaCacheUpdate = time.Now()
log.Info().Int("count", len(tokens)).Msg("Alpha token cache refreshed successfully")
}
// GetAlphaToken returns Alpha token info by symbol
func (ms *MarketData) GetAlphaToken(symbol string) (AlphaTokenInfo, bool) {
ms.alphaCacheMutex.RLock()
defer ms.alphaCacheMutex.RUnlock()
token, exists := ms.alphaTokens[symbol]
return token, exists
}
// IsAlphaToken checks if a symbol is an Alpha token
func (ms *MarketData) IsAlphaToken(symbol string) bool {
_, exists := ms.GetAlphaToken(symbol)
return exists
}