public ImmutableArray <CapitalGain> Process(ITrade trade) { var baseCcy = trade.Base; var baseAsset = GetAsset(baseCcy); var quoteCcy = trade.Quote; var quoteAsset = GetAsset(quoteCcy); if (trade.IsBuyer) { // we are selling trade.GetQuoteQuantity of quoteAsset. // to calculate capital gain we need to price this quantity at the time it has been bought var proceed = _fiatConversion.GetProceed(trade); var assetCost = new AssetCost(trade.Time, trade.Quantity, proceed / trade.Quantity, trade); baseAsset.IncrementAmount(assetCost); return(quoteAsset.DecrementAmount(trade.GetQuoteQuantity(), trade) .Select(t => { var multiplier = t.RemainingQuantity / trade.GetQuoteQuantity(); return new CapitalGain { Asset = quoteCcy, SoldTime = trade.Time, BoughtTime = t.Time, Quantity = t.RemainingQuantity, Cost = t.CostPerUnit * t.RemainingQuantity, Proceed = proceed * multiplier, BoughtTag = GetTag(t.Item) }; }) .Concat(GetFeeCapitalGains(trade)) .ToImmutableArray()); } else { // we are selling trade.Quantity of baseAsset. // to calculate capital gain we need to price this quantity at the time it has been bought var proceed = _fiatConversion.GetProceed(trade); var assetCost = new AssetCost(trade.Time, trade.GetQuoteQuantity(), proceed / trade.GetQuoteQuantity(), trade); quoteAsset.IncrementAmount(assetCost); return(baseAsset.DecrementAmount(trade.Quantity, trade) .Select(t => { var multiplier = t.RemainingQuantity / trade.Quantity; return new CapitalGain { Asset = baseCcy, SoldTime = trade.Time, BoughtTime = t.Time, Quantity = t.RemainingQuantity, Cost = t.CostPerUnit * t.RemainingQuantity, Proceed = proceed * multiplier, BoughtTag = GetTag(t.Item) }; }) .Concat(GetFeeCapitalGains(trade)) .ToImmutableArray()); } }
public static decimal GetProceed(this IFiatConversion fiatConversion, ITrade trade) { if (trade is LaunchpadTrade) { // we go through BNB var bnbValue = fiatConversion.TryGetExactPriceInFiat(trade.Quote, trade.Time); if (bnbValue.HasValue) { return(trade.GetQuoteQuantity() * bnbValue.Value); } } if (trade.IsBuyer) { // we are buying baseCcy var result = fiatConversion.TryGetExactPriceInFiat(trade.Base, trade.Time); if (result.HasValue) { return(trade.Quantity * result.Value); } } var tryGetExactPriceInFiat = fiatConversion.TryGetExactPriceInFiat(trade.Quote, trade.Time); if (tryGetExactPriceInFiat.HasValue) { return(trade.GetQuoteQuantity() * tryGetExactPriceInFiat.Value); } if (trade is DelistingTrade) { // for delisting trade we are trying up to 7 days after for (int i = 1; i <= 7; i++) { var resultViaBase = fiatConversion.TryGetExactPriceInFiat(trade.Base, trade.Time.AddDays(i)); if (resultViaBase.HasValue) { return(trade.Quantity * resultViaBase.Value); } var resultViaQuote = fiatConversion.TryGetExactPriceInFiat(trade.Quote, trade.Time.AddDays(i)); if (resultViaQuote.HasValue) { return(trade.GetQuoteQuantity() * resultViaQuote.Value); } var baseViaBtc = fiatConversion.TryGetExactPriceInBtc(trade.Base, trade.Time.AddDays(i)); if (baseViaBtc.HasValue) { return(trade.Quantity * baseViaBtc.Value * fiatConversion.GetExactPriceInFiat("BTC", trade.Time.AddDays(i))); } var quoteViaBtc = fiatConversion.TryGetExactPriceInBtc(trade.Quote, trade.Time.AddDays(i)); if (quoteViaBtc.HasValue) { return(trade.GetQuoteQuantity() * quoteViaBtc.Value * fiatConversion.GetExactPriceInFiat("BTC", trade.Time.AddDays(i))); } } } throw new Exception($"Unable to price {trade.GetSymbol()} for date {trade.Time} {trade.GetTimeReadable():dd/MM/yyyy}"); }