Skip to main content

Historical Candles

Query historical futures and options candles by product symbol. Supports day / week / month K and minute K, regular and after-hours sessions; for futures the contract month can be a specific month or a continuous contract 1! / 2! / 3!, while options require the contract month, strike price and call/put. A single query range must be shorter than 1 year; day / week / month K goes back to 2010, and minute K is available from 2017-06.

historical/candles/{product}
Version Note

Available since v2.4.0; options (strikePrice, callPut) supported since v2.5.0

Parameters​

NameTypeDescription
product*stringProduct symbol (upper case), e.g. TXF, MXF, CDF for futures and TXO for options. Specify the contract month with contractMonth; weekly contracts are also queried by product symbol (e.g. MXF with contractMonth=202609W2) — a weekly prefix such as MX4 is not a product symbol. A contract code (e.g. TXFI6, TXO48000J6) is not accepted as product and returns 400; see Converting Intraday Contract Codes below. Spread contracts are not yet available
contractMonthstringContract month. Futures: defaults to 1! (front month) if omitted; accepts a specific month yyyyMM (e.g. 202609), a weekly contract yyyyMMWn (e.g. 202609W2), or a continuous contract 1! front month, 2! second month, 3! third month (4! and beyond return 400). Options: required; accepts yyyyMM, a weekly contract yyyyMMWn (Wednesday expiry) or yyyyMMFn (Friday expiry); continuous contracts are not supported
strikePricenumberOptions only, required. Strike price, e.g. 48000; must be given together with callPut
callPutstringOptions only, required. CALL or PUT; must be given together with strikePrice
fromstringStart date (format: yyyy-MM-dd), defaults to 1 week ago if omitted
tostringEnd date (format: yyyy-MM-dd), defaults to today if omitted
timeframestringKLine timeframe, defaults to D (day) if omitted; offer 1 1m; 5 5m; 10 10m; 15 15m; 30 30m; 60 60m; D day; W week; M month
sessionstringTrading session, defaults to regular if omitted; offer afterhours for the after-hours session
fieldsstringField selection, defaults to open,high,low,close,volume if omitted (average, transaction and change are not included, specify them explicitly when needed); offer open, high, low, close, volume, average, transaction, change (see the Response table below for applicable timeframes). turnover is not provided and returns 400 if requested
sortstringSorting, defaults to desc (descending) if omitted; also offer asc (ascending)
info
  • Data coverage: day / week / month K from 2010; minute K from 2017-06. Data for the current day can be queried from about 17:30.
  • A single query range must be shorter than 1 year, otherwise 400 is returned.
  • from / to are trading days, and an after-hours session belongs to the next trading day: e.g. session=afterhours&from=2026-09-10&to=2026-09-10 returns the after-hours session from 2026-09-09 15:00 to 2026-09-10 05:00.
  • If no data is found, 404 is returned instead of an empty array.
  • Continuous contracts (1! / 2! / 3!) roll over on the trading day after the expiring contract's last trading day. No roll adjustment is applied, so the candle on the rollover day may gap. Continuous contracts are ranked among monthly contracts only, excluding weekly contracts.
  • Minute K counts outright-order trades only (excluding the legs of spread orders and block trades), so a contract's day K volume can exceed the sum of that day's minute K.

Converting Intraday Contract Codes​

An intraday contract code cannot be used as product. Convert it into query parameters as follows:

Intraday codeQuery parameters
TXFI6product=TXF, contractMonth=202609
TXF1!product=TXF, contractMonth=1!
TXO48000J6product=TXO, contractMonth=202610, strikePrice=48000, callPut=CALL

Month codes are A–L for futures and calls and M–X for puts, for January–December; the last character is the last digit of the year.

Response​

NameTypeDescriptionApplicable Timeframe
product*stringProduct symbol—
contractMonth*stringThe contract month passed in the query (1! / 2! / 3! for continuous contracts)—
exchange*stringExchange—
session*stringSession, REGULAR or AFTERHOURS—
timeframe*stringKLine timeframe—
sort*stringSorting direction (desc or asc)—
strikePricenumberOptions only. The strike price passed in the query—
callPutstringOptions only. The call/put passed in the query, CALL or PUT—
data*object[]KLine data—
data.date*stringTrading day for day K, Monday of the week for week K, first day of the month for month K (yyyy-MM-dd); start time of the candle for minute K, ISO 8601 with timezone (e.g. 2026-09-10T08:45:00.000+08:00)All
data.contractMonth*stringThe contract month this candle actually belongs to. Use it to see where the rollover happens in a continuous-contract query; a week / month K spanning a rollover is labelled with the contract it closed onAll
data.opennumberOpening Price; null for a candle with no tradeAll
data.highnumberHighest Price; null for a candle with no trade or when TAIFEX does not provide itAll
data.lownumberLowest Price; null for a candle with no trade or when TAIFEX does not provide itAll
data.closenumberClose Price; null for a candle with no tradeAll
data.volumenumberVolume (contracts), 0 for a candle with no tradeAll
data.averagenumberVolume-weighted average price (VWAP) of the candleMinute K only
data.transactionnumberNumber of transactions in the candleMinute K only
data.changenumberPrice Change; null for a candle with no tradeDay / Week / Month K only
info

