Or, even easier...
Start at the beginning aggregating balances. As you encounter each new block, record the block height and current balances in a database. Then when you want to know any historical balance, your can just query your database for the block height in question. Meanwhile, your node can continue to remain synchronized and can continue to update your database as new blocks are received.
Wouldn't that require a huge database?
I think it wouldn't be practical to save all balances for all addresses that ever existed at each blockheight, but you could probably save balance of each address whose balance was changed by a transaction in a block at each height... That way you should be able to query the value of the sum of the unspent outputs funding address x at height y where the blockheight = the max blockheight for an entry for address x.
Something like this
CREATE TABLE balances (
id int NOT NULL AUTO_INCREMENT,
address varchar(45),
balance_at_height int(15),
height int(10)
PRIMARY KEY (id)
);
For example, if my address was funded for the very first time at height 40000, then was funded for a second time at 401000 and i spent both outputs at 402000, only 3 inserts would be needed for my total history...
insert into (address, balace_at_height, height) values ("1MocACiWLM8bYn8pCrYjy6uHq4U3CkxLaa", 100000, 400000);
insert into (address, balace_at_height, height) values ("1MocACiWLM8bYn8pCrYjy6uHq4U3CkxLaa", 200000, 401000);
insert into (address, balace_at_height, height) values ("1MocACiWLM8bYn8pCrYjy6uHq4U3CkxLaa", 0, 402000);
Each new block you'd have to parse 1500? transactions, so if you'd only have to save the balances of addresses whose balance changed at each blockheight, you'd have to insert at least ~1500 changes/block * ~144 blocks/day = 216000 changes each day... That seems doable