Separately account unrealised gains and unrealised losses
This commit is contained in:
parent
7fe942df5f
commit
0d9f9a096e
@ -15,7 +15,7 @@ oci_account: OCI # Other Comprehensive Income
|
||||
separate_pandl: []
|
||||
|
||||
# These accounts will automatically be populated on reports
|
||||
unrealized_gains: 'OCI:Unrealized Gains'
|
||||
unrealized_gains: ['OCI:Unrealized Gains', 'OCI: Unrealized Losses']
|
||||
|
||||
accumulated_oci: 'Equity:Accumulated Other Comprehensive Income'
|
||||
current_year_oci: 'Equity:Current Year Other Comprehensive Income'
|
||||
|
@ -47,39 +47,54 @@ def trial_balance(ledger, date, pstart, commodity, label=None):
|
||||
|
||||
for account in set(list(r_date.keys()) + list(r_pstart.keys())):
|
||||
if account in r_pstart:
|
||||
tb_date.balances[account.name] = tb_date.get_balance(account) + r_pstart[account].postings[0].amount
|
||||
if r_pstart[account].postings[1].account.is_income or r_pstart[account].postings[1].account.is_expense:
|
||||
tb_date.balances[config['retained_earnings']] = tb_date.get_balance(ledger.get_account(config['retained_earnings'])) - r_pstart[account].postings[0].amount
|
||||
elif r_pstart[account].postings[1].account.is_oci:
|
||||
tb_date.balances[config['accumulated_oci']] = tb_date.get_balance(ledger.get_account(config['accumulated_oci'])) - r_pstart[account].postings[0].amount
|
||||
for trn in r_pstart[account]:
|
||||
# Update/accumulate trial balances
|
||||
tb_date.balances[account.name] = tb_date.get_balance(account) + trn.postings[0].amount
|
||||
|
||||
if trn.postings[1].account.is_income or trn.postings[1].account.is_expense:
|
||||
tb_date.balances[config['retained_earnings']] = tb_date.get_balance(ledger.get_account(config['retained_earnings'])) - trn.postings[0].amount
|
||||
elif trn.postings[1].account.is_oci:
|
||||
tb_date.balances[config['accumulated_oci']] = tb_date.get_balance(ledger.get_account(config['accumulated_oci'])) - trn.postings[0].amount
|
||||
else:
|
||||
tb_date.balances[config['unrealized_gains']] = tb_date.get_balance(ledger.get_account(config['accumulated_oci'])) - r_pstart[account].postings[0].amount
|
||||
tb_date.balances[trn.postings[1].account.name] = tb_date.get_balance(trn.postings[1].account) - trn.postings[0].amount
|
||||
|
||||
# Reversing entry
|
||||
trn_reversal = r_pstart[account].reverse(None, pstart, '<Reversal of Unrealized Gains>')
|
||||
trn_reversal = trn.reverse(None, pstart, '<Reversal of {}>'.format(trn.description[1:-1]))
|
||||
ledger.transactions.insert(0, trn_reversal)
|
||||
|
||||
tb_date.balances[account.name] = tb_date.get_balance(account) + trn_reversal.postings[0].amount
|
||||
tb_date.balances[config['unrealized_gains']] = tb_date.get_balance(ledger.get_account(config['unrealized_gains'])) - trn_reversal.postings[0].amount
|
||||
tb_date.balances[trn_reversal.postings[1].account.name] = tb_date.get_balance(trn_reversal.postings[1].account) - trn_reversal.postings[0].amount
|
||||
|
||||
if account in r_date:
|
||||
tb_date.balances[account.name] = tb_date.get_balance(account) + r_date[account].postings[0].amount
|
||||
tb_date.balances[config['unrealized_gains']] = tb_date.get_balance(ledger.get_account(config['unrealized_gains'])) - r_date[account].postings[0].amount
|
||||
for trn in r_date[account]:
|
||||
# Update trial balances
|
||||
tb_date.balances[account.name] = tb_date.get_balance(account) + trn.postings[0].amount
|
||||
tb_date.balances[trn.postings[1].account.name] = tb_date.get_balance(trn.postings[1].account) - trn.postings[0].amount
|
||||
|
||||
return tb_date
|
||||
|
||||
# Adjust (in place) a trial balance for unrealized gains without accumulating OCI
|
||||
def _add_unrealized_gains(tb, commodity):
|
||||
results = {}
|
||||
unrealized_gain_account = tb.ledger.get_account(config['unrealized_gains'])
|
||||
unrealized_gain_account = tb.ledger.get_account(config['unrealized_gains'][0])
|
||||
unrealized_loss_account = tb.ledger.get_account(config['unrealized_gains'][1])
|
||||
|
||||
for account in list(tb.ledger.accounts.values()):
|
||||
if not account.is_market:
|
||||
continue
|
||||
|
||||
total_cost = tb.get_balance(account).exchange(commodity, True)
|
||||
total_market = tb.get_balance(account).exchange(commodity, False, tb.date, tb.ledger)
|
||||
unrealized_gain = total_market - total_cost
|
||||
unrealized_gain = Amount(0, commodity)
|
||||
unrealized_loss = Amount(0, commodity)
|
||||
|
||||
for amount in tb.get_balance(account).amounts:
|
||||
amt_cost = amount.exchange(commodity, True)
|
||||
amt_market = amount.exchange(commodity, False, date=tb.date, ledger=tb.ledger)
|
||||
amt_gain = amt_market - amt_cost
|
||||
|
||||
if amt_gain > 0:
|
||||
unrealized_gain += amt_gain
|
||||
if amt_gain < 0:
|
||||
unrealized_loss += amt_gain
|
||||
|
||||
if unrealized_gain != 0:
|
||||
transaction = Transaction(tb.ledger, None, tb.date, '<Unrealized Gains>')
|
||||
@ -87,7 +102,15 @@ def _add_unrealized_gains(tb, commodity):
|
||||
transaction.postings.append(Posting(transaction, unrealized_gain_account, -unrealized_gain))
|
||||
tb.ledger.transactions.append(transaction)
|
||||
|
||||
results[account] = transaction
|
||||
results[account] = results.get(account, []) + [transaction]
|
||||
|
||||
if unrealized_loss != 0:
|
||||
transaction = Transaction(tb.ledger, None, tb.date, '<Unrealized Losses>')
|
||||
transaction.postings.append(Posting(transaction, account, unrealized_loss))
|
||||
transaction.postings.append(Posting(transaction, unrealized_loss_account, -unrealized_loss))
|
||||
tb.ledger.transactions.append(transaction)
|
||||
|
||||
results[account] = results.get(account, []) + [transaction]
|
||||
|
||||
return tb, results
|
||||
|
||||
|
@ -267,7 +267,7 @@ class Amount:
|
||||
def __rsub__(self, other):
|
||||
return Amount(other - self.amount, self.commodity)
|
||||
|
||||
def exchange(self, commodity, is_cost, price=None):
|
||||
def exchange(self, commodity, is_cost, price=None, date=None, ledger=None):
|
||||
if self.commodity.name == commodity.name:
|
||||
return Amount(self)
|
||||
|
||||
@ -277,6 +277,16 @@ class Amount:
|
||||
if price:
|
||||
return Amount(self.amount * price.amount, commodity)
|
||||
|
||||
if date and ledger:
|
||||
if any(p[1] == self.commodity.name for p in ledger.prices):
|
||||
# This commodity has price information
|
||||
# Measured at fair value
|
||||
return self.exchange(commodity, is_cost, ledger.get_price(self.commodity, commodity, date))
|
||||
else:
|
||||
# This commodity has no price information
|
||||
# Measured at historical cost
|
||||
return self.exchange(commodity, True)
|
||||
|
||||
raise TypeError('Cannot exchange {} to {}'.format(self.commodity, commodity))
|
||||
|
||||
@property
|
||||
@ -308,14 +318,7 @@ class Balance:
|
||||
if is_cost or amount.commodity.name == commodity.name:
|
||||
result += amount.exchange(commodity, is_cost)
|
||||
else:
|
||||
if any(p[1] == amount.commodity.name for p in ledger.prices):
|
||||
# This commodity has price information
|
||||
# Measured at fair value
|
||||
result += amount.exchange(commodity, is_cost, ledger.get_price(amount.commodity, commodity, date))
|
||||
else:
|
||||
# This commodity has no price information
|
||||
# Measured at historical cost
|
||||
result += amount.exchange(commodity, True)
|
||||
result += amount.exchange(commodity, is_cost, date=date, ledger=ledger)
|
||||
return result
|
||||
|
||||
def __neg__(self):
|
||||
|
Reference in New Issue
Block a user