From a43e560d3a09b8087c1648ce35c96344d97d55ac Mon Sep 17 00:00:00 2001 From: Oda <102867384+CryptoOda@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:38:40 +0700 Subject: [PATCH] Fix leaderboard (#3) --- src/Managing.Api.Workers/Program.cs | 2 - src/Managing.Api.Workers/appsettings.Oda.json | 4 +- .../appsettings.Prod.json | 2 +- .../Shared/Helpers/TradingHelpers.cs | 16 +- .../Discord/DiscordHelpers.cs | 4 +- .../Models/TradaoList.cs | 20 +- .../Models/TradaoUserDetails.cs | 197 ++++++++++++++---- .../Services/TradaoService.cs | 61 ++++-- 8 files changed, 235 insertions(+), 71 deletions(-) diff --git a/src/Managing.Api.Workers/Program.cs b/src/Managing.Api.Workers/Program.cs index a941830..90f277e 100644 --- a/src/Managing.Api.Workers/Program.cs +++ b/src/Managing.Api.Workers/Program.cs @@ -110,11 +110,9 @@ builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); -builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); builder.Services.AddHostedService(); -builder.Services.AddHostedService(); builder.Services.AddHostedService(); // App diff --git a/src/Managing.Api.Workers/appsettings.Oda.json b/src/Managing.Api.Workers/appsettings.Oda.json index 643d440..266482d 100644 --- a/src/Managing.Api.Workers/appsettings.Oda.json +++ b/src/Managing.Api.Workers/appsettings.Oda.json @@ -5,8 +5,8 @@ }, "InfluxDb": { "Url": "http://localhost:8086/", - "Organization": "", - "Token": "" + "Organization": "managing-org", + "Token": "Fw2FPL2OwTzDHzSbR2Sd5xs0EKQYy00Q-hYKYAhr9cC1_q5YySONpxuf_Ck0PTjyUiF13xXmi__bu_pXH-H9zA==" }, "Serilog": { "MinimumLevel": { diff --git a/src/Managing.Api.Workers/appsettings.Prod.json b/src/Managing.Api.Workers/appsettings.Prod.json index f764630..57210b8 100644 --- a/src/Managing.Api.Workers/appsettings.Prod.json +++ b/src/Managing.Api.Workers/appsettings.Prod.json @@ -18,7 +18,7 @@ } }, "ElasticConfiguration": { - "Uri": "http://localhost:9200" + "Uri": "http://elasticsearch:9200" }, "AllowedHosts": "*" } \ No newline at end of file diff --git a/src/Managing.Domain/Shared/Helpers/TradingHelpers.cs b/src/Managing.Domain/Shared/Helpers/TradingHelpers.cs index c89ba22..eff5939 100644 --- a/src/Managing.Domain/Shared/Helpers/TradingHelpers.cs +++ b/src/Managing.Domain/Shared/Helpers/TradingHelpers.cs @@ -41,18 +41,18 @@ public static class TradingHelpers public static bool IsAGoodTrader(Trader trader) { - return trader.Winrate > 80 - && trader.TradeCount > 8 - && trader.AverageWin > Math.Abs(trader.AverageLoss) * 3 - && trader.Pnl > 0; + return trader.Winrate > 30 + && trader.TradeCount > 8 + && trader.AverageWin > Math.Abs(trader.AverageLoss) + && trader.Pnl > 0; } public static bool IsABadTrader(Trader trader) { return trader.Winrate < 30 - && trader.TradeCount > 8 - && trader.AverageWin * 3 < Math.Abs(trader.AverageLoss) - && trader.Pnl < 0; + && trader.TradeCount > 8 + && trader.AverageWin * 3 < Math.Abs(trader.AverageLoss) + && trader.Pnl < 0; } public static List FindBadTrader(this List traders) @@ -96,4 +96,4 @@ public static class TradingHelpers return traders; } -} +} \ No newline at end of file diff --git a/src/Managing.Infrastructure.Messengers/Discord/DiscordHelpers.cs b/src/Managing.Infrastructure.Messengers/Discord/DiscordHelpers.cs index c5d48c2..ee99071 100644 --- a/src/Managing.Infrastructure.Messengers/Discord/DiscordHelpers.cs +++ b/src/Managing.Infrastructure.Messengers/Discord/DiscordHelpers.cs @@ -23,7 +23,7 @@ public static class DiscordHelpers var embed = new EmbedBuilder { - Author = new EmbedAuthorBuilder() { Name = "GMX" }, + Author = new EmbedAuthorBuilder() { Name = "GMX v2" }, Title = $"{title} {DateTime.UtcNow:d}", Color = Color.Gold, Fields = fields, @@ -88,7 +88,7 @@ public static class DiscordHelpers private static string GetExplorerUrl(string key) { - return $"https://www.tradao.xyz/#/user/{key}/1"; + return $"https://www.tradao.xyz/#/user/{key}/arb-gmx-v2/"; } internal static Embed GetTradesEmbed(List trades, string title) diff --git a/src/Managing.Infrastructure.Web3/Models/TradaoList.cs b/src/Managing.Infrastructure.Web3/Models/TradaoList.cs index 478a7a7..26f9940 100644 --- a/src/Managing.Infrastructure.Web3/Models/TradaoList.cs +++ b/src/Managing.Infrastructure.Web3/Models/TradaoList.cs @@ -11,10 +11,28 @@ public class Row { public string user { get; set; } public string pnl { get; set; } + public string fee { get; set; } public string roi { get; set; } public string longSize { get; set; } public string shortSize { get; set; } public string openLatestCollateralSum { get; set; } public string chainId { get; set; } - + public int tradeTimes { get; set; } + public int lastTrade { get; set; } + public decimal volume { get; set; } + public int winTime { get; set; } + public int lossTime { get; set; } + public List indexTokens { get; set; } + public TradaoBacktest backtest { get; set; } } + +public class TradaoBacktest +{ + public string roi { get; set; } + public string pnl { get; set; } + public string winRate { get; set; } + public string liquidate { get; set; } + public string maxDrawdown { get; set; } + public int initialBalance { get; set; } + public int updateTime { get; set; } +} \ No newline at end of file diff --git a/src/Managing.Infrastructure.Web3/Models/TradaoUserDetails.cs b/src/Managing.Infrastructure.Web3/Models/TradaoUserDetails.cs index 02c7a49..3fdb26c 100644 --- a/src/Managing.Infrastructure.Web3/Models/TradaoUserDetails.cs +++ b/src/Managing.Infrastructure.Web3/Models/TradaoUserDetails.cs @@ -1,49 +1,174 @@ -namespace Managing.Infrastructure.Evm.Models; +using System.Text.Json.Serialization; + +namespace Managing.Infrastructure.Evm.Models; public class TradaoUserDetails { - public int updatetime { get; set; } - public Summary summary { get; set; } - public IList preference { get; set; } - public IList openPositions { get; set; } + [JsonPropertyName("gmxv2_42161")] public Gmxv242161 gmxv2_42161 { get; set; } } - public class Summary { - public string pnl { get; set; } - public string roi { get; set; } - public double winRate { get; set; } - public int trades { get; set; } - public int winTrades { get; set; } - public int lossTrades { get; set; } - public string averageWin { get; set; } - public string averageLoss { get; set; } - public string openCollateralSum { get; set; } - public string fee { get; set; } + [JsonPropertyName("pnl")] public decimal pnl { get; set; } + [JsonPropertyName("roi")] public decimal roi { get; set; } + + [JsonPropertyName("winRate")] public decimal winRate { get; set; } + + [JsonPropertyName("trades")] public int trades { get; set; } + + [JsonPropertyName("winTrades")] public int winTrades { get; set; } + + [JsonPropertyName("lossTrades")] public int lossTrades { get; set; } + + [JsonPropertyName("averageWin")] public decimal averageWin { get; set; } + + [JsonPropertyName("averageLoss")] public decimal averageLoss { get; set; } + + [JsonPropertyName("fee")] public decimal fee { get; set; } + + [JsonPropertyName("tradingVolume")] public decimal tradingVolume { get; set; } + + [JsonPropertyName("lastTradeTime")] public int lastTradeTime { get; set; } + + [JsonPropertyName("maxIncreaseTimes")] public int maxIncreaseTimes { get; set; } } + +// GMX v1 +public class Gmx42161 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } +} + +public class Gmx43114 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } +} + +public class Gmxv242161 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } + [JsonPropertyName("prices")] public Dictionary prices { get; set; } +} + +public class Record +{ + [JsonPropertyName("indexToken")] public string indexToken { get; set; } + + [JsonPropertyName("collateralToken")] public string collateralToken { get; set; } + + [JsonPropertyName("isLong")] public bool isLong { get; set; } + + [JsonPropertyName("isOpen")] public bool isOpen { get; set; } + + [JsonPropertyName("positionId")] public string positionId { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } + + [JsonPropertyName("averagePrice")] public string averagePrice { get; set; } + + [JsonPropertyName("liqPrice")] public string liqPrice { get; set; } + + [JsonPropertyName("borrowFee")] public string borrowFee { get; set; } + + [JsonPropertyName("closeFee")] public string closeFee { get; set; } + + [JsonPropertyName("fundingFee")] public string fundingFee { get; set; } +} + +public class RecordDetail +{ + [JsonPropertyName("timestamp")] public int timestamp { get; set; } + + [JsonPropertyName("indexToken")] public string indexToken { get; set; } + + [JsonPropertyName("collateralToken")] public string collateralToken { get; set; } + + [JsonPropertyName("isLong")] public bool isLong { get; set; } + + [JsonPropertyName("sizeDelta")] public double sizeDelta { get; set; } + + [JsonPropertyName("collateralDelta")] public double collateralDelta { get; set; } + + [JsonPropertyName("price")] public double price { get; set; } + + [JsonPropertyName("fee")] public double fee { get; set; } + + [JsonPropertyName("isLiquidation")] public bool isLiquidation { get; set; } + + [JsonPropertyName("eventType")] public int eventType { get; set; } + + [JsonPropertyName("pnlDelta")] public double pnlDelta { get; set; } + + [JsonPropertyName("averagePrice")] public double averagePrice { get; set; } + + [JsonPropertyName("positionId")] public string positionId { get; set; } + + [JsonPropertyName("status")] public string status { get; set; } + + [JsonPropertyName("blocknum")] public int blocknum { get; set; } + + [JsonPropertyName("transactionIndex")] public int transactionIndex { get; set; } +} + +public class Gmxv243114 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } +} + +public class Kwenta10 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } +} + +public class Polynomial10 +{ + [JsonPropertyName("updatetime")] public int updatetime { get; set; } + + [JsonPropertyName("summary")] public Summary summary { get; set; } + + [JsonPropertyName("preference")] public List preference { get; set; } + + [JsonPropertyName("records")] public List records { get; set; } +} + public class Preference { - public string tokenAddress { get; set; } - public int winTrades { get; set; } - public int lossTrades { get; set; } - public string pnl { get; set; } -} + [JsonPropertyName("tokenAddress")] public string tokenAddress { get; set; } -public class OpenPositions -{ - public string indexTokenAddress { get; set; } - public string collateralTokenAddress { get; set; } - public bool isLong { get; set; } - public string position { get; set; } - public string collateral { get; set; } - public string realizedPnl { get; set; } - public string averagePrice { get; set; } - public string totalFee { get; set; } - public string entryFundingRate { get; set; } - public string borrowFee { get; set; } - public string closeFee { get; set; } - public string liqPrice { get; set; } + [JsonPropertyName("winTrades")] public int winTrades { get; set; } -} + [JsonPropertyName("lossTrades")] public int lossTrades { get; set; } + + [JsonPropertyName("pnl")] public double pnl { get; set; } +} \ No newline at end of file diff --git a/src/Managing.Infrastructure.Web3/Services/TradaoService.cs b/src/Managing.Infrastructure.Web3/Services/TradaoService.cs index 7812000..ab27092 100644 --- a/src/Managing.Infrastructure.Web3/Services/TradaoService.cs +++ b/src/Managing.Infrastructure.Web3/Services/TradaoService.cs @@ -31,13 +31,12 @@ public class TradaoService : ITradaoService public TradaoService() { _httpClient = new HttpClient(); - ; } public async Task> GetBadTrader() { var bestTraders = await _httpClient.GetFromJsonAsync( - $"https://api.tradao.xyz/v1/td/dashboard/42161/gmx/pnlTop/500/asc/2592000/0/?current=1&limit=500&order=asc&window=2592000&chain=42161&exchange=gmx&openPosition=0"); + $"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) { @@ -47,11 +46,10 @@ public class TradaoService : ITradaoService return await GetTraderDetails(bestTraders); } - public async Task> GetBestTrader() { var bestTraders = await _httpClient.GetFromJsonAsync( - $"https://api.tradao.xyz/v1/td/dashboard/42161/gmx/pnlTop/500/desc/2592000/0/?current=1&limit=500&order=desc&window=2592000&chain=42161&exchange=gmx&openPosition=0"); + $"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) { @@ -65,24 +63,27 @@ public class TradaoService : ITradaoService { var response = await _httpClient.GetFromJsonAsync( - $"https://api.tradao.xyz/v1/td/trader/42161/gmx/insights/{address}"); + $"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 position in response.openPositions) + 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, - position.isLong ? Common.Enums.TradeDirection.Long : Common.Enums.TradeDirection.Short, + record.isLong ? Common.Enums.TradeDirection.Long : Common.Enums.TradeDirection.Short, Common.Enums.TradeStatus.Filled, Common.Enums.TradeType.Market, - TokenService.GetTicker(position.indexTokenAddress), - Convert.ToDecimal(position.collateral), - Convert.ToDecimal(position.averagePrice), - Convert.ToDecimal(position.position) / Convert.ToDecimal(position.collateral), - address, position.liqPrice + 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); @@ -91,6 +92,28 @@ public class TradaoService : ITradaoService 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) { @@ -99,7 +122,7 @@ public class TradaoService : ITradaoService { var response = await _httpClient.GetFromJsonAsync( - $"https://api.tradao.xyz/v1/td/trader/42161/gmx/insights/{trader.user}"); + $"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)); @@ -113,12 +136,12 @@ public class TradaoService : ITradaoService return new Trader { Address = address, - Winrate = (int)(response.summary.winRate * 100), - Pnl = Convert.ToDecimal(response.summary.pnl), - TradeCount = response.summary.trades, - AverageWin = Convert.ToDecimal(response.summary.averageWin), - AverageLoss = Convert.ToDecimal(response.summary.averageLoss), - Roi = Convert.ToDecimal(response.summary.roi) + 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 }; }