URI: 
       tcomputation of capital gains for outgoing transactions - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 42a16d9c3e19785ad39f272517aa2ce54b9e0f7f
   DIR parent c32435c15e99ff952a309548dfafacd68a434adb
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Sat,  6 Jan 2018 12:57:04 +0100
       
       computation of capital gains for outgoing transactions
       
       Diffstat:
         M gui/qt/history_list.py              |       5 +++++
         M lib/exchange_rate.py                |       5 +++++
         M lib/wallet.py                       |      42 +++++++++++++++++++++++++++++++
       
       3 files changed, 52 insertions(+), 0 deletions(-)
       ---
   DIR diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py
       t@@ -62,6 +62,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
                fx = self.parent.fx
                if fx and fx.show_history():
                    headers.extend(['%s '%fx.ccy + _('Amount'), '%s '%fx.ccy + _('Balance')])
       +            headers.extend(['%s '%fx.ccy + _('Capital Gains')])
                self.update_headers(headers)
        
            def get_domain(self):
       t@@ -91,6 +92,10 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
                        for amount in [value, balance]:
                            text = fx.historical_value_str(amount, date)
                            entry.append(text)
       +                # fixme: should use is_mine
       +                if value < 0:
       +                    cg = self.wallet.capital_gain(tx_hash, self.parent.fx.timestamp_rate)
       +                    entry.append("%.2f"%cg if cg is not None else _('No data'))
                    item = QTreeWidgetItem(entry)
                    item.setIcon(0, icon)
                    item.setToolTip(0, str(conf) + " confirmation" + ("s" if conf != 1 else ""))
   DIR diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py
       t@@ -493,3 +493,8 @@ class FxThread(ThreadJob):
            def historical_value_str(self, satoshis, d_t):
                rate = self.history_rate(d_t)
                return self.value_str(satoshis, rate)
       +
       +    def timestamp_rate(self, timestamp):
       +        from electrum.util import timestamp_to_datetime
       +        date = timestamp_to_datetime(timestamp)
       +        return self.history_rate(date)
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -962,6 +962,8 @@ class Abstract_Wallet(PrintError):
                        date = timestamp_to_datetime(time.time() if conf <= 0 else timestamp)
                        item['fiat_value'] = fx.historical_value_str(value, date)
                        item['fiat_balance'] = fx.historical_value_str(balance, date)
       +                if value < 0:
       +                    item['capital_gain'] = self.capital_gain(tx_hash, fx.timestamp_rate)
                    out.append(item)
                return out
        
       t@@ -1586,6 +1588,46 @@ class Abstract_Wallet(PrintError):
                            children |= self.get_depending_transactions(other_hash)
                return children
        
       +    def txin_value(self, txin):
       +        txid = txin['prevout_hash']
       +        prev_n = txin['prevout_n']
       +        for address, d in self.txo[txid].items():
       +            for n, v, cb in d:
       +                if n == prev_n:
       +                    return v
       +        raise BaseException('unknown txin value')
       +
       +    def capital_gain(self, txid, price_func):
       +        """
       +        Difference between the fiat price of coins leaving the wallet because of transaction txid,
       +        and the price of these coins when they entered the wallet.
       +        price_func: function that returns the fiat price given a timestamp
       +        """
       +        height, conf, timestamp = self.get_tx_height(txid)
       +        tx = self.transactions[txid]
       +        out_value = sum([ (value if not self.is_mine(address) else 0) for otype, address, value in tx.outputs() ])
       +        try:
       +            return out_value/1e8 * (price_func(timestamp) - self.average_price(tx, price_func))
       +        except:
       +            return None
       +
       +    def average_price(self, tx, price_func):
       +        """ average price of the inputs of a transaction """
       +        return sum(self.coin_price(txin, price_func) * self.txin_value(txin) for txin in tx.inputs()) / sum(self.txin_value(txin) for txin in tx.inputs())
       +
       +    def coin_price(self, coin, price_func):
       +        """ fiat price of acquisition of coin """
       +        txid = coin['prevout_hash']
       +        tx = self.transactions[txid]
       +        if all([self.is_mine(txin['address']) for txin in tx.inputs()]):
       +            return self.average_price(tx, price_func)
       +        elif all([ not self.is_mine(txin['address']) for txin in tx.inputs()]):
       +            height, conf, timestamp = self.get_tx_height(txid)
       +            return price_func(timestamp)
       +        else:
       +            # could be some coinjoin transaction..
       +            return None
       +
        
        class Simple_Wallet(Abstract_Wallet):
            # wallet with a single keystore