Exemplo n.º 1
0
        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}");
        }