How do I get a priced portfolio for one address?
Run it
pip install auradefi python examples/01_holdings_for_an_address.py
No keys, no setup: this runs in the Sandbox environment, which replays a recording bundled in the package. Every layer above the transport is the production one, so what you see here is what live code does.
The three things worth noticing are the whole design:
- the total is exact. It is computed in
Decimal, never a float: the comparison at the end shows the float answer already wrong at the 17th digit, and that error compounds across a portfolio; - an asset nobody will price is held, listed and named in
report.unpriced, never valued at zero; - going live is one line:
Auradefi.from_env()instead ofAuradefi.sandbox(), withAURADEFI_ETHERSCAN_API_KEYin your environment. The last section does exactly that if you have a key set.
What it prints
holdings for 0x1111111111111111111111111111111111111111 on eip155:1
asset quantity price value
ETH 2 2500 USD 5000.000000000000000000 USD
USDC 25 1 USD 25.000000 USD
TOTAL 5025.000000000000000000 USD
4878.123456789012345678 ETH @ 3584.17
exact 17484023.75011947437900871726
float 17484023.750119474 <- 17 significant digits, then guesses
drift 3.7900871726E-10 USD on ONE holding
unpriced: (none in the sandbox recording)
quantity on the wire: {'raw': '2000000000000000000', 'decimals': 18, 'numeric': '2', 'float': 2.0}
total on the wire: {'amount': '5025.000000000000000000', 'currency': 'USD'}
live: set AURADEFI_ETHERSCAN_API_KEY and this file will also
run Auradefi.from_env() against mainnet. Same code below it.
OK: priced exactly, offline, with one line between here and mainnet.
The whole file
"""How do I get a priced portfolio for one address? pip install auradefi python examples/01_holdings_for_an_address.py No keys, no setup: this runs in the Sandbox environment, which replays a recording bundled in the package. Every layer above the transport is the production one, so what you see here is what live code does. The three things worth noticing are the whole design: * the total is exact. It is computed in `Decimal`, never a float: the comparison at the end shows the float answer already wrong at the 17th digit, and that error compounds across a portfolio; * an asset nobody will price is **held, listed and named** in `report.unpriced`, never valued at zero; * going live is one line: `Auradefi.from_env()` instead of `Auradefi.sandbox()`, with `AURADEFI_ETHERSCAN_API_KEY` in your environment. The last section does exactly that if you have a key set. """ from __future__ import annotations import os from decimal import Decimal from auradefi import Auradefi from auradefi.money.decimal_json import money_to_wire, quantity_to_wire from auradefi.money.fiat import Money from auradefi.money.quantity import Quantity # ------------------------------------------------------------- the whole ask aura = Auradefi.sandbox() (report,) = aura.holdings() print(f"holdings for {report.address} on {report.chain_id}\n") print(f" {'asset':<6}{'quantity':>12}{'price':>14} value") for holding in report.holdings: print(f" {holding.symbol:<6}{str(holding.quantity):>12}" f"{str(holding.price):>14} {holding.value}") print(f" {'TOTAL':<6}{'':>12}{'':>14} {report.total_value}") assert report.total_value == Money(Decimal("5025"), "USD") # ------------------------------------------------------------------ exactness # These sandbox numbers are round, so a float would survive them. 5025.0 is # 5025. That is exactly why the guarantee has to be structural rather than # lucky: below is a real wallet-sized balance, and the float answer is wrong # at the 17th digit before anything is even summed. whale = Quantity(4_878_123_456_789_012_345_678, 18) exact = whale.as_decimal() * Decimal("3584.17") lossy = Decimal(str(float(whale.as_decimal()) * 3584.17)) assert exact != lossy print(f"\n 4878.123456789012345678 ETH @ 3584.17") print(f" exact {exact}") print(f" float {lossy} <- 17 significant digits, then guesses") print(f" drift {abs(exact - lossy)} USD on ONE holding") # ----------------------------------------------------------- unpriced assets # Nothing in this recording is unpriced, so here is what it looks like when # something is: the asset stays in `holdings` with price=None and value=None, # and its id is named in `report.unpriced`. It is NEVER counted as zero, and # there is no price source for Bitcoin or Solana assets in this package at # all, so this is the normal case for them, not an edge case. print(f"\n unpriced: {report.unpriced or '(none in the sandbox recording)'}") for holding in report.holdings: if holding.price is None: print(f" {holding.symbol} held, not valued: {holding.quantity}") # -------------------------------------------------------------- on the wire # Rule #2: a raw amount is a tagged decimal STRING, never a JSON number, so # no JavaScript client can quietly round it. The lossy float rides alongside, # clearly labelled, for clients that only want to draw a chart. wire = quantity_to_wire(report.holdings[0].quantity) assert isinstance(wire["raw"], str) print(f"\n quantity on the wire: {wire}") print(f" total on the wire: {money_to_wire(report.total_value)}") # --------------------------------------------------------------- going live # One line different. The key is OPTIONAL, without it Etherscan's keyless # tier applies, and one key covers every eip155 chain. if os.environ.get("AURADEFI_ETHERSCAN_API_KEY"): live = Auradefi.from_env() user = live.user("your-opaque-user-id") user.connect_address("eip155:1", "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045") (live_report,) = live.holdings() print(f"\n LIVE: {live_report.total_value} across " f"{len(live_report.holdings)} assets, {len(live_report.unpriced)} unpriced") else: print("\n live: set AURADEFI_ETHERSCAN_API_KEY and this file will also") print(" run Auradefi.from_env() against mainnet. Same code below it.") print("\nOK: priced exactly, offline, with one line between here and mainnet.")