commit 0f16bcdc1ff5cda748f3079d7efd983b426277fb
parent b2c035024006f72efc711b37b39010067a5487cf
Author: ThomasV <thomasv@electrum.org>
Date: Wed, 14 Feb 2018 10:42:09 +0100
Capital gains:
* Show acquisition price in history.
* Add summary to history command
Diffstat:
3 files changed, 66 insertions(+), 19 deletions(-)
diff --git a/gui/qt/history_list.py b/gui/qt/history_list.py
@@ -61,7 +61,8 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
headers = ['', '', _('Date'), _('Description') , _('Amount'), _('Balance')]
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 + _('Value')])
+ headers.extend(['%s '%fx.ccy + _('Acquisition price')])
headers.extend(['%s '%fx.ccy + _('Capital Gains')])
self.editable_columns.extend([6])
self.update_headers(headers)
@@ -89,20 +90,22 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
label = self.wallet.get_label(tx_hash)
entry = ['', tx_hash, status_str, label, v_str, balance_str]
fiat_value = None
- if fx and fx.show_history():
+ if value is not None and fx and fx.show_history():
date = timestamp_to_datetime(time.time() if conf <= 0 else timestamp)
fiat_value = self.wallet.get_fiat_value(tx_hash, fx.ccy)
if not fiat_value:
- value_str = fx.historical_value_str(value, date)
+ fiat_value = fx.historical_value(value, date)
+ fiat_default = True
else:
- value_str = str(fiat_value)
+ fiat_default = False
+ value_str = fx.format_fiat(fiat_value)
entry.append(value_str)
- balance_str = fx.historical_value_str(balance, date)
- entry.append(balance_str)
# fixme: should use is_mine
- if value is not None and value < 0:
- cg = self.wallet.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy)
- entry.append("%.2f"%cg if cg is not None else _('No data'))
+ if value < 0:
+ ap, lp = self.wallet.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy)
+ cg = None if lp is None or ap is None else lp - ap
+ entry.append(fx.format_fiat(ap))
+ entry.append(fx.format_fiat(cg))
item = QTreeWidgetItem(entry)
item.setIcon(0, icon)
item.setToolTip(0, str(conf) + " confirmation" + ("s" if conf != 1 else ""))
@@ -116,7 +119,7 @@ class HistoryList(MyTreeWidget, AcceptFileDragDrop):
if value and value < 0:
item.setForeground(3, QBrush(QColor("#BC1E1E")))
item.setForeground(4, QBrush(QColor("#BC1E1E")))
- if fiat_value:
+ if not fiat_default:
item.setForeground(6, QBrush(QColor("#1E1EFF")))
if tx_hash:
item.setData(0, Qt.UserRole, tx_hash)
diff --git a/lib/exchange_rate.py b/lib/exchange_rate.py
@@ -506,10 +506,14 @@ class FxThread(ThreadJob):
self.value_str(COIN / (10**(8 - decimal_point)), rate), self.ccy)
def value_str(self, satoshis, rate):
- if satoshis is None: # Can happen with incomplete history
- return _("Unknown")
- if rate:
+ if satoshis is not None and rate is not None:
value = Decimal(satoshis) / COIN * Decimal(rate)
+ else:
+ value = None
+ 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")
diff --git a/lib/wallet.py b/lib/wallet.py
@@ -943,10 +943,21 @@ class Abstract_Wallet(PrintError):
return h2
+ def balance_at_timestamp(self, domain, target_timestamp):
+ h = self.get_history(domain)
+ for tx_hash, height, conf, timestamp, value, balance in h:
+ if timestamp > target_timestamp:
+ return balance - value
+ # return last balance
+ return balance
+
def export_history(self, domain=None, from_timestamp=None, to_timestamp=None, fx=None, show_addresses=False):
from .util import format_time, format_satoshis, timestamp_to_datetime
h = self.get_history(domain)
out = []
+ init_balance = None
+ capital_gains = 0
+ fiat_income = 0
for tx_hash, height, conf, timestamp, value, balance in h:
if from_timestamp and timestamp < from_timestamp:
continue
@@ -960,6 +971,9 @@ class Abstract_Wallet(PrintError):
'value': format_satoshis(value, True) if value is not None else '--',
'balance': format_satoshis(balance)
}
+ if init_balance is None:
+ init_balance = balance - value
+ end_balance = balance
if item['height']>0:
date_str = format_time(timestamp) if timestamp is not None else _("unverified")
else:
@@ -988,11 +1002,36 @@ class Abstract_Wallet(PrintError):
item['output_addresses'] = output_addresses
if fx is not None:
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)
+ fiat_value = self.get_fiat_value(tx_hash, fx.ccy)
+ if fiat_value is None:
+ fiat_value = fx.historical_value(value, date)
+ item['fiat_value'] = fx.format_fiat(fiat_value)
if value < 0:
- item['capital_gain'] = self.capital_gain(tx_hash, fx.timestamp_rate, fx.ccy)
+ 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
+ item['acquisition_price'] = fx.format_fiat(ap)
+ item['capital_gain'] = fx.format_fiat(cg)
+ capital_gains += cg
+ else:
+ fiat_income += fiat_value
out.append(item)
+
+ if from_timestamp and to_timestamp:
+ summary = {
+ 'start_date': format_time(from_timestamp),
+ 'end_date': format_time(to_timestamp),
+ 'initial_balance': format_satoshis(init_balance),
+ 'final_balance': format_satoshis(end_balance),
+ 'capital_gains': fx.format_fiat(capital_gains),
+ 'fiat_income': fx.format_fiat(fiat_income)
+ }
+ if fx:
+ start_date = timestamp_to_datetime(from_timestamp)
+ end_date = timestamp_to_datetime(to_timestamp)
+ summary['initial_fiat_value'] = fx.format_fiat(fx.historical_value(init_balance, start_date))
+ summary['final_fiat_value'] = fx.format_fiat(fx.historical_value(end_balance, end_date))
+ out.append(summary)
+
return out
def get_label(self, tx_hash):
@@ -1644,11 +1683,12 @@ class Abstract_Wallet(PrintError):
liquidation_price = None if p is None else out_value/Decimal(COIN) * p
else:
liquidation_price = - fiat_value
-
try:
- return liquidation_price - out_value/Decimal(COIN) * self.average_price(tx, price_func, ccy)
+ acquisition_price = out_value/Decimal(COIN) * self.average_price(tx, price_func, ccy)
except:
- return None
+ acquisition_price = None
+ return acquisition_price, liquidation_price
+
def average_price(self, tx, price_func, ccy):
""" average price of the inputs of a transaction """