Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 41c1bdfa22 |
@@ -4,5 +4,4 @@ const (
|
|||||||
LogEnv = "LOG_ENV"
|
LogEnv = "LOG_ENV"
|
||||||
|
|
||||||
TelegramToken = "TELEGRAM_TOKEN"
|
TelegramToken = "TELEGRAM_TOKEN"
|
||||||
AdminChatID = "ADMIN_CHAT_ID"
|
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ 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)
|
||||||
@@ -13,9 +12,4 @@ type IMarket interface {
|
|||||||
// Alpha token methods
|
// Alpha token methods
|
||||||
IsAlphaToken(symbol string) bool
|
IsAlphaToken(symbol string) bool
|
||||||
GetAlphaToken(symbol string) (market.AlphaTokenInfo, bool)
|
GetAlphaToken(symbol string) (market.AlphaTokenInfo, bool)
|
||||||
|
|
||||||
// Trading pair methods
|
|
||||||
IsSpotPair(symbol string) bool
|
|
||||||
IsFuturesPair(symbol string) bool
|
|
||||||
RefreshTradingPairCache() error
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,85 +1,64 @@
|
|||||||
package market
|
package market
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"github.com/adshao/go-binance/v2/futures"
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ms *MarketData) GetFuturePrice(symbol string) (float64, float64, int64, bool) {
|
func (ms *MarketData) GetFuturePrice(symbol string) (float64, float64, int64, bool) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ms.mu.RLock()
|
||||||
defer cancel()
|
defer ms.mu.RUnlock()
|
||||||
|
p, ok := ms.futureMarkPrice[symbol]
|
||||||
premiums, err := ms.futuresClient.NewPremiumIndexService().Symbol(symbol).Do(ctx)
|
if !ok {
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Str("symbol", symbol).Msg("Failed to fetch futures premium index")
|
|
||||||
return 0, 0, 0, false
|
return 0, 0, 0, false
|
||||||
}
|
}
|
||||||
|
return p, ms.futureFundingRate[symbol], ms.futureNextFundingTime[symbol], true
|
||||||
if len(premiums) == 0 {
|
|
||||||
return 0, 0, 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
p := premiums[0]
|
|
||||||
markPrice, err := strconv.ParseFloat(p.MarkPrice, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0, 0, 0, false
|
|
||||||
}
|
|
||||||
|
|
||||||
fundingRate, err := strconv.ParseFloat(p.LastFundingRate, 64)
|
|
||||||
if err != nil {
|
|
||||||
fundingRate = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return markPrice, fundingRate, p.NextFundingTime, true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PremiumIndex struct {
|
func (ms *MarketData) StartFutureWsMarkPrice() error {
|
||||||
MarkPrice float64
|
_, _, err := futures.WsAllMarkPriceServe(ms.futureWsMarkPriceHandler, ms.futureWsErrHandler)
|
||||||
FundingRate float64
|
if err != nil {
|
||||||
NextFundingTime int64
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MarketData) GetAllPremiumIndex() (map[string]PremiumIndex, error) {
|
func (ms *MarketData) futureWsMarkPriceHandler(event futures.WsAllMarkPriceEvent) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
ms.mu.Lock()
|
||||||
defer cancel()
|
defer ms.mu.Unlock()
|
||||||
|
for _, priceEvent := range event {
|
||||||
premiums, err := ms.futuresClient.NewPremiumIndexService().Do(ctx)
|
price, err := strconv.ParseFloat(priceEvent.MarkPrice, 64)
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to fetch all futures premium index")
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make(map[string]PremiumIndex, len(premiums))
|
|
||||||
for _, p := range premiums {
|
|
||||||
markPrice, err := strconv.ParseFloat(p.MarkPrice, 64)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
rate, _ := strconv.ParseFloat(p.LastFundingRate, 64)
|
|
||||||
result[p.Symbol] = PremiumIndex{
|
|
||||||
MarkPrice: markPrice,
|
|
||||||
FundingRate: rate,
|
|
||||||
NextFundingTime: p.NextFundingTime,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) futureWsErrHandler(err error) {
|
||||||
|
log.Debug().Err(err).Msg("Ws Error. Restart socket")
|
||||||
|
_ = ms.StartFutureWsMarkPrice()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MarketData) GetAllFundRate() (map[string]float64, map[string]int64) {
|
func (ms *MarketData) GetAllFundRate() (map[string]float64, map[string]int64) {
|
||||||
all, err := ms.GetAllPremiumIndex()
|
ms.mu.RLock()
|
||||||
if err != nil {
|
defer ms.mu.RUnlock()
|
||||||
return make(map[string]float64), make(map[string]int64)
|
rates := make(map[string]float64, len(ms.futureFundingRate))
|
||||||
|
for k, v := range ms.futureFundingRate {
|
||||||
|
rates[k] = v
|
||||||
}
|
}
|
||||||
|
times := make(map[string]int64, len(ms.futureNextFundingTime))
|
||||||
rates := make(map[string]float64, len(all))
|
for k, v := range ms.futureNextFundingTime {
|
||||||
times := make(map[string]int64, len(all))
|
times[k] = v
|
||||||
for sym, p := range all {
|
|
||||||
rates[sym] = p.FundingRate
|
|
||||||
times[sym] = p.NextFundingTime
|
|
||||||
}
|
}
|
||||||
return rates, times
|
return rates, times
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,42 +4,37 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/adshao/go-binance/v2"
|
|
||||||
"github.com/adshao/go-binance/v2/futures"
|
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MarketData struct {
|
type MarketData struct {
|
||||||
// Trading pair caches
|
mu sync.RWMutex
|
||||||
spotPairs map[string]bool
|
futureMarkPrice map[string]float64
|
||||||
futuresPairs map[string]bool
|
futureFundingRate map[string]float64
|
||||||
pairCacheMutex sync.RWMutex
|
futureNextFundingTime map[string]int64
|
||||||
lastPairCacheUpdate time.Time
|
|
||||||
|
spotPrice map[string]float64
|
||||||
|
|
||||||
// Alpha token cache
|
// Alpha token cache
|
||||||
alphaTokens map[string]AlphaTokenInfo
|
alphaTokens map[string]AlphaTokenInfo
|
||||||
alphaCacheMutex sync.RWMutex
|
alphaCacheMutex sync.RWMutex
|
||||||
lastAlphaCacheUpdate time.Time
|
lastAlphaCacheUpdate time.Time
|
||||||
|
|
||||||
// Binance REST clients
|
|
||||||
spotClient *binance.Client
|
|
||||||
futuresClient *futures.Client
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewMarketData() *MarketData {
|
func NewMarketData() *MarketData {
|
||||||
log.Info().Msg("Start market service")
|
log.Info().Msg("Start market service")
|
||||||
ms := &MarketData{
|
ms := &MarketData{
|
||||||
spotPairs: make(map[string]bool),
|
futureMarkPrice: make(map[string]float64),
|
||||||
futuresPairs: make(map[string]bool),
|
futureFundingRate: make(map[string]float64),
|
||||||
alphaTokens: make(map[string]AlphaTokenInfo),
|
futureNextFundingTime: make(map[string]int64),
|
||||||
spotClient: binance.NewClient("", ""),
|
|
||||||
futuresClient: futures.NewClient("", ""),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ms.refreshTradingPairCache(); err != nil {
|
spotPrice: make(map[string]float64),
|
||||||
log.Error().Err(err).Msg("Failed initial trading pair cache load")
|
alphaTokens: make(map[string]AlphaTokenInfo),
|
||||||
}
|
}
|
||||||
go ms.pairCacheRefreshLoop()
|
_ = ms.StartFutureWsMarkPrice()
|
||||||
|
_ = ms.StartSpotWsMarkPrice()
|
||||||
|
|
||||||
|
// Initialize Alpha token cache and refresh every hour
|
||||||
go ms.alphaCacheRefreshLoop()
|
go ms.alphaCacheRefreshLoop()
|
||||||
|
|
||||||
return ms
|
return ms
|
||||||
|
|||||||
@@ -1,36 +1,21 @@
|
|||||||
package market
|
package market
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
|
"github.com/adshao/go-binance/v2"
|
||||||
"github.com/rs/zerolog/log"
|
"github.com/rs/zerolog/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (ms *MarketData) GetSpotPrice(symbol string) (float64, bool) {
|
func (ms *MarketData) GetSpotPrice(symbol string) (float64, bool) {
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
ms.mu.RLock()
|
||||||
defer cancel()
|
p, ok := ms.spotPrice[symbol]
|
||||||
|
ms.mu.RUnlock()
|
||||||
prices, err := ms.spotClient.NewListPricesService().Symbol(symbol).Do(ctx)
|
if ok {
|
||||||
if err != nil {
|
return p, true
|
||||||
log.Error().Err(err).Str("symbol", symbol).Msg("Failed to fetch spot price")
|
|
||||||
return ms.getAlphaPrice(symbol)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(prices) == 0 {
|
// If not found, check if it's an Alpha token
|
||||||
return ms.getAlphaPrice(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
price, err := strconv.ParseFloat(prices[0].Price, 64)
|
|
||||||
if err != nil || price == 0 {
|
|
||||||
return ms.getAlphaPrice(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
return price, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *MarketData) getAlphaPrice(symbol string) (float64, bool) {
|
|
||||||
if ms.IsAlphaToken(symbol) {
|
if ms.IsAlphaToken(symbol) {
|
||||||
if alphaToken, exists := ms.GetAlphaToken(symbol); exists {
|
if alphaToken, exists := ms.GetAlphaToken(symbol); exists {
|
||||||
if price := alphaToken.GetPrice(); price > 0 {
|
if price := alphaToken.GetPrice(); price > 0 {
|
||||||
@@ -38,5 +23,32 @@ func (ms *MarketData) getAlphaPrice(symbol string) (float64, bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) StartSpotWsMarkPrice() error {
|
||||||
|
_, _, err := binance.WsAllMarketsStatServe(ms.spotWsAllMarketsStatHandler, ms.spotWsErrHandler) //.WsAllMarkPriceServe(ms.futureWsMarkPriceHandler, ms.futureWsErrHandler)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) spotWsAllMarketsStatHandler(event binance.WsAllMarketsStatEvent) {
|
||||||
|
ms.mu.Lock()
|
||||||
|
defer ms.mu.Unlock()
|
||||||
|
for _, priceEvent := range event {
|
||||||
|
price, err := strconv.ParseFloat(priceEvent.LastPrice, 64)
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ms.spotPrice[priceEvent.Symbol] = price
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ms *MarketData) spotWsErrHandler(err error) {
|
||||||
|
log.Debug().Err(err).Msg("Spot Ws Error. Restart socket")
|
||||||
|
_ = ms.StartSpotWsMarkPrice()
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
package market
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (ms *MarketData) refreshTradingPairCache() error {
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
spotInfo, err := ms.spotClient.NewExchangeInfoService().Do(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to fetch spot exchange info")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
futuresInfo, err := ms.futuresClient.NewExchangeInfoService().Do(ctx)
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Err(err).Msg("Failed to fetch futures exchange info")
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.pairCacheMutex.Lock()
|
|
||||||
defer ms.pairCacheMutex.Unlock()
|
|
||||||
|
|
||||||
ms.spotPairs = make(map[string]bool, len(spotInfo.Symbols))
|
|
||||||
for _, s := range spotInfo.Symbols {
|
|
||||||
if s.Status == "TRADING" {
|
|
||||||
ms.spotPairs[s.Symbol] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.futuresPairs = make(map[string]bool, len(futuresInfo.Symbols))
|
|
||||||
for _, s := range futuresInfo.Symbols {
|
|
||||||
if s.Status == "TRADING" {
|
|
||||||
ms.futuresPairs[s.Symbol] = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ms.lastPairCacheUpdate = time.Now()
|
|
||||||
log.Info().
|
|
||||||
Int("spot", len(ms.spotPairs)).
|
|
||||||
Int("futures", len(ms.futuresPairs)).
|
|
||||||
Msg("Trading pair cache refreshed")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *MarketData) pairCacheRefreshLoop() {
|
|
||||||
ms.refreshTradingPairCache()
|
|
||||||
ticker := time.NewTicker(time.Hour)
|
|
||||||
defer ticker.Stop()
|
|
||||||
for range ticker.C {
|
|
||||||
ms.refreshTradingPairCache()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *MarketData) IsSpotPair(symbol string) bool {
|
|
||||||
ms.pairCacheMutex.RLock()
|
|
||||||
defer ms.pairCacheMutex.RUnlock()
|
|
||||||
return ms.spotPairs[symbol]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *MarketData) IsFuturesPair(symbol string) bool {
|
|
||||||
ms.pairCacheMutex.RLock()
|
|
||||||
defer ms.pairCacheMutex.RUnlock()
|
|
||||||
return ms.futuresPairs[symbol]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ms *MarketData) RefreshTradingPairCache() error {
|
|
||||||
return ms.refreshTradingPairCache()
|
|
||||||
}
|
|
||||||
@@ -29,7 +29,8 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func testSym(sym string) bool {
|
func testSym(sym string) bool {
|
||||||
return data.Market.IsFuturesPair(sym)
|
_, _, _, test := data.Market.GetFuturePrice(sym)
|
||||||
|
return test
|
||||||
}
|
}
|
||||||
|
|
||||||
func Token2Symbols(token string) []string {
|
func Token2Symbols(token string) []string {
|
||||||
|
|||||||
@@ -13,19 +13,15 @@ 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 {
|
||||||
p, ok := all[sym]
|
price, rate, _, ok := data.Market.GetFuturePrice(sym)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
topSym[i] = sym
|
topSym[i] = sym
|
||||||
topPrice[i] = p.MarkPrice
|
topPrice[i] = price
|
||||||
topRate[i] = p.FundingRate
|
topRate[i] = rate
|
||||||
|
|
||||||
}
|
}
|
||||||
return topSym, topPrice, topRate
|
return topSym, topPrice, topRate
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ var commandList = []telebot.Command{
|
|||||||
Text: "fee",
|
Text: "fee",
|
||||||
Description: "(f) - show top funding fee",
|
Description: "(f) - show top funding fee",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
Text: "refresh",
|
|
||||||
Description: "Refresh trading pair cache",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupCommands(b *telebot.Bot) error {
|
func setupCommands(b *telebot.Bot) error {
|
||||||
@@ -40,7 +36,6 @@ func setupCommands(b *telebot.Bot) error {
|
|||||||
//info
|
//info
|
||||||
b.Handle("/p", commands.OnGetTopPrices)
|
b.Handle("/p", commands.OnGetTopPrices)
|
||||||
b.Handle("/fee", commands.OnGetTopFundingFee)
|
b.Handle("/fee", commands.OnGetTopFundingFee)
|
||||||
b.Handle("/refresh", commands.OnRefreshPairCache)
|
|
||||||
|
|
||||||
//any text
|
//any text
|
||||||
b.Handle(telebot.OnText, commands.OnChatHandler)
|
b.Handle(telebot.OnText, commands.OnChatHandler)
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
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/services/controllers"
|
"me.thuanle/bbot/internal/services/controllers"
|
||||||
"me.thuanle/bbot/internal/services/tele/chat"
|
"me.thuanle/bbot/internal/services/tele/chat"
|
||||||
"me.thuanle/bbot/internal/services/tele/view"
|
"me.thuanle/bbot/internal/services/tele/view"
|
||||||
@@ -21,14 +16,3 @@ func OnGetTopFundingFee(context telebot.Context) error {
|
|||||||
fee, float64s, cds := controllers.GetTopFundingFee()
|
fee, float64s, cds := controllers.GetTopFundingFee()
|
||||||
return chat.ReplyMessagePre(context, view.RenderOnGetTopFundingFeeMessage(fee, float64s, cds))
|
return chat.ReplyMessagePre(context, view.RenderOnGetTopFundingFeeMessage(fee, float64s, cds))
|
||||||
}
|
}
|
||||||
|
|
||||||
func OnRefreshPairCache(context telebot.Context) error {
|
|
||||||
adminID, err := strconv.ParseInt(os.Getenv(key.AdminChatID), 10, 64)
|
|
||||||
if err != nil || adminID == 0 || context.Sender().ID != adminID {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err := data.Market.RefreshTradingPairCache(); err != nil {
|
|
||||||
return chat.ReplyMessage(context, "Failed to refresh trading pair cache")
|
|
||||||
}
|
|
||||||
return chat.ReplyMessage(context, "Trading pair cache refreshed")
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package commands
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"golang.org/x/text/message"
|
||||||
"gopkg.in/telebot.v3"
|
"gopkg.in/telebot.v3"
|
||||||
"me.thuanle/bbot/internal/configs/tele"
|
"me.thuanle/bbot/internal/configs/tele"
|
||||||
"me.thuanle/bbot/internal/data"
|
"me.thuanle/bbot/internal/data"
|
||||||
@@ -11,6 +13,8 @@ import (
|
|||||||
"me.thuanle/bbot/internal/services/tele/view"
|
"me.thuanle/bbot/internal/services/tele/view"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var lastEthPrice float64
|
||||||
|
|
||||||
func showStickerMode(context telebot.Context, token string) {
|
func showStickerMode(context telebot.Context, token string) {
|
||||||
token = strings.ToUpper(token)
|
token = strings.ToUpper(token)
|
||||||
stickerIdx, ok := tele.Token2StickerIdxMap[token]
|
stickerIdx, ok := tele.Token2StickerIdxMap[token]
|
||||||
@@ -56,6 +60,53 @@ func OnTokenInfoByToken(context telebot.Context, token string) error {
|
|||||||
sp, _ := data.Market.GetSpotPrice(sSymbol)
|
sp, _ := data.Market.GetSpotPrice(sSymbol)
|
||||||
|
|
||||||
_ = chat.ReplyMessage(context, view.RenderOnPriceMessage(symbols[0], sp, fp, fundRate, fundTime, tokenInterestRate))
|
_ = chat.ReplyMessage(context, view.RenderOnPriceMessage(symbols[0], sp, fp, fundRate, fundTime, tokenInterestRate))
|
||||||
|
if strings.ToUpper(token) == "ETH" {
|
||||||
|
mFmt := message.NewPrinter(language.AmericanEnglish)
|
||||||
|
realAmount := 35.
|
||||||
|
trangBucAmount := 14.
|
||||||
|
basePrice := 2500.0
|
||||||
|
baseTotal := realAmount * basePrice
|
||||||
|
trangBucTotal := trangBucAmount * basePrice
|
||||||
|
realCurTotal := realAmount * sp
|
||||||
|
trangBucCurTotal := trangBucAmount * sp
|
||||||
|
|
||||||
|
lastDelta := ""
|
||||||
|
if lastEthPrice == 0 {
|
||||||
|
lastEthPrice = sp
|
||||||
|
} else {
|
||||||
|
lastDelta = mFmt.Sprintf(
|
||||||
|
"Δ price: $%+.0f\n"+
|
||||||
|
"Δ Usdt: $%+.0f\n",
|
||||||
|
sp-lastEthPrice,
|
||||||
|
(sp-lastEthPrice)*realAmount,
|
||||||
|
)
|
||||||
|
lastEthPrice = sp
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := mFmt.Sprintf(
|
||||||
|
"🎉🎊🎊🦈🦈🦈 @th13vn Real 🦈🦈🦈🎊🎊🎉\n"+
|
||||||
|
"∑ USDT: $%.0f\n"+
|
||||||
|
"Lợi nhuận: $%.0f\n"+
|
||||||
|
"%s\n"+
|
||||||
|
"\n"+
|
||||||
|
"🚀🚀🚀🚀🚀 Road to 5k 🚀🚀🚀🚀🚀: \n"+
|
||||||
|
"- Δ Price: $%0.0f\n"+
|
||||||
|
"- Δ Vol: $%0.0f\n"+
|
||||||
|
"\n"+
|
||||||
|
"💸💸💸💸💸 Trang Bức balance 💸💸💸💸💸\n"+
|
||||||
|
"∑ USDT: $%.0f\n"+
|
||||||
|
"Lợi nhuận: $%.0f\n",
|
||||||
|
realCurTotal,
|
||||||
|
realCurTotal-baseTotal,
|
||||||
|
lastDelta,
|
||||||
|
5000-sp,
|
||||||
|
5000*realAmount-realCurTotal,
|
||||||
|
trangBucCurTotal,
|
||||||
|
trangBucCurTotal-trangBucTotal,
|
||||||
|
)
|
||||||
|
|
||||||
|
_ = chat.ReplyMessage(context, msg)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user