Day K change is the day's close minus the previous trading day's settlement price (the same as the price change in TAIFEX daily market data); on a continuous contract's rollover day it is calculated against the new contract's own settlement price. Week / month K change is the sum of the daily changes within the period.

Examples​

Day K Example (Continuous Contract)​

Query day K with the front-month continuous contract 1! and a specified date range. The range spans the expiry of the 2026 August contract (8/19), and contractMonth shows the rollover on 8/20:

from fubon_neo.sdk import FubonSDK, Order

sdk = FubonSDK()

accounts = sdk.login("Your ID", "Your password", "Your cert path", "Your cert password") # Login first before connecting market-data

sdk.init_realtime() # Establish market-data

restfutopt = sdk.marketdata.rest_client.futopt

## After version 2.2.4 (use Exception for exception handling)
from fubon_neo.fugle_marketdata.rest.base_rest import FugleAPIError

try:
restfutopt.historical.candles(**{"product": "TXF", "contractMonth": "1!", "from": "2026-08-17", "to": "2026-08-21", "fields": "open,high,low,close,volume,change"})
except FugleAPIError as e:
print(f"Error: {e}")
print("------------")
print(f"Status Code: {e.status_code}") # Ex: 429
print(f"Response Text: {e.response_text}") # Ex: {"statusCode":429,"message":"Rate limit exceeded"}

Response Body:

{
"product": "TXF",
"contractMonth": "1!",
"exchange": "TAIFEX",
"session": "REGULAR",
"timeframe": "D",
"sort": "desc",
"data": [
{
"date": "2026-08-21",
"contractMonth": "202609",
"open": 44887,
"high": 45294,
"low": 44566,
"close": 45148,
"volume": 51446,
"change": 245
},
{
"date": "2026-08-20",
"contractMonth": "202609",
"open": 44950,
"high": 45122,
"low": 44448,
"close": 44868,
"volume": 53693,
"change": 368
},
{
"date": "2026-08-19",
"contractMonth": "202608",
"open": 44411,
"high": 44869,
"low": 44208,
"close": 44612,
"volume": 27795,
"change": -476
},
{
"date": "2026-08-18",
"contractMonth": "202608",
"open": 45967,
"high": 45977,
"low": 45070,
"close": 45085,
"volume": 83392,
"change": -782
},
{
"date": "2026-08-17",
"contractMonth": "202608",
"open": 45850,
"high": 46140,
"low": 45738,
"close": 45888,
"volume": 79450,
"change": 76
}
]
}

Minute K Example​

Query 60-minute K with a specific contract month and a specified date range (including average price average and number of transactions transaction):

from fubon_neo.sdk import FubonSDK, Order

sdk = FubonSDK()

accounts = sdk.login("Your ID", "Your password", "Your cert path", "Your cert password") # Login first before connecting market-data

sdk.init_realtime() # Establish market-data

restfutopt = sdk.marketdata.rest_client.futopt

## After version 2.2.4 (use Exception for exception handling)
from fubon_neo.fugle_marketdata.rest.base_rest import FugleAPIError

try:
restfutopt.historical.candles(**{"product": "TXF", "contractMonth": "202609", "timeframe": "60", "from": "2026-09-10", "to": "2026-09-10", "fields": "open,high,low,close,volume,average,transaction"})
except FugleAPIError as e:
print(f"Error: {e}")
print("------------")
print(f"Status Code: {e.status_code}") # Ex: 429
print(f"Response Text: {e.response_text}") # Ex: {"statusCode":429,"message":"Rate limit exceeded"}

Response Body:

{
"product": "TXF",
"contractMonth": "202609",
"exchange": "TAIFEX",
"session": "REGULAR",
"timeframe": "60",
"sort": "desc",
"data": [
{
"date": "2026-09-10T12:45:00.000+08:00",
"contractMonth": "202609",
"open": 46733,
"high": 46949,
"low": 46733,
"close": 46870,
"volume": 10066,
"average": 46868.04,
"transaction": 7729
},
{
"date": "2026-09-10T11:45:00.000+08:00",
"contractMonth": "202609",
"open": 46673,
"high": 46820,
"low": 46666,
"close": 46730,
"volume": 4133,
"average": 46745.72,
"transaction": 3212
},
{
"date": "2026-09-10T10:45:00.000+08:00",
"contractMonth": "202609",
"open": 46748,
"high": 46803,
"low": 46652,
"close": 46677,
"volume": 3896,
"average": 46719.47,
"transaction": 3192
},
{
"date": "2026-09-10T09:45:00.000+08:00",
"contractMonth": "202609",
"open": 46661,
"high": 46800,
"low": 46589,
"close": 46747,
"volume": 7357,
"average": 46688.19,
"transaction": 5398
},
{
"date": "2026-09-10T08:45:00.000+08:00",
"contractMonth": "202609",
"open": 46940,
"high": 46950,
"low": 46506,
"close": 46663,
"volume": 20094,
"average": 46683.01,
"transaction": 16071
}
]
}

