private AdvisorRanking GetStartAdvisorRanking(DomainObjects.Advisor.Advisor advisor, DateTime referenceDate, int totalAdvisors) { return(advisor == null || !advisor.Enabled ? null : new AdvisorRanking() { Id = advisor.Id, Email = advisor.Email, Password = advisor.Password, CreationDate = advisor.CreationDate, ConfirmationCode = advisor.ConfirmationCode, ConfirmationDate = advisor.ConfirmationDate, ReferralCode = advisor.ReferralCode, ReferralStatus = advisor.ReferralStatus, BonusToReferred = advisor.BonusToReferred, ReferredId = advisor.ReferredId, AllowNotifications = advisor.AllowNotifications, DiscountProvided = advisor.DiscountProvided, IsAdvisor = true, Name = advisor.Name, Description = advisor.Description, UrlGuid = advisor.UrlGuid, BecameAdvisorDate = advisor.BecameAdvisorDate, Enabled = advisor.Enabled, UpdateDate = referenceDate, Rating = 2.5, Ranking = totalAdvisors + 1, TotalAdvisors = totalAdvisors + 1, AdvisorProfit = new List <AdvisorProfit>() { AdvisorProfitBusiness.GetBaseUsdAdvisorProfit(advisor.Id, referenceDate) } }); }
public void SetAdvisorRankingAndProfit() { var advisors = AdvisorBusiness.ListAllAdvisors().Select(c => c.Id).Distinct().ToList(); List <Order> orders = null; List <AssetCurrentValue> assetsCurrentValues = null; List <Order> finishedOrders = null; var now = Data.GetDateTimeNow(); Parallel.Invoke(() => orders = OrderBusiness.ListOrdersForRankingProfitCalculation(advisors), () => assetsCurrentValues = AssetCurrentValueBusiness.ListAllAssets(true), () => finishedOrders = OrderBusiness.ListOrders(advisors, null, new OrderStatusType[] { OrderStatusType.Finished })); var assetsBidValues = assetsCurrentValues.ToDictionary(c => c.Id, c => c.BidValue); var assetsAskValues = assetsCurrentValues.ToDictionary(c => c.Id, c => c.AskValue); var groupedOrders = orders.GroupBy(c => c.UserId).ToDictionary(c => c.Key, c => c.ToList()); var advisorRankingAndProfitData = new Dictionary <int, AdvisorRankingAndProfitData>(); foreach (var advisorOrders in groupedOrders) { advisorRankingAndProfitData[advisorOrders.Key] = GetAdvisorRankingAndProfitData(now, advisorOrders.Value, assetsBidValues, assetsAskValues); } var totalCount = advisorRankingAndProfitData.Sum(c => c.Value.OrderCount); if (totalCount == 0) { return; } var totalWeight = advisorRankingAndProfitData.Sum(c => c.Value.RankingWeight); var generalAvg = totalWeight != 0 ? advisorRankingAndProfitData.Sum(c => c.Value.RankingWeightedProfit) / totalWeight : 0; var weightedStdDivisor = totalWeight * (totalCount - 1) / totalCount; var consideredAdvisors = advisorRankingAndProfitData.Where(c => c.Value.RankingWeight != 0 && c.Value.OrderCount > 0); double weightedStd = 0; if (weightedStdDivisor != 0) { weightedStd = Math.Sqrt(consideredAdvisors .Sum(c => (Math.Pow((c.Value.RankingWeightedProfit / c.Value.RankingWeight) - generalAvg, 2) * c.Value.RankingWeight) / weightedStdDivisor)); } var z = new Dictionary <int, double>(); var minZ = 0.0; var normalizationDivisor = 1.0; if (weightedStd != 0) { z = consideredAdvisors.ToDictionary(c => c.Key, c => ((c.Value.RankingWeightedProfit / c.Value.RankingWeight) - generalAvg) / (weightedStd / Math.Sqrt(c.Value.OrderCount))); minZ = z.Min(c => c.Value); normalizationDivisor = z.Max(c => c.Value) - minZ; } else { var value = 1.0001; z = consideredAdvisors.OrderByDescending(c => c.Value.OrderCount).ToDictionary(c => c.Key, c => { value -= 0.0001; return(value); }); } var advisorRating = new Dictionary <int, double>(); advisors.ForEach(c => { if (!z.ContainsKey(c)) { advisorRating[c] = 2.5; } else { advisorRating[c] = 2.501 + (2.499 * ((z[c] - minZ) / normalizationDivisor)); } }); var advisorsOrdered = advisorRating.OrderByDescending(c => c.Value).ThenByDescending(c => c.Key); var advisorsRanking = new List <AdvisorRanking>(); var advisorsProfit = new List <AdvisorProfit>(); for (int i = 0; i < advisorsOrdered.Count(); ++i) { var id = advisorsOrdered.ElementAt(i).Key; advisorsRanking.Add(new AdvisorRanking() { Id = id, UpdateDate = now, Ranking = i + 1, Rating = advisorsOrdered.ElementAt(i).Value }); var usdPosition = AdvisorProfitBusiness.GetBaseUsdAdvisorProfit(id, now); if (advisorRankingAndProfitData.ContainsKey(id)) { var advisorProfit = BuildAdvisorsProfit(id, now, advisorRankingAndProfitData[id].AssetProfitData); if (advisorProfit.Any()) { var closedPositions = groupedOrders[id].Where(c => c.OrderStatusType == OrderStatusType.Close); if (closedPositions.Any()) { usdPosition.TotalDollar += closedPositions.Sum(c => GetExpectedCloseValue(c) - c.Fee.Value); } var openOrders = groupedOrders[id].Where(c => c.AssetId != AssetUSDId && (c.OrderStatusType == OrderStatusType.Open)); if (openOrders.Any()) { usdPosition.TotalDollar -= openOrders.Sum(c => c.Price * c.Quantity); } var openPositions = groupedOrders[id].Where(c => c.AssetId != AssetUSDId && (c.OrderStatusType == OrderStatusType.Executed)); if (openPositions.Any()) { usdPosition.TotalDollar -= openPositions.Sum(c => c.Price * c.Quantity + c.Fee.Value); } var userFinishedOrders = finishedOrders.Where(c => c.UserId == id); if (userFinishedOrders.Any()) { usdPosition.TotalDollar -= userFinishedOrders.Sum(c => c.Price * c.Quantity + c.Fee.Value); } usdPosition.TotalQuantity = usdPosition.TotalDollar; advisorsProfit.AddRange(advisorProfit); } } advisorsProfit.Add(usdPosition); } Parallel.Invoke(() => Data.SetAdvisorRanking(advisorsRanking), () => AdvisorProfitBusiness.SetAdvisorProfit(advisorsProfit)); UpdateAdvisorsFullDataCache(Data.ListAdvisorsRankingAndProfit(null, null)); }
public async Task <LoginResponse> CreateAsync(string email, string password, string name, string description, string referralCode, bool changePicture, Stream pictureStream, string pictureExtension) { if (string.IsNullOrWhiteSpace(name)) { throw new BusinessException("Name must be filled."); } if (name.Length > 50) { throw new BusinessException("Name cannot have more than 50 characters."); } if (!string.IsNullOrWhiteSpace(description) && description.Length > 160) { throw new BusinessException("Short description cannot have more than 160 characters."); } byte[] picture = null; if (changePicture && pictureStream != null) { picture = AdvisorBusiness.GetPictureBytes(pictureStream, pictureExtension); } User user = null; var updateUser = false; if (LoggedEmail != null) { if (!string.IsNullOrWhiteSpace(email) && email != LoggedEmail) { throw new BusinessException("Invalid email."); } if (!string.IsNullOrWhiteSpace(password)) { throw new BusinessException("Invalid password."); } user = UserBusiness.GetForLoginByEmail(LoggedEmail); if (UserBusiness.IsValidAdvisor(user)) { throw new BusinessException("User already registered."); } if (!user.ReferredId.HasValue) { var referredUser = UserBusiness.GetReferredUser(referralCode); if (referredUser != null) { updateUser = true; user.ReferralStatus = ReferralStatusType.InProgress.Value; user.ReferredId = referredUser.Id; user.BonusToReferred = UserBusiness.GetBonusToReferredUser(referredUser); } } else if (!string.IsNullOrEmpty(referralCode)) { throw new BusinessException("User already has a referral code defined."); } } else { user = UserBusiness.GetValidUserToRegister(email, password, referralCode); } var advisorsCount = AdvisorRankingBusiness.ListAdvisorsFullData().Count; Guid urlGuid = Guid.NewGuid(); var creationDate = Data.GetDateTimeNow(); using (var transaction = TransactionalDapperCommand) { if (LoggedEmail == null) { transaction.Insert(user); } else if (updateUser) { transaction.Update(user); } var advisor = new DomainObjects.Advisor.Advisor() { Id = user.Id, Name = name, Description = description, BecameAdvisorDate = creationDate, Enabled = true, UrlGuid = urlGuid }; transaction.Insert(advisor); var virtualDolar = new Order() { AssetId = AssetUSDId, CreationDate = creationDate, Price = 1, Quantity = VirtualMoney, RemainingQuantity = VirtualMoney, Status = OrderStatusType.Executed.Value, StatusDate = creationDate, Type = OrderType.Buy.Value, UserId = user.Id, ActionType = OrderActionType.Automated.Value, Fee = 0 }; transaction.Insert(virtualDolar); var rating = 2.5; var ranking = advisorsCount + 1; transaction.Insert(new AdvisorRanking() { Id = user.Id, UpdateDate = creationDate, Rating = rating, Ranking = ranking }); transaction.Insert(new AdvisorRankingHistory() { UserId = user.Id, ReferenceDate = creationDate, Rating = rating, Ranking = ranking }); var baseProfit = AdvisorProfitBusiness.GetBaseUsdAdvisorProfit(user.Id, creationDate); transaction.Insert(baseProfit); transaction.Insert(new AdvisorProfitHistory() { AssetId = baseProfit.AssetId, OrderCount = baseProfit.OrderCount, ReferenceDate = baseProfit.UpdateDate, Status = baseProfit.Status, SuccessCount = baseProfit.SuccessCount, SummedProfitDollar = baseProfit.SummedProfitDollar, SummedProfitPercentage = baseProfit.SummedProfitPercentage, SummedTradeMinutes = baseProfit.SummedTradeMinutes, TotalDollar = baseProfit.TotalDollar, TotalQuantity = baseProfit.TotalQuantity, Type = baseProfit.Type, UserId = baseProfit.UserId, TotalFee = baseProfit.TotalFee }); transaction.Commit(); } await AzureStorageBusiness.UploadUserPictureFromBytesAsync($"{urlGuid}.png", picture ?? AdvisorBusiness.GetNoUploadedImageForAdvisor(user)); if (LoggedEmail == null || !user.ConfirmationDate.HasValue) { await UserBusiness.SendEmailConfirmationAsync(user.Email, user.ConfirmationCode); } UserBusiness.ClearUserCache(user.Email); AdvisorRankingBusiness.AppendNewAdvisorToCache(user.Id); return(new LoginResponse() { Id = user.Id, Email = user.Email, PendingConfirmation = !user.ConfirmationDate.HasValue, AdvisorName = name, ProfileUrlGuid = urlGuid.ToString(), HasInvestment = false, IsAdvisor = true, RequestedToBeAdvisor = false }); }