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}
Available since v2.4.0; options (strikePrice, callPut) supported since v2.5.0
Parameters
| Name | Type | Description |
|---|---|---|
product* | string | Product 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 |
contractMonth | string | Contract 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 |
strikePrice | number | Options only, required. Strike price, e.g. 48000; must be given together with callPut |
callPut | string | Options only, required. CALL or PUT; must be given together with strikePrice |
from | string | Start date (format: yyyy-MM-dd), defaults to 1 week ago if omitted |
to | string | End date (format: yyyy-MM-dd), defaults to today if omitted |
timeframe | string | KLine 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 |
session | string | Trading session, defaults to regular if omitted; offer afterhours for the after-hours session |
fields | string | Field 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 |
sort | string | Sorting, defaults to desc (descending) if omitted; also offer asc (ascending) |
- 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/toare trading days, and an after-hours session belongs to the next trading day: e.g.session=afterhours&from=2026-09-10&to=2026-09-10returns 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 code | Query parameters |
|---|---|
TXFI6 | product=TXF, contractMonth=202609 |
TXF1! | product=TXF, contractMonth=1! |
TXO48000J6 | product=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
| Name | Type | Description | Applicable Timeframe |
|---|---|---|---|
product* | string | Product symbol | — |
contractMonth* | string | The contract month passed in the query (1! / 2! / 3! for continuous contracts) | — |
exchange* | string | Exchange | — |
session* | string | Session, REGULAR or AFTERHOURS | — |
timeframe* | string | KLine timeframe | — |
sort* | string | Sorting direction (desc or asc) | — |
strikePrice | number | Options only. The strike price passed in the query | — |
callPut | string | Options only. The call/put passed in the query, CALL or PUT | — |
data* | object[] | KLine data | — |
data.date* | string | Trading 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* | string | The 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 on | All |
data.open | number | Opening Price; null for a candle with no trade | All |
data.high | number | Highest Price; null for a candle with no trade or when TAIFEX does not provide it | All |
data.low | number | Lowest Price; null for a candle with no trade or when TAIFEX does not provide it | All |
data.close | number | Close Price; null for a candle with no trade | All |
data.volume | number | Volume (contracts), 0 for a candle with no trade | All |
data.average | number | Volume-weighted average price (VWAP) of the candle | Minute K only |
data.transaction | number | Number of transactions in the candle | Minute K only |
data.change | number | Price Change; null for a candle with no trade | Day / Week / Month K only |
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:
- Python
- Node.js
- C#
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"}
const { FubonSDK } = require('fubon-neo');
const sdk = new FubonSDK();
const accounts = sdk.login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.initRealtime(); // Establish market-data
const client = sdk.marketdata.restClient
client.futopt.historical.candles({ product: 'TXF', contractMonth: '1!', from: '2026-08-17', to: '2026-08-21', fields: 'open,high,low,close,volume,change' })
.then(data => console.log(data));
using FubonNeo.Sdk;
using FugleMarketData.QueryModels.FuOpt.Historical; //import HistoricalTimeFrame, HistoricalFieldsType
var sdk = new FubonSDK();
var result = sdk.Login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.InitRealtime(); // Establish market-data
var rest = sdk.MarketData.RestClient.FutureOption;
var candles = await rest.Historical.Candles("TXF", new(new DateTime(2026,8,17), new DateTime(2026,8,21), HistoricalTimeFrame.Day, HistoricalFieldsType.Open|HistoricalFieldsType.High|HistoricalFieldsType.Low|HistoricalFieldsType.Close|HistoricalFieldsType.Volume|HistoricalFieldsType.Change, "1!"));
var candles_cont = candles.Content.ReadAsStringAsync().Result;
Console.WriteLine(candles_cont);
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):
- Python
- Node.js
- C#
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"}
const { FubonSDK } = require('fubon-neo');
const sdk = new FubonSDK();
const accounts = sdk.login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.initRealtime(); // Establish market-data
const client = sdk.marketdata.restClient
client.futopt.historical.candles({ product: 'TXF', contractMonth: '202609', timeframe: '60', from: '2026-09-10', to: '2026-09-10', fields: 'open,high,low,close,volume,average,transaction' })
.then(data => console.log(data));
using FubonNeo.Sdk;
using FugleMarketData.QueryModels.FuOpt.Historical; //import HistoricalTimeFrame, HistoricalFieldsType
var sdk = new FubonSDK();
var result = sdk.Login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.InitRealtime(); // Establish market-data
var rest = sdk.MarketData.RestClient.FutureOption;
var candles = await rest.Historical.Candles("TXF", new(new DateTime(2026,9,10), new DateTime(2026,9,10), HistoricalTimeFrame.SixtyMin, HistoricalFieldsType.Open|HistoricalFieldsType.High|HistoricalFieldsType.Low|HistoricalFieldsType.Close|HistoricalFieldsType.Volume|HistoricalFieldsType.Average|HistoricalFieldsType.Transaction, "202609"));
var candles_cont = candles.Content.ReadAsStringAsync().Result;
Console.WriteLine(candles_cont);
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:
- Python
- Node.js
- C#
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"}
const { FubonSDK } = require('fubon-neo');
const sdk = new FubonSDK();
const accounts = sdk.login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.initRealtime(); // Establish market-data
const client = sdk.marketdata.restClient
client.futopt.historical.candles({ product: 'TXF', contractMonth: '202609', timeframe: '60', session: 'afterhours', from: '2026-09-10', to: '2026-09-10' })
.then(data => console.log(data));
using FubonNeo.Sdk;
using FugleMarketData.QueryModels.FuOpt; //import TradeSession
using FugleMarketData.QueryModels.FuOpt.Historical; //import HistoricalTimeFrame
var sdk = new FubonSDK();
var result = sdk.Login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.InitRealtime(); // Establish market-data
var rest = sdk.MarketData.RestClient.FutureOption;
var candles = await rest.Historical.Candles("TXF", new(new DateTime(2026,9,10), new DateTime(2026,9,10), HistoricalTimeFrame.SixtyMin, contractMonth: "202609", session: TradeSession.AfterHours));
var candles_cont = candles.Content.ReadAsStringAsync().Result;
Console.WriteLine(candles_cont);
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
}
]
}
'*' Indicates mandatory disclosure fields.
Options Day K Example
Query day K of the TAIEX option, October 2026 contract, strike 48000 call:
- Python
- Node.js
- C#
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}
const { FubonSDK } = require('fubon-neo');
const sdk = new FubonSDK();
const accounts = sdk.login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.initRealtime(); // Establish the market data connection
const client = sdk.marketdata.restClient
client.futopt.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' })
.then(data => console.log(data));
using FubonNeo.Sdk;
using FugleMarketData.QueryModels.FuOpt; // import FutOptCallPut
using FugleMarketData.QueryModels.FuOpt.Historical; // import HistoricalTimeFrame, HistoricalFieldsType
var sdk = new FubonSDK();
var result = sdk.Login("Your ID", "Your Password", "Your Cert Path", "Your Cert Password");
sdk.InitRealtime(); // Establish the market data connection
var rest = sdk.MarketData.RestClient.FutureOption;
var candles = await rest.Historical.Candles("TXO", new HistoricalCandlesRequest(
from: new DateTime(2026,10,1),
to: new DateTime(2026,10,7),
timeFrame: HistoricalTimeFrame.Day,
fields: HistoricalFieldsType.Open|HistoricalFieldsType.High|HistoricalFieldsType.Low|HistoricalFieldsType.Close|HistoricalFieldsType.Volume|HistoricalFieldsType.Change,
contractMonth: "202610",
strikePrice: 48000m,
callPut: FutOptCallPut.Call));
var candles_cont = candles.Content.ReadAsStringAsync().Result;
Console.WriteLine(candles_cont);
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
}
]
}