After-hours Example​

Query 60-minute K of the after-hours session with session=afterhours. from / to take the trading day the session belongs to (2026-09-10); the response covers the after-hours session from 2026-09-09 15:00 to 2026-09-10 05:00:

from fubon_neo.sdk import FubonSDK, Order

sdk = FubonSDK()

accounts = sdk.login("Your ID", "Your password", "Your cert path", "Your cert password") # Login first before connecting market-data

sdk.init_realtime() # Establish market-data

restfutopt = sdk.marketdata.rest_client.futopt

## After version 2.2.4 (use Exception for exception handling)
from fubon_neo.fugle_marketdata.rest.base_rest import FugleAPIError

try:
restfutopt.historical.candles(**{"product": "TXF", "contractMonth": "202609", "timeframe": "60", "session": "afterhours", "from": "2026-09-10", "to": "2026-09-10"})
except FugleAPIError as e:
print(f"Error: {e}")
print("------------")
print(f"Status Code: {e.status_code}") # Ex: 429
print(f"Response Text: {e.response_text}") # Ex: {"statusCode":429,"message":"Rate limit exceeded"}

Response Body (excerpt):

{
"product": "TXF",
"contractMonth": "202609",
"exchange": "TAIFEX",
"session": "AFTERHOURS",
"timeframe": "60",
"sort": "desc",
"data": [
{
"date": "2026-09-10T04:00:00.000+08:00",
"contractMonth": "202609",
"open": 46987,
"high": 47019,
"low": 46971,
"close": 46984,
"volume": 359
},
{
"date": "2026-09-10T03:00:00.000+08:00",
"contractMonth": "202609",
"open": 47024,
"high": 47086,
"low": 46965,
"close": 46992,
"volume": 671
},
...
{
"date": "2026-09-09T16:00:00.000+08:00",
"contractMonth": "202609",
"open": 47234,
"high": 47295,
"low": 47182,
"close": 47233,
"volume": 1608
},
{
"date": "2026-09-09T15:00:00.000+08:00",
"contractMonth": "202609",
"open": 47214,
"high": 47267,
"low": 47136,
"close": 47232,
"volume": 2098
}
]
}
info

'*' Indicates mandatory disclosure fields.

Options Day K Example​

Query day K of the TAIEX option, October 2026 contract, strike 48000 call:

from fubon_neo.sdk import FubonSDK, Order

sdk = FubonSDK()

accounts = sdk.login("Your ID", "Your password", "Your cert path", "Your cert password") # Login is required to get market data access

sdk.init_realtime() # Establish the market data connection

restfutopt = sdk.marketdata.rest_client.futopt

## After version 2.2.4 (use Exception for exception handling)
from fubon_neo.fugle_marketdata.rest.base_rest import FugleAPIError

try:
restfutopt.historical.candles(**{"product": "TXO", "contractMonth": "202610", "strikePrice": 48000, "callPut": "CALL", "from": "2026-10-01", "to": "2026-10-07", "fields": "open,high,low,close,volume,change"})
except FugleAPIError as e:
print(f"Error: {e}")
print("------------")
print(f"Status Code: {e.status_code}") # e.g. 400
print(f"Response Text: {e.response_text}") # e.g. {"message":"strikePrice and callPut must be given together","error":"Bad Request","statusCode":400}

Response Body:

{
"product": "TXO",
"contractMonth": "202610",
"exchange": "TAIFEX",
"session": "REGULAR",
"timeframe": "D",
"sort": "desc",
"strikePrice": 48000,
"callPut": "CALL",
"data": [
{
"date": "2026-10-07",
"contractMonth": "202610",
"open": 2100,
"high": 2250,
"low": 2100,
"close": 2150,
"volume": 23,
"change": -100
},
{
"date": "2026-10-06",
"contractMonth": "202610",
"open": 2300,
"high": 2300,
"low": 2250,
"close": 2250,
"volume": 3,
"change": 60
},
{
"date": "2026-10-05",
"contractMonth": "202610",
"open": 1850,
"high": 2320,
"low": 1800,
"close": 2140,
"volume": 154,
"change": 920
},
{
"date": "2026-10-02",
"contractMonth": "202610",
"open": 1170,
"high": 1320,
"low": 1150,
"close": 1220,
"volume": 95,
"change": -60
},
{
"date": "2026-10-01",
"contractMonth": "202610",
"open": 1150,
"high": 1280,
"low": 990,
"close": 1280,
"volume": 105,
"change": 160
}
]
}