using System.Net.Http.Json; using Managing.Application.Abstractions.Services; using Managing.Common; using Managing.Core; using Managing.Domain.Statistics; using Managing.Domain.Trades; using Managing.Infrastructure.Evm.Models; namespace Managing.Infrastructure.Evm.Services; public class TradaoService : ITradaoService { private readonly HttpClient _httpClient; public TradaoService() { _httpClient = new HttpClient(); } public async Task> GetBadTrader() { var bestTraders = await _httpClient.GetFromJsonAsync( $"https://api.tradao.xyz/v2/td/dashboard/pnlTop/12/asc/604800/0/?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114¤t=1&limit=20&order=desc&window=2592000&exchangeDic=exchangeId%3Dgmx_42161%26exchangeId%3Dgmx_43114%26exchangeId%3Dgmxv2_42161%26exchangeId%3Dgmxv2_43114&chain=0&exchange=gmx&openPosition=0"); if (bestTraders == null || bestTraders.row.Count == 0) { return new List(); } return await GetTraderDetails(bestTraders); } public async Task> GetBestTrader() { var bestTraders = await _httpClient.GetFromJsonAsync( $"https://api.tradao.xyz/v2/td/dashboard/roiTop/12/desc/2592000/0/?exchangeId=gmxv2_42161¤t=1&limit=12&order=desc&window=2592000&exchangeDic=exchangeId%3Dgmxv2_42161&chain=42161&exchange=gmxv2&openPosition=0&volumeL=100000&tradeTimesL=10&tradeTimesH=50&winRateL=0.6"); if (bestTraders == null || bestTraders.row.Count == 0) { return new List(); } return await GetTraderDetails(bestTraders); } public async Task> GetTrades(string address) { var response = await _httpClient.GetFromJsonAsync( $"https://api.tradao.xyz/v2/td/trader/insightsV2/{address}?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114"); var trades = new List(); if (response == null) return trades; foreach (var record in response.gmxv2_42161.records.Where(p => p.isOpen)) { var computedData = GetComputedData(record.records); var marketPrice = response.gmxv2_42161.prices.FirstOrDefault(p => p.Key == record.indexToken).Value; var trade = new Trade( DateTime.UtcNow, record.isLong ? Common.Enums.TradeDirection.Long : Common.Enums.TradeDirection.Short, Common.Enums.TradeStatus.Filled, Common.Enums.TradeType.Market, TokenService.GetTicker(record.indexToken), Convert.ToDecimal(computedData.Collateral) / Convert.ToDecimal(marketPrice), Convert.ToDecimal(record.averagePrice), Convert.ToDecimal(computedData.Size) / Convert.ToDecimal(computedData.Collateral), record.positionId, record.liqPrice ); trades.Add(trade); } return trades; } private (decimal Collateral, decimal Size) GetComputedData(List positionRecords) { decimal computedCollateral = 0; decimal computedSize = 0; foreach (var record in positionRecords) { if (record.eventType == 1) // Increase { computedCollateral += Convert.ToDecimal(record.collateralDelta); computedSize += Convert.ToDecimal(record.sizeDelta); } else if (record.eventType == 2) // Decrease { computedCollateral -= Convert.ToDecimal(record.collateralDelta); computedSize -= Convert.ToDecimal(record.sizeDelta); } } return (computedCollateral, computedSize); } private async Task> GetTraderDetails(TradaoList traders) { var result = new List(); foreach (var trader in traders.row) { var response = await _httpClient.GetFromJsonAsync( $"https://api.tradao.xyz/v2/td/trader/insightsV2/{trader.user}?exchangeId=gmx_42161&exchangeId=gmx_43114&exchangeId=gmxv2_42161&exchangeId=gmxv2_43114"); if (response != null) result.Add(Map(response, trader.user)); } return result; } private Trader Map(TradaoUserDetails response, string address) { return new Trader { Address = address, Winrate = (int)(response.gmxv2_42161.summary.winRate * 100), Pnl = response.gmxv2_42161.summary.pnl, TradeCount = response.gmxv2_42161.summary.trades, AverageWin = response.gmxv2_42161.summary.averageWin, AverageLoss = response.gmxv2_42161.summary.averageLoss, Roi = response.gmxv2_42161.summary.roi * 100 }; } public async Task> GetFundingRates() { _httpClient.DefaultRequestHeaders.Accept.Clear(); _httpClient.DefaultRequestHeaders.Accept.Add( new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json")); var response = await _httpClient.GetFromJsonAsync>("https://api.tradao.xyz/v1/td/fr/all"); return Map(response); } private List Map(List? response) { if (response == null) { return new List(); } var result = new List(); foreach (var fundingRate in response) { var ticker = Map(fundingRate.Symbol); if (ticker == null || fundingRate.ExchangeName != "gmxv2") continue; if (!Constants.GMX.Config.DeltaNeutralTickers.Contains(ticker.Value)) continue; var longRate = GetApy(fundingRate.LongFundingRate); var shortRate = GetApy(fundingRate.ShortFundingRate); result.Add(new FundingRate { Ticker = ticker.Value, Rate = longRate, Direction = Enums.TradeDirection.Long, Date = DateTimeOffset.FromUnixTimeSeconds(fundingRate.Timestamp).DateTime }); result.Add(new FundingRate { Ticker = ticker.Value, Rate = shortRate, Direction = Enums.TradeDirection.Short, Date = DateTimeOffset.FromUnixTimeSeconds(fundingRate.Timestamp).DateTime }); } return result; } private Enums.Ticker? Map(string fundingRateSymbol) { try { return MiscExtensions.ParseEnum(fundingRateSymbol); } catch (Exception e) { return null; } } public decimal GetApy(string fundingRate) { try { decimal rate = Convert.ToDecimal(fundingRate, System.Globalization.CultureInfo.InvariantCulture); return rate * 100 * 24 * 365; } catch (FormatException) { // Handle the case where conversion fails due to an incorrect format // Log the error, return 0, or handle as appropriate for your application return 0; } } public class TradaoFundingRate { public string Symbol { get; set; } public string ChainId { get; set; } public string ExchangeName { get; set; } public string LongFundingRate { get; set; } public string ShortFundingRate { get; set; } public long Timestamp { get; set; } } }