Add funding rate watcher (#2)

* Add FundingRate interfaces and worker

* Add build on PR

* Remove zip

* Specify the solution path

* Add build for worker too

* Set up StatisticService.cs for funding rate

* Add Fundingrate alerts

* Send alert when big funding rate change + add SlashCommands.cs for fundingrate

* Remove fixtures

* Refact names

* Renames
This commit is contained in:
Oda
2024-07-19 08:31:09 +07:00
committed by GitHub
parent 545c9d8e4a
commit 029ba5f40e
41 changed files with 914 additions and 304 deletions

View File

@@ -16,7 +16,8 @@ public static class DiscordHelpers
fields.Add(new EmbedFieldBuilder
{
Name = $"{GetExplorerUrl(trader.Address)}",
Value = $"Avg Win / Avg Loss / Winrate / ROI \n {trader.AverageWin:#.##}$ / {trader.AverageLoss:#.##}$ / {trader.Winrate}% / {Convert.ToDecimal(trader.Roi) * 100:#.##}%",
Value =
$"Avg Win / Avg Loss / Winrate / ROI \n {trader.AverageWin:#.##}$ / {trader.AverageLoss:#.##}$ / {trader.Winrate}% / {Convert.ToDecimal(trader.Roi) * 100:#.##}%",
});
}
@@ -31,6 +32,48 @@ public static class DiscordHelpers
return embed;
}
public static Embed GetFundingRateEmbed(FundingRate fundingRate, string title, FundingRate? oldRate = null)
{
var fields = new List<EmbedFieldBuilder>();
decimal ratePerYear = fundingRate.Rate; // Rate per year
decimal ratePerDay = ratePerYear / 365; // Rate per day
decimal ratePerMonth = ratePerYear / 12; // Rate per month
decimal ratePerHour = ratePerDay / 24; // Rate per hour
if (oldRate != null)
{
var oldRatePerYear = oldRate.Rate; // Rate per year
var oldRatePerDay = oldRatePerYear / 365; // Rate per day
var oldRatePerMonth = oldRatePerYear / 12; // Rate per month
var oldRatePerHour = oldRatePerDay / 24; // Rate per hour
fields.Add(new EmbedFieldBuilder
{
Name = $"{fundingRate.Direction} - Previous Rate",
Value =
$"Hour: {oldRatePerHour:#.##}% / Day: {oldRatePerDay:#.##}% / Month: {oldRatePerMonth:#.##}% / Year: {oldRatePerYear:#.##}%",
});
}
fields.Add(new EmbedFieldBuilder
{
Name = $"{fundingRate.Direction} - Current rate",
Value =
$"Hour: {ratePerHour:#.##}% / Day: {ratePerDay:#.##}% / Month: {ratePerMonth:#.##}% / Year: {ratePerYear:#.##}%",
});
var embed = new EmbedBuilder
{
Author = new EmbedAuthorBuilder() { Name = "GMX" },
Title = $"{title} {DateTime.UtcNow:d}",
Color = Color.DarkGreen,
Fields = fields,
}.Build();
return embed;
}
public static Embed GetEmbed(string address, string title, List<EmbedFieldBuilder> fields, Color color)
{
return new EmbedBuilder
@@ -57,14 +100,16 @@ public static class DiscordHelpers
fields.Add(new EmbedFieldBuilder
{
Name = $"{GetExplorerUrl(trade.ExchangeOrderId)}",
Value = $"Side / Ticker / Open / Qty / Leverage / LiqPrice \n {trade.Direction} / {trade.Ticker} / {trade.Price:#.##}$ / {trade.Quantity:#.##}$ / x{trade.Leverage:#.##} / {Convert.ToDecimal(trade.Message):#.##}$",
Value =
$"Side / Ticker / Open / Qty / Leverage / LiqPrice \n {trade.Direction} / {trade.Ticker} / {trade.Price:#.##}$ / {trade.Quantity:#.##}$ / x{trade.Leverage:#.##} / {Convert.ToDecimal(trade.Message):#.##}$",
});
}
fields.Add(new EmbedFieldBuilder
{
Name = "Summary",
Value = $"Long / Short / \n {trades.Count(t => t.Direction == Common.Enums.TradeDirection.Long)} / {trades.Count(t => t.Direction == Common.Enums.TradeDirection.Short)}"
Value =
$"Long / Short / \n {trades.Count(t => t.Direction == Common.Enums.TradeDirection.Long)} / {trades.Count(t => t.Direction == Common.Enums.TradeDirection.Short)}"
});
var embed = new EmbedBuilder
@@ -77,4 +122,34 @@ public static class DiscordHelpers
return embed;
}
}
public static Embed GetFundingRatesEmbed(List<FundingRate> fundingRates, string leaderboardOpenPosition)
{
var fields = new List<EmbedFieldBuilder>();
foreach (var fundingRate in fundingRates)
{
decimal ratePerYear = fundingRate.Rate; // Rate per year
decimal ratePerDay = ratePerYear / 365; // Rate per day
decimal ratePerMonth = ratePerYear / 12; // Rate per month
decimal ratePerHour = ratePerDay / 24; // Rate per hour
fields.Add(new EmbedFieldBuilder
{
Name = $"{fundingRate.Ticker}",
Value =
$"Hour: {ratePerHour:#.##}% / Day: {ratePerDay:#.##}% / Month: {ratePerMonth:#.##}% / Year: {ratePerYear:#.##}%",
});
}
var embed = new EmbedBuilder
{
Author = new EmbedAuthorBuilder() { Name = "GMX" },
Title = $"Best Funding Rate {DateTime.UtcNow:d}",
Color = Color.DarkGreen,
Fields = fields,
}.Build();
return embed;
}
}

