def test_aggregate_holdings_list(self): test_holdings = list(itertools.starmap(holdings.Holding, [ ('Assets:Account1', D('10'), 'HOOL', D('518.73'), 'USD', D('5187.30'), D('5780.20'), D('578.02'), datetime.date(2014, 2, 1)), ('Assets:Account2', D('20'), 'HOOL', D('519.24'), 'USD', D('10384.80'), D('11622.00'), D('581.10'), datetime.date(2014, 2, 15)), ])) expected_holding = holdings.Holding( 'Assets', D('30'), 'HOOL', D('519.07'), 'USD', D('15572.10'), D('17402.20'), D('580.0733333333333333333333333'), None) self.assertEqual(expected_holding, holdings.aggregate_holdings_list(test_holdings)) # Test with zero units. test_holdings = list(itertools.starmap(holdings.Holding, [ ('Assets:Acc1', D('10'), 'HOOL', D('300'), 'USD', D('3000'), None, None, None), ('Assets:Acc1', D('-10'), 'HOOL', D('400'), 'USD', D('-4000'), None, None, None), ])) expected_holding = holdings.Holding( 'Assets:Acc1', D('0'), 'HOOL', None, 'USD', D('-1000'), None, None, None) self.assertEqual(expected_holding, holdings.aggregate_holdings_list(test_holdings)) # Test with aggregate holdings with no cost nor price price. test_holdings = list(itertools.starmap(holdings.Holding, [ ('Assets:Account1', D('10'), 'HOOL', None, 'USD', D('5187.30'), D('5780.20'), None, None), ('Assets:Account2', D('20'), 'HOOL', None, 'USD', D('10384.80'), D('11622.00'), None, None), ])) expected_holding = holdings.Holding( 'Assets', D('30'), 'HOOL', D('519.07'), 'USD', D('15572.10'), D('17402.20'), D('580.0733333333333333333333333'), None) self.assertEqual(expected_holding, holdings.aggregate_holdings_list(test_holdings))
def test_scale_holding(self): test_holding = holdings.Holding( 'Assets:US:Checking', D('100'), 'MSFT', D('54.34'), 'USD', D('5434.00'), D('6000.00'), D('60'), datetime.date(2012, 5, 2)) expected_holding = holdings.Holding( 'Assets:US:Checking', D('70.0'), 'MSFT', D('54.34'), 'USD', D('3803.80'), D('4200.00'), D('60'), datetime.date(2012, 5, 2)) self.assertEqual(expected_holding, holdings.scale_holding(test_holding, D('0.7')))
def test_holding_to_position(self): test_holding = holdings.Holding( 'Assets:US:Checking', D('100'), 'MSFT', D('54.34'), 'USD', D('5434.00'), D('6000.00'), D('60'), datetime.date(2012, 5, 2)) actual_position = holdings.holding_to_position(test_holding) expected_position = position.from_string('100 MSFT {54.34 USD}') self.assertEqual(expected_position, actual_position) test_holding = holdings.Holding( 'Assets:US:Checking', D('100'), 'USD', None, None, None, None, None, datetime.date(2012, 5, 2)) actual_position = holdings.holding_to_position(test_holding) expected_position = position.from_string('100.00 USD') self.assertEqual(expected_position, actual_position)
def test_holding_to_posting(self): test_holding = holdings.Holding( 'Assets:US:Checking', D('100'), 'MSFT', D('54.34'), 'USD', D('5434.00'), D('6000.00'), D('60'), datetime.date(2012, 5, 2)) posting = holdings.holding_to_posting(test_holding) self.assertTrue(isinstance(posting, data.Posting)) expected_position = position.from_string('100 MSFT {54.34 USD}') self.assertEqual(expected_position, position.Position(posting.units, posting.cost)) expected_price = A('60.00 USD') self.assertEqual(expected_price, posting.price)
def load_from_csv(fileobj): """Load a list of holdings from a CSV file. Args: fileobj: A file object. Yields: Instances of Holding, as read from the file. """ column_spec = [ ('Account', 'account', None), ('Units', 'number', D), ('Currency', 'currency', None), ('Cost Currency', 'cost_currency', None), ('Average Cost', 'cost_number', D), ('Price', 'price_number', D), ('Book Value', 'book_value', D), ('Market Value', 'market_value', D), ('Price Date', 'price_date', None), ] column_dict = { name: (attr, converter) for name, attr, converter in column_spec } klass = holdings.Holding # Create a set of default values for the namedtuple. defaults_dict = {attr: None for attr in klass._fields} # Start reading the file. reader = csv.reader(fileobj) # Check that the header is readable. header = next(reader) attr_converters = [] for header_name in header: try: attr_converter = column_dict[header_name] attr_converters.append(attr_converter) except KeyError: raise IOError("Invalid file contents for holdings") for line in reader: value_dict = defaults_dict.copy() for (attr, converter), value in zip(attr_converters, line): if converter: value = converter(value) value_dict[attr] = value yield holdings.Holding(**value_dict)
def test_convert_to_currency(self, entries, _, __): """ 2013-01-01 price CAD 1.1 USD ; We don't include a price point for NOK. It's unknown. ; 2013-01-01 open Assets:Account2 """ test_holdings = list(itertools.starmap(holdings.Holding, [ # ------------ cost currency == target currency # currency != target currency (None, D('100.00'), 'IVV', D('200'), 'USD', D('10'), D('11'), D('12'), None), # currency == target currency (None, D('100.00'), 'USD', D('200'), 'USD', D('10'), D('11'), D('12'), None), # currency == None (None, D('100.00'), None, D('200'), 'USD', D('10'), D('11'), D('12'), None), # ------------ cost currency == other currency # cost currency available in price map (None, D('100.00'), 'XSP', D('200'), 'CAD', D('10'), D('11'), D('12'), None), # cost currency not available in price map (None, D('100.00'), 'AGF', D('200'), 'NOK', D('10'), D('11'), D('12'), None), # currency == target currency, available in price map (None, D('100.00'), 'USD', D('200'), 'CAD', D('10'), D('11'), D('12'), None), # currency == target currency, not available in price map (None, D('100.00'), 'USD', D('200'), 'NOK', D('10'), D('11'), D('12'), None), # cost currency available in price map, and currency == None (None, D('100.00'), None, D('200'), 'CAD', D('10'), D('11'), D('12'), None), # ------------ cost currency == None # currency available in price map (None, D('100.00'), 'CAD', D('1.2'), None, D('10'), D('11'), D('12'), None), # currency available in price map, with no values (should be filled in) (None, D('100.00'), 'CAD', D('1.2'), None, None, None, None, None), # currency not available in price map (None, D('100.00'), 'EUR', D('1.2'), None, D('10'), D('11'), D('12'), None), # currency = target currency (None, D('100.00'), 'USD', D('1.2'), None, D('10'), D('11'), D('12'), None), ])) price_map = prices.build_price_map(entries) converted_holdings = holdings.convert_to_currency(price_map, 'USD', test_holdings) expected_holdings = list(itertools.starmap(holdings.Holding, [ (None, D('100.00'), 'IVV', D('200'), 'USD', D('10'), D('11'), D('12'), None), (None, D('100.00'), 'USD', D('200'), 'USD', D('10'), D('11'), D('12'), None), (None, D('100.00'), None, D('200'), 'USD', D('10'), D('11'), D('12'), None), (None, D('100.00'), 'XSP', D('220.0'), 'USD', D('11.0'), D('12.1'), D('13.2'), None), (None, D('100.00'), 'AGF', None, None, None, None, None, None), (None, D('100.00'), 'USD', D('220.0'), 'USD', D('11.0'), D('12.1'), D('13.2'), None), (None, D('100.00'), 'USD', None, None, None, None, None, None), (None, D('100.00'), None, D('220.0'), 'USD', D('11.0'), D('12.1'), D('13.2'), None), (None, D('100.00'), 'CAD', D('1.32'), 'USD', D('11.0'), D('12.1'), D('13.2'), None), (None, D('100.00'), 'CAD', D('1.32'), 'USD', D('110.0'), D('110.0'), None, None), (None, D('100.00'), 'EUR', None, None, None, None, None, None), (None, D('100.00'), 'USD', D('1.2'), 'USD', D('10'), D('11'), D('12'), None), ])) self.assertEqual(expected_holdings, converted_holdings) # Fail elegantly if the currency itself is None. none_holding = holdings.Holding(None, D('100.00'), None, D('200'), None, None, None, None, None) with self.assertRaises(ValueError): converted_holdings = holdings.convert_to_currency(price_map, 'USD', [none_holding])