Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
)
samplefile = tmpdir.mkdir("fava_util_file3").join("example.beancount")
samplefile.write(file_content)
postings = [
data.Posting(
"Liabilities:US:Chase:Slate",
amount.Amount(D("-10.00"), "USD"),
None,
None,
None,
None,
),
data.Posting(
"Expenses:Food",
amount.Amount(D("10.00"), "USD"),
None,
None,
None,
None,
),
]
transaction = data.Transaction(
{},
datetime.date(2016, 1, 1),
"*",
"new payee",
"narr",
None,
None,
postings,
maxlen = max(len(real_child.account)
for real_child in iter_children(real_root, leaf_only=True))
line_format = '{{:{width}}} {{}}\n'.format(width=maxlen)
else:
line_format = '{} {}\n'
output = file or io.StringIO()
for first_line, cont_line, real_account in dump(real_root):
if not real_account.balance.is_empty():
if at_cost:
rinv = real_account.balance.reduce(convert.get_cost)
else:
rinv = real_account.balance.reduce(convert.get_units)
amounts = [position.units for position in rinv.get_positions()]
positions = [amount_.to_string(dformat)
for amount_ in sorted(amounts, key=amount.sortkey)]
else:
positions = ['']
if fullnames:
for position in positions:
if not position and len(real_account) > 0:
continue # Skip parent accounts with no position to render.
output.write(line_format.format(real_account.account, position))
else:
line = first_line
for position in positions:
output.write(line_format.format(line, position))
line = cont_line
if file is None:
return output.getvalue()
fileloc = data.new_metadata('<{}>'.format(type(psource.module).__name__), 0)
# The datetime instance is required to be aware. We always convert to the
# user's timezone before extracting the date. This means that if the market
# returns a timestamp for a particular date, once we convert to the user's
# timezone the returned date may be different by a day. The intent is that
# whatever we print is assumed coherent with the user's timezone. See
# discussion at
# https://groups.google.com/d/msg/beancount/9j1E_HLEMBQ/fYRuCQK_BwAJ
srctime = srcprice.time
if srctime.tzinfo is None:
raise ValueError("Time returned by the price source is not timezone aware.")
date = srctime.astimezone(tz.tzlocal()).date()
return data.Price(fileloc, date, base,
amount.Amount(price, quote or UNKNOWN_CURRENCY))
fees = ZERO
number = ZERO
code = ttype
if ttype == 'XFER':
desc = "CLIENT REQUESTED ELECTRONIC FUNDING"
number = D(random.uniform(3000, 15000)).quantize(PENNY)
elif ttype == 'BUY':
core = 'TRD'
stock = random.choice(STOCKS)
approx_number = D(random.uniform(2000, 10000))
price = D(random.uniform(5, 100)).quantize(PENNY)
shares = D(int(approx_number / price))
number = -shares * price
desc = "BOUGHT +{} {} @{}".format(stock, shares, price)
inv.add_amount(amount.Amount(shares, stock),
position.Cost(price, 'USD', date, None))
if shares * price > balance:
continue
fees = D('7.95')
number -= fees
elif ttype == 'SELL':
if inv.is_empty():
continue
core = 'TRD'
pos = random.choice(inv)
shares = (D(random.uniform(0.3, 0.7)) * pos.units.number).quantize(ZERO)
price = (pos.cost.number * D(random.normalvariate(1.0, 0.1))).quantize(PENNY)
number = price * shares
desc = "SOLD +{} {} @{} (LOT {})".format(pos.units.currency,
def get_money_instruments(commodities_map):
"""Get the money-market stand-ins for cash positions.
Args:
commodities_map: A map of currency to their corresponding Commodity directives.
Returns:
A dict of quote currency to the ticker symbol that stands for it,
e.g. {'USD': 'VMMXX'}.
"""
instruments = {}
for currency, entry in commodities_map.items():
export = entry.meta.get(FIELD, '')
paren_match = re.search(r'\((.*)\)', export)
if paren_match:
match = re.match('MONEY:({})'.format(amount.CURRENCY_RE), paren_match.group(1))
if match:
instruments[match.group(1)] = (
re.sub(r'\(.*\)', '', export).strip() or currency)
else:
logging.error("Invalid money specification: %s", export)
return instruments
if entry.account == account_:
# Mark this newly encountered pad as active and allow all lots
# to be padded heretofore.
active_pad = entry
padded_lots = set()
elif isinstance(entry, data.Balance):
check_amount = entry.amount
# Compare the current balance amount to the expected one from
# the check entry. IMPORTANT: You need to understand that this
# does not check a single position, but rather checks that the
# total amount for a particular currency (which itself is
# distinct from the cost).
balance_amount = pad_balance.get_currency_units(check_amount.currency)
diff_amount = amount.sub(balance_amount, check_amount)
# Use the specified tolerance or automatically infer it.
tolerance = balance.get_balance_tolerance(entry, options_map)
if abs(diff_amount.number) > tolerance:
# The check fails; we need to pad.
# Pad only if pad entry is active and we haven't already
# padded that lot since it was last encountered.
if active_pad and (check_amount.currency not in padded_lots):
# Note: we decide that it's an error to try to pad
# positions at cost; we check here that all the existing
# positions with that currency have no cost.
positions = [pos
for pos in pad_balance.get_positions()
# Note: this is a rather convenient but arbitrary choice--maybe it would be best to
# let the user decide to what account to book it, but I don't a nice way to let the
# user specify this.
#
# Note: we never set a price because we don't want these to end up in Conversions.
entry.postings.extend([
data.Posting(
asset_account,
amount.Amount(pnl, holding.cost_currency),
None,
None,
None,
None),
data.Posting(
income_account,
amount.Amount(-pnl, holding.cost_currency),
None,
None,
None,
None)
])
new_entries.append(entry)
# Ensure that the accounts we're going to use to book the postings exist, by
# creating open entries for those that we generated that weren't already
# existing accounts.
new_accounts = {posting.account
for entry in new_entries
for posting in entry.postings}
open_entries = getters.get_account_open_close(entries)
new_open_entries = []
data.Posting(self.account_fees, fees, None, None, None, None),
data.Posting(account_inst, units_inst, cost, None, None, None),
])
elif rtype == 'SELL':
# Extract the lot. In practice this information not be there
# and you will have to identify the lots manually by editing
# the resulting output. You can leave the cost.number slot
# set to None if you like.
match = re.search(r'\(LOT ([0-9.]+)\)', row['DESCRIPTION'])
if not match:
logging.error("Missing cost basis in '%s'", row['DESCRIPTION'])
continue
cost_number = D(match.group(1))
cost = position.Cost(cost_number, self.currency, None, None)
price = amount.Amount(rate, self.currency)
account_gains = self.account_gains.format(instrument)
txn = data.Transaction(
meta, date, self.FLAG, None, desc, None, {link}, [
data.Posting(self.account_cash, units, None, None, None, None),
data.Posting(self.account_fees, fees, None, None, None, None),
data.Posting(account_inst, units_inst, cost, price, None, None),
data.Posting(account_gains, None, None, None, None, None),
])
else:
logging.error("Unknown row type: %s; skipping", rtype)
continue
entries.append(txn)
# Insert a final balance check.
def add_amount(a: Optional[Amount], b: Optional[Amount]) -> Optional[Amount]:
if a is None:
return b
if b is None:
return a
return beancount.core.amount.add(a, b)
is_asset_account,
entry)
# Compute the market value before the external flow.
inventory_before = get_inventory_market_value(balance_before, date, price_map)
value_before = inventory_value(inventory_before)
# Compute the market value after the external flow.
inventory_after = get_inventory_market_value(balance_after, date, price_map)
value_after = inventory_value(inventory_after)
print(',--------------------------------')
print(' {} -> {}'.format(date_previous, date))
print(' previous : {} : {}'.format(value_previous, balance_previous))
print(' before : {} : {}'.format(value_before, balance_before))
print(' after : {} : {}'.format(value_after, balance_after))
if value_previous == amount.ZERO:
if value_before == amount.ZERO:
period_return = 1.0
else:
raise ValueError("Portfolio with zero value grew to non-zero value.")
else:
period_return = float(value_before)/float(value_previous)
print(' return : {:.5f}'.format(period_return))
print('`--------------------------------')
if entry:
printer.print_entry(entry)
periods.append(period_return)
date_previous = date