docker files fixes from liaqat

This commit is contained in:
alirehmani
2024-05-03 16:39:25 +05:00
commit 464a8730e8
587 changed files with 44288 additions and 0 deletions

View File

@@ -0,0 +1,557 @@
using Discord;
using Discord.Commands;
using Discord.Net;
using Discord.WebSocket;
using Managing.Application.Abstractions;
using Managing.Application.Abstractions.Services;
using Managing.Application.Trading;
using Managing.Application.Trading.Commands;
using Managing.Application.Workers.Abstractions;
using Managing.Common;
using Managing.Core;
using Managing.Domain.Statistics;
using Managing.Domain.Trades;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static Managing.Common.Enums;
namespace Managing.Infrastructure.Messengers.Discord
{
public class DiscordService : IHostedService, IDisposable, IDiscordService
{
private const string _separator = "|";
private readonly DiscordSocketClient _client;
private readonly CommandService _commandService;
private readonly IServiceProvider _services;
private readonly IExchangeService _exchangeService;
private readonly IMoneyManagementService _moneyManagementService;
private readonly IAccountService _accountService;
private readonly ITradingService _tradingService;
private readonly IStatisticService _statisticService;
private readonly DiscordSettings _settings;
private readonly ILogger<DiscordService> _logger;
private readonly string _explorerUrl = "";
public DiscordService(DiscordSocketClient client,
CommandService commandService,
IServiceProvider services,
DiscordSettings settings, ILogger<DiscordService> logger)
{
_client = client;
_commandService = commandService;
_services = services;
_settings = settings;
_logger = logger;
}
#region Setup
// The hosted service has started
public async Task StartAsync(CancellationToken cancellationToken)
{
if (_settings.HandleUserAction)
{
_client.ButtonExecuted += ButtonHandler;
_commandService.CommandExecuted += CommandExecuted;
_client.SlashCommandExecuted += SlashCommandHandler;
}
_client.Ready += ClientReady;
_client.Log += Log;
_commandService.Log += Log;
// look for classes implementing ModuleBase to load commands from
await _commandService.AddModulesAsync(GetType().Assembly, _services);
// log in to Discord, using the provided token
await _client.LoginAsync(TokenType.Bot, _settings.Token);
// start bot
await _client.StartAsync();
}
private async Task SlashCommandHandler(SocketSlashCommand command)
{
await command.DeferAsync();
// Let's add a switch statement for the command name so we can handle multiple commands in one event.
switch (command.Data.Name)
{
case Constants.DiscordSlashCommand.Leaderboard:
await SlashCommands.HandleLeaderboardCommand(_services, command);
break;
case Constants.DiscordSlashCommand.Noobiesboard:
await SlashCommands.HandleNoobiesboardCommand(_services, command);
break;
case Constants.DiscordSlashCommand.LeaderboardPosition:
await SlashCommands.HandleLeadboardPositionCommand(_services, command);
break;
}
}
private async Task ClientReady()
{
// set status to online
await _client.SetStatusAsync(UserStatus.Online);
// Discord started as a game chat service, so it has the option to show what games you are playing
// Here the bot will display "Playing dead" while listening
await _client.SetGameAsync(_settings.BotActivity, "https://moon.com", ActivityType.Playing);
if (!_settings.HandleUserAction) return;
List<ApplicationCommandProperties> applicationCommandProperties = new();
try
{
var leaderBoardCommand = new SlashCommandBuilder();
leaderBoardCommand.WithName(Constants.DiscordSlashCommand.Leaderboard);
leaderBoardCommand.WithDescription("Shows the last leaderboard");
applicationCommandProperties.Add(leaderBoardCommand.Build());
var leadboardPositionsCommand = new SlashCommandBuilder();
leadboardPositionsCommand.WithName(Constants.DiscordSlashCommand.LeaderboardPosition);
leadboardPositionsCommand.WithDescription("Shows the opened position of the leaderboard");
applicationCommandProperties.Add(leadboardPositionsCommand.Build());
var noobiesboardCommand = new SlashCommandBuilder();
noobiesboardCommand.WithName(Constants.DiscordSlashCommand.Noobiesboard);
noobiesboardCommand.WithDescription("Shows the last Noobies board");
applicationCommandProperties.Add(noobiesboardCommand.Build());
await _client.BulkOverwriteGlobalApplicationCommandsAsync(applicationCommandProperties.ToArray());
}
catch (ApplicationCommandException exception)
{
var json = JsonConvert.SerializeObject(exception, Formatting.Indented);
Console.WriteLine(json);
}
}
public static List<ApplicationCommandProperties> GetSlashCommands()
{
List<ApplicationCommandProperties> commands = new();
return commands;
}
// logging
private async Task Log(LogMessage arg)
{
await Task.Run(() =>
{
_logger.LogInformation(arg.ToString());
});
}
private async Task CommandExecuted(Optional<CommandInfo> command, ICommandContext context, IResult result)
{
// if a command isn't found
if (!command.IsSpecified)
{
await context.Message.AddReactionAsync(new Emoji("🤨")); // eyebrow raised emoji
return;
}
// log failure to the console
if (!result.IsSuccess)
{
await Log(new LogMessage(LogSeverity.Error, nameof(CommandExecuted), $"Error: {result.ErrorReason}"));
return;
}
// react to message
await context.Message.AddReactionAsync(new Emoji("🤖")); // robot emoji
}
// the hosted service is stopping
public async Task StopAsync(CancellationToken cancellationToken)
{
await _client.SetGameAsync(null);
await _client.SetStatusAsync(UserStatus.Offline);
await _client.StopAsync();
_client.Log -= Log;
_client.Ready -= ClientReady;
_commandService.Log -= Log;
_commandService.CommandExecuted -= CommandExecuted;
_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);
var command = parameters[0];
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");
}
else
{
switch (command)
{
case Constants.DiscordButtonAction.OpenPosition:
await OpenPosition(component, parameters);
break;
case Constants.DiscordButtonAction.ClosePosition:
await ClosePosition(component, parameters);
break;
case Constants.DiscordButtonAction.CopyPosition:
await CopyPosition(component, parameters);
break;
default:
break;
}
}
}
private async Task CopyPosition(SocketMessageComponent component, string[] parameters)
{
await component.Channel.SendMessageAsync("Let met few seconds to copy this position");
await component.Channel.TriggerTypingAsync();
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); ;
}
public async Task OpenPosition(SocketMessageComponent component, string[] parameters)
{
await component.Channel.SendMessageAsync("Let met few seconds to open a position");
await component.Channel.TriggerTypingAsync();
var accountName = MiscExtensions.ParseEnum<string>(parameters[1]);
var ticker = MiscExtensions.ParseEnum<Ticker>(parameters[2]);
var direction = MiscExtensions.ParseEnum<TradeDirection>(parameters[3]);
var timeframe = MiscExtensions.ParseEnum<Timeframe>(parameters[4]);
var moneyManagementName = parameters[5];
var expiration = DateTime.Parse(parameters[6]);
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)
{
if (DateTime.Now > expiration)
{
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 accountService = (IAccountService)_services.GetService(typeof(IAccountService));
var tradingService = (ITradingService)_services.GetService(typeof(ITradingService));
var tradeCommand = new OpenPositionRequest(
accountName,
await moneyManagementService.GetMoneyMangement(moneyManagement),
direction,
ticker,
initiator,
DateTime.UtcNow,
ignoreSLTP: ignoreSLTP);
var position = await new OpenPositionCommandHandler(exchangeService, accountService, tradingService)
.Handle(tradeCommand);
var builder = new ComponentBuilder().WithButton("Close Position", $"{Constants.DiscordButtonAction.ClosePosition}{_separator}{position.Identifier}");
await component.Channel.SendMessageAsync(MessengerHelpers.GetPositionMessage(position),
components: builder.Build());
}
}
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} $";
}
private async Task ClosePosition(SocketMessageComponent component, string[] parameters)
{
var exchangeService = (IExchangeService)_services.GetService(typeof(IExchangeService));
var accountService = (IAccountService)_services.GetService(typeof(IAccountService));
var tradingService = (ITradingService)_services.GetService(typeof(ITradingService));
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 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
},
};
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;
var builder = new ComponentBuilder().WithButton("Open Position", $"openposition{_separator}");
await channel.SendMessageAsync(message, components: builder.Build());
}
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}");
await channel.SendMessageAsync(message, components: builder.Build());
}
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>()
{
new EmbedFieldBuilder
{
Name = "Last size update",
Value = $"{trade.Date:s}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Entry Price",
Value = $"{trade.Price:#.##} $",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Quantity",
Value = $"{trade.Quantity / trade.Leverage:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Leverage",
Value = $"x{trade.Leverage:#.##}",
IsInline = true
}
};
if (oldTrade != null)
{
fields.Add(new EmbedFieldBuilder { Name = "Increasy by", Value = $"{(trade.Quantity - oldTrade.Quantity) / trade.Leverage:#.##} $" });
}
var titlePrefix = oldTrade != null ? "Increase " : "";
var builder = new ComponentBuilder();
var moneyManagementService = (IMoneyManagementService)_services.GetService(typeof(IMoneyManagementService));
var moneyManagements = moneyManagementService.GetMoneyMangements();
foreach (var mm in moneyManagements)
{
var data = new CopyTradeData
{
Direction = trade.Direction,
Ticker = trade.Ticker,
AccountName = copyAccountName,
ExpirationMinute = 10,
Leverage = trade.Leverage,
};
data.MoneyManagementName = mm.Name;
var encodedData = MiscExtensions.Base64Encode(JsonConvert.SerializeObject(data));
if (oldTrade == null)
{
builder.WithButton($"Copy with {mm.Name}", $"{Constants.DiscordButtonAction.CopyPosition}{_separator}{encodedData}");
}
else
{
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);
await channel.SendMessageAsync("", components: builder.Build(), embed: embed);
}
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}");
await channel.SendMessageAsync(message, components: builder.Build());
}
public async Task SendMessage(string message)
{
var channel = _client.GetChannel(_settings.TradesChannelId) as IMessageChannel;
await channel.SendMessageAsync(message);
}
public async Task SendClosingPosition(Position position)
{
var channel = _client.GetChannel(_settings.TradesChannelId) as IMessageChannel;
await channel.SendMessageAsync(GetClosingPositionMessage(position));
}
public async Task SendTradeMessage(string message, bool isBadBehavior = false)
{
var channel = _client.GetChannel(isBadBehavior ? _settings.TroublesChannelId : _settings.TradesChannelId) as IMessageChannel;
await channel.SendMessageAsync(message);
}
public async Task SendClosedPosition(string address, Trade oldTrade)
{
var fields = new List<EmbedFieldBuilder>()
{
new EmbedFieldBuilder
{
Name = "Last size update",
Value = $"{oldTrade.Date:s}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Entry Price",
Value = $"{oldTrade.Price:#.##} $",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Quantity",
Value = $"{oldTrade.Quantity / oldTrade.Leverage:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Leverage",
Value = $"x{oldTrade.Leverage:#.##}",
IsInline = true
}
};
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);
}
public async Task SendDecreasePosition(string address, Trade trade, decimal decreaseAmount)
{
var fields = new List<EmbedFieldBuilder>()
{
new EmbedFieldBuilder
{
Name = "Last size update",
Value = $"{trade.Date:s}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Entry Price",
Value = $"{trade.Price:#.##} $",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Quantity",
Value = $"{trade.Quantity / trade.Leverage:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Leverage",
Value = $"x{trade.Leverage:#.##}",
IsInline = true
},
new EmbedFieldBuilder
{
Name = "Decrease amount",
Value = $"{decreaseAmount:#.##} $"
}
};
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);
}
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}");
await channel.SendMessageAsync(MessengerHelpers.GetPositionMessage(position), components: builder.Build());
}
public async Task SendBestTraders(List<Trader> traders)
{
var channel = _client.GetChannel(_settings.LeaderboardChannelId) as IMessageChannel;
await channel.SendMessageAsync("", embed: DiscordHelpers.GetTradersEmbed(traders, "Leaderboard"));
}
public async Task SendBadTraders(List<Trader> traders)
{
var channel = _client.GetChannel(_settings.NoobiesboardChannelId) as IMessageChannel;
await channel.SendMessageAsync("", embed: DiscordHelpers.GetTradersEmbed(traders, "Noobiesboard"));
}
#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; }
}
}
}