public void AddTransactions(SortedList <DateTime, Transaction> txList, FXMarketHistory fxmh) { PnLElements = new SortedDictionary <DateTime, PnLElement> { }; DateTime lastDate = new DateTime(2008, 1, 1); foreach (var item in txList) { Transaction tx = item.Value; if ((tx.Date.ToOADate() - lastDate.ToOADate()) * 24 * 60 * 60 < 1) { lastDate = lastDate.AddSeconds(1); } else { lastDate = tx.Date; } bool justFees = true; if (tx.Received.Ccy == Ccy) { justFees = false; switch (tx.Type) { case TransactionType.Deposit: if (Ccy.IsFiat()) { PnLElement pnlD = GetLastPnLElement(); PnLElement newPnLD = (PnLElement)pnlD.Clone(); CurrencyPair cpD = new CurrencyPair(tx.Received.Ccy, CcyRef); XChangeRate xrD = fxmh.GetQuote(lastDate, cpD, isArtificial: true).Item2; double newWeightD = 1 / (1 + pnlD.Position / tx.Received.Amount); newPnLD.AverageCost = (1 - newWeightD) * pnlD.AverageCost + newWeightD * xrD.Rate; newPnLD.Position += tx.Received.Amount; newPnLD.Deposit += tx.Received.Amount * xrD.Rate; PnLElements.Add(lastDate, newPnLD); } else { PnLElement pnlDCrypto = GetLastPnLElement(); PnLElement newPnLDCrypto = (PnLElement)pnlDCrypto.Clone(); newPnLDCrypto.Position -= tx.Fees.Amount; newPnLDCrypto.Fees += tx.Fees.Amount; PnLElements.Add(lastDate, newPnLDCrypto); } break; case TransactionType.Trade: PnLElement pnlT = GetLastPnLElement(); PnLElement newPnLT = (PnLElement)pnlT.Clone(); CurrencyPair cpT = new CurrencyPair(tx.Received.Ccy, CcyRef); //XChangeRate xrT = fxmh.GetQuote(lastDate, cpT, isArtificial: true).Item2; XChangeRate xrT = GetAdjustedFXRate(lastDate, tx.XRate, fxmh); double amount = tx.Received.Amount; if (tx.Fees.Ccy == Ccy) { amount -= tx.Fees.Amount; newPnLT.Fees += tx.Fees.Amount * xrT.Rate; } double newWeight = 1 / (1 + pnlT.Position / amount); newPnLT.AverageCost = (1 - newWeight) * pnlT.AverageCost + newWeight * xrT.Rate; newPnLT.Position += amount; PnLElements.Add(lastDate, newPnLT); break; case TransactionType.Transfer: PnLElement pnlTf = GetLastPnLElement(); PnLElement newPnLTf = (PnLElement)pnlTf.Clone(); newPnLTf.Position += tx.Received.Amount; double newWeightTf = 1 / (1 + pnlTf.Position / tx.Received.Amount); newPnLT.AverageCost = (1 - newWeightTf) * pnlTf.AverageCost + newWeightTf * 0; PnLElements.Add(lastDate, newPnLTf); break; default: break; } } if (tx.Paid.Ccy == Ccy) { justFees = false; switch (tx.Type) { case TransactionType.Trade: PnLElement pnlTrade = GetLastPnLElement(); PnLElement newPnLTrade = (PnLElement)pnlTrade.Clone(); newPnLTrade.Position -= tx.Paid.Amount; Price feesT = tx.Fees; if (tx.Fees.Ccy == Ccy) { CurrencyPair cpFT = new CurrencyPair(feesT.Ccy, CcyRef); XChangeRate xrFT = fxmh.GetQuote(lastDate, cpFT, isArtificial: true).Item2; newPnLTrade.Fees += xrFT.ConvertPrice(feesT).Amount; newPnLTrade.Position -= feesT.Amount; } CurrencyPair cpT2 = new CurrencyPair(tx.Paid.Ccy, CcyRef); //XChangeRate xrT2 = fxmh.GetQuote(lastDate, cpT2, isArtificial: true).Item2; XChangeRate xrT2 = GetAdjustedFXRate(lastDate, tx.XRate, fxmh); newPnLTrade.RealizedPnL += tx.Paid.Amount * (xrT2.Rate - newPnLTrade.AverageCost); PnLElements.Add(lastDate, newPnLTrade); break; case TransactionType.WithDrawal: PnLElement pnl = GetLastPnLElement(); PnLElement newPnLW = (PnLElement)pnl.Clone(); Price feesW = tx.Fees; CurrencyPair cpW = new CurrencyPair(feesW.Ccy, CcyRef); XChangeRate xW = fxmh.GetQuote(lastDate, cpW, isArtificial: true).Item2; newPnLW.Fees += xW.ConvertPrice(feesW).Amount; newPnLW.Position -= feesW.Amount; if (tx.Paid.Ccy.IsFiat()) { newPnLW.Position -= tx.Paid.Amount; newPnLW.Withdrawal += xW.ConvertPrice(tx.Paid).Amount; newPnLW.RealizedPnL += (tx.Paid.Amount + feesW.Amount) * (xW.Rate - newPnLW.AverageCost); } else { newPnLW.RealizedPnL += feesW.Amount * (xW.Rate - newPnLW.AverageCost); } PnLElements.Add(lastDate, newPnLW); break; default: break; } } if (tx.Fees.Ccy == Ccy && justFees) { throw new Exception("ERROR JUST FEES!"); } } }