public void Calculate( List <BalanceChange> balanceChanges, List <MarketOrder> marketOrders, DateTime startDate) { // первый трансфер считаем за начальный баланс InitialBalance = (float)balanceChanges[0].SignedAmountDepo; balanceChanges.RemoveAt(0); if (listEquity.Count < 2) { return; } // считаем результат по открытым позициям var openPosList = PositionSummary.GetPositionSummary(marketOrders.Where(o => o.State == PositionState.Opened).ToList(), AccountStatus.Instance.AccountData.Currency, (float)AccountStatus.Instance.AccountData.Balance); sumOpenResult = openPosList[openPosList.Count - 1].Profit; // посчитать суммарный результат по сделкам (дельта эквити за вычетом пополнений/списаний) // все закрытые позиции var dueBalance = balanceChanges.Where(bc => bc.ValueDate >= listEquity[0].time && (bc.ChangeType == BalanceChangeType.Deposit || bc.ChangeType == BalanceChangeType.Withdrawal)).ToList(); var closedList = balanceChanges.Where(bc => bc.ValueDate >= listEquity[0].time && (bc.ChangeType == BalanceChangeType.Profit || bc.ChangeType == BalanceChangeType.Loss)).ToList(); // результат по всем закрытым сделкам sumClosedResult = (float)closedList.Sum(bc => bc.SignedAmountDepo); // сумма всех неторговых операций sumDeltaBalance = (float)dueBalance.Sum(bc => bc.SignedAmountDepo); //CurrentBalance = InitialBalance + sumClosedResult + sumDeltaBalance + sumOpenResult; // получить список ROR var listROR = new List <Cortege2 <DateTime, float> >(); for (var i = 1; i < listEquity.Count; i++) { var endEquity = listEquity[i]; var startEquity = listEquity[i - 1]; if (startEquity.equity == 0) { break; } var deltaBalance = 0f; for (var j = 0; j < dueBalance.Count; j++) { if (dueBalance[j].ValueDate > listEquity[i].time) { break; } deltaBalance += (float)dueBalance[j].SignedAmountDepo; dueBalance.RemoveAt(j); j--; } var rateOfReturn = ((endEquity.equity - startEquity.equity - deltaBalance) / startEquity.equity); listROR.Add(new Cortege2 <DateTime, float>(listEquity[i].time, rateOfReturn)); } // убрать все 0-е значения от начала отсчета for (var i = 0; i < listROR.Count; i++) { if (listROR[i].b == 0) { listROR.RemoveAt(i); i--; } else { break; } } if (listROR.Count == 0) { return; } // получить кривую доходности на виртуальную 1000 listProfit1000 = new List <EquityOnTime>(); var startBalance1000 = 1000f; listProfit1000.Add(new EquityOnTime(startBalance1000, startDate)); foreach (var ret in listROR) { startBalance1000 += startBalance1000 * ret.b; listProfit1000.Add(new EquityOnTime(startBalance1000, ret.a)); } // посчитать макс. проседание CalculateDrawdown(); // посчитать среднегеометрическую дневную, месячную и годовую доходность var avgROR = listROR.Average(ret => ret.b); ProfitGeomMonth = (float)Math.Pow(1 + avgROR, 20f) - 1; ProfitGeomYear = (float)Math.Pow(1 + avgROR, 250f) - 1; ProfitGeomDay = avgROR; }
private static void GetClosedDealsResult( float balance, string depoCurx, Dictionary <string, QuoteData> quotes, Dictionary <int, TradeSignalProfit> signalResult) { List <MarketOrder> orders; try { var status = TradeSharpAccount.Instance.proxy.GetHistoryOrders(AccountStatus.Instance.accountID, null, out orders); if (status != RequestStatus.OK) { Logger.ErrorFormat("SignalProfitReport - не удалось получить закрытые сделки ({0})", status); return; } } catch (Exception ex) { Logger.Error("SignalProfitReport - не удалось получить закрытые сделки:", ex); return; } foreach (var order in orders) { int signalCatId, parentDealId; if (!MarketOrder.GetTradeSignalFromDeal(order, out signalCatId, out parentDealId)) { continue; } TradeSignalProfit result; signalResult.TryGetValue(signalCatId, out result); if (result == null) { result = new TradeSignalProfit(); signalResult.Add(signalCatId, result); } result.closedDeals.Add(order); } // суммарные позы foreach (var result in signalResult.Values) { // список суммарных поз по каждому тикеру - EURUSD, ... if (result.closedDeals.Count == 0) { continue; } var sumPos = PositionSummary.GetPositionSummary(quotes, result.closedDeals, depoCurx, balance); result.closedDeals.Clear(); foreach (var pos in sumPos) { pos.Command = MakeDealsCountString(pos.orders.Count); if (string.IsNullOrEmpty(pos.Symbol)) { continue; } result.closedDeals.Add(new MarketOrder { Side = pos.Side, Symbol = pos.Symbol, Volume = pos.Volume, Comment = pos.Command, ResultPoints = pos.ProfitInPoints, ResultDepo = pos.Profit, ResultBase = pos.ProfitInPercent }); } // суммарная поза var totalPos = sumPos.First(p => string.IsNullOrEmpty(p.Symbol)); sumPos.Remove(totalPos); result.totalClosedDealsCount = sumPos.Sum(p => p.orders.Count); result.totalClosedResult = sumPos.Sum(p => p.Profit); result.totalClosedVolume = totalPos.Volume; } }
private static Dictionary <int, TradeSignalProfit> GetOpenDealsResult( float balance, string depoCurx, Dictionary <string, QuoteData> quotes) { var signalResult = new Dictionary <int, TradeSignalProfit>(); // получить открытые сделки var orders = MarketOrdersStorage.Instance.MarketOrders; foreach (var order in orders) { int signalCatId, parentDealId; if (!MarketOrder.GetTradeSignalFromDeal(order, out signalCatId, out parentDealId)) { continue; } TradeSignalProfit result; signalResult.TryGetValue(signalCatId, out result); if (result == null) { result = new TradeSignalProfit(); signalResult.Add(signalCatId, result); } result.openDeals.Add(order); } if (signalResult.Count == 0) { return(signalResult); } // агрегировать открытые сделки - суммарные позы по ордерам foreach (var result in signalResult.Values) { // список суммарных поз по каждому тикеру - EURUSD, ... if (result.openDeals.Count == 0) { continue; } var sumPos = PositionSummary.GetPositionSummary(quotes, result.openDeals, depoCurx, balance); result.openDeals.Clear(); foreach (var pos in sumPos) { pos.Command = MakeDealsCountString(pos.orders.Count); if (string.IsNullOrEmpty(pos.Symbol)) { continue; } result.openDeals.Add(new MarketOrder { Side = pos.Side, Symbol = pos.Symbol, Volume = pos.Volume, Comment = pos.Command, PriceEnter = pos.AveragePrice, ResultPoints = pos.ProfitInPoints, ResultDepo = pos.Profit, ResultBase = pos.ProfitInPercent }); } // суммарная поза var totalPos = sumPos.First(p => string.IsNullOrEmpty(p.Symbol)); sumPos.Remove(totalPos); result.totalOpenPosCount = sumPos.Sum(p => p.orders.Count); result.totalOpenResultDepo = sumPos.Sum(p => p.Profit); result.totalOpenResultPercent = 100 * result.totalOpenResultDepo / balance; result.totalVolumeOpenDepo = totalPos.Volume; } return(signalResult); }
private void SetupGridSummaryMarketOrders() { var blank = new PositionSummary(); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Leverage), Localizer.GetString("TitleLeverage")) { ColumnFont = fontBold, colorColumnFormatter = delegate(object cellValue, out Color? backColor, out Color? fontColor) { fontColor = null; backColor = colorTextAboveLeverage; if (cellValue == null) return; var lev = (float) cellValue; foreach (var pair in dicLeverageLevel.Where(pair => pair.Key >= lev)) { backColor = pair.Value; break; } } }); if (HiddenModes.ManagerMode) dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.LeverageProtected), Localizer.GetString("TitleFreeLeverage")) { ColumnFont = fontBold }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Symbol), Localizer.GetString("TitleSymbol"))); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Side), Localizer.GetString("TitleType")) { formatter = (s => (int) s > 0 ? "BUY" : (int) s == 0 ? "" : "SELL"), colorColumnFormatter = delegate(object cellValue, out Color? backColor, out Color? fontColor) { backColor = null; fontColor = (int) cellValue == 1 ? colorTextSideBuy : colorTextSideSell; } }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Volume), Localizer.GetString("TitleSum")) { formatter = v => Math.Abs((int) v).ToStringUniformMoneyFormat() }); if (HiddenModes.ManagerMode) dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.VolumeProtected), Localizer.GetString("TitleFreeSum")) {ColumnFont = fontBold}); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.AveragePrice), Localizer.GetString("TitleEnterPrice")) { formatter = (s => (float) s == 0 ? "" : s.ToString()), ColumnFont = fontBold }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Profit), Localizer.GetString("TitleOpenedPL")) { colorColumnFormatter = ColorColumnSide, formatter = value => ((float) value).ToStringUniformMoneyFormat() }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.ProfitInPoints), Localizer.GetString("TitlePLInPoints")) { colorColumnFormatter = ColorColumnSide, formatter = value => ((int)value).ToStringUniformMoneyFormat() }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.ProfitInPercent), Localizer.GetString("TitlePLInPercents")) { colorColumnFormatter = ColorColumnSide }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Exposition), Localizer.GetString("TitleExposition")) { colorColumnFormatter = ColorColumnSide, formatter = v => ((int) v).ToStringUniformMoneyFormat() }); dgSummary.Columns.Add(new FastColumn(blank.Property(p=>p.TakeProfit), "T/P") { IsHyperlinkStyleColumn = true, HyperlinkFontActive = new Font(Font, FontStyle.Bold), HyperlinkActiveCursor = Cursors.Hand }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.StopLoss), "S/L") { IsHyperlinkStyleColumn = true, HyperlinkFontActive = fontBold, HyperlinkActiveCursor = Cursors.Hand }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Command), Localizer.GetString("TitleOrder")) { IsHyperlinkStyleColumn = true, HyperlinkFontActive = fontBold, HyperlinkActiveCursor = Cursors.Hand }); dgSummary.Columns.Add(new FastColumn(blank.Property(p => p.Equity), Localizer.GetString("TitleFunds"))); dgSummary.UserHitCell += GridOpenPosUserHitCell; dgSummary.ColorAltCellBackground = colorAltCell; dgSummary.CalcSetTableMinWidth(85); // применить настройки var sets = GridSettings.EnsureSettings(GridSettings.ListAccountSummaryOrders); sets.ApplyToGrid(dgSummary); dgSummary.ColumnSettingsChanged += OnDgSummaryColumnSettingsChange; dgSummary.DataBind(new List<PositionSummary>(), typeof(PositionSummary)); dgSummary.CheckSize(true); }
public static List<PositionSummary> GetPositionSummary(Dictionary<string, QuoteData> quotes, List<MarketOrder> orders, string accountCurrency, float accountBalance) { var summary = new List<PositionSummary>(); if (orders == null) orders = new List<MarketOrder>(); var symbols = orders.Select(o => o.Symbol).Distinct(); foreach (var symbol in symbols) { float sumBuys = 0, sumSell = 0; var sum = new PositionSummary { Symbol = symbol, orders = new List<MarketOrder>() }; var curSymbol = symbol; var sumDeals = orders.FindAll(o => o.Symbol == curSymbol); sum.ProfitInPercent = 0; sum.Profit = 0; sum.Volume = 0; //var rate = var tpflag = true; var slflag = true; float? tp = null; float? sl = null; foreach (var sumDeal in sumDeals) { if (tpflag) { if (sumDeal.TakeProfit != null) { if (tp == null) tp = sumDeal.TakeProfit; else { if (tp != null && tp != sumDeal.TakeProfit) tpflag = false; } } else tpflag = false; } if (slflag) { if (sumDeal.StopLoss != null) { if (sl == null) sl = sumDeal.StopLoss; else { if (sl != null && sl != sumDeal.StopLoss) slflag = false; } } else slflag = false; } var profitDepo = DalSpot.Instance.CalculateProfitInDepoCurrency(sumDeal, quotes, accountCurrency); //var profitStr = profitDepo.HasValue ? profitDepo.Value.ToString("f2") : "-"; if (AccountStatus.Instance.AccountData != null) { var profitPercent = (profitDepo ?? 0) / accountBalance * 100; sum.ProfitInPercent += profitPercent; sum.Profit += profitDepo ?? 0; } sum.orders.Add(sumDeal); sum.Volume += sumDeal.Side * sumDeal.Volume; // в админском режиме - посчитать объем и сумму "Free" if (HiddenModes.ManagerMode) if (sumDeal.StopLoss.HasValue) { // проверяем позиция поджата или нет if ((sumDeal.Side > 0 && sumDeal.PriceEnter < sumDeal.StopLoss) || (sumDeal.Side < 0 && sumDeal.PriceEnter > sumDeal.StopLoss)) { // позиция поджата (защищена) sum.VolumeProtected += sumDeal.Side * sumDeal.Volume; } } if (sumDeal.Side > 0) sumBuys += sumDeal.Volume * sumDeal.PriceEnter; else sumSell += sumDeal.Volume * sumDeal.PriceEnter; } sum.AveragePrice = (float) Math.Round(sum.Volume == 0 ? 0 : (sumBuys - sumSell) / sum.Volume, DalSpot.Instance.GetPrecision(sum.Symbol)); sum.Exposition = (int)sum.ConvertExpositionToDepo(sum.Symbol, accountCurrency, quotes, sum.Volume > 0 ? QuoteType.Bid : QuoteType.Ask, sum.Volume); sum.Side = sum.Exposition > 0 ? 1 : -1; // в менеджерском режиме - считаем параметры "free" // в остальных режимах эти данные не нужны if (HiddenModes.ManagerMode) if (sum.VolumeProtected != 0 && AccountStatus.Instance.AccountData != null) { // вычисляем плечо защищенных позиций sum.LeverageProtected = (float)Math.Round(Math.Abs(sum.ConvertExpositionToDepo(sum.Symbol, accountCurrency, quotes, sum.VolumeProtected > 0 ? QuoteType.Bid : QuoteType.Ask, sum.VolumeProtected)) / (float)AccountStatus.Instance.AccountData.Equity, 2); } var quote = QuoteStorage.Instance.ReceiveValue(sum.Symbol); var currPrice = quote == null ? 0 : (sum.Side == 1 ? quote.bid : quote.ask); sum.ProfitInPoints = sum.Volume == 0 ? 0 : (int)Math.Round(DalSpot.Instance.GetPointsValue(sum.Symbol, sum.Side == 1 ? (currPrice - sum.AveragePrice) : sum.AveragePrice - currPrice)); var acData = AccountStatus.Instance.AccountData; if (acData != null && acData.Equity != 0) sum.Leverage = (float) Math.Round(Math.Abs(sum.Exposition) / AccountStatus.Instance.AccountData.Equity, 2); // вычисляю хеш sum.hashCode = 0; foreach (var order in sumDeals) sum.hashCode += order.PriceEnter * 1000 + (order.TakeProfit ?? 0) * 50 + (order.StopLoss ?? 0) * 50 + (order.Swap ?? 0) * 10; sum.Equity = string.Format("Позиций:{0}", sumDeals.Count); sum.StopLoss = slflag ? sl.ToString() : "Установить"; sum.TakeProfit = tpflag ? tp.ToString() : "Установить"; sum.Command = "Закрыть всё"; summary.Add(sum); } // записываем итоговую информацию var overallSum = new PositionSummary { Symbol = "", orders = new List<MarketOrder>() }; foreach (var item in summary) { overallSum.Leverage += item.Leverage; overallSum.Exposition += Math.Abs(item.Exposition); overallSum.Volume += Math.Abs(item.Volume); overallSum.Profit += item.Profit; overallSum.ProfitInPercent += item.ProfitInPercent; overallSum.ProfitInPoints += item.ProfitInPoints; if (HiddenModes.ManagerMode) { overallSum.VolumeProtected += Math.Abs(item.VolumeProtected); overallSum.LeverageProtected += item.LeverageProtected; } overallSum.Side = 0; } var accountData = AccountStatus.Instance.AccountData; if (accountData != null && accountData.Equity != 0) overallSum.Equity = "Средства = " + accountData.Equity.ToStringUniform(2); summary.Add(overallSum); if (orders.Count > 0 && orders[0].State == PositionState.Opened) { AccountStatus.Instance.Leverage = overallSum.Leverage; AccountStatus.Instance.Trades = orders.Count; AccountStatus.Instance.Points = overallSum.ProfitInPoints; AccountStatus.Instance.ProfitInPercents = overallSum.ProfitInPercent; } else AccountStatus.Instance.Trades = 0; return summary; }
public static List <PositionSummary> GetPositionSummary(Dictionary <string, QuoteData> quotes, List <MarketOrder> orders, string accountCurrency, float accountBalance) { var summary = new List <PositionSummary>(); if (orders == null) { orders = new List <MarketOrder>(); } var symbols = orders.Select(o => o.Symbol).Distinct(); foreach (var symbol in symbols) { float sumBuys = 0, sumSell = 0; var sum = new PositionSummary { Symbol = symbol, orders = new List <MarketOrder>() }; var curSymbol = symbol; var sumDeals = orders.FindAll(o => o.Symbol == curSymbol); sum.ProfitInPercent = 0; sum.Profit = 0; sum.Volume = 0; //var rate = var tpflag = true; var slflag = true; float?tp = null; float?sl = null; foreach (var sumDeal in sumDeals) { if (tpflag) { if (sumDeal.TakeProfit != null) { if (tp == null) { tp = sumDeal.TakeProfit; } else { if (tp != null && tp != sumDeal.TakeProfit) { tpflag = false; } } } else { tpflag = false; } } if (slflag) { if (sumDeal.StopLoss != null) { if (sl == null) { sl = sumDeal.StopLoss; } else { if (sl != null && sl != sumDeal.StopLoss) { slflag = false; } } } else { slflag = false; } } var profitDepo = DalSpot.Instance.CalculateProfitInDepoCurrency(sumDeal, quotes, accountCurrency); //var profitStr = profitDepo.HasValue ? profitDepo.Value.ToString("f2") : "-"; if (AccountStatus.Instance.AccountData != null) { var profitPercent = (profitDepo ?? 0) / accountBalance * 100; sum.ProfitInPercent += profitPercent; sum.Profit += profitDepo ?? 0; } sum.orders.Add(sumDeal); sum.Volume += sumDeal.Side * sumDeal.Volume; // в админском режиме - посчитать объем и сумму "Free" if (HiddenModes.ManagerMode) { if (sumDeal.StopLoss.HasValue) { // проверяем позиция поджата или нет if ((sumDeal.Side > 0 && sumDeal.PriceEnter < sumDeal.StopLoss) || (sumDeal.Side < 0 && sumDeal.PriceEnter > sumDeal.StopLoss)) { // позиция поджата (защищена) sum.VolumeProtected += sumDeal.Side * sumDeal.Volume; } } } if (sumDeal.Side > 0) { sumBuys += sumDeal.Volume * sumDeal.PriceEnter; } else { sumSell += sumDeal.Volume * sumDeal.PriceEnter; } } sum.AveragePrice = (float) Math.Round(sum.Volume == 0 ? 0 : (sumBuys - sumSell) / sum.Volume, DalSpot.Instance.GetPrecision(sum.Symbol)); sum.Exposition = (int)sum.ConvertExpositionToDepo(sum.Symbol, accountCurrency, quotes, sum.Volume > 0 ? QuoteType.Bid : QuoteType.Ask, sum.Volume); sum.Side = sum.Exposition > 0 ? 1 : -1; // в менеджерском режиме - считаем параметры "free" // в остальных режимах эти данные не нужны if (HiddenModes.ManagerMode) { if (sum.VolumeProtected != 0 && AccountStatus.Instance.AccountData != null) { // вычисляем плечо защищенных позиций sum.LeverageProtected = (float)Math.Round(Math.Abs(sum.ConvertExpositionToDepo(sum.Symbol, accountCurrency, quotes, sum.VolumeProtected > 0 ? QuoteType.Bid : QuoteType.Ask, sum.VolumeProtected)) / (float)AccountStatus.Instance.AccountData.Equity, 2); } } var quote = QuoteStorage.Instance.ReceiveValue(sum.Symbol); var currPrice = quote == null ? 0 : (sum.Side == 1 ? quote.bid : quote.ask); sum.ProfitInPoints = sum.Volume == 0 ? 0 : (int)Math.Round(DalSpot.Instance.GetPointsValue(sum.Symbol, sum.Side == 1 ? (currPrice - sum.AveragePrice) : sum.AveragePrice - currPrice)); var acData = AccountStatus.Instance.AccountData; if (acData != null && acData.Equity != 0) { sum.Leverage = (float)Math.Round(Math.Abs(sum.Exposition) / AccountStatus.Instance.AccountData.Equity, 2); } // вычисляю хеш sum.hashCode = 0; foreach (var order in sumDeals) { sum.hashCode += order.PriceEnter * 1000 + (order.TakeProfit ?? 0) * 50 + (order.StopLoss ?? 0) * 50 + (order.Swap ?? 0) * 10; } sum.Equity = string.Format("Позиций:{0}", sumDeals.Count); sum.StopLoss = slflag ? sl.ToString() : "Установить"; sum.TakeProfit = tpflag ? tp.ToString() : "Установить"; sum.Command = "Закрыть всё"; summary.Add(sum); } // записываем итоговую информацию var overallSum = new PositionSummary { Symbol = "", orders = new List <MarketOrder>() }; foreach (var item in summary) { overallSum.Leverage += item.Leverage; overallSum.Exposition += Math.Abs(item.Exposition); overallSum.Volume += Math.Abs(item.Volume); overallSum.Profit += item.Profit; overallSum.ProfitInPercent += item.ProfitInPercent; overallSum.ProfitInPoints += item.ProfitInPoints; if (HiddenModes.ManagerMode) { overallSum.VolumeProtected += Math.Abs(item.VolumeProtected); overallSum.LeverageProtected += item.LeverageProtected; } overallSum.Side = 0; } var accountData = AccountStatus.Instance.AccountData; if (accountData != null && accountData.Equity != 0) { overallSum.Equity = "Средства = " + accountData.Equity.ToStringUniform(2); } summary.Add(overallSum); if (orders.Count > 0 && orders[0].State == PositionState.Opened) { AccountStatus.Instance.Leverage = overallSum.Leverage; AccountStatus.Instance.Trades = orders.Count; AccountStatus.Instance.Points = overallSum.ProfitInPoints; AccountStatus.Instance.ProfitInPercents = overallSum.ProfitInPercent; } else { AccountStatus.Instance.Trades = 0; } return(summary); }