URI: 
       tfix #3912: Use Decimal('NaN') instead of None when exchange rate is not available. - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit d77e522721b98c8d455f866bc40b778c6a0fb74e
   DIR parent 7578ac6abb79347bee0a3848b2af243c9c0e0dd2
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Tue, 20 Feb 2018 21:53:12 +0100
       
       fix #3912: Use Decimal('NaN') instead of None when exchange rate is not available.
       
       Diffstat:
         M lib/exchange_rate.py                |      35 ++++++++++++++-----------------
         M lib/wallet.py                       |      22 +++++++++-------------
       
       2 files changed, 25 insertions(+), 32 deletions(-)
       ---
   DIR diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py
       t@@ -109,8 +109,8 @@ class ExchangeBase(PrintError):
        
            def historical_rate(self, ccy, d_t):
                if d_t is None:
       -            return None
       -        return self.history.get(ccy, {}).get(d_t.strftime('%Y-%m-%d'))
       +            return 'NaN'
       +        return self.history.get(ccy, {}).get(d_t.strftime('%Y-%m-%d'), 'NaN')
        
            def get_currencies(self):
                rates = self.get_rates('')
       t@@ -497,40 +497,38 @@ class FxThread(ThreadJob):
            def exchange_rate(self):
                '''Returns None, or the exchange rate as a Decimal'''
                rate = self.exchange.quotes.get(self.ccy)
       -        if rate:
       -            return Decimal(rate)
       +        if rate is None:
       +            return Decimal('NaN')
       +        return Decimal(rate)
        
            def format_amount_and_units(self, btc_balance):
                rate = self.exchange_rate()
       -        return '' if rate is None else "%s %s" % (self.value_str(btc_balance, rate), self.ccy)
       +        return '' if rate.is_nan() else "%s %s" % (self.value_str(btc_balance, rate), self.ccy)
        
            def get_fiat_status_text(self, btc_balance, base_unit, decimal_point):
                rate = self.exchange_rate()
       -        return _("  (No FX rate available)") if rate is None else " 1 %s~%s %s" % (base_unit,
       +        return _("  (No FX rate available)") if rate.is_nan() else " 1 %s~%s %s" % (base_unit,
                    self.value_str(COIN / (10**(8 - decimal_point)), rate), self.ccy)
        
            def value_str(self, satoshis, rate):
       -        if satoshis is not None and rate is not None:
       -            value = Decimal(satoshis) / COIN * Decimal(rate)
       -        else:
       -            value = None
       +        value = Decimal('NaN') if satoshis is None else Decimal(satoshis) / COIN * Decimal(rate)
                return self.format_fiat(value)
        
            def format_fiat(self, value):
       -        if value is not None:
       -            return "%s" % (self.ccy_amount_str(value, True))
       -        return _("No data")
       +        if value.is_nan():
       +            return _("No data")
       +        return "%s" % (self.ccy_amount_str(value, True))
        
            def history_rate(self, d_t):
                if d_t is None:
       -            return None
       +            return Decimal('NaN')
                rate = self.exchange.historical_rate(self.ccy, d_t)
                # Frequently there is no rate for today, until tomorrow :)
                # Use spot quotes in that case
       -        if rate is None and (datetime.today().date() - d_t.date()).days <= 2:
       -            rate = self.exchange.quotes.get(self.ccy)
       +        if rate == 'NaN' and (datetime.today().date() - d_t.date()).days <= 2:
       +            rate = self.exchange.quotes.get(self.ccy, 'NaN')
                    self.history_used_spot = True
       -        return Decimal(rate) if rate is not None else None
       +        return Decimal(rate)
        
            def historical_value_str(self, satoshis, d_t):
                rate = self.history_rate(d_t)
       t@@ -538,8 +536,7 @@ class FxThread(ThreadJob):
        
            def historical_value(self, satoshis, d_t):
                rate = self.history_rate(d_t)
       -        if rate:
       -            return Decimal(satoshis) / COIN * Decimal(rate)
       +        return Decimal(satoshis) / COIN * Decimal(rate)
        
            def timestamp_rate(self, timestamp):
                from electrum.util import timestamp_to_datetime
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -958,6 +958,7 @@ class Abstract_Wallet(PrintError):
                # return last balance
                return balance
        
       +    @profiler
            def get_full_history(self, domain=None, from_timestamp=None, to_timestamp=None, fx=None, show_addresses=False):
                from .util import timestamp_to_datetime, Satoshis, Fiat
                out = []
       t@@ -1016,11 +1017,10 @@ class Abstract_Wallet(PrintError):
                        item['fiat_default'] = fiat_default
                        if value < 0:
                            ap, lp = self.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy)
       -                    cg = None if lp is None or ap is None else lp - ap
       +                    cg = lp - ap
                            item['acquisition_price'] = Fiat(ap, fx.ccy)
                            item['capital_gain'] = Fiat(cg, fx.ccy)
       -                    if cg is not None:
       -                        capital_gains += cg
       +                    capital_gains += cg
                        else:
                            if fiat_value is not None:
                                fiat_income += fiat_value
       t@@ -1686,11 +1686,9 @@ class Abstract_Wallet(PrintError):
                coins = self.get_utxos(domain)
                now = time.time()
                p = price_func(now)
       -        if p is None:
       -            return
                ap = sum(self.coin_price(coin, price_func, ccy, self.txin_value(coin)) for coin in coins)
                lp = sum([coin['value'] for coin in coins]) * p / Decimal(COIN)
       -        return None if ap is None or lp is None else lp - ap
       +        return lp - ap
        
            def capital_gain(self, txid, price_func, ccy):
                """
       t@@ -1704,13 +1702,11 @@ class Abstract_Wallet(PrintError):
                fiat_value = self.get_fiat_value(txid, ccy)
                if fiat_value is None:
                    p = self.price_at_timestamp(txid, price_func)
       -            liquidation_price = None if p is None else out_value/Decimal(COIN) * p
       +            liquidation_price = out_value/Decimal(COIN) * p
                else:
                    liquidation_price = - fiat_value
       -        try:
       -            acquisition_price = out_value/Decimal(COIN) * self.average_price(tx, price_func, ccy)
       -        except:
       -            acquisition_price = None
       +
       +        acquisition_price = out_value/Decimal(COIN) * self.average_price(tx, price_func, ccy)
                return acquisition_price, liquidation_price
        
            def average_price(self, tx, price_func, ccy):
       t@@ -1731,10 +1727,10 @@ class Abstract_Wallet(PrintError):
                        return fiat_value
                    else:
                        p = self.price_at_timestamp(txid, price_func)
       -                return None if p is None else p * txin_value/Decimal(COIN)
       +                return p * txin_value/Decimal(COIN)
                else:
                    # could be some coinjoin transaction..
       -            return None
       +            return Decimal('NaN')
        
        
        class Simple_Wallet(Abstract_Wallet):