electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 42a16d9c3e19785ad39f272517aa2ce54b9e0f7f
parent c32435c15e99ff952a309548dfafacd68a434adb
Author: ThomasV <thomasv@electrum.org>
Date:   Sat,  6 Jan 2018 12:57:04 +0100

computation of capital gains for outgoing transactions

Diffstat:
Mgui/qt/history_list.py | 5+++++
Mlib/exchange_rate.py | 5+++++
Mlib/wallet.py | 42++++++++++++++++++++++++++++++++++++++++++
3 files changed, 52 insertions(+), 0 deletions(-)

diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py @@ -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): @@ -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 "")) diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py @@ -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) diff --git a/lib/wallet.py b/lib/wallet.py @@ -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 @@ -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