private void UpdateTablesAndCharts(AccountStatistics stat)
 {
     ShowStatistics(stat);
     BuildEquityChartSafe(stat);
 }
 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 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);
        }
        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 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 void BuildEquityChartSafe(AccountStatistics stat)
 {
     Invoke(new Action<AccountStatistics>(BuildEquityChartUnsafe),
            stat);
 }