Model and numeric basics¶
FiveTwenty keeps OANDA's response structure while parsing nested objects into Pydantic models. Most endpoint results are dictionaries: select the response key, then use model attributes. This distinction makes the code easier to read and preserves native numeric and datetime types.
Read a model from a response¶
This read-only helper accepts a client that is already open:
from decimal import Decimal
from fivetwenty import AsyncClient
async def show_balance(client: AsyncClient) -> Decimal:
response = await client.accounts.get_account_summary(client.account_id)
account = response["account"]
print(f"Balance: {account.balance} {account.currency}")
print(f"NAV: {account.nav} {account.currency}")
return account.balance
balance and nav are Decimal values. Balance and net asset value describe
separate account metrics; unrealized profit or loss affects NAV. The response also
contains lastTransactionID, which is an account transaction cursor, not a balance.
get_accounts() is an exception to the usual envelope pattern: it returns a list
of account property models directly. Check each endpoint's documented return type.
Construct decimal values deliberately¶
from decimal import Decimal
bid = Decimal("1.10000")
ask = Decimal("1.10012")
spread = ask - bid
print(spread) # 0.00012, in quote-currency price units
Strings avoid introducing a binary floating-point approximation before the decimal
is constructed. Decimal arithmetic still has a precision context and rounding
rules; it is not unlimited-precision arithmetic. Financial models use Decimal,
but elapsed seconds and retry delays use ordinary numeric timing values.
For FX, price is expressed in quote currency per base-currency unit. Do not treat a price difference as account-currency profit. Conversion and costs may be needed.
Read instrument constraints¶
Instrument metadata includes pip_location, display_precision,
trade_units_precision and minimum_trade_size. A pip's price size is
Decimal("10") ** instrument.pip_location; display precision is a separate concept.
Fetch metadata for the account and instrument you will use rather than assuming
all products accept integer units or five decimal places.
Request models validate supported local constraints and serialize field names for the wire. OANDA still decides whether a request is valid for the current account, price, margin and instrument conditions.
Keep datetime objects until serialization¶
Time-bearing response attributes are Python datetime objects. Use timezone-aware
values for request boundaries. The client's datetime_format controls wire values
and the Accept-Datetime-Format header; it does not turn model attributes into
strings. Python datetime precision is microseconds, so sub-microsecond source
precision is not retained.
Use attributes for calculations. Compatibility access such as model["openTime"]
returns serialized values and can differ in type from model.open_time.
Continue with market data, or consult the model reference.