Skip to content

Pricing Endpoint

OANDA Reference: Pricing Endpoints

Real-time pricing data and streaming.


get_pricing

Get current prices for instruments.

OANDA Endpoint: GET /v3/accounts/{accountID}/pricing

import asyncio

from dotenv import load_dotenv

from fivetwenty import AsyncClient

load_dotenv()


async def main() -> None:
    async with AsyncClient() as client:
        # Get current pricing for multiple instruments
        result = await client.pricing.get_pricing(
            account_id=client.account_id,
            instruments=["EUR_USD", "GBP_USD"],  # Change to your instruments
            include_units_available=True,
        )
        print(f"Got {len(result['prices'])} prices at {result['time']}")
        # homeConversions is optional, only present if include_home_conversions=True
        if "homeConversions" in result:
            print(f"Got {len(result['homeConversions'])} home conversions")


asyncio.run(main())

🔗 OANDA Documentation: Get Pricing

🔗 Source: pricing.get_pricing

Parameters:

Parameter Type Required Description
account_id AccountID ✅ Account ID
instruments list[str] ✅ List of instruments to get prices for
* Keyword-only parameters below
since str | None âž– Only get prices changed since this time
include_units_available bool âž– Include units available info (default: True)
include_home_conversions bool âž– Include home currency conversions (default: False)

Returns: GetPricingResponse - Dictionary containing prices (list[ClientPrice]), time (str), and optionally homeConversions (list[HomeConversions])

Raises:

FiveTwentyError - API errors:

  • 400: Invalid request parameters (check e.is_bad_request)
  • 401/403: Authentication failed (check e.is_authentication_error)
  • 404: Account not found (check e.is_not_found)
  • 429: Rate limit exceeded (check e.is_rate_limited)

get_pricing_stream

Stream real-time pricing data.

OANDA Endpoint: GET /v3/accounts/{accountID}/pricing/stream

import asyncio
from contextlib import aclosing

from dotenv import load_dotenv

from fivetwenty import AsyncClient

load_dotenv()


async def main() -> None:
    async with AsyncClient() as client:
        # Stream real-time pricing data for instruments
        count = 0
        stream = client.pricing.get_pricing_stream(
            account_id=client.account_id,
            instruments=["EUR_USD", "GBP_USD"],  # Change to your instruments
            snapshot=True,
        )
        async with aclosing(stream):  # type: ignore[type-var]
            async for price in stream:
                print(f"Price update: {price}")
                count += 1
                if count >= 5:  # Stop after 5 updates for testing
                    break


asyncio.run(main())

🔗 OANDA Documentation: Stream Pricing

🔗 Source: pricing.get_pricing_stream

Parameters:

Parameter Type Required Description
account_id AccountID ✅ Account ID
instruments list[str] ✅ List of instruments to stream
* Keyword-only parameters below
snapshot bool âž– Include initial snapshot (default: True)
include_home_conversions bool âž– Include home currency conversion factors (default: False)
stall_timeout float âž– Timeout for detecting stream stalls in seconds (default: 30.0)

Returns: AsyncIterator[ClientPrice | PricingHeartbeat] - Async iterator yielding ClientPrice or PricingHeartbeat objects

Raises:

FiveTwentyError - API errors:

  • 400: Invalid request parameters (check e.is_bad_request)
  • 401/403: Authentication failed (check e.is_authentication_error)
  • 404: Account not found (check e.is_not_found)
  • 429: Rate limit exceeded (check e.is_rate_limited)

StreamStall - On stream timeout or connection issues


get_account_instrument_candles

Get account-specific historical candle data for an instrument.

OANDA Endpoint: GET /v3/accounts/{accountID}/instruments/{instrument}/candles

import asyncio

from dotenv import load_dotenv

from fivetwenty import AsyncClient

load_dotenv()


async def main() -> None:
    async with AsyncClient() as client:
        # Get historical candlestick data for an instrument
        candles = await client.pricing.get_account_instrument_candles(
            account_id=client.account_id,
            instrument="EUR_USD",  # Change to your instrument
            granularity="H1",  # Change to desired granularity (S5, M1, H1, D, etc.)
            count=100,  # Number of candles to retrieve (use count OR from_time/to_time)
        )
        print(f"Got {len(candles['candles'])} candles for {candles['instrument']}")


asyncio.run(main())

🔗 OANDA Documentation: Get Candles

🔗 Source: pricing.get_account_instrument_candles

Parameters:

Parameter Type Required Description
account_id AccountID ✅ Account ID
instrument str ✅ Instrument to get candles for
* Keyword-only parameters below
price str âž– Price type ("M", "B", "A", "BA", "BM", "AM", "BAM") (default: "M")
granularity str âž– Granularity of candles (default: "S5")
count int | None âž– Number of candles to return (max 5000)
from_time datetime | None âž– Start time for candle range
to_time datetime | None âž– End time for candle range
smooth bool âž– Smooth candles (default: False)
include_first bool âž– Include first candle (default: True, only used with from_time)
daily_alignment int âž– Daily alignment hour (default: 17)
alignment_timezone str âž– Timezone for alignment (default: "America/New_York")
weekly_alignment str âž– Weekly alignment day (default: "Friday")

