
Twelvedata
- 7.6k installs
- 18 repo stars
- Updated July 27, 2026
- starchild-ai-agent/official-skills
twelvedata is a script-mode agent skill for stocks, forex, and commodities quotes and historical bars via Twelve Data.
About
The twelvedata skill provides traditional market price data for stocks, forex, and commodities through script-mode Python exports backed by Twelve Data. It is explicitly not for crypto prices. TWELVEDATA_API_KEY is required in the environment for API access. Functions in exports.py include twelvedata_price, twelvedata_quote, and twelvedata_time_series invoked from bash Python blocks with sys.path pointed at the skill directory. Use cases cover AAPL quotes, EUR/USD charts, gold prices, and SPY historical bars. The skill ships as a single exports module with standardized proxied HTTP patterns consistent with other Starchild script-mode skills. Agents import functions directly rather than constructing raw REST calls. Use when users ask for stock quotes, forex rates, commodity prices, or historical traditional market bars excluding cryptocurrency pairs.
- Stocks, forex, and commodities data via Twelve Data API.
- Script-mode exports.py with price, quote, and time_series functions.
- Traditional markets only, explicitly not for crypto.
- TWELVEDATA_API_KEY environment requirement.
- Bash Python invocation pattern with sys.path skill directory.
Twelvedata by the numbers
- 7,553 all-time installs (skills.sh)
- +63 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #11 of 1,136 Finance & Trading skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
twelvedata capabilities & compatibility
- Capabilities
- real time quote retrieval · historical time series bars · stock forex commodity symbol lookup · script mode python export functions
- Use cases
- trading · research · data analysis
- Pricing
- Bring your own API key
What twelvedata says it does
Stocks, forex, and commodities prices: real-time quotes and historical bars.
Traditional markets only — not for crypto.
npx skills add https://github.com/starchild-ai-agent/official-skills --skill twelvedataAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 7.6k |
|---|---|
| repo stars | ★ 18 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | starchild-ai-agent/official-skills ↗ |
How do I look up AAPL, EUR/USD, or gold prices with historical bars from an agent script?
Fetch stocks, forex, and commodities real-time quotes and historical bars via Twelve Data script-mode exports.
Who is it for?
Developers fetching traditional market prices and historical bars, not cryptocurrency data.
Skip if: Skip for crypto token prices; this skill covers traditional markets only.
When should I use this skill?
User asks for stock quote, forex rate, commodity price, or SPY historical chart data.
What you get
Structured quote or time series data from Twelve Data for traditional market symbols.
- registered market-data tools
- quote and time-series responses
Files
Twelve Data
Stocks, forex, and commodities price data. Traditional markets only — not for crypto.
Script Usage
This skill ships a single exports.py with all functions. Call it from a bash block:
python3 - <<'EOF'
import sys, json
sys.path.insert(0, "/data/workspace/skills/twelvedata")
from exports import twelvedata_price, twelvedata_quote, twelvedata_time_series
# Single quote
print(twelvedata_quote(symbol="AAPL"))
# Time series (last 30 daily candles)
series = twelvedata_time_series(symbol="AAPL", interval="1day", outputsize=30)
print(json.dumps(series.get("values", [])[:3], indent=2))
EOFAvailable functions in exports.py: twelvedata_price, twelvedata_quote, twelvedata_time_series, twelvedata_eod, twelvedata_quote_batch, twelvedata_price_batch, twelvedata_search, twelvedata_stocks, twelvedata_forex_pairs, twelvedata_exchanges. Read exports.py directly when you need exact signatures.
Function Reference (signatures)
All functions are in exports.py. Symbols use TwelveData format (e.g. AAPL, EUR/USD, XAU/USD). Use prepost=True for pre/post-market data on US stocks.
| Function | Description |
|---|---|
twelvedata_price(symbol, prepost=False) | Current price for one symbol. |
twelvedata_price_batch(symbols, prepost=False) | Prices for multiple symbols (symbols = comma-separated string). |
twelvedata_quote(symbol, prepost=False) | Detailed quote: price, volume, 52w high/low, change %. |
twelvedata_quote_batch(symbols, prepost=False) | Detailed quotes for multiple symbols. |
twelvedata_time_series(symbol, interval='1day', outputsize=30, start_date=None, end_date=None, prepost=False) | OHLCV bars. interval = 1min/5min/15min/30min/1h/2h/4h/1day/1week/1month. |
twelvedata_eod(symbol, date=None, prepost=False) | End-of-day price for a date (default: latest). |
twelvedata_search(query) | Search symbols by name or ticker. |
twelvedata_stocks(exchange=None, country=None) | List supported stocks (filterable). |
twelvedata_forex_pairs() | List all supported forex pairs. |
twelvedata_exchanges() | List supported exchanges. |
Keyword → Tool Lookup
| User asks about | Tool | NOT this |
|---|---|---|
| "AAPL 股价", "current price" (single) | twelvedata_quote | Not twelvedata_price (less detail) |
| "just the price number" | twelvedata_price | — |
| "多只股票对比" (2+ symbols) | twelvedata_quote_batch | Not multiple twelvedata_quote calls |
| "K线", "历史数据", "time series" | twelvedata_time_series | — |
| "收盘价" | twelvedata_eod | — |
| "找股票代码" | twelvedata_search | — |
| "NASDAQ 有哪些股票" | twelvedata_stocks | — |
| "汇率", "EUR/USD" | twelvedata_quote(symbol="EUR/USD") | — |
| "外汇对列表" | twelvedata_forex_pairs | — |
| "金价", "oil price" | twelvedata_quote(symbol="XAU/USD") | Not CoinGecko |
| "BTC price", any crypto | CoinGecko coin_price | ❌ Never twelvedata for crypto |
TwelveData vs CoinGecko — Boundary
| Asset class | Use | Why |
|---|---|---|
| Stocks (AAPL, TSLA) | TwelveData | CoinGecko has no stocks |
| Forex (EUR/USD) | TwelveData | CoinGecko has no forex |
| Commodities (gold, oil) | TwelveData | CoinGecko has no commodities |
| Crypto (BTC, ETH, SOL) | CoinGecko | TwelveData crypto data is limited/unreliable |
MISTAKES — Read Before Calling
❌ MISTAKE 1: Using TwelveData for crypto
User: "BTC 价格"
❌ WRONG: twelvedata_quote(symbol="BTC/USD")
✅ RIGHT: coin_price(ids="bitcoin") ← CoinGecko❌ MISTAKE 2: Calling quote individually for multiple stocks
User: "AAPL MSFT GOOGL 现在什么价"
❌ WRONG: twelvedata_quote("AAPL"), twelvedata_quote("MSFT"), twelvedata_quote("GOOGL") ← 3 calls
✅ RIGHT: twelvedata_quote_batch(symbols=["AAPL", "MSFT", "GOOGL"]) ← 1 call, up to 120 symbols❌ MISTAKE 3: Forex without slash
❌ WRONG: twelvedata_quote(symbol="EURUSD")
✅ RIGHT: twelvedata_quote(symbol="EUR/USD") ← always slash formatAlso: USD/CNH not USDCNH, GBP/JPY not GBPJPY.
❌ MISTAKE 4: Expecting bid/ask from quote
❌ WRONG: "EUR/USD bid: 1.0850, ask: 1.0852" ← quote only returns close
✅ RIGHT: "EUR/USD current price: 1.0851 (close/last price — bid/ask spread not available)"❌ MISTAKE 5: Wrong interval format
❌ WRONG: twelvedata_time_series(interval="1D") ← uppercase
✅ RIGHT: twelvedata_time_series(interval="1day")Valid: 1min, 5min, 15min, 30min, 1h, 2h, 4h, 8h, 1day, 1week, 1month
❌ MISTAKE 6: Using full output when compact suffices
User: "AAPL 最近走势"
❌ WRONG: twelvedata_time_series(symbol="AAPL", interval="1day", outputsize="full") ← 5000 candles
✅ RIGHT: twelvedata_time_series(symbol="AAPL", interval="1day", outputsize="compact") ← 30 candlesUse full only when user explicitly needs deep history.
Symbol Reference
Commodities (verified)
| Asset | Symbol |
|---|---|
| Gold | XAU/USD |
| Silver | XAG/USD |
| Platinum | XPT/USD |
| Palladium | XPD/USD |
| Crude Oil (WTI) | WTI/USD |
| Natural Gas | NG/USD |
Popular Forex Pairs
| Pair | Symbol |
|---|---|
| Euro / USD | EUR/USD |
| GBP / USD | GBP/USD |
| USD / JPY | USD/JPY |
| USD / CNH | USD/CNH |
Use twelvedata_search to discover others.
Pre/Post-Market Data
twelvedata_quote(symbol="AAPL", prepost=true)
twelvedata_time_series(symbol="AAPL", interval="1min", prepost=true)Returns premarket_change, premarket_change_percent, postmarket_change, postmarket_change_percent when available.
Output Sizes
compact— Last 30 data points (default, faster). Use for "最近走势".full— Up to 5000 data points. Use for deep analysis / charting.
Proxy-Safe Usage
1. Agent tool calls: Always prefer twelvedata_* tools (this skill). 2. Platform code (skills/, tools/): use core.http_client. 3. Workspace scripts (bash): Do NOT call TwelveData directly. Use skill tools.
Compound Queries
Stock Comparison
1. twelvedata_quote_batch(symbols=["AAPL", "MSFT", "GOOGL", "TSLA"])
2. twelvedata_time_series(symbol="AAPL", interval="1day", outputsize="compact") ← only for the one user cares most aboutMacro Dashboard (stocks + forex + commodities)
1. twelvedata_quote_batch(symbols=["SPY", "QQQ"]) → US indices
2. twelvedata_quote_batch(symbols=["EUR/USD", "USD/JPY"]) → Forex
3. twelvedata_quote(symbol="XAU/USD") → Gold"""
Twelve Data Extension - Stocks and Forex Market Data
Provides stocks and forex market data including:
- Real-time quotes (with pre/post-market support)
- Historical time series (OHLCV)
- Reference data (stocks, forex pairs, exchanges)
- Search
Environment Variables Required:
- TWELVEDATA_API_KEY: Twelve Data Pro API key
"""
import os
import sys
import logging
from typing import List
logger = logging.getLogger(__name__)
# Add local tools directory to path for imports
TOOLS_DIR = os.path.join(os.path.dirname(__file__), 'tools')
if TOOLS_DIR not in sys.path:
sys.path.insert(0, TOOLS_DIR)
def register(api) -> List[str]:
"""Extension entry point - register all Twelve Data tools."""
registered = []
try:
from .tools.time_series import (
TwelveDataTimeSeriesTools,
TwelveDataPriceTool,
TwelveDataEODTool,
)
from .tools.quote import (
TwelveDataQuoteTool,
TwelveDataQuoteBatchTool,
TwelveDataPriceBatchTool,
)
from .tools.reference_data import (
TwelveDataSearchTool,
TwelveDataStocksTool,
TwelveDataForexPairsTool,
TwelveDataExchangesTool,
)
tools = [
TwelveDataTimeSeriesTools(),
TwelveDataPriceTool(),
TwelveDataEODTool(),
TwelveDataQuoteTool(),
TwelveDataQuoteBatchTool(),
TwelveDataPriceBatchTool(),
TwelveDataSearchTool(),
TwelveDataStocksTool(),
TwelveDataForexPairsTool(),
TwelveDataExchangesTool(),
]
for tool in tools:
api.register_tool(tool)
registered.append(tool.name)
logger.info(f"Registered {len(registered)} Twelve Data tools (Pro tier)")
except Exception as e:
logger.warning(f"Failed to load Twelve Data tools: {e}")
return registered
EXTENSION_INFO = {
"name": "twelvedata",
"version": "1.1.0",
"description": "Twelve Data stocks and forex market data tools (with pre/post-market support)",
}
"""
TwelveData skill exports — script-mode skill.
Usage from a bash block:
python3 - <<'EOF'
import sys
sys.path.insert(0, "/data/workspace/skills/twelvedata")
from exports import twelvedata_price, twelvedata_time_series
print(twelvedata_price(symbol="AAPL"))
EOF
Imports from sidecar.proxy_client (NOT core.http_client) so this skill
stays runnable without the agent platform's core/* modules on PYTHONPATH.
"""
import os
# Make sidecar/ importable when the script is invoked directly via
# `python3 -c` from the agent's bash tool. /app is already on PYTHONPATH
# inside the container (set by entrypoint.sh), so `from sidecar...` works
# in production. The fallback covers local-dev runs from outside /app.
try:
from sidecar.proxy_client import proxied_get
except ImportError:
# Local dev / running outside the deployed image: fall back to
# core.http_client which is identical. Skill still works either way.
from core.http_client import proxied_get
API_KEY = os.environ.get("TWELVEDATA_API_KEY", "")
BASE = "https://api.twelvedata.com"
def _explain_error(code, body):
"""Map a TwelveData error code to a short, actionable message.
Never echoes the raw JSON body back to the agent (issue #243)."""
code = str(code)
msg = ""
if isinstance(body, dict):
msg = str(body.get("message", "")).strip()
if code == "404":
return (
"Symbol not found in TwelveData. Check the spelling, or use "
"twelvedata_search to find the correct ticker."
)
if code == "401":
return "TwelveData API key is invalid or missing (TWELVEDATA_API_KEY)."
if code == "429":
return "TwelveData rate limit hit. Wait before retrying."
# Generic: include the upstream message text only (not the full JSON).
return f"TwelveData API error {code}" + (f": {msg}" if msg else "")
def _get(endpoint, params=None):
"""Make a GET request to TwelveData API.
TwelveData signals invalid symbols in two ways:
- an HTTP 4xx status, or
- HTTP 200 with an error envelope {"code": 404, "status": "error",
"message": ...} in the body.
Both are normalised into a clean RuntimeError so the agent sees an
actionable message instead of a raw JSON dump (issue #243)."""
if params is None:
params = {}
params["apikey"] = API_KEY
r = proxied_get(f"{BASE}/{endpoint}", params=params)
# Non-2xx: surface a short readable error, not the raw body.
if r.status_code >= 400:
try:
body = r.json()
except Exception:
body = {}
raise RuntimeError(_explain_error(body.get("code", r.status_code), body))
data = r.json()
# TwelveData frequently returns HTTP 200 with an error envelope.
if isinstance(data, dict) and str(data.get("status")) == "error":
raise RuntimeError(_explain_error(data.get("code", r.status_code), data))
return data
def twelvedata_time_series(symbol, interval="1day", outputsize=30, start_date=None, end_date=None, prepost=False):
"""Get OHLCV time series data."""
params = {"symbol": symbol, "interval": interval, "outputsize": outputsize}
if start_date:
params["start_date"] = start_date
if end_date:
params["end_date"] = end_date
if prepost:
params["prepost"] = "true"
return _get("time_series", params)
def twelvedata_price(symbol, prepost=False):
"""Get current price for a symbol."""
params = {"symbol": symbol}
if prepost:
params["prepost"] = "true"
return _get("price", params)
def twelvedata_eod(symbol, date=None, prepost=False):
"""Get end-of-day price."""
params = {"symbol": symbol}
if date:
params["date"] = date
if prepost:
params["prepost"] = "true"
return _get("eod", params)
def twelvedata_quote(symbol, prepost=False):
"""Get detailed quote (price, volume, 52w high/low, change %)."""
params = {"symbol": symbol}
if prepost:
params["prepost"] = "true"
return _get("quote", params)
def twelvedata_quote_batch(symbols, prepost=False):
"""Get quotes for multiple symbols. symbols: comma-separated string."""
params = {"symbol": symbols}
if prepost:
params["prepost"] = "true"
return _get("quote", params)
def twelvedata_price_batch(symbols, prepost=False):
"""Get prices for multiple symbols. symbols: comma-separated string."""
params = {"symbol": symbols}
if prepost:
params["prepost"] = "true"
return _get("price", params)
def twelvedata_search(query):
"""Search for symbols by name or ticker."""
return _get("symbol_search", {"symbol": query})
def twelvedata_stocks(exchange=None, country=None):
"""Get list of available stocks, optionally filtered."""
params = {}
if exchange:
params["exchange"] = exchange
if country:
params["country"] = country
return _get("stocks", params)
def twelvedata_forex_pairs():
"""Get all available forex pairs."""
return _get("forex_pairs")
def twelvedata_exchanges():
"""Get list of supported exchanges."""
return _get("exchanges")
"""
Twelve Data Integration Tools
Professional stocks and forex market data via Twelve Data API.
"""
"""
Twelve Data API Client — Async HTTP client for stocks and forex market data.
Supports stocks and forex (FX) data via REST API.
Configured for Pro subscription tier endpoints only.
Environment Variables:
- TWELVEDATA_API_KEY: Twelve Data API key (required, get from twelvedata.com)
Supported Endpoints (Pro Tier):
- Time series data (price, quote, EOD, historical OHLCV)
- Reference data (search, stocks list, forex pairs, exchanges)
- Batch requests (multiple symbols)
Not Included (Requires Grow/Pro+/Ultra/Enterprise):
- Fundamental data (financials, statistics, earnings)
- Executive data (key executives, compensation)
API Documentation: https://twelvedata.com/docs
"""
import logging
import os
from typing import Any, Dict, Optional, List
import aiohttp
from core.http_client import get_aiohttp_proxy_kwargs
from core.tool import ToolResult
logger = logging.getLogger(__name__)
# ── Singleton client ──────────────────────────────────────────────
_client: Optional["TwelveDataClient"] = None
def get_client() -> "TwelveDataClient":
"""Return a shared TwelveDataClient singleton."""
global _client
if _client is None:
_client = TwelveDataClient()
return _client
def handle_api_error(e: Exception) -> ToolResult:
"""Unified error handler for all Twelve Data tool execute() methods."""
error_str = str(e)
if "401" in error_str:
return ToolResult(
success=False,
error="API key error. The TWELVEDATA_API_KEY may be invalid or missing.",
)
if "429" in error_str:
return ToolResult(
success=False,
error="Rate limit exceeded. Please wait before making more requests.",
)
return ToolResult(success=False, error=f"Twelve Data API error: {error_str}")
# API Configuration
BASE_URL = "https://api.twelvedata.com"
# Supported intervals for time series
INTERVALS = ["1min", "5min", "15min", "30min", "45min", "1h", "2h", "4h", "8h", "1day", "1week", "1month"]
class TwelveDataClient:
"""
Async Twelve Data client for stocks and forex.
All methods call the Twelve Data REST API with API key authentication.
Supports both header and query parameter authentication methods.
"""
def __init__(self, api_key: Optional[str] = None):
self.api_key = api_key or os.environ.get("TWELVEDATA_API_KEY", "")
if not self.api_key:
logger.warning("TWELVEDATA_API_KEY not set — API calls will fail")
# ── Internal helpers ─────────────────────────────────────────────────
async def _get(self, endpoint: str, params: Optional[Dict[str, Any]] = None) -> Any:
"""GET request to Twelve Data API with API key auth."""
url = f"{BASE_URL}/{endpoint}"
# Add API key to params (can also use header: Authorization: apikey YOUR_KEY)
if params is None:
params = {}
params["apikey"] = self.api_key
headers = {
"Accept": "application/json",
}
proxy_kw = get_aiohttp_proxy_kwargs(url)
async with aiohttp.ClientSession() as session:
async with session.get(
url,
headers=headers,
params=params,
timeout=aiohttp.ClientTimeout(total=30),
**proxy_kw,
) as resp:
if resp.status >= 400:
body = await resp.text()
raise Exception(f"Twelve Data API {resp.status}: {body}")
return await resp.json()
# ── Time Series & Price Data ─────────────────────────────────────────
async def get_time_series(
self,
symbol: str,
interval: str = "1day",
outputsize: int = 30,
start_date: Optional[str] = None,
end_date: Optional[str] = None,
prepost: bool = False,
) -> dict:
"""
Get historical OHLCV time series data.
Args:
symbol: Stock symbol (AAPL, MSFT) or forex pair (EUR/USD, GBP/JPY)
interval: Time interval (1min, 5min, 15min, 30min, 1h, 4h, 1day, 1week, 1month)
outputsize: Number of data points to return (1-5000). Default 30.
start_date: Start date in YYYY-MM-DD format (optional)
end_date: End date in YYYY-MM-DD format (optional)
Returns:
dict with meta and values (OHLCV data)
"""
params = {
"symbol": symbol,
"interval": interval,
"outputsize": outputsize,
}
if start_date:
params["start_date"] = start_date
if end_date:
params["end_date"] = end_date
if prepost:
params["prepost"] = "true"
return await self._get("time_series", params)
async def get_quote(self, symbol: str, prepost: bool = False) -> dict:
"""
Get real-time quote for a stock or forex pair.
Args:
symbol: Stock symbol (AAPL) or forex pair (EUR/USD)
prepost: Include pre/post-market data when available (US/Cboe Europe, Pro+)
Returns:
dict with current price, open, high, low, volume, change, etc.
"""
params = {"symbol": symbol}
if prepost:
params["prepost"] = "true"
return await self._get("quote", params)
async def get_price(self, symbol: str, prepost: bool = False) -> dict:
"""
Get latest trading price.
Args:
symbol: Stock symbol or forex pair
prepost: Include pre/post-market data when available (US/Cboe Europe, Pro+)
Returns:
dict with price value
"""
params = {"symbol": symbol}
if prepost:
params["prepost"] = "true"
return await self._get("price", params)
async def get_eod(self, symbol: str, date: Optional[str] = None, prepost: bool = False) -> dict:
"""
Get end-of-day price.
Args:
symbol: Stock symbol or forex pair
date: Specific date in YYYY-MM-DD format (optional, defaults to latest)
prepost: Include pre/post-market data when available (US/Cboe Europe, Pro+)
Returns:
dict with EOD price data
"""
params = {"symbol": symbol}
if date:
params["date"] = date
if prepost:
params["prepost"] = "true"
return await self._get("eod", params)
# ── Reference Data ───────────────────────────────────────────────────
async def search_symbol(self, query: str) -> dict:
"""
Search for stocks or forex pairs by name or symbol.
Args:
query: Search query (company name, stock symbol, or currency pair)
Returns:
dict with search results array
"""
params = {"symbol": query}
return await self._get("symbol_search", params)
async def get_stocks(
self,
exchange: Optional[str] = None,
country: Optional[str] = None,
) -> dict:
"""
Get list of available stocks.
Args:
exchange: Filter by exchange (NASDAQ, NYSE, etc.)
country: Filter by country code (US, GB, etc.)
Returns:
dict with stocks array
"""
params = {}
if exchange:
params["exchange"] = exchange
if country:
params["country"] = country
return await self._get("stocks", params)
async def get_forex_pairs(self) -> dict:
"""
Get list of available forex pairs.
Returns:
dict with forex pairs array
"""
return await self._get("forex_pairs")
async def get_exchanges(self) -> dict:
"""
Get list of supported exchanges.
Returns:
dict with exchanges array
"""
return await self._get("exchanges")
# ── Batch Requests ───────────────────────────────────────────────────
async def get_quote_batch(self, symbols: List[str], prepost: bool = False) -> dict:
"""
Get quotes for multiple symbols in one request.
Args:
symbols: List of stock symbols or forex pairs (max 120)
prepost: Include pre/post-market data when available (US/Cboe Europe, Pro+)
Returns:
dict with quotes for each symbol
"""
if len(symbols) > 120:
logger.warning(f"Maximum 120 symbols per batch request. Truncating from {len(symbols)} to 120.")
symbols = symbols[:120]
params = {"symbol": ",".join(symbols)}
if prepost:
params["prepost"] = "true"
return await self._get("quote", params)
async def get_price_batch(self, symbols: List[str], prepost: bool = False) -> dict:
"""
Get prices for multiple symbols in one request.
Args:
symbols: List of stock symbols or forex pairs (max 120)
prepost: Include pre/post-market data when available (US/Cboe Europe, Pro+)
Returns:
dict with prices for each symbol
"""
if len(symbols) > 120:
logger.warning(f"Maximum 120 symbols per batch request. Truncating from {len(symbols)} to 120.")
symbols = symbols[:120]
params = {"symbol": ",".join(symbols)}
if prepost:
params["prepost"] = "true"
return await self._get("price", params)
"""
Twelve Data Quote Tools — Real-time market quotes for stocks and forex.
Provides tools for fetching current market data including price, volume, and 52-week metrics.
"""
import logging
from typing import List
from core.tool import BaseTool, ToolContext, ToolResult
from .client import get_client, handle_api_error
logger = logging.getLogger(__name__)
class TwelveDataQuoteTool(BaseTool):
"""Get real-time quote for a stock or forex pair."""
@property
def name(self) -> str:
return "twelvedata_quote"
@property
def description(self) -> str:
return """Get real-time market quote for a stock or forex pair.
Returns comprehensive current market data including:
- Current price, open, high, low, close
- Volume and trading data
- Price change and percent change
- 52-week high and low
- Previous close and timestamp
Use this for current market analysis and live monitoring.
Parameters:
- symbol: Stock symbol (e.g., AAPL, MSFT, TSLA) or forex pair (e.g., EUR/USD, GBP/JPY)
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: Real-time quote with all current market metrics"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol (AAPL, MSFT) or forex pair (EUR/USD, GBP/JPY)",
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbol"],
}
async def execute(self, ctx: ToolContext, symbol: str = "", prepost: bool = False, **kwargs) -> ToolResult:
if not symbol:
return ToolResult(success=False, error="'symbol' is required")
try:
data = await get_client().get_quote(symbol=symbol, prepost=prepost)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataQuoteBatchTool(BaseTool):
"""Get real-time quotes for multiple stocks or forex pairs at once."""
@property
def name(self) -> str:
return "twelvedata_quote_batch"
@property
def description(self) -> str:
return """Get real-time quotes for multiple stocks or forex pairs in a single API call.
Efficient way to fetch market data for multiple symbols simultaneously. Maximum 120 symbols per request.
Parameters:
- symbols: Array of stock symbols or forex pairs (max 120)
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: Quotes for all requested symbols"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbols": {
"type": "array",
"items": {"type": "string"},
"description": "Array of stock symbols or forex pairs (max 120)",
"minItems": 1,
"maxItems": 120,
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbols"],
}
async def execute(self, ctx: ToolContext, symbols: List[str] = None, prepost: bool = False, **kwargs) -> ToolResult:
if not symbols:
return ToolResult(success=False, error="'symbols' array is required and must not be empty")
try:
data = await get_client().get_quote_batch(symbols=symbols, prepost=prepost)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataPriceBatchTool(BaseTool):
"""Get latest prices for multiple stocks or forex pairs at once."""
@property
def name(self) -> str:
return "twelvedata_price_batch"
@property
def description(self) -> str:
return """Get latest trading prices for multiple stocks or forex pairs in a single API call.
Lightweight endpoint for quick price checks on multiple symbols. Maximum 120 symbols per request.
Parameters:
- symbols: Array of stock symbols or forex pairs (max 120)
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: Current prices for all requested symbols"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbols": {
"type": "array",
"items": {"type": "string"},
"description": "Array of stock symbols or forex pairs (max 120)",
"minItems": 1,
"maxItems": 120,
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbols"],
}
async def execute(self, ctx: ToolContext, symbols: List[str] = None, prepost: bool = False, **kwargs) -> ToolResult:
if not symbols:
return ToolResult(success=False, error="'symbols' array is required and must not be empty")
try:
data = await get_client().get_price_batch(symbols=symbols, prepost=prepost)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
"""
Twelve Data Reference Data Tools — Search and discover stocks and forex pairs.
Provides tools for searching symbols, listing available stocks, forex pairs, and exchanges.
"""
import logging
from core.tool import BaseTool, ToolContext, ToolResult
from .client import get_client, handle_api_error
logger = logging.getLogger(__name__)
class TwelveDataSearchTool(BaseTool):
"""Search for stocks or forex pairs by name or symbol."""
@property
def name(self) -> str:
return "twelvedata_search"
@property
def description(self) -> str:
return """Search for stocks or forex pairs by company name, symbol, or currency.
Use this to find the correct symbol before fetching quotes or time series data.
Examples:
- Search for "Apple" to find AAPL
- Search for "EUR" to find EUR/USD and other EUR pairs
- Search for "MSFT" to get Microsoft details
Parameters:
- query: Search query (company name, stock symbol, or currency pair)
Returns: Array of matching symbols with name, exchange, type, and currency info"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Search query (company name, stock symbol, or currency)",
},
},
"required": ["query"],
}
async def execute(self, ctx: ToolContext, query: str = "", **kwargs) -> ToolResult:
if not query:
return ToolResult(success=False, error="'query' is required")
try:
data = await get_client().search_symbol(query=query)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataStocksTool(BaseTool):
"""Get list of available stocks, optionally filtered by exchange or country."""
@property
def name(self) -> str:
return "twelvedata_stocks"
@property
def description(self) -> str:
return """Get list of available stocks on Twelve Data.
Can filter by exchange (NASDAQ, NYSE, etc.) or country (US, GB, etc.) to narrow results.
Parameters:
- exchange: (optional) Filter by exchange code (e.g., NASDAQ, NYSE, LSE)
- country: (optional) Filter by country code (e.g., US, GB, JP)
Returns: Array of stocks with symbol, name, currency, exchange, and type"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"exchange": {
"type": "string",
"description": "Filter by exchange code (NASDAQ, NYSE, etc.) - optional",
},
"country": {
"type": "string",
"description": "Filter by country code (US, GB, JP, etc.) - optional",
},
},
}
async def execute(self, ctx: ToolContext, exchange: str = "", country: str = "", **kwargs) -> ToolResult:
try:
data = await get_client().get_stocks(
exchange=exchange if exchange else None,
country=country if country else None,
)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataForexPairsTool(BaseTool):
"""Get list of available forex pairs."""
@property
def name(self) -> str:
return "twelvedata_forex_pairs"
@property
def description(self) -> str:
return """Get list of all available forex (currency) pairs on Twelve Data.
Returns major, minor, and exotic forex pairs including:
- Major pairs: EUR/USD, GBP/USD, USD/JPY, etc.
- Minor pairs: EUR/GBP, GBP/JPY, etc.
- Exotic pairs: USD/TRY, EUR/HUF, etc.
No parameters required.
Returns: Array of forex pairs with symbol, currency base, currency quote"""
@property
def parameters(self) -> dict:
return {"type": "object", "properties": {}}
async def execute(self, ctx: ToolContext, **kwargs) -> ToolResult:
try:
data = await get_client().get_forex_pairs()
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataExchangesTool(BaseTool):
"""Get list of supported stock exchanges."""
@property
def name(self) -> str:
return "twelvedata_exchanges"
@property
def description(self) -> str:
return """Get list of all supported stock exchanges on Twelve Data.
Returns global exchanges including NASDAQ, NYSE, LSE, TSE, and many more.
No parameters required.
Returns: Array of exchanges with name, code, country, and timezone"""
@property
def parameters(self) -> dict:
return {"type": "object", "properties": {}}
async def execute(self, ctx: ToolContext, **kwargs) -> ToolResult:
try:
data = await get_client().get_exchanges()
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
"""
Twelve Data Time Series Tools — Historical OHLCV data for stocks and forex.
Provides tools for fetching historical price data and end-of-day prices.
"""
import logging
from core.tool import BaseTool, ToolContext, ToolResult
from .client import get_client, handle_api_error, INTERVALS
logger = logging.getLogger(__name__)
class TwelveDataTimeSeriesTools(BaseTool):
"""Get historical OHLCV time series data."""
@property
def name(self) -> str:
return "twelvedata_time_series"
@property
def description(self) -> str:
return """Get historical OHLCV (Open, High, Low, Close, Volume) time series data for stocks and forex pairs.
Use this for historical price analysis, backtesting, and charting. Supports multiple intervals from 1-minute to monthly data.
Parameters:
- symbol: Stock symbol (e.g., AAPL, MSFT, TSLA) or forex pair (e.g., EUR/USD, GBP/JPY)
- interval: Time interval - 1min, 5min, 15min, 30min, 1h, 4h, 1day, 1week, 1month (default: 1day)
- outputsize: Number of data points to return (1-5000, default: 30). Common values: 30 (compact), 100, 500, 5000 (maximum)
- start_date: (optional) Start date in YYYY-MM-DD format
- end_date: (optional) End date in YYYY-MM-DD format
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: Historical OHLCV data with metadata including symbol, exchange, currency, and interval"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol (AAPL, MSFT) or forex pair (EUR/USD, GBP/JPY)",
},
"interval": {
"type": "string",
"description": "Time interval: 1min, 5min, 15min, 30min, 45min, 1h, 2h, 4h, 8h, 1day, 1week, 1month (default: 1day)",
"enum": INTERVALS,
},
"outputsize": {
"type": "integer",
"description": "Number of data points to return (1-5000). Default 30.",
"minimum": 1,
"maximum": 5000,
},
"start_date": {
"type": "string",
"description": "Start date in YYYY-MM-DD format (optional)",
},
"end_date": {
"type": "string",
"description": "End date in YYYY-MM-DD format (optional)",
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbol"],
}
async def execute(
self,
ctx: ToolContext,
symbol: str = "",
interval: str = "1day",
outputsize: int = 30,
start_date: str = "",
end_date: str = "",
prepost: bool = False,
**kwargs,
) -> ToolResult:
if not symbol:
return ToolResult(success=False, error="'symbol' is required")
if interval not in INTERVALS:
return ToolResult(success=False, error=f"Invalid interval '{interval}'. Must be one of: {', '.join(INTERVALS)}")
try:
data = await get_client().get_time_series(
symbol=symbol,
interval=interval,
outputsize=outputsize,
start_date=start_date if start_date else None,
end_date=end_date if end_date else None,
prepost=prepost,
)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataPriceTool(BaseTool):
"""Get latest trading price for a stock or forex pair."""
@property
def name(self) -> str:
return "twelvedata_price"
@property
def description(self) -> str:
return """Get the latest available trading price for a stock or forex pair.
This is a lightweight endpoint for quick price checks without full quote data.
Parameters:
- symbol: Stock symbol (AAPL, MSFT) or forex pair (EUR/USD, GBP/JPY)
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: Current price value"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol or forex pair",
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbol"],
}
async def execute(self, ctx: ToolContext, symbol: str = "", prepost: bool = False, **kwargs) -> ToolResult:
if not symbol:
return ToolResult(success=False, error="'symbol' is required")
try:
data = await get_client().get_price(symbol=symbol, prepost=prepost)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
class TwelveDataEODTool(BaseTool):
"""Get end-of-day closing price for a stock or forex pair."""
@property
def name(self) -> str:
return "twelvedata_eod"
@property
def description(self) -> str:
return """Get end-of-day (EOD) closing price for a stock or forex pair.
Useful for daily analysis and reports. Returns the closing price for the most recent trading day or a specific date.
Parameters:
- symbol: Stock symbol (AAPL, MSFT) or forex pair (EUR/USD, GBP/JPY)
- date: (optional) Specific date in YYYY-MM-DD format (defaults to latest available)
- prepost: (optional) Include pre/post-market data when available (US/Cboe Europe, Pro+ only)
Returns: EOD price data with close, high, low, open, volume"""
@property
def parameters(self) -> dict:
return {
"type": "object",
"properties": {
"symbol": {
"type": "string",
"description": "Stock symbol or forex pair",
},
"date": {
"type": "string",
"description": "Specific date in YYYY-MM-DD format (optional)",
},
"prepost": {
"type": "boolean",
"description": "Include pre/post-market data when available (US/Cboe Europe, Pro+ only)",
},
},
"required": ["symbol"],
}
async def execute(self, ctx: ToolContext, symbol: str = "", date: str = "", prepost: bool = False, **kwargs) -> ToolResult:
if not symbol:
return ToolResult(success=False, error="'symbol' is required")
try:
data = await get_client().get_eod(
symbol=symbol,
date=date if date else None,
prepost=prepost,
)
if data.get("status") == "error":
return ToolResult(success=False, error=f"API Error: {data.get('message', 'Unknown error')}")
return ToolResult(success=True, output=data)
except Exception as e:
return handle_api_error(e)
Related skills
FAQ
What data does the Twelve Data skill provide?
The Twelve Data skill exposes real-time stock and forex quotes, historical OHLCV time series, reference data for stocks, forex pairs, and exchanges, plus symbol search. Pre- and post-market quote support is included for equities.
What API key does Twelve Data require?
The Twelve Data extension requires a `TWELVEDATA_API_KEY` environment variable tied to a Twelve Data Pro API key. The Python `register(api)` entry point loads tools from a local `tools` directory after the key is set.
Is Twelvedata safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.