View File

@@ -48,6 +48,7 @@ namespace Managing.Infrastructure.Messengers.Discord
}
#region Setup
// The hosted service has started
public async Task StartAsync(CancellationToken cancellationToken)
{
@@ -85,7 +86,9 @@ namespace Managing.Infrastructure.Messengers.Discord
case Constants.DiscordSlashCommand.LeaderboardPosition:
await SlashCommands.HandleLeadboardPositionCommand(_services, command);
break;
case Constants.DiscordSlashCommand.FundingRates:
await SlashCommands.HandleFundingRateCommand(_services, command);
break;
}
}
@@ -117,6 +120,10 @@ namespace Managing.Infrastructure.Messengers.Discord
noobiesboardCommand.WithDescription("Shows the last Noobies board");
applicationCommandProperties.Add(noobiesboardCommand.Build());
var fundingRatesCommand = new SlashCommandBuilder();
fundingRatesCommand.WithName(Constants.DiscordSlashCommand.FundingRates);
fundingRatesCommand.WithDescription("Shows the last funding rates");
applicationCommandProperties.Add(fundingRatesCommand.Build());
await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray());
}
@@ -131,7 +138,6 @@ namespace Managing.Infrastructure.Messengers.Discord
{
List<ApplicationCommandProperties> commands = new();
return commands;
}
@@ -139,10 +145,7 @@ namespace Managing.Infrastructure.Messengers.Discord
// logging
private async Task Log(LogMessage arg)
{
await Task.Run(() =>
{
_logger.LogInformation(arg.ToString());
});
await Task.Run(() => { _logger.LogInformation(arg.ToString()); });
}
private async Task CommandExecuted(Optional<CommandInfo> command, ICommandContext context, IResult result)
@@ -160,6 +163,7 @@ namespace Managing.Infrastructure.Messengers.Discord
await Log(new LogMessage(LogSeverity.Error, nameof(CommandExecuted), $"Error: {result.ErrorReason}"));
return;
}
// react to message
await context.Message.AddReactionAsync(new Emoji("🤖")); // robot emoji
}
@@ -177,13 +181,16 @@ namespace Managing.Infrastructure.Messengers.Discord
_client.ButtonExecuted -= ButtonHandler;
_client.SlashCommandExecuted -= SlashCommandHandler;
}
public void Dispose()
{
_client?.Dispose();
}
#endregion
#region In
public async Task ButtonHandler(SocketMessageComponent component)
{
var parameters = component.Data.CustomId.Split(new[] { _separator }, StringSplitOptions.None);
@@ -191,7 +198,8 @@ namespace Managing.Infrastructure.Messengers.Discord
if (component.User.GlobalName != "crypto_saitama")
{
await component.Channel.SendMessageAsync("Sorry bro, this feature is not accessible for you.. Do not hesitate to send me approx. 456 121 $ and i give you full access");
await component.Channel.SendMessageAsync(
"Sorry bro, this feature is not accessible for you.. Do not hesitate to send me approx. 456 121 $ and i give you full access");
}
else
{
@@ -219,7 +227,10 @@ namespace Managing.Infrastructure.Messengers.Discord
var json = MiscExtensions.Base64Decode(parameters[1]);
var trade = JsonConvert.DeserializeObject<CopyTradeData>(json);
await OpenPosition(component, trade.AccountName, trade.MoneyManagementName, PositionInitiator.CopyTrading, trade.Ticker, trade.Direction, Timeframe.FifteenMinutes, DateTime.Now.AddMinutes(trade.ExpirationMinute), true, trade.Leverage); ;
await OpenPosition(component, trade.AccountName, trade.MoneyManagementName, PositionInitiator.CopyTrading,
trade.Ticker, trade.Direction, Timeframe.FifteenMinutes,
DateTime.Now.AddMinutes(trade.ExpirationMinute), true, trade.Leverage);
;
}
public async Task OpenPosition(SocketMessageComponent component, string[] parameters)
@@ -234,19 +245,24 @@ namespace Managing.Infrastructure.Messengers.Discord
var moneyManagementName = parameters[5];
var expiration = DateTime.Parse(parameters[6]);
await OpenPosition(component, accountName, moneyManagementName, PositionInitiator.User, ticker, direction, timeframe, expiration, false);
await OpenPosition(component, accountName, moneyManagementName, PositionInitiator.User, ticker, direction,
timeframe, expiration, false);
}
private async Task OpenPosition(SocketMessageComponent component, string accountName, string moneyManagement, PositionInitiator initiator, Ticker ticker, TradeDirection direction, Timeframe timeframe, DateTime expiration, bool ignoreSLTP, decimal? leverage = null)
private async Task OpenPosition(SocketMessageComponent component, string accountName, string moneyManagement,
PositionInitiator initiator, Ticker ticker, TradeDirection direction, Timeframe timeframe,
DateTime expiration, bool ignoreSLTP, decimal? leverage = null)
{
if (DateTime.Now > expiration)
{
await component.Channel.SendMessageAsync("Sorry I can't open position because you tried to click on a expired button.");
await component.Channel.SendMessageAsync(
"Sorry I can't open position because you tried to click on a expired button.");
}
else
{
var exchangeService = (IExchangeService)_services.GetService(typeof(IExchangeService));
var moneyManagementService = (IMoneyManagementService)_services.GetService(typeof(IMoneyManagementService));
var moneyManagementService =
(IMoneyManagementService)_services.GetService(typeof(IMoneyManagementService));
var accountService = (IAccountService)_services.GetService(typeof(IAccountService));
var tradingService = (ITradingService)_services.GetService(typeof(ITradingService));
@@ -261,7 +277,8 @@ namespace Managing.Infrastructure.Messengers.Discord
var position = await new OpenPositionCommandHandler(exchangeService, accountService, tradingService)
.Handle(tradeCommand);
var builder = new ComponentBuilder().WithButton("Close Position", $"{Constants.DiscordButtonAction.ClosePosition}{_separator}{position.Identifier}");
var builder = new ComponentBuilder().WithButton("Close Position",
$"{Constants.DiscordButtonAction.ClosePosition}{_separator}{position.Identifier}");
await component.Channel.SendMessageAsync(MessengerHelpers.GetPositionMessage(position),
components: builder.Build());
@@ -272,10 +289,10 @@ namespace Managing.Infrastructure.Messengers.Discord
private string GetClosingPositionMessage(Position position)
{
return $"Closing : {position.OriginDirection} {position.Open.Ticker} \n" +
$"Open Price : {position.Open.Price} \n" +
$"Closing Price : {position.Open.Price} \n" +
$"Quantity :{position.Open.Quantity} \n" +
$"PNL : {position.ProfitAndLoss.Net} $";
$"Open Price : {position.Open.Price} \n" +
$"Closing Price : {position.Open.Price} \n" +
$"Quantity :{position.Open.Quantity} \n" +
$"PNL : {position.ProfitAndLoss.Net} $";
}
private async Task ClosePosition(SocketMessageComponent component, string[] parameters)
@@ -287,42 +304,45 @@ namespace Managing.Infrastructure.Messengers.Discord
await component.RespondAsync("Alright, let met few seconds to close this position");
var position = _tradingService.GetPositionByIdentifier(parameters[1]);
var command = new ClosePositionCommand(position);
var result = await new ClosePositionCommandHandler(exchangeService, accountService, tradingService).Handle(command);
var result =
await new ClosePositionCommandHandler(exchangeService, accountService, tradingService).Handle(command);
var fields = new List<EmbedFieldBuilder>()
{
new EmbedFieldBuilder
{
Name = "Direction",
Value = position.OriginDirection,
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Open Price",
Value = $"{position.Open.Price:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Quantity",
Value = $"{position.Open.Quantity:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Pnl",
Value = $"{position.ProfitAndLoss.Net:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Direction",
Value = position.OriginDirection,
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Open Price",
Value = $"{position.Open.Price:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Quantity",
Value = $"{position.Open.Quantity:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Pnl",
Value = $"{position.ProfitAndLoss.Net:#.##}",
IsInline = true
},
};
var embed = DiscordHelpers.GetEmbed(position.AccountName, $"Position status is now {result.Status}", fields, position.ProfitAndLoss.Net > 0 ? Color.Green : Color.Red);
var embed = DiscordHelpers.GetEmbed(position.AccountName, $"Position status is now {result.Status}", fields,
position.ProfitAndLoss.Net > 0 ? Color.Green : Color.Red);
await component.Channel.SendMessageAsync("", embed: embed);
}
#endregion
#region Out
public async Task SendSignal(string message)
{
var channel = _client.GetChannel(_settings.SignalChannelId) as IMessageChannel;
@@ -330,18 +350,21 @@ namespace Managing.Infrastructure.Messengers.Discord
await channel.SendMessageAsync(message, components: builder.Build());
}
public async Task SendSignal(string message, TradingExchanges exchange, Ticker ticker, TradeDirection direction, Timeframe timeframe)
public async Task SendSignal(string message, TradingExchanges exchange, Ticker ticker, TradeDirection direction,
Timeframe timeframe)
{
var expirationDate = DateTime.Now.AddMinutes(_settings.ButtonExpirationMinutes).ToString("G");
var channel = _client.GetChannel(_settings.SignalChannelId) as IMessageChannel;
var builder = new ComponentBuilder().WithButton("Open Position", $"{Constants.DiscordButtonAction.OpenPosition}{_separator}{exchange}{_separator}{ticker}{_separator}{direction}{_separator}{timeframe}{_separator}{expirationDate}");
var builder = new ComponentBuilder().WithButton("Open Position",
$"{Constants.DiscordButtonAction.OpenPosition}{_separator}{exchange}{_separator}{ticker}{_separator}{direction}{_separator}{timeframe}{_separator}{expirationDate}");
await channel.SendMessageAsync(message, components: builder.Build());
}
public async Task SendIncreasePosition(string address, Trade trade, string copyAccountName, Trade? oldTrade = null)
public async Task SendIncreasePosition(string address, Trade trade, string copyAccountName,
Trade? oldTrade = null)
{
var channel = _client.GetChannel(_settings.CopyTradingChannelId) as IMessageChannel;
var fields = new List<EmbedFieldBuilder>()
{
@@ -373,7 +396,10 @@ namespace Managing.Infrastructure.Messengers.Discord
if (oldTrade != null)
{
fields.Add(new EmbedFieldBuilder { Name = "Increasy by", Value = $"{(trade.Quantity - oldTrade.Quantity) / trade.Leverage:#.##} $" });
fields.Add(new EmbedFieldBuilder
{
Name = "Increasy by", Value = $"{(trade.Quantity - oldTrade.Quantity) / trade.Leverage:#.##} $"
});
}
var titlePrefix = oldTrade != null ? "Increase " : "";
@@ -398,24 +424,29 @@ namespace Managing.Infrastructure.Messengers.Discord
if (oldTrade == null)
{
builder.WithButton($"Copy with {mm.Name}", $"{Constants.DiscordButtonAction.CopyPosition}{_separator}{encodedData}");
builder.WithButton($"Copy with {mm.Name}",
$"{Constants.DiscordButtonAction.CopyPosition}{_separator}{encodedData}");
}
else
{
builder.WithButton($"Increase with {mm.Name}", $"{Constants.DiscordButtonAction.CopyPosition}{_separator}{encodedData}");
builder.WithButton($"Increase with {mm.Name}",
$"{Constants.DiscordButtonAction.CopyPosition}{_separator}{encodedData}");
}
}
var embed = DiscordHelpers.GetEmbed(address, $"{titlePrefix}{trade.Direction} {trade.Ticker}", fields, trade.Direction == TradeDirection.Long ? Color.Green : Color.Red);
var embed = DiscordHelpers.GetEmbed(address, $"{titlePrefix}{trade.Direction} {trade.Ticker}", fields,
trade.Direction == TradeDirection.Long ? Color.Green : Color.Red);
await channel.SendMessageAsync("", components: builder.Build(), embed: embed);
}
public async Task SendPosition(string message, TradingExchanges exchange, Ticker ticker, TradeDirection direction, Timeframe timeframe)
public async Task SendPosition(string message, TradingExchanges exchange, Ticker ticker,
TradeDirection direction, Timeframe timeframe)
{
var expirationDate = DateTime.Now.AddMinutes(_settings.ButtonExpirationMinutes).ToString("G");
var channel = _client.GetChannel(_settings.SignalChannelId) as IMessageChannel;
var builder = new ComponentBuilder().WithButton("Open Position", $"{Constants.DiscordButtonAction.OpenPosition}{_separator}{exchange}{_separator}{ticker}{_separator}{direction}{_separator}{timeframe}{_separator}{expirationDate}");
var builder = new ComponentBuilder().WithButton("Open Position",
$"{Constants.DiscordButtonAction.OpenPosition}{_separator}{exchange}{_separator}{ticker}{_separator}{direction}{_separator}{timeframe}{_separator}{expirationDate}");
await channel.SendMessageAsync(message, components: builder.Build());
}
@@ -433,7 +464,9 @@ namespace Managing.Infrastructure.Messengers.Discord
public async Task SendTradeMessage(string message, bool isBadBehavior = false)
{
var channel = _client.GetChannel(isBadBehavior ? _settings.TroublesChannelId : _settings.TradesChannelId) as IMessageChannel;
var channel =
_client.GetChannel(isBadBehavior ? _settings.TroublesChannelId : _settings.TradesChannelId) as
IMessageChannel;
await channel.SendMessageAsync(message);
}
@@ -467,7 +500,8 @@ namespace Managing.Infrastructure.Messengers.Discord
}
};
var embed = DiscordHelpers.GetEmbed(address, $"Closed {oldTrade.Direction} {oldTrade.Ticker}", fields, oldTrade.Direction == TradeDirection.Long ? Color.DarkGreen : Color.DarkRed);
var embed = DiscordHelpers.GetEmbed(address, $"Closed {oldTrade.Direction} {oldTrade.Ticker}", fields,
oldTrade.Direction == TradeDirection.Long ? Color.DarkGreen : Color.DarkRed);
var channel = _client.GetChannel(_settings.CopyTradingChannelId) as IMessageChannel;
await channel.SendMessageAsync("", embed: embed);
}
@@ -508,7 +542,8 @@ namespace Managing.Infrastructure.Messengers.Discord
}
};
var embed = DiscordHelpers.GetEmbed(address, $"Decrease {trade.Direction} {trade.Ticker}", fields, Color.Blue);
var embed = DiscordHelpers.GetEmbed(address, $"Decrease {trade.Direction} {trade.Ticker}", fields,
Color.Blue);
var channel = _client.GetChannel(_settings.CopyTradingChannelId) as IMessageChannel;
await channel.SendMessageAsync("", embed: embed);
}
@@ -517,7 +552,8 @@ namespace Managing.Infrastructure.Messengers.Discord
public async Task SendPosition(Position position)
{
var channel = _client.GetChannel(_settings.TradesChannelId) as IMessageChannel;
var builder = new ComponentBuilder().WithButton("Close Position", $"{Constants.DiscordButtonAction.ClosePosition}{_separator}{position.Open.ExchangeOrderId}");
var builder = new ComponentBuilder().WithButton("Close Position",
$"{Constants.DiscordButtonAction.ClosePosition}{_separator}{position.Open.ExchangeOrderId}");
await channel.SendMessageAsync(MessengerHelpers.GetPositionMessage(position), components: builder.Build());
}
@@ -525,7 +561,6 @@ namespace Managing.Infrastructure.Messengers.Discord
{
var channel = _client.GetChannel(_settings.LeaderboardChannelId) as IMessageChannel;
await channel.SendMessageAsync("", embed: DiscordHelpers.GetTradersEmbed(traders, "Leaderboard"));
}
public async Task SendBadTraders(List<Trader> traders)
@@ -534,24 +569,37 @@ namespace Managing.Infrastructure.Messengers.Discord
await channel.SendMessageAsync("", embed: DiscordHelpers.GetTradersEmbed(traders, "Noobiesboard"));
}
public async Task SendDowngradedFundingRate(FundingRate fundingRate)
{
var channel = _client.GetChannel(_settings.FundingRateChannelId) as IMessageChannel;
await channel.SendMessageAsync("",
embed: DiscordHelpers.GetFundingRateEmbed(fundingRate, "Funding rate new opportunity"));
}
public Task SendNewTopFundingRate(FundingRate newRate)
{
var channel = _client.GetChannel(_settings.FundingRateChannelId) as IMessageChannel;
return channel.SendMessageAsync("",
embed: DiscordHelpers.GetFundingRateEmbed(newRate, "Funding rate new opportunity"));
}
public Task SendFundingRateUpdate(FundingRate oldRate, FundingRate newRate)
{
var channel = _client.GetChannel(_settings.FundingRateChannelId) as IMessageChannel;
return channel.SendMessageAsync("",
embed: DiscordHelpers.GetFundingRateEmbed(newRate, "Funding rate new opportunity", oldRate));
}
#endregion
public class CopyTradeData
{
[JsonProperty(PropertyName = "D")]
public TradeDirection Direction { get; set; }
[JsonProperty(PropertyName = "T")]
public Ticker Ticker { get; set; }
[JsonProperty(PropertyName = "A")]
public string AccountName { get; set; }
[JsonProperty(PropertyName = "E")]
public int ExpirationMinute { get; set; }
[JsonProperty(PropertyName = "L")]
public decimal Leverage { get; set; }
[JsonProperty(PropertyName = "M")]
public string MoneyManagementName { get; internal set; }
[JsonProperty(PropertyName = "D")] public TradeDirection Direction { get; set; }
[JsonProperty(PropertyName = "T")] public Ticker Ticker { get; set; }
[JsonProperty(PropertyName = "A")] public string AccountName { get; set; }
[JsonProperty(PropertyName = "E")] public int ExpirationMinute { get; set; }
[JsonProperty(PropertyName = "L")] public decimal Leverage { get; set; }
[JsonProperty(PropertyName = "M")] public string MoneyManagementName { get; internal set; }
}
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Managing.Infrastructure.Messengers.Discord
RequestsChannelId = config.GetValue<ulong>("Discord:RequestsChannelId");
LeaderboardChannelId = config.GetValue<ulong>("Discord:LeaderboardChannelId");
NoobiesboardChannelId = config.GetValue<ulong>("Discord:NoobiesboardChannelId");
FundingRateChannelId = config.GetValue<ulong>("Discord:FundingRateChannelId");
ButtonExpirationMinutes = config.GetValue<int>("Discord:ButtonExpirationMinutes");
HandleUserAction = config.GetValue<bool>("Discord:HandleUserAction");
BotActivity = config.GetValue<string>("Discord:BotActivity");
@@ -32,6 +33,6 @@ namespace Managing.Infrastructure.Messengers.Discord
public bool BotEnabled { get; set; }
public ulong LeaderboardChannelId { get; set; }
public ulong NoobiesboardChannelId { get; set; }
public ulong FundingRateChannelId { get; set; }
}
}
}

View File

@@ -1,5 +1,6 @@
using Discord.WebSocket;
using Managing.Application.Workers.Abstractions;
using Managing.Domain.Statistics;
namespace Managing.Infrastructure.Messengers.Discord;
@@ -23,6 +24,15 @@ public static class SlashCommands
{
var statisticService = (IStatisticService)service.GetService(typeof(IStatisticService));
var trades = await statisticService.GetLeadboardPositons();
await command.FollowupAsync(embed: DiscordHelpers.GetTradesEmbed(trades, "Leaderboard Open position"), ephemeral: true);
await command.FollowupAsync(embed: DiscordHelpers.GetTradesEmbed(trades, "Leaderboard Open position"),
ephemeral: true);
}
}
public static async Task HandleFundingRateCommand(IServiceProvider service, SocketSlashCommand command)
{
var statisticService = (IStatisticService)service.GetService(typeof(IStatisticService));
List<FundingRate> fundingRates = await statisticService.GetFundingRates();
await command.FollowupAsync(
embed: DiscordHelpers.GetFundingRatesEmbed(fundingRates, "Leaderboard Open position"), ephemeral: true);
}
}