Returns: CandlesResponse - Dictionary containing instrument, granularity, and list of candlesticks

Raises:

FiveTwentyError - API errors:

  • 400: Invalid request parameters (check e.is_bad_request)
  • 401/403: Authentication failed (check e.is_authentication_error)
  • 404: Instrument or account not found (check e.is_not_found)
  • 429: Rate limit exceeded (check e.is_rate_limited)

ValueError - If both count and time range are specified


get_latest_candles

Get latest candles for multiple instruments.

OANDA Endpoint: GET /v3/accounts/{accountID}/candles/latest

import asyncio

from dotenv import load_dotenv

from fivetwenty import AsyncClient

load_dotenv()


async def main() -> None:
    async with AsyncClient() as client:
        # Get latest candles for multiple instrument/granularity combinations
        result = await client.pricing.get_latest_candles(
            account_id=client.account_id,
            # Format: instrument:granularity:price_type
            candle_specifications=["EUR_USD:S5:BM", "GBP_USD:M1:BM"],
            units=50,  # Number of candles per specification
        )
        for candle_data in result["latestCandles"]:
            print(f"{candle_data['instrument']}: {len(candle_data['candles'])} candles")


asyncio.run(main())

🔗 OANDA Documentation: Get Latest Candles

🔗 Source: pricing.get_latest_candles

Parameters:

Parameter Type Required Description
account_id AccountID ✅ Account ID
candle_specifications list[str] ✅ List of candle specifications (instrument:granularity:price)
* Keyword-only parameters below
units int âž– Number of units for each candle spec (1-5000, default: 1)
smooth bool âž– Smooth candles (default: False)
daily_alignment int âž– Daily alignment hour (default: 17)
alignment_timezone str âž– Timezone for alignment (default: "America/New_York")
weekly_alignment str âž– Weekly alignment day (default: "Friday")

Returns: LatestCandlesResponse - Dictionary containing latest candle data for multiple instruments

Raises:

FiveTwentyError - API errors:

  • 400: Invalid request parameters (check e.is_bad_request)
  • 401/403: Authentication failed (check e.is_authentication_error)
  • 404: Account not found (check e.is_not_found)
  • 429: Rate limit exceeded (check e.is_rate_limited)

ValueError - On invalid parameters


stream_pricing_with_retries

Stream pricing with automatic reconnection and configuration.

OANDA Endpoint: GET /v3/accounts/{accountID}/pricing/stream

import asyncio
from contextlib import aclosing

from dotenv import load_dotenv

from fivetwenty import AsyncClient
from fivetwenty.models.streaming import (
    ReconnectionPolicy,
    StreamingConfiguration,
    StreamState,
)

load_dotenv()


async def main() -> None:
    async with AsyncClient() as client:
        # Configure automatic reconnection for robust streaming
        config = StreamingConfiguration(
            reconnection_policy=ReconnectionPolicy(
                max_attempts=5,
                delay_seconds=2.0,  # Retry up to 5 times with 2s delay
            )
        )

        # Stream pricing with automatic reconnection on failures
        count = 0
        stream = client.pricing.stream_pricing_with_retries(
            account_id=client.account_id,
            instruments=["EUR_USD", "GBP_USD"],  # Change to your instruments
            config=config,
        )
        async with aclosing(stream):  # type: ignore[type-var]
            async for price_data, state in stream:
                if state == StreamState.RECONNECTING:
                    print("Connection lost, retrying...")
                elif state == StreamState.CONNECTED:
                    print(f"Price update: {price_data}")
                    count += 1
                    if count >= 5:  # Stop after 5 updates for testing
                        break


asyncio.run(main())

🔗 OANDA Documentation: Stream Pricing

🔗 Source: pricing.stream_pricing_with_retries

Parameters:

Parameter Type Required Description
account_id AccountID ✅ Account ID
instruments list[str] ✅ List of instruments to stream
* Keyword-only parameters below
snapshot bool âž– Include snapshot of current prices (default: True)
include_home_conversions bool âž– Include home currency conversions (default: False)
config StreamingConfiguration | None âž– Streaming configuration with reconnection policy

Returns: AsyncIterator[tuple[ClientPrice | PricingHeartbeat, StreamState]] - Async iterator yielding tuples of (price_data, stream_state)

Raises:

FiveTwentyError - API errors:

  • 400: Invalid request parameters (check e.is_bad_request)
  • 401/403: Authentication failed (check e.is_authentication_error)
  • 404: Account not found (check e.is_not_found)
  • 429: Rate limit exceeded (check e.is_rate_limited)

StreamStall - If all retry attempts are exhausted