Skip to content

Market Data API

Real-time market data subscriptions and historical data retrieval.

Access via client.market_data.

MarketDataAPI

MarketDataAPI

Market data subscriptions and historical data.

Provides methods to subscribe to real-time market data (spots, trendbars,
depth of market) and retrieve historical data.

Example
# Subscribe to spot prices
await client.market_data.subscribe_spots(account_id, [270, 271])


# Handle spot events via decorator
@client.on(SpotEvent, symbol_id=270)
async def on_eurusd(event: SpotEvent) -> None:
    print(f"EURUSD: {event.bid}/{event.ask}")


# Get historical candles
trendbars = await client.market_data.get_trendbars(
    account_id,
    symbol_id=270,
    period=TrendbarPeriod.H1,
    from_timestamp=start,
    to_timestamp=end,
)

subscribe_spots(account_id, symbol_ids, timeout=None)

Subscribe to spot price updates.

After subscribing, spot events will be delivered via the event system.
Use @client.on(SpotEvent) to handle them.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_ids list[int]

Symbols to subscribe to.

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

unsubscribe_spots(account_id, symbol_ids, timeout=None)

Unsubscribe from spot price updates.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_ids list[int]

Symbols to unsubscribe from.

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

subscribe_trendbars(account_id, symbol_id, period, timeout=None)

Subscribe to live trendbar (candle) updates.

Requires subscribing to spots for the same symbol beforehand.

After subscribing, trendbar data will be delivered via the event system inside the SpotEvent object.
Use @client.on(SpotEvent) to handle them.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_id int

Symbol to subscribe to.

required
period TrendbarPeriod

Trendbar period (M1, H1, D1, etc.).

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

unsubscribe_trendbars(account_id, symbol_id, period, timeout=None)

Unsubscribe from live trendbar updates.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_id int

Symbol to unsubscribe from.

required
period TrendbarPeriod

Trendbar period.

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

subscribe_depth(account_id, symbol_ids, timeout=None)

Subscribe to depth of market (order book) updates.

After subscribing, depth events will be delivered via the event system.
Use @client.on(DepthEvent) to handle them.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_ids list[int]

Symbols to subscribe to.

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

unsubscribe_depth(account_id, symbol_ids, timeout=None)

Unsubscribe from depth of market updates.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_ids list[int]

Symbols to unsubscribe from.

required
timeout float | None

Request timeout (uses default if None).

None

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

get_trendbars(account_id, symbol_id, period, from_timestamp, to_timestamp, timeout=None)

Get historical trendbars (candles).

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_id int

Symbol to get data for.

required
period TrendbarPeriod

Trendbar period (M1, H1, D1, etc.).

required
from_timestamp datetime

Start of time range (inclusive).

required
to_timestamp datetime

End of time range (inclusive).

required
timeout float | None

Request timeout (uses default if None).

None

Returns:

Type Description
list[Trendbar]

List of Trendbar objects, ordered by timestamp ascending.

Note

The server may limit the number of bars returned per request.
For large ranges, consider paginating with smaller time windows.

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

get_tick_data(account_id, symbol_id, from_timestamp, to_timestamp, quote_type='BID', timeout=None)

Get historical tick data.

Parameters:

Name Type Description Default
account_id int

The cTID trader account ID.

required
symbol_id int

Symbol to get data for.

required
from_timestamp datetime

Start of time range (inclusive).

required
to_timestamp datetime

End of time range (inclusive).

required
quote_type str

"BID" or "ASK".

'BID'
timeout float | None

Request timeout (uses default if None).

None

Returns:

Type Description
Sequence[TickData]

List of TickData objects, ordered by newest first.

Note

Tick data can be voluminous. Use small time windows to avoid
timeout issues and excessive memory usage.

Raises:

Type Description
APIError

If request fails.

CTraderConnectionTimeoutError

If request times out.

Usage Examples

Subscribe to Spot Prices

from ctrader_api_client.events import SpotEvent

# Subscribe to symbols
await client.market_data.subscribe_spots(account_id, [270, 271])


# Handle price updates - bid/ask are floats
@client.on(SpotEvent, symbol_id=270)
async def on_price(event: SpotEvent):
    print(f"Bid: {event.bid}, Ask: {event.ask}")

Subscribe to Live Trendbars

from ctrader_api_client.events import SpotEvent
from ctrader_api_client.enums import TrendbarPeriod

# Subscribe to M1 trendbars
await client.market_data.subscribe_trendbars(account_id, symbol_id=270, period=TrendbarPeriod.M1)

# Trendbar data is delivered inside SpotEvent
@client.on(SpotEvent, symbol_id=270)
async def on_spot(event: SpotEvent):
    print(f"Price: {event.bid}/{event.ask}")

    # Check if this event contains trendbar data
    if event.trendbar:
        bar = event.trendbar
        print(f"Bar: O={bar.open} H={bar.high} L={bar.low} C={bar.close} V={bar.volume}")

Subscribe to Depth of Market

from ctrader_api_client.events import DepthEvent

# Subscribe to order book
await client.market_data.subscribe_depth(account_id, symbol_id=270)


@client.on(DepthEvent, symbol_id=270)
async def on_depth(event: DepthEvent):
    for quote in event.new_quotes:
        side = "BID" if quote.is_bid else "ASK"
        print(f"{side}: {quote.price} x {quote.size}")

Get Historical Trendbars

from datetime import datetime, timedelta, UTC
from ctrader_api_client.enums import TrendbarPeriod

trendbars = await client.market_data.get_trendbars(
    account_id,
    symbol_id=270,
    period=TrendbarPeriod.H1,
    from_timestamp=datetime.now(UTC) - timedelta(days=7),
    to_timestamp=datetime.now(UTC),
)

# OHLC values are already floats (converted from raw integers)
for bar in trendbars:
    print(f"{bar.timestamp}: O={bar.open} H={bar.high} L={bar.low} C={bar.close} V={bar.volume}")

Get Tick Data

from datetime import datetime, timedelta, UTC

ticks = await client.market_data.get_tick_data(
    account_id,
    symbol_id=270,
    from_timestamp=datetime.now(UTC) - timedelta(hours=1),
    to_timestamp=datetime.now(UTC),
    quote_type="BID",  # or "ASK"
)

# Price is already a float
for tick in ticks:
    print(f"{tick.timestamp}: {tick.price}")

Unsubscribe

# Unsubscribe from spots
await client.market_data.unsubscribe_spots(account_id, [270])

# Unsubscribe from trendbars
await client.market_data.unsubscribe_trendbars(
    account_id,
    symbol_id=270,
    period=TrendbarPeriod.M1,
)

# Unsubscribe from depth
await client.market_data.unsubscribe_depth(account_id, symbol_id=270)

Note on Subscriptions

Subscriptions are not automatically restored after reconnection.
It is recommended to use ReadyEvent to keep all subscriptions centralized in one place and ensure they are re-established after any disconnects.

from ctrader_api_client.events import ReadyEvent
from ctrader_api_client.enums import TrendbarPeriod

@client.on(ReadyEvent)
async def on_ready(event: ReadyEvent):
    # This runs on initial auth AND after reconnection
    await client.market_data.subscribe_spots(event.account_id, [270, 271])
    await client.market_data.subscribe_trendbars(event.account_id, 270, TrendbarPeriod.M1)