def SumPostings(postings: Iterable[Posting]) -> Inventory: """Aggregate all the positions for the given postings.""" acc = Inventory() for elem in postings: # Note: 'elem' can be a Posting or an Inventory (the intermediate result # from a subcombiner). if isinstance(elem, Inventory): acc.add_inventory(elem) else: assert isinstance(elem, Posting) acc.add_position(elem) return acc
def recently_sold_at_loss(accapi, options): """Looking back 30 days for sales that caused losses. These were likely to have been TLH (but not necessarily so. This tells us what NOT to buy in order to avoid wash sales.""" operating_currencies = accapi.get_operating_currencies_regex() wash_pattern = options.get('wash_pattern', '') account_field = options.get('account_field', 'LEAF(account)') wash_pattern_sql = 'AND account ~ "{}"'.format( wash_pattern) if wash_pattern else '' sql = ''' SELECT date as sale_date, DATE_ADD(date, 30) as until, currency, NEG(SUM(COST(position))) as basis, NEG(SUM(CONVERT(position, cost_currency, date))) as proceeds WHERE date >= DATE_ADD(TODAY(), -30) AND number < 0 AND not currency ~ "{operating_currencies}" GROUP BY sale_date,until,currency '''.format(**locals()) rtypes, rrows = accapi.query_func(sql) if not rtypes: return [], [] # filter out losses retrow_types = rtypes + [('loss', Inventory)] RetRow = collections.namedtuple('RetRow', [i[0] for i in retrow_types]) return_rows = [] for row in rrows: loss = Inventory(row.proceeds) loss.add_inventory(-(row.basis)) if loss != Inventory() and val(loss) < 0: return_rows.append(RetRow(*row, loss)) footer = build_table_footer(retrow_types, return_rows, accapi) return retrow_types, return_rows, None, footer
def sum_inventories(invs): """Sum the given list of inventory into a single inventory""" retval = Inventory() for i in invs: retval.add_inventory(i) return retval
def _row_children(self, rows, a): sum = Inventory() for sub in rows: if sub.startswith(a.account): sum.add_inventory(rows.get(sub, Inventory())) return -self._only_position(sum.reduce(convert.get_weight))