private void BuildEquityChartUnsafe(AccountStatistics stat) { chartProfit.Graphs[0].Series[0].Clear(); //chartProfit.Graphs[0].Series[1].Clear(); chartProfit1000.Graphs[0].Series[0].Clear(); if (stat.listEquity == null || stat.listEquity.Count == 0) { return; } if (stat.listEquity != null) { foreach (var pt in stat.listEquity) { chartProfit.Graphs[0].Series[0].Add(new BalanceByDate(pt.time, pt.equity)); } } chartProfit.Initialize(); // доход на 1000 foreach (var pt in stat.listProfit1000) { chartProfit1000.Graphs[0].Series[0].Add(new BalanceByDate(pt.time, pt.equity)); } chartProfit1000.Initialize(); }
private StringBuilder GetProfitStatistic(List <EquityOnTime> accountStatistics, decimal accountBalance, decimal accountEquity) { var result = new StringBuilder(); var balanceChangesText = "- "; var balanceChangesPercentText = "- "; var currentDrawDownText = "- "; var maxDrawDownText = "- "; try { if (accountStatistics.Count > 1) { var equtyByDay = accountStatistics.Skip(Math.Max(0, accountStatistics.Count - 7)).Select(x => x.equity).ToList(); var profitWeek = 0F; for (int i = 0; i < equtyByDay.Count - 1; i++) { profitWeek += (equtyByDay[i + 1] - equtyByDay[i]); } var profitWeekPercent = (equtyByDay.Last() - equtyByDay.First()) / equtyByDay.Last(); var profitToday = equtyByDay[equtyByDay.Count - 1] - equtyByDay[equtyByDay.Count - 2]; var profitTodayPercent = (equtyByDay[equtyByDay.Count - 1] - equtyByDay[equtyByDay.Count - 2]) / equtyByDay[equtyByDay.Count - 1]; balanceChangesText = $"{profitToday:F3} / {profitWeek:F3}"; balanceChangesPercentText = $"{profitTodayPercent * 100:F3} % / {profitWeekPercent * 100:F3} %"; var stat = new AccountStatistics(); var maxDrawDown = stat.CalculateMaxDrawdown(accountStatistics); maxDrawDownText = $"{maxDrawDown:F3} %"; var currentDrawDown = accountEquity < accountBalance ? 100 * (accountEquity - accountBalance) / accountBalance : 0; currentDrawDownText = $"{currentDrawDown} %"; } } catch (Exception ex) { Logger.Error("Ошибка скрипта AccountInfoCommentScript", ex); } result.AppendLine($"[b] Баланс {accountBalance}"); result.AppendLine($"[b] Прирост за сутки / неделю: {balanceChangesText}"); result.AppendLine($"[b] Прирост за сутки / неделю (%/%): {balanceChangesPercentText}"); result.AppendLine($"[b] Текущее draw down (%): {currentDrawDownText}"); result.AppendLine($"[b] Max draw down (%): {maxDrawDownText}"); return(result); }
public void JsonIsReadProperly() { string json = ReadDataFile("AccountStatistics.json"); AccountStatistics stat = new AccountStatistics(json, false); Assert.Equal(1, stat.Memory); Assert.Equal(2, stat.Storage); Assert.Equal(3, stat.Streams); Assert.Equal(4, stat.Consumers); stat = new AccountStatistics("{}", false); Assert.Equal(0, stat.Memory); Assert.Equal(0, stat.Storage); Assert.Equal(0, stat.Streams); Assert.Equal(0, stat.Consumers); }
public string RenderReport(Account account, AccountStatistics stat, List <MarketOrder> openedOrders, List <MarketOrder> closedOrders, bool renderClosedDeals) { this.account = account; this.stat = stat; this.openedOrders = openedOrders; this.closedOrders = closedOrders; this.renderClosedDeals = renderClosedDeals; var sb = new StringBuilder(); RenderDocumentHead(sb); RenderBody(sb); RenderDocumentCloseTag(sb); return(sb.ToString()); }
private void ShowStatistics(AccountStatistics stat) { var depoCurx = AccountStatus.Instance.AccountData.Currency; var statList = new List <StatItem> { new StatItem(Localizer.GetString("TitleAccountNumber"), AccountStatus.Instance.AccountData.ID.ToString()), new StatItem(Localizer.GetString("TitleDate"), string.Format("{0:dd.MM.yyyy}", DateTime.Now)), new StatItem(Localizer.GetString("TitleInitialDate"), string.Format("{0:dd.MM.yyyy}", stat.listEquity.Count > 0 ? stat.listEquity[0].time : cbStartFrom.Checked ? dpStart.Value : DateTime.Now)), new StatItem(Localizer.GetString("TitleInitialDeposit"), stat.InitialBalance.ToStringUniformMoneyFormat(false) + " " + depoCurx), new StatItem(Localizer.GetString("TitleCurrentDeposit"), stat.Statistics.Equity.ToStringUniformMoneyFormat(false) + " " + depoCurx), new StatItem(Localizer.GetString("TitleDealsTotal"), stat.Statistics.DealsCount.ToString()), new StatItem(Localizer.GetString("TitleOpenedDeals"), stat.DealsStillOpened.ToString()), new StatItem(Localizer.GetString("TitleSummaryResult"), (stat.sumClosedResult + stat.sumOpenResult).ToStringUniformMoneyFormat() + " " + depoCurx), new StatItem(Localizer.GetString("TitleSummaryResultInClosedDeals"), stat.sumClosedResult.ToStringUniformMoneyFormat() + " " + depoCurx), new StatItem(Localizer.GetString("TitleSummaryResultInOpenedDeals"), stat.sumOpenResult.ToStringUniformMoneyFormat() + " " + depoCurx), new StatItem(Localizer.GetString("TitleSummaryDepositsAndWithdraws"), stat.sumDeltaBalance.ToStringUniformMoneyFormat() + " " + depoCurx), new StatItem(Localizer.GetString("TitleMaximumRelativeDrawdown"), stat.Statistics.MaxRelDrawDown.ToString("f1") + "%"), new StatItem(Localizer.GetString("TitleGADailyProfit"), (100 * stat.ProfitGeomDay).ToStringUniformMoneyFormat() + "%"), new StatItem(Localizer.GetString("TitleGAMonthlyProfit"), (100 * stat.ProfitGeomMonth).ToStringUniformMoneyFormat() + "%"), new StatItem(Localizer.GetString("TitleGAAnnualProfit"), (100 * stat.ProfitGeomYear).ToStringUniformMoneyFormat() + "%") }; dgStat.DataBind(statList, typeof(StatItem)); }
private AccountStatistics BuildEquityCurve( List <MarketOrder> orders, List <MarketOrder> openOrders, List <BalanceChange> balanceChanges) { var stat = new AccountStatistics { Statistics = new PerformerStat { DealsCount = orders.Count + openOrders.Count, }, DealsStillOpened = openOrders.Count, listEquity = new List <EquityOnTime>() }; if (worker.CancellationPending) { return(stat); } SetProgressValueSafe(40, Localizer.GetString("MessageActualizingQuoteHistory") + "..."); if (balanceChanges.Count == 0) { MessageBox.Show(Localizer.GetString("MessageNoTransfersData")); return(stat); } var curxDepo = AccountStatus.Instance.AccountData.Currency; // запросить котировки, если стоит соотв. флаг var quotesDic = UpdateQuotesForStats(orders, openOrders, curxDepo); // построить кривую эквити // отсчет от первого движения на счете либо от стартовой даты balanceChanges = balanceChanges.OrderBy(bc => bc.ValueDate).ToList(); var startDate = cbStartFrom.Checked ? dpStart.Value : balanceChanges[0].ValueDate; // начальный баланс var initialBalance = !cbStartFrom.Checked ? balanceChanges[0].SignedAmountDepo : balanceChanges.Where(bc => bc.ValueDate <= startDate).Sum(bc => bc.SignedAmountDepo); // движения от начального баланса с заданным интервалом дискретизации var dueBalances = balanceChanges.Where(bc => bc.ValueDate > startDate).ToList(); var dueDeals = orders.Union(openOrders).OrderBy(o => o.TimeEnter).ToList(); var endDate = DateTime.Now; var balance = initialBalance; var cursor = new BacktestTickerCursor(); var path = ExecutablePath.ExecPath + TerminalEnvironment.QuoteCacheFolder; if (!cursor.SetupCursor(path, quotesDic.Keys.ToList(), quotesDic.Min(t => t.Value))) { MessageBox.Show(Localizer.GetString("MessageErrorGettingQuotesFromFiles")); return(stat); } var currentQuotes = new Dictionary <string, QuoteData>(); var timeframeMinutes = Timeframe; SetProgressValueSafe(60, Localizer.GetString("MessageCalculationInProcess") + "..."); try { for (var time = startDate; time < endDate; time = time.AddMinutes(timeframeMinutes)) { if (worker.CancellationPending) { return(stat); } // получить баланс на дату for (var i = 0; i < dueBalances.Count; i++) { if (dueBalances[i].ValueDate > time) { break; } balance += dueBalances[i].SignedAmountDepo; dueBalances.RemoveAt(i); i--; } var equity = balance; // получить текущие котировки var candles = cursor.MoveToTime(time); foreach (var candle in candles) { var quote = new QuoteData(candle.Value.open, DalSpot.Instance.GetAskPriceWithDefaultSpread(candle.Key, candle.Value.open), candle.Value.timeOpen); if (currentQuotes.ContainsKey(candle.Key)) { currentQuotes[candle.Key] = quote; } else { currentQuotes.Add(candle.Key, quote); } } // уточнить результат по открытым позициям for (var i = 0; i < dueDeals.Count; i++) { if (worker.CancellationPending) { return(stat); } if (dueDeals[i].TimeExit.HasValue) { if (dueDeals[i].TimeExit.Value <= time) { dueDeals.RemoveAt(i); i--; continue; } } var deal = dueDeals[i]; if (deal.TimeEnter <= time) { // посчитать текущий результат сделки // в контрвалюте if (!currentQuotes.ContainsKey(deal.Symbol)) { continue; } var dealTickerQuote = currentQuotes[deal.Symbol]; var dealTickerPrice = deal.Side > 0 ? dealTickerQuote.bid : dealTickerQuote.ask; var dealResult = deal.Volume * deal.Side * (dealTickerPrice - deal.PriceEnter); // перевод прибыли в валюту депо bool inverse, areSame; var dealTransferSymbol = DalSpot.Instance.FindSymbol(deal.Symbol, false, curxDepo, out inverse, out areSame); float?baseDepoRate = null; if (areSame) { baseDepoRate = 1f; } else { if (!string.IsNullOrEmpty(dealTransferSymbol)) { if (currentQuotes.ContainsKey(dealTransferSymbol)) { var quote = currentQuotes[dealTransferSymbol]; if (quote.time >= time) { baseDepoRate = !inverse ? (deal.Side > 0 ? quote.bid : quote.ask) : (deal.Side > 0 ? 1 / quote.ask : 1 / quote.bid); } } } } if (!baseDepoRate.HasValue) { continue; } dealResult *= baseDepoRate.Value; equity += (decimal)dealResult; } } // for (deal ... // сохранить отметку - время/доходность stat.listEquity.Add(new EquityOnTime((float)equity, time)); } // for (time ... += Timeframe } finally { cursor.Close(); } // если история начинается с пустого депо - изъять эти строки из истории var firstNotEmpty = stat.listEquity.FindIndex(e => e.equity > 0); if (firstNotEmpty == stat.listEquity.Count - 1) { stat.listEquity.Clear(); } else if (firstNotEmpty > 0) { stat.listEquity.RemoveRange(0, firstNotEmpty); } SetProgressValueSafe(70, Localizer.GetString("MessageBuildingEquityChart") + "..."); stat.Calculate(balanceChanges, openOrders, startDate); return(stat); }
private void BuildEquityChartSafe(AccountStatistics stat) { Invoke(new Action <AccountStatistics>(BuildEquityChartUnsafe), stat); }
private void UpdateTablesAndCharts(AccountStatistics stat) { ShowStatistics(stat); BuildEquityChartSafe(stat); }
private void MakeCalculation(object obj, DoWorkEventArgs args) { if (AccountStatus.Instance.AccountData == null || MainForm.serverProxyTrade.proxy == null) { MessageBox.Show(Localizer.GetString("MessageNoConnectionServer")); return; } var accountId = AccountStatus.Instance.AccountData.ID; // получить сделки за указанный период и эквити на начало периода // и все пополнения - снятия SetProgressValueSafe(10, Localizer.GetString("MessageGettingOrderHistory") + "..."); if (worker.CancellationPending) { return; } List <MarketOrder> orders; var status = TradeSharpAccount.Instance.GetHistoryOrdersUncompressed(accountId, cbStartFrom.Checked ? dpStart.Value : (DateTime?)null, out orders); if (status != RequestStatus.OK || orders == null) { MessageBox.Show(string.Format( Localizer.GetString("MessageUnableToGetOrderHistory") + ": {0}", EnumFriendlyName <RequestStatus> .GetString(status))); return; } // получить изменения баланса if (worker.CancellationPending) { return; } SetProgressValueSafe(20, Localizer.GetString("MessageGettingTransfersHistory") + "..."); List <BalanceChange> balanceChanges; status = TradeSharpAccount.Instance.proxy.GetBalanceChanges(accountId, null, out balanceChanges); if (status != RequestStatus.OK || balanceChanges == null) { MessageBox.Show(string.Format(Localizer.GetString("MessageUnableToGetTransfersHistory") + ": {0}", EnumFriendlyName <RequestStatus> .GetString(status))); return; } // получить открытые ордера if (worker.CancellationPending) { return; } SetProgressValueSafe(30, Localizer.GetString("MessageGettingOpenPosHistory") + "..."); List <MarketOrder> openOrders; status = TradeSharpAccount.Instance.proxy.GetMarketOrders(accountId, out openOrders); if (status != RequestStatus.OK || openOrders == null) { MessageBox.Show(string.Format(Localizer.GetString("MessageUnableToGetOpenPosHistory") + ": {0}", EnumFriendlyName <RequestStatus> .GetString(status))); return; } // построить кривую equity и посчитать характеристики торговли по счету var stat = BuildEquityCurve(orders, openOrders, balanceChanges); statistics = stat; // сохранить доходность в словаре if (statByAccount.ContainsKey(accountId)) { statByAccount[accountId] = stat; } else { statByAccount.Add(accountId, stat); } if (worker.CancellationPending) { return; } // построить график и вывести показатели доходности SetProgressValueSafe(90, Localizer.GetString("MessageMakingReport") + "..."); SetProgressValueSafe(100, Localizer.GetString("MessageCalculationCompleted") + "..."); Invoke(new Action(() => { UpdateTablesAndCharts(stat); MessageBox.Show(this, Localizer.GetString("MessageCalculationCompleted"), Localizer.GetString("TitleNotice"), MessageBoxButtons.OK, MessageBoxIcon.Information); })); SetProgressValueSafe(0, string.Empty); }