示例#1
0
        private bool LegalEntityPredicate(OvernightSwapReportType reportType, string legalEntity)
        {
            var filter = reportType == OvernightSwapReportType.Daily
                ? _dailyNotificationsSettings.Filter
                : _monthlyNotificationsSettings.Filter;

            return(string.IsNullOrWhiteSpace(filter.LegalEntityRegex) ||
                   (!string.IsNullOrWhiteSpace(legalEntity) &&
                    Regex.IsMatch(legalEntity, filter.LegalEntityRegex, RegexOptions.IgnoreCase)));
        }
示例#2
0
        private async Task SendNotifications(OvernightSwapReportType reportType,
                                             IEnumerable <PeriodicTradingNotification> notifications, IReadOnlyDictionary <string, string> emails)
        {
            var       failedNotifications = new Dictionary <PeriodicTradingNotification, Exception>();
            Exception anyException        = null;

            foreach (var notification in notifications)
            {
                if (reportType == OvernightSwapReportType.Monthly ||
                    notification.Accounts.Sum(x => x.ClosedTrades.Count) > 0 ||
                    notification.Accounts.Sum(x => x.OpenPositions.Count) > 0 ||
                    notification.Accounts.Sum(x => x.PendingPositions.Count) > 0)
                {
                    try
                    {
                        await _emailService.PrepareAndSendEmailAsync(emails[notification.ClientId],
                                                                     "Margin Trading - " + (reportType == OvernightSwapReportType.Daily ? "Daily" : "Monthly")
                                                                     + $" trading report for {notification.CurrentPeriod}",
                                                                     reportType == OvernightSwapReportType.Daily? "DailyTradingReport" : "MonthlyTradingReport",
                                                                     notification);

                        await _log.WriteInfoAsync(nameof(NotificationGenerator), nameof(TradingReportService),
                                                  nameof(PerformReporting), notification.GetLogData(), _systemClock.UtcNow.DateTime);
                    }
                    catch (Exception ex)
                    {
                        anyException = ex;
                        failedNotifications.Add(notification, ex);
                    }
                }
            }

            if (failedNotifications.Any())
            {
                //TODO handle failed notifications
                await _log.WriteWarningAsync(nameof(NotificationGenerator), nameof(TradingReportService),
                                             nameof(PerformReporting), $"{failedNotifications.Count} notifications failed to be send.",
                                             anyException, _systemClock.UtcNow.DateTime);
            }
        }
示例#3
0
        public async Task PerformReporting(OvernightSwapReportType reportType)
        {
            var invocationTime = GetInvocationTime(reportType);
            var from           = reportType == OvernightSwapReportType.Daily
                ? _systemClock.UtcNow.Date.AddDays(-1)
                : _systemClock.UtcNow.Date.AddMonths(-1);
            var to = new DateTime(_systemClock.UtcNow.Year, _systemClock.UtcNow.Month, _systemClock.UtcNow.Day,
                                  invocationTime.Hours, invocationTime.Minutes, invocationTime.Seconds);
            var reportPeriodIndex = reportType == OvernightSwapReportType.Daily
                ? from.DayOfWeek.ToString()
                : from.Month.ToString("MMMM");

            await _log.WriteInfoAsync(nameof(TradingReportService), nameof(PerformReporting),
                                      $"Report invoked for {reportPeriodIndex}, period from {from:s} to {to:s}");

            var(clientIds, accounts, closedTrades, openPositions, pendingPositions, accountTransactions) =
                await GetDataForNotifications(reportType, to, from);

            //prepare notification models
            var notifications = clientIds.Select(x =>
                                                 PrepareNotification(reportType, from, to, x, closedTrades, openPositions,
                                                                     pendingPositions, accounts, accountTransactions)).ToList();

            //retrieve emails
            var emails = (await _clientAccountClient.GetClientsByIdsAsync(clientIds))
                         .ToDictionary(x => x.Id, x => x.Email);

            if (reportType == OvernightSwapReportType.Daily
                ? _dailyNotificationsSettings.EmailNotificationEnabled
                : _monthlyNotificationsSettings.EmailNotificationEnabled)
            {
                await SendNotifications(reportType, notifications, emails);
            }
            else
            {
                await _log.WriteInfoAsync(nameof(TradingReportService), nameof(PerformReporting),
                                          $"Email notifications are disabled for {reportType.ToString()} reports.");
            }
        }
示例#4
0
        private static PeriodicTradingNotification PrepareNotification(OvernightSwapReportType reportType,
                                                                       DateTime from, DateTime to, string clientId,
                                                                       IReadOnlyCollection <OrderHistory> closedTrades, IReadOnlyCollection <OrderHistory> openPositions,
                                                                       IEnumerable <OrderHistory> pendingPositions, IEnumerable <Account> accounts,
                                                                       IEnumerable <AccountHistory> accountTransactions)
        {
            bool TimeClause(DateTime t) => t > @from && t < to;

            var closedTradesFiltered = closedTrades.Where(x => TimeClause(x.CloseDate ?? DateTime.MaxValue)).ToList();

            var orderInstruments = closedTradesFiltered.Concat(openPositions).ToDictionary(x => x.Id, x => x.Instrument);
            var closedTradesPnls = closedTradesFiltered.GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.Sum(ct => ct.PnL));
            var floatingPnls     = openPositions.GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.Sum(ct => ct.PnL));

            var closedTradesByAccount = closedTradesFiltered.Where(x => x.ClientId == clientId)
                                        .GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.OrderByDescending(z => z.CloseDate).ToList());
            var openPositionsByAccount = openPositions.Where(x => x.ClientId == clientId)
                                         .GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.OrderByDescending(z => z.OpenDate).ToList());
            var pendingPositionsByAccount = pendingPositions.Where(x => x.ClientId == clientId)
                                            .GroupBy(x => x.AccountId).ToDictionary(x => x.Key, x => x.OrderByDescending(z => z.CreateDate).ToList());

            var filteredAccounts = accounts.Where(x => x.ClientId == clientId)
                                   .Select(x =>
            {
                x.AccountTransactions = accountTransactions.Where(at => TimeClause(at.Date) &&
                                                                  at.ClientId == clientId &&
                                                                  at.AccountId == x.Id)
                                        .Select(at =>
                {
                    at.Comment = !string.IsNullOrEmpty(at.OrderId) &&
                                 orderInstruments.TryGetValue(at.OrderId, out var instrument)
                                ? $"position id: {at.OrderId} ({instrument})"
                                : at.Comment;
                    return(at);
                })
                                        .OrderByDescending(at => at.Date).ToList();

                if (closedTradesPnls.TryGetValue(x.Id, out var closedTradesPnl))
                {
                    x.ClosedTradesPnl = closedTradesPnl;
                }
                if (floatingPnls.TryGetValue(x.Id, out var floatingPnl))
                {
                    x.FloatingPnl = floatingPnl;
                }
                x.CashTransactions = x.AccountTransactions.Sum(at => at.Amount);
                x.Equity           = x.Balance + x.FloatingPnl;
                x.ChangeInBalance  = x.ClosedTradesPnl + x.CashTransactions;
                x.AvailableMargin  = x.Equity - x.MarginRequirements;

                x.ClosedTrades = closedTradesByAccount.TryGetValue(x.Id, out var extractedClosed)
                        ? extractedClosed
                        : new List <OrderHistory>();
                x.OpenPositions = openPositionsByAccount.TryGetValue(x.Id, out var extractedOpened)
                        ? extractedOpened
                        : new List <OrderHistory>();
                x.PendingPositions = pendingPositionsByAccount.TryGetValue(x.Id, out var extractedPending)
                        ? extractedPending
                        : new List <OrderHistory>();

                return(x);
            })
                                   .OrderByDescending(x => x.Balance).ThenBy(x => x.BaseAssetId).ToList();

            return(new PeriodicTradingNotification
            {
                CurrentPeriod = reportType == OvernightSwapReportType.Daily
                    ? from.ToString("dd.MM.yyyy")
                    : from.ToString("MM.yyyy"),
                From = $"{@from:dd.MM.yyyy} 00:00",
                To = $"{to.AddMinutes(-1):dd.MM.yyyy HH:mm}",
                ClientId = clientId,
                Accounts = filteredAccounts,
                ReportType = reportType,
            });