Fetch Your Transactions
Use client.info for account history reads. These methods take a user address and time windows in UTC milliseconds where applicable.
Fetch Trades
Use user_fills() for recent fills or user_fills_by_time() for a specific window.
from datetime import datetime, timedelta, timezone
from typed_hyperliquid import Hyperliquid
user = '0xYourAccountAddress'
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(days=7)
async with Hyperliquid.new(public=True) as client:
fills = await client.info.user_fills_by_time(user=user, start_time=start_time, end_time=end_time)
for fill in fills:
print(fill['coin'], fill['side'], fill['px'], fill['sz'])For large windows, use user_fills_by_time_paged().
Fetch Funding Payments
from datetime import datetime, timedelta, timezone
from typed_hyperliquid import Hyperliquid
user = '0xYourAccountAddress'
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(days=7)
async with Hyperliquid.new(public=True) as client:
funding = await client.info.user_funding(user=user, start_time=start_time, end_time=end_time)
for entry in funding:
delta = entry['delta']
print(delta['coin'], delta['usdc'], delta['fundingRate'])For long ranges, use user_funding_paged().
from datetime import datetime, timedelta, timezone
from typed_hyperliquid import Hyperliquid
user = '0xYourAccountAddress'
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(days=7)
async with Hyperliquid.new(public=True) as client:
async for chunk in client.info.user_funding_paged(user=user, start_time=start_time, end_time=end_time):
print(len(chunk))Fetch Other Ledger Flows
Use user_non_funding_ledger_updates() for non-funding transfers and ledger events:
deposits, withdrawals, spot and sub-account transfers, vault flows, staking, liquidations,
and rewards.
from datetime import datetime, timedelta, timezone
from typed_hyperliquid import Hyperliquid
user = '0xYourAccountAddress'
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(days=7)
async with Hyperliquid.new(public=True) as client:
flows = await client.info.user_non_funding_ledger_updates(
user=user,
start_time=start_time,
end_time=end_time,
)
for entry in flows:
print(entry['time'], entry['delta']['type'])Each delta is a union discriminated on type, so checking type narrows the entry to
the exact variant and its fields:
from datetime import datetime, timedelta, timezone
from typed_hyperliquid import Hyperliquid
user = '0xYourAccountAddress'
end_time = datetime.now(timezone.utc)
start_time = end_time - timedelta(days=7)
async with Hyperliquid.new(public=True) as client:
flows = await client.info.user_non_funding_ledger_updates(
user=user, start_time=start_time, end_time=end_time,
)
for entry in flows:
delta = entry['delta']
if delta['type'] == 'deposit':
print('deposited', delta['usdc'])
elif delta['type'] == 'withdraw':
print('withdrew', delta['usdc'], 'fee', delta['fee'])
elif delta['type'] == 'send':
print('sent', delta['amount'], delta['token'], 'to', delta['destination'])
elif delta['type'] == 'vaultWithdraw':
print('vault withdrawal', delta['netWithdrawnUsd'], 'from', delta['vault'])All monetary amounts are decimal strings straight off the wire, so no precision is lost
parsing them. Never convert them to float for arithmetic; use decimal.Decimal instead.
Hyperliquid adds ledger types over time, and an unrecognized type raises a
ValidationError rather than validating as an opaque value. This is deliberate: ledger
deltas move balances, so a silently-ignored new type would corrupt any accounting built on
this endpoint. Failing loudly surfaces the new type so it can be modeled.
To tolerate unmodeled types, validate each delta individually and handle the failures explicitly, rather than letting one unknown row abort a whole history read:
from datetime import datetime, timezone
from typed_hyperliquid.info import Info
from typed_hyperliquid.info.user_non_funding_ledger_updates import UserNonFundingLedgerEntry
import pydantic
entry_adapter = pydantic.TypeAdapter(UserNonFundingLedgerEntry)
address = '0xYourAccountAddress'
start_time = datetime.fromtimestamp(0, tz=timezone.utc)
info = Info.http(validate=False)
for raw in await info.user_non_funding_ledger_updates(user=address, start_time=start_time):
try:
entry_adapter.validate_python(raw)
except pydantic.ValidationError:
print('unrecognized ledger entry', raw) # log it, or surface it as an unclassified record
continuePagination
This endpoint returns at most 2000 entries, keeping the oldest and silently dropping the rest -- no error, no indicator. Accounts with more history must be paginated:
from datetime import datetime, timedelta
from typed_hyperliquid.info import Info
async def all_ledger_updates(info: Info, address: str, start_time: datetime):
while True:
page = await info.user_non_funding_ledger_updates(user=address, start_time=start_time)
if not page:
return
yield page
if len(page) < 2000:
return
start_time = max(entry['time'] for entry in page) + timedelta(milliseconds=1)Note that hash is not unique: one transaction can emit several deltas, so (time, hash) is not a primary key. Deduplicating on it will silently drop rows.