diff --git a/Core/Core/Controllers/ForecastController.cs b/Core/Core/Controllers/ForecastController.cs index 248bcecc5d29e65377184b9d1ca119213d7362cc..dcb71a54acc6f310a965e77fb1967ff36f7b86e3 100644 --- a/Core/Core/Controllers/ForecastController.cs +++ b/Core/Core/Controllers/ForecastController.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using Core.BusinessLogic.Predicators; using Core.Controllers.containers; using Core.Data; using Core.Models; @@ -28,22 +29,26 @@ namespace Core.Controllers // GET: api/Forecast [HttpGet] [Authorize(Policy = "RequireLoggedIn")] - public TransactionSumsContainer Get() + public ForecastTransactionContainer Get() { Claim userJwtID = User.Claims.First(c => c.Type == "UserID"); long userID = long.Parse(userJwtID.Value); var transactions = Context.Files .Where(f => f.UserID == userID) - .SelectMany(f => f.Transactions); + .SelectMany(f => f.Transactions) + .Where(t => t.Amount < -2); if (!transactions.Any()) return null; - return GetWeekSums(transactions, userID); + var averagePrediction = AveragePrediction.Predict(transactions); + var amountPrediction = AmountPrediction.GetWeekComparsion(transactions); + var neuralPrediction = GetNeuralNetworkPrediction(transactions, userID); + return new ForecastTransactionContainer(averagePrediction, amountPrediction, neuralPrediction); } - private TransactionSumsContainer GetWeekSums(IQueryable<Transaction> transactions, long userID) + private List<TransactionContainer> GetNeuralNetworkPrediction(IQueryable<Transaction> transactions, long userID) { DateTime maxDate = transactions.Max(t => t.Date); DateTime lowerbound = maxDate.AddDays(-7); @@ -52,24 +57,31 @@ namespace Core.Controllers var intervalTransactions = transactions .Where(t => t.Date >= lowerbound); - List<double> expenses = intervalTransactions + List<TransactionContainer> expenses = intervalTransactions .Where(t => t.Amount < -2)//TODO: repetitive================================ - .Select(t => (double) t.Amount) - .ToList(); + .Select(t => new TransactionContainer() + { + amount = (double)t.Amount, + name = t.ConstantSymbol != null && t.ConstantSymbol.Kind != null ? t.ConstantSymbol.Kind.Value : "NezaĹ™azeno" + }).ToList(); + + //NeuralNet ann = GetNetwork(userID); //feed network - int smallCount = intervalTransactions.Where(t => t.Amount < -2 && t.Amount >= -500).Count(); - int mediumCount = intervalTransactions.Where(t => t.Amount < -500 && t.Amount >= -5000).Count(); - int hugeCount = intervalTransactions.Where(t => t.Amount < -5000).Count(); + return expenses; - return new TransactionSumsContainer(expenses, smallCount, mediumCount, hugeCount); + //int smallCount = intervalTransactions.Where(t => t.Amount < -2 && t.Amount >= -500).Count(); + //int mediumCount = intervalTransactions.Where(t => t.Amount < -500 && t.Amount >= -5000).Count(); + //int hugeCount = intervalTransactions.Where(t => t.Amount < -5000).Count(); + + //return new TransactionSumsContainer(expenses, smallCount, mediumCount, hugeCount); } private NeuralNet GetNetwork(long userID) { - + long? networkID = Context.Users .FirstOrDefault(u => u.ID == userID) .NetworkID; @@ -86,11 +98,5 @@ namespace Core.Controllers ann.Import(network.ToImportList()); return ann; } - - // POST: api/Forecast - [HttpPost] - public void Post([FromBody] string value) - { - } } } diff --git a/Core/Core/Controllers/HistoryController.cs b/Core/Core/Controllers/HistoryController.cs index 40c0b72d7c1b269ba63cca271f63cda1f62b50bb..aa041f4f8d10fcf6c7c9bfd20d3648b0035c0a89 100644 --- a/Core/Core/Controllers/HistoryController.cs +++ b/Core/Core/Controllers/HistoryController.cs @@ -74,28 +74,38 @@ namespace Core.Controllers } private bool IsInInterval(int low, int high, decimal value) => value > low && value <= high; + private TransactionContainer MakeTransactionContainer(IQueryable<Transaction> transactions, string name) + { + return new TransactionContainer() + { + amount = (double)transactions.Sum(t => Math.Abs(t.Amount)), + count = transactions.Count(), + name = name + }; + } //Add count as tooltip private List<TransactionContainer> GetTransactionTypes(IQueryable<Transaction> transactions) { return new List<TransactionContainer>() { - new TransactionContainer((double) transactions.Where(t => IsInInterval(2,500,Math.Abs(t.Amount))).Sum(t => Math.Abs(t.Amount)),"DrobnĂ©"), - new TransactionContainer((double) transactions.Where(t => IsInInterval(500,5000,Math.Abs(t.Amount))).Sum(t => Math.Abs(t.Amount)),"MalĂ©"), - new TransactionContainer((double) transactions.Where(t => IsInInterval(5000,25000,Math.Abs(t.Amount))).Sum(t => Math.Abs(t.Amount)),"StĹ™ednĂ"), - new TransactionContainer((double) transactions.Where(t => IsInInterval(25000,50000,Math.Abs(t.Amount))).Sum(t => Math.Abs(t.Amount)),"VelkĂ©"), - new TransactionContainer((double) transactions.Where(t => IsInInterval(50000,500000,Math.Abs(t.Amount))).Sum(t => Math.Abs(t.Amount)),"Velmi velkĂ©"), - new TransactionContainer((double) transactions.Where(t => Math.Abs(t.Amount)>500000).Sum(t => Math.Abs(t.Amount)),"ZnaÄŤnÄ› velkĂ©") + MakeTransactionContainer( transactions.Where(t => IsInInterval(2,500,Math.Abs(t.Amount))),"DrobnĂ©"), + MakeTransactionContainer( transactions.Where(t => IsInInterval(500,5000,Math.Abs(t.Amount))),"MalĂ©"), + MakeTransactionContainer( transactions.Where(t => IsInInterval(5000,25000,Math.Abs(t.Amount))),"StĹ™ednĂ"), + MakeTransactionContainer( transactions.Where(t => IsInInterval(25000,50000,Math.Abs(t.Amount))),"VelkĂ©"), + MakeTransactionContainer( transactions.Where(t => IsInInterval(50000,500000,Math.Abs(t.Amount))),"Velmi velkĂ©"), + MakeTransactionContainer( transactions.Where(t => Math.Abs(t.Amount)>500000),"ZnaÄŤnÄ› velkĂ©") }; } - private List<TransactionContainer> MakeGroup(IQueryable<Tuple<double, AbstractConstantSymbolVariation>> transactions, double undeterminedAmount = 0) + private List<TransactionContainer> MakeGroup(IQueryable<Tuple<double, AbstractConstantSymbolVariation>> transactions, double undeterminedAmount = 0, double undeterminedCount = 0) { const string labelUndefined = "NezaĹ™azeno"; List<TransactionContainer> list = transactions.GroupBy(s => s.Item2) .Select(group => new TransactionContainer( group.Sum(x => x.Item1), + group.Count(), group.First().Item2 != null ? group.First().Item2.Value : labelUndefined )).ToList(); @@ -106,9 +116,9 @@ namespace Core.Controllers int index = list.FindIndex(t => t.name == labelUndefined); if (index == -1) - list.Add(new TransactionContainer(undeterminedAmount, labelUndefined)); + list.Add(new TransactionContainer(undeterminedAmount, undeterminedCount, labelUndefined)); else - list[index] = new TransactionContainer(undeterminedAmount + list[index].amount, labelUndefined); + list[index] = new TransactionContainer(undeterminedAmount + list[index].amount, undeterminedCount + list[index].count, labelUndefined); return list; } diff --git a/Core/Core/Controllers/containers/ForecastTransactionContainer.cs b/Core/Core/Controllers/containers/ForecastTransactionContainer.cs index ccfd29d0d6551e683fa7549f2f564ce70c3f8a95..b078e8e00ba00b74c675f6fa9804e2143ed09ed0 100644 --- a/Core/Core/Controllers/containers/ForecastTransactionContainer.cs +++ b/Core/Core/Controllers/containers/ForecastTransactionContainer.cs @@ -7,13 +7,66 @@ namespace Core.Controllers.containers { public class ForecastTransactionContainer { - public List<Tuple<double[], double[]>> averagePrediction; - public List<Tuple<double, string, bool>> amountPrediction; + /// <summary> + /// Mon - Sun numbered list + /// each transactionContainer contains only amount and count + /// </summary> + public List<List<TransactionContainer>> averagePrediction; - public ForecastTransactionContainer(List<Tuple<double[], double[]>> averagePrediction, List<Tuple<double, string, bool>> amountPrediction) + /// <summary> + /// one week prediction with fields for each day + /// each TransactionContainer contains only values: amount, kind (=name), repetitivness, sizeType + /// </summary> + public List<TransactionContainer> amountPrediction; + + /// <summary> + /// neural net prediction for next 4 weeks + /// contains amount, kind, sizeType + /// </summary> + public List<TransactionContainer> neuralPrediction; + + public ForecastTransactionContainer(List<Tuple<double[], double[]>> averagePrediction, List<Tuple<double, string, bool>> amountPrediction, List<TransactionContainer> neuralPrediction) { - this.averagePrediction = averagePrediction; - this.amountPrediction = amountPrediction; + //converts averagePrediction tuples to list of transactions + this.averagePrediction = new List<List<TransactionContainer>>(averagePrediction.Count); + for (int i = 0; i < averagePrediction.Count; i++) + { + this.averagePrediction.Add(new List<TransactionContainer>(7)); + + for (int j = 0; j < 7; j++) + this.averagePrediction[i].Add(new TransactionContainer + { + count = averagePrediction[i].Item1[j], + amount = averagePrediction[i].Item2[j], + }); + } + + //converts amountPrediction tuples to list of transactions + this.amountPrediction = amountPrediction.ConvertAll(x => new TransactionContainer() { + amount = x.Item1, + name = x.Item2, + repetitive = x.Item3, + sizeType = GetTransactionTypes(Math.Abs(x.Item1)) + }); + + this.neuralPrediction = neuralPrediction; + this.neuralPrediction.ForEach(c => c.sizeType = GetTransactionTypes(c.amount)); + } + + private string GetTransactionTypes(double amount) + { + if (amount < 500) + return "DrobnĂ©"; + if (amount < 5000) + return "MalĂ©"; + if (amount < 25000) + return "StĹ™ednĂ"; + if (amount < 50000) + return "VelkĂ©"; + if (amount < 500000) + return "Velmi velkĂ©"; + + return "ZnaÄŤnÄ› velkĂ©"; } } } diff --git a/Core/Core/Controllers/containers/TransactionContainer.cs b/Core/Core/Controllers/containers/TransactionContainer.cs index 1be1565ce6b2cf3adc99e3d47041e1dd9d544c1f..067d6fc153b11ea7d91847e018fddd022c113916 100644 --- a/Core/Core/Controllers/containers/TransactionContainer.cs +++ b/Core/Core/Controllers/containers/TransactionContainer.cs @@ -7,13 +7,20 @@ namespace Core.Controllers.containers { public class TransactionContainer { - public readonly double amount; - public readonly int count; - public readonly string name; + public double amount; + public double count; + public string name; + public string sizeType; + public bool repetitive; - public TransactionContainer(double amount, string name) + public TransactionContainer() + { + } + + public TransactionContainer(double amount, double count, string name) { this.amount = amount; + this.count = count; this.name = name; } } diff --git a/Core/Core/Controllers/containers/TransactionSumsContainer.cs b/Core/Core/Controllers/containers/TransactionSumsContainer.cs index 62127a51640993efd4c8b2e34b25af6286099e97..673a7fd22f0ccf61728962169fa2c5cd5f7e5082 100644 --- a/Core/Core/Controllers/containers/TransactionSumsContainer.cs +++ b/Core/Core/Controllers/containers/TransactionSumsContainer.cs @@ -9,10 +9,6 @@ namespace Core.Controllers.containers { public readonly List<double> expenses; - public readonly int smallCount; - public readonly int mediumCount; - public readonly int hugeCount; - //TransactionContainer.name = constant symbol //TransactionContainer.amount = amount per selcted constant symbol public readonly List<TransactionContainer> expensesPerSymbolCategory; @@ -22,14 +18,6 @@ namespace Core.Controllers.containers //TransactionContainer.amount = amount per type public readonly List<TransactionContainer> expensesPerSize; - public TransactionSumsContainer(List<double> expenses, int smallCount, int mediumCount, int hugeCount) - { - this.expenses = expenses; - this.smallCount = smallCount; - this.mediumCount = mediumCount; - this.hugeCount = hugeCount; - } - public TransactionSumsContainer(List<double> expenses, List<TransactionContainer> expensesPerSymbolCategory, List<TransactionContainer> expensesPerSymbolType, List<TransactionContainer> expensesPerSize) { this.expenses = expenses;