public void TestPackUnpack() { // подготовить липу var lstEq = new List <EquityOnTime>(); var timeStart = DateTime.Now.Date.AddDays(-190); var timeEnd = DateTime.Now.Date; var i = 0; for (var date = timeStart; date < timeEnd; date = date.AddDays(1)) { var y = 1.5 + Math.Sin(i++ / 20.0); lstEq.Add(new EquityOnTime((float)y, date)); } // упаковать var chartMini = MiniChartPacker.PackChartInArray(lstEq); Assert.Greater(chartMini.Length, 0, "Chart is not empty"); var min = chartMini.Min(); var max = chartMini.Max(); Assert.Greater(max - min, 250, "Chart range is close to 255"); // распаковать var points = MiniChartPacker.MakePolygon(chartMini, 60, 30, 2, 2); Assert.AreEqual(chartMini.Length + 2, points.Length, "unpacked has the same size"); }
public bool Calculate(AccountEfficiency ef) { if (ef == null) { throw new ArgumentException("EfficiencyCalculator.Calculate - input ptr is NULL"); } if (ef.Statistics.Account == 0) { throw new ArgumentException("EfficiencyCalculator.Calculate - input_ptr.AccountId is 0"); } // получить сделки var deals = DealStorage.Instance.GetDeals(ef.Statistics.Account); ef.openedDeals = new List <MarketOrder>(); ef.closedDeals = new List <MarketOrder>(); foreach (var deal in deals) { if (deal.IsOpened) { ef.openedDeals.Add(deal); } else { ef.closedDeals.Add(deal); } } if (deals.Count == 0) { Logger.Info("AccountEfficiency.Calculate - нет сделок"); return(false); } ef.Statistics.DealsCount = deals.Count; ef.DealsStillOpened = ef.openedDeals.Count; // транзакции ef.listTransaction = BalanceStorage.Instance.GetBalanceChanges(ef.Statistics.Account); if (ef.listTransaction == null || ef.listTransaction.Count == 0) { Logger.Info("AccountEfficiency.Calculate - нет транзакций"); return(false); } Logger.Info("AccountEfficiency.Calculate(" + ef.Statistics.Account + ")"); // время отсчета - время первого заведения средств var startDate = ef.listTransaction.Min(t => t.ValueDate); // получить список используемых котировок var symbolsUsed = ef.closedDeals.Select(d => d.Symbol).Union(ef.openedDeals.Select(o => o.Symbol)).Distinct().ToList(); // ... в т.ч., котировок для перевода базовой валюты в валюту депо (плечо) // и перевода контрвалюты в валюту депо (профит) var symbolsMore = new List <string>(); foreach (var smb in symbolsUsed) { bool inverse, eq; var smbBase = DalSpot.Instance.FindSymbol(smb, true, ef.Statistics.DepoCurrency, out inverse, out eq); if (!string.IsNullOrEmpty(smbBase)) { symbolsMore.Add(smbBase); } var smbCounter = DalSpot.Instance.FindSymbol(smb, false, ef.Statistics.DepoCurrency, out inverse, out eq); if (!string.IsNullOrEmpty(smbCounter)) { symbolsMore.Add(smbCounter); } } symbolsUsed.AddRange(symbolsMore); symbolsUsed = symbolsUsed.Distinct().ToList(); // котировки var dicQuote = new Dictionary <string, List <QuoteData> >(); foreach (var smb in symbolsUsed) { dicQuote.Add(smb, dailyQuoteStorage.GetQuotes(smb).Select(q => new QuoteData(q.b, q.b, q.a)).ToList()); } //TickerStorage.Instance.GetQuotes(symbolsUsed.ToDictionary(s => s, s => (DateTime?)null)); if (dicQuote == null || dicQuote.Count == 0) { Logger.Info("AccountEfficiency.Calculate - нет котировок"); return(false); } if (ef.openedDeals.Count > 0) { foreach (var t in ef.openedDeals) { List <QuoteData> dicQuoteValue; if (!dicQuote.TryGetValue(t.Symbol, out dicQuoteValue)) { Logger.Error(String.Format("Symbol {0} was not found in dicQuote", t.Symbol)); } else if (dicQuoteValue.Count == 0) { Logger.Error(String.Format("No quote data for symbol {0}", t.Symbol)); } else { t.PriceExit = dicQuoteValue.Last().GetPrice(t.Side == 1 ? QuoteType.Bid : QuoteType.Ask); } } } var quoteArc = new QuoteArchive(dicQuote); AccountPerformanceRaw performance; try { performance = equityCurveCalculator.CalculateEquityCurve(deals, ef.Statistics.DepoCurrency, quoteArc, ef.listTransaction); } catch (Exception ex) { Logger.Error("Ошибка в EfficiencyCalculator.CalculateEquityCurve()", ex); return(false); } ef.Statistics.TotalTradedInDepoCurrency = performance.totalTradedVolume; var lstEquity = performance.equity; if (lstEquity == null) { return(false); } ef.listLeverage = performance.leverage; // исключить пустые значения с начала отсчета ef.listEquity = new List <EquityOnTime>(); var startCopy = false; foreach (var eq in lstEquity) { if (eq.equity > 0) { startCopy = true; } if (startCopy) { ef.listEquity.Add(eq); } } if (ef.listEquity.Count == 0) { return(false); } ef.StartDate = startDate; ef.InitialBalance = ef.listEquity[0].equity; // рассчитать коэффициенты доходности CalculateProfitCoeffs(ef); CalculateRiskCoeffs(ef); // актуальные котировки ef.currentQuotes = quoteArc.GetCurrentQuotes(); ef.Statistics.Chart = ef.listProfit1000 == null || ef.listProfit1000.Count == 0 ? new byte[MiniChartPacker.profitChartPointCount] : MiniChartPacker.PackChartInArray(ef.listProfit1000); // дней торгует var startDayOpen = DateTime.Now; if (ef.openedDeals.Count > 0) { startDayOpen = ef.openedDeals.Max(d => d.TimeEnter); } if (ef.closedDeals.Count > 0) { var dateClosed = ef.closedDeals.Min(d => d.TimeEnter); if (dateClosed < startDayOpen) { startDayOpen = dateClosed; } } ef.Statistics.DaysTraded = (int)Math.Round((DateTime.Now - startDayOpen).TotalDays); // сумма профитных сделок (результат) к сумме убыточных сделок var sumProf = ef.closedDeals.Sum(d => d.ResultDepo > 0 ? d.ResultDepo : 0) + ef.openedDeals.Sum(d => d.ResultDepo > 0 ? d.ResultDepo : 0); var sumLoss = ef.closedDeals.Sum(d => d.ResultDepo > 0 ? d.ResultDepo : 0) + ef.openedDeals.Sum(d => d.ResultDepo > 0 ? d.ResultDepo : 0); ef.Statistics.AvgWeightedDealProfitToLoss = sumLoss == 0 && sumProf == 0 ? 0 : 100 * sumProf / (sumProf + sumLoss); var dateFirst = DateTime.Now.Date.AddMonths(-3); ef.Statistics.WithdrawalLastMonths = (float)ef.listTransaction.Sum(t => (t.ChangeType == BalanceChangeType.Withdrawal && t.ValueDate >= dateFirst) ? t.AmountDepo : 0); // профит в ПП ef.Statistics.SumProfitPoints = ef.closedDeals.Sum(d => d.ResultPoints); return(true); }