Historical Candles
Query historical futures candles by product symbol. Supports day / week / month K and minute K, regular and after-hours sessions; the contract month can be a specific month or a continuous contract 1! / 2! / 3!. 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
Parameters
| Name | Type | Description |
|---|---|---|
product* | string | Futures product symbol, e.g. TXF, MXF, CDF (upper case). 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) is not accepted as product and returns 404; see the conversion note below. Only futures are supported for now; options and spread contracts are not yet available |
contractMonth | string | Contract month, defaults to 1! (front month) if omitted. Accepts a specific month yyyyMM (e.g. 202609), a weekly contract (e.g. 202609W2), or a continuous contract: 1! front month, 2! second month, 3! third month (4! and beyond return 400) |
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) |
- Day / week / month K goes back to 2010.
- Minute K (regular and after-hours sessions) is available from 2017-06 (the after-hours session starts at 15:00 and belongs to the next trading day).
- Minute K is built from outright-order trades only; the two legs filled through spread (combination) orders and block trades are not counted, so a contract's daily K volume can exceed the sum of that day's minute K, and a day with daily K volume but no minute K is expected.
- A single query range (
from~to) must be shorter than 1 year. A range of exactly or more than 1 year returns 400 Bad Request (error message:Date range must be less than one year).frommust not be later thanto, otherwise 400 is returned as well. from/toare trading days. Per TAIFEX rules 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.- Continuous contracts (
1!/2!/3!) roll over on contract expiry: on the last trading day the alias still points to the expiring contract and switches to the next one from the following trading day;data.contractMonthon each candle shows the contract it actually belongs to. 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. - If no data exists in the query range, the API returns 404 Resource Not Found instead of an empty array (e.g. the range contains no trading days, falls entirely before the start date of that timeframe, the product symbol or contract month does not exist, or an options symbol is queried).
- If you have an intraday contract code (e.g.
TXFI6), split it into product symbol and contract month: the first 3 characters are the product symbol (TXF), the 4th is the month codeA–Lfor January–December (I= September), and the 5th is the last digit of the year (6= 2026), i.e.product=TXFwithcontractMonth=202609; the continuous aliasTXF1!maps toproduct=TXFwithcontractMonth=1!.
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) | — |
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 | All |
data.high | number | Highest Price | All |
data.low | number | Lowest Price | All |
data.close | number | Close Price | All |
data.volume | number | Volume (contracts) | 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 | Day / Week / Month K only |
How change is calculated:
- Day K: the difference from the previous trading day's close of the same contract. In a continuous-contract query,
changeon the rollover day is calculated against the new contract's own previous close, not against the previous contract. - Week / Month K: 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.