221 lines
7.6 KiB
C#
221 lines
7.6 KiB
C#
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<List<Trader>> GetBadTrader()
|
|
{
|
|
var bestTraders = await _httpClient.GetFromJsonAsync<TradaoList>(
|
|
$"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<Trader>();
|
|
}
|
|
|
|
return await GetTraderDetails(bestTraders);
|
|
}
|
|
|
|
public async Task<List<Trader>> GetBestTrader()
|
|
{
|
|
var bestTraders = await _httpClient.GetFromJsonAsync<TradaoList>(
|
|
$"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<Trader>();
|
|
}
|
|
|
|
return await GetTraderDetails(bestTraders);
|
|
}
|
|
|
|
public async Task<List<Trade>> GetTrades(string address)
|
|
{
|
|
var response =
|
|
await _httpClient.GetFromJsonAsync<TradaoUserDetails>(
|
|
$"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<Trade>();
|
|
|
|
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<RecordDetail> 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<List<Trader>> GetTraderDetails(TradaoList traders)
|
|
{
|
|
var result = new List<Trader>();
|
|
foreach (var trader in traders.row)
|
|
{
|
|
var response =
|
|
await _httpClient.GetFromJsonAsync<TradaoUserDetails>(
|
|
$"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<List<FundingRate>> GetFundingRates()
|
|
{
|
|
_httpClient.DefaultRequestHeaders.Accept.Clear();
|
|
_httpClient.DefaultRequestHeaders.Accept.Add(
|
|
new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
|
|
|
|
var response =
|
|
await _httpClient.GetFromJsonAsync<List<TradaoFundingRate>>("https://api.tradao.xyz/v1/td/fr/all");
|
|
|
|
return Map(response);
|
|
}
|
|
|
|
private List<FundingRate> Map(List<TradaoFundingRate>? response)
|
|
{
|
|
if (response == null)
|
|
{
|
|
return new List<FundingRate>();
|
|
}
|
|
|
|
var result = new List<FundingRate>();
|
|
|
|
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<Enums.Ticker>(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; }
|
|
}
|
|
} |