# FTMarkets
[](https://badge.fury.io/py/ftgo)
[](https://www.python.org/downloads/)
[](https://opensource.org/licenses/MIT)
A Python library for fetching financial data from Financial Times Markets, including historical stock prices, ETF holdings, fund profiles, and allocation breakdowns.
## Features
- **Historical Data**: Fetch historical OHLCV data for stocks and ETFs
- **Holdings Data**: Get ETF/fund holdings, asset allocation, and sector breakdowns
- **Fund Profiles**: Access fund information, statistics, and investment details
- **Symbol Search**: Find FT Markets XIDs by ticker symbols
- **Concurrent Processing**: Fast data retrieval using multithreading
- **Pandas Integration**: Returns data as pandas DataFrames for easy analysis
## Installation
```bash
pip install ftgo
```
## Quick Start
```python
from ftgo import search_securities, get_xid, get_historical_prices, get_holdings
# Search for a security
results = search_securities('AAPL')
print(results)
# Get XID for a ticker
xid = get_xid('AAPL')
# Fetch historical data
df = get_historical_prices(xid, "01012024", "31012024")
print(df.head())
# Get ETF holdings
spy_xid = get_xid('SPY')
holdings = get_holdings(spy_xid, "top_holdings")
print(holdings)
```
## API Reference
### Search Functions
#### `search_securities(query)`
Search for securities on FT Markets.
**Parameters:**
- `query` (str): Search term for securities (ticker symbol or company name)
**Returns:** pandas.DataFrame with search results containing xid, name, symbol, asset_class, url
```python
# Search for Apple
results = search_securities('Apple')
print(results)
# Search by ticker
results = search_securities('AAPL')
```
#### `get_xid(ticker, display_mode="first")`
Get FT Markets XID for given ticker symbol.
**Parameters:**
- `ticker` (str): Ticker symbol
- `display_mode` (str): "first" to return first match XID, "all" to return all matches
**Returns:** String XID (if display_mode="first") or DataFrame (if display_mode="all")
```python
# Get XID for Apple
xid = get_xid('AAPL')
print(xid) # Returns XID string
# Get all matches
all_results = get_xid('AAPL', display_mode='all')
print(all_results)
```
### Historical Data
#### `get_historical_prices(xid, date_from, date_to)`
Get historical price data for a security with full OHLCV data.
**Parameters:**
- `xid` (str): The FT Markets XID
- `date_from` (str): Start date in DDMMYYYY format (e.g., "01012024")
- `date_to` (str): End date in DDMMYYYY format (e.g., "31122024")
**Returns:** pandas.DataFrame with columns: date, open, high, low, close, volume
```python
xid = get_xid('AAPL')
df = get_historical_prices(xid, "01012024", "31012024")
print(df.head())
```
#### `get_multiple_historical_prices(xids, date_from, date_to)`
Get historical data for multiple securities concurrently.
**Parameters:**
- `xids` (list): List of FT Markets XIDs
- `date_from` (str): Start date in DDMMYYYY format
- `date_to` (str): End date in DDMMYYYY format
**Returns:** pandas.DataFrame with concatenated data for all securities
```python
xids = [get_xid('AAPL'), get_xid('MSFT')]
df = get_multiple_historical_prices(xids, "01012024", "31012024")
```
### Holdings Data
#### `get_holdings(xid, holdings_type="all")`
Get holdings and allocation data for ETFs and funds.
**Parameters:**
- `xid` (str): The FT Markets XID
- `holdings_type` (str): Type of holdings data:
- `"asset_allocation"`: Asset class breakdown (stocks, bonds, cash)
- `"sector_weights"`: Sector allocation
- `"geographic_allocation"`: Geographic allocation
- `"top_holdings"`: Top holdings by weight
- `"all"`: All holdings data types as a tuple
**Returns:** pandas.DataFrame or tuple of DataFrames
```python
# Get top holdings for SPY ETF
spy_xid = get_xid('SPY')
top_holdings = get_holdings(spy_xid, "top_holdings")
# Get asset allocation
allocation = get_holdings(spy_xid, "asset_allocation")
# Get all holdings data
all_data = get_holdings(spy_xid, "all")
asset_alloc, sectors, regions, holdings = all_data
```
#### `get_fund_breakdown(xid)`
Get complete fund breakdown with all allocation data.
**Parameters:**
- `xid` (str): The FT Markets XID
**Returns:** Dictionary with all DataFrames
```python
qqq_xid = get_xid('QQQ')
breakdown = get_fund_breakdown(qqq_xid)
print(breakdown['asset_allocation'])
print(breakdown['top_holdings'])
```
### Fund Profile Data
#### `get_fund_profile(xid)`
Get profile and investment information for ETFs and funds.
**Parameters:**
- `xid` (str): The FT Markets XID
**Returns:** pandas.DataFrame with Field and Value columns
```python
xid = get_xid('SPY')
profile = get_fund_profile(xid)
print(profile)
# Filter for specific information
fees = profile[profile['Field'].str.contains('fee', case=False)]
```
#### `get_fund_stats(xid)`
Get fund profile data as a dictionary for easy access.
**Parameters:**
- `xid` (str): The FT Markets XID
**Returns:** Dictionary with all available fund fields and values
```python
xid = get_xid('QQQ')
stats = get_fund_stats(xid)
# Access any available field safely
inception = stats.get('Inception date', 'Not available')
fees = stats.get('Ongoing charge', 'Not available')
```
#### `get_available_fields(xid)`
Get list of all available profile fields for a fund.
**Parameters:**
- `xid` (str): The FT Markets XID
**Returns:** List of all field names available
```python
xid = get_xid('SPY')
fields = get_available_fields(xid)
print("Available fields:")
for field in fields:
print(f" - {field}")
```
#### `search_profile_field(xid, search_term)`
Search for specific fields in the fund profile data.
**Parameters:**
- `xid` (str): The FT Markets XID
- `search_term` (str): Term to search for in field names (case-insensitive)
**Returns:** pandas.DataFrame with matching fields and values
```python
xid = get_xid('SPY')
fees = search_profile_field(xid, 'fee')
inception = search_profile_field(xid, 'inception')
```
## Complete Example
```python
from ftgo import get_xid, get_historical_prices, get_holdings, get_fund_profile
import matplotlib.pyplot as plt
# Search for QQQ ETF
qqq_xid = get_xid('QQQ')
# Get 1 year of historical data
historical_data = get_historical_prices(qqq_xid, "01012023", "31122023")
# Get fund information
profile = get_fund_profile(qqq_xid)
top_holdings = get_holdings(qqq_xid, "top_holdings")
asset_allocation = get_holdings(qqq_xid, "asset_allocation")
# Plot price chart
historical_data.set_index('date')['close'].plot(title='QQQ Price History')
plt.show()
# Display fund information
print("Fund Profile:")
print(profile.head(10))
print("\nTop 10 Holdings:")
print(top_holdings.head(10))
print("\nAsset Allocation:")
print(asset_allocation)
```
## Error Handling
The library includes logging and error handling, but you should wrap calls in try-except blocks for production use:
```python
try:
xid = get_xid('INVALID_TICKER')
data = get_historical_prices(xid, "01012024", "31012024")
except ValueError as e:
print(f"Error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")
```
## Requirements
- Python 3.7+
- cloudscraper >= 1.2.68
- pandas >= 1.3.0
- beautifulsoup4 >= 4.11.0
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## Disclaimer
This library is for educational and research purposes.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
Raw data
{
"_id": null,
"home_page": "https://github.com/gohibiki/ftgo",
"name": "ftgo",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "gohibiki <gohibiki@protonmail.com>",
"keywords": "finance, stocks, etf, historical-data, financial-analysis, market-data, ft-markets, financial-times",
"author": "gohibiki",
"author_email": "gohibiki <gohibiki@protonmail.com>",
"download_url": "https://files.pythonhosted.org/packages/98/d8/06ab954883963cd3c922f699d9ee4f43bf1766344d93a42bb21b0724d245/ftgo-1.0.0.tar.gz",
"platform": null,
"description": "# FTMarkets\n\n[](https://badge.fury.io/py/ftgo)\n[](https://www.python.org/downloads/)\n[](https://opensource.org/licenses/MIT)\n\nA Python library for fetching financial data from Financial Times Markets, including historical stock prices, ETF holdings, fund profiles, and allocation breakdowns.\n\n## Features\n\n- **Historical Data**: Fetch historical OHLCV data for stocks and ETFs\n- **Holdings Data**: Get ETF/fund holdings, asset allocation, and sector breakdowns\n- **Fund Profiles**: Access fund information, statistics, and investment details\n- **Symbol Search**: Find FT Markets XIDs by ticker symbols\n- **Concurrent Processing**: Fast data retrieval using multithreading\n- **Pandas Integration**: Returns data as pandas DataFrames for easy analysis\n\n## Installation\n\n```bash\npip install ftgo\n```\n\n## Quick Start\n\n```python\nfrom ftgo import search_securities, get_xid, get_historical_prices, get_holdings\n\n# Search for a security\nresults = search_securities('AAPL')\nprint(results)\n\n# Get XID for a ticker\nxid = get_xid('AAPL')\n\n# Fetch historical data\ndf = get_historical_prices(xid, \"01012024\", \"31012024\")\nprint(df.head())\n\n# Get ETF holdings\nspy_xid = get_xid('SPY')\nholdings = get_holdings(spy_xid, \"top_holdings\")\nprint(holdings)\n```\n\n## API Reference\n\n### Search Functions\n\n#### `search_securities(query)`\n\nSearch for securities on FT Markets.\n\n**Parameters:**\n- `query` (str): Search term for securities (ticker symbol or company name)\n\n**Returns:** pandas.DataFrame with search results containing xid, name, symbol, asset_class, url\n\n```python\n# Search for Apple\nresults = search_securities('Apple')\nprint(results)\n\n# Search by ticker\nresults = search_securities('AAPL')\n```\n\n#### `get_xid(ticker, display_mode=\"first\")`\n\nGet FT Markets XID for given ticker symbol.\n\n**Parameters:**\n- `ticker` (str): Ticker symbol\n- `display_mode` (str): \"first\" to return first match XID, \"all\" to return all matches\n\n**Returns:** String XID (if display_mode=\"first\") or DataFrame (if display_mode=\"all\")\n\n```python\n# Get XID for Apple\nxid = get_xid('AAPL')\nprint(xid) # Returns XID string\n\n# Get all matches\nall_results = get_xid('AAPL', display_mode='all')\nprint(all_results)\n```\n\n### Historical Data\n\n#### `get_historical_prices(xid, date_from, date_to)`\n\nGet historical price data for a security with full OHLCV data.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n- `date_from` (str): Start date in DDMMYYYY format (e.g., \"01012024\")\n- `date_to` (str): End date in DDMMYYYY format (e.g., \"31122024\")\n\n**Returns:** pandas.DataFrame with columns: date, open, high, low, close, volume\n\n```python\nxid = get_xid('AAPL')\ndf = get_historical_prices(xid, \"01012024\", \"31012024\")\nprint(df.head())\n```\n\n#### `get_multiple_historical_prices(xids, date_from, date_to)`\n\nGet historical data for multiple securities concurrently.\n\n**Parameters:**\n- `xids` (list): List of FT Markets XIDs\n- `date_from` (str): Start date in DDMMYYYY format\n- `date_to` (str): End date in DDMMYYYY format\n\n**Returns:** pandas.DataFrame with concatenated data for all securities\n\n```python\nxids = [get_xid('AAPL'), get_xid('MSFT')]\ndf = get_multiple_historical_prices(xids, \"01012024\", \"31012024\")\n```\n\n### Holdings Data\n\n#### `get_holdings(xid, holdings_type=\"all\")`\n\nGet holdings and allocation data for ETFs and funds.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n- `holdings_type` (str): Type of holdings data:\n - `\"asset_allocation\"`: Asset class breakdown (stocks, bonds, cash)\n - `\"sector_weights\"`: Sector allocation\n - `\"geographic_allocation\"`: Geographic allocation\n - `\"top_holdings\"`: Top holdings by weight\n - `\"all\"`: All holdings data types as a tuple\n\n**Returns:** pandas.DataFrame or tuple of DataFrames\n\n```python\n# Get top holdings for SPY ETF\nspy_xid = get_xid('SPY')\ntop_holdings = get_holdings(spy_xid, \"top_holdings\")\n\n# Get asset allocation\nallocation = get_holdings(spy_xid, \"asset_allocation\")\n\n# Get all holdings data\nall_data = get_holdings(spy_xid, \"all\")\nasset_alloc, sectors, regions, holdings = all_data\n```\n\n#### `get_fund_breakdown(xid)`\n\nGet complete fund breakdown with all allocation data.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n\n**Returns:** Dictionary with all DataFrames\n\n```python\nqqq_xid = get_xid('QQQ')\nbreakdown = get_fund_breakdown(qqq_xid)\nprint(breakdown['asset_allocation'])\nprint(breakdown['top_holdings'])\n```\n\n### Fund Profile Data\n\n#### `get_fund_profile(xid)`\n\nGet profile and investment information for ETFs and funds.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n\n**Returns:** pandas.DataFrame with Field and Value columns\n\n```python\nxid = get_xid('SPY')\nprofile = get_fund_profile(xid)\nprint(profile)\n\n# Filter for specific information\nfees = profile[profile['Field'].str.contains('fee', case=False)]\n```\n\n#### `get_fund_stats(xid)`\n\nGet fund profile data as a dictionary for easy access.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n\n**Returns:** Dictionary with all available fund fields and values\n\n```python\nxid = get_xid('QQQ')\nstats = get_fund_stats(xid)\n\n# Access any available field safely\ninception = stats.get('Inception date', 'Not available')\nfees = stats.get('Ongoing charge', 'Not available')\n```\n\n#### `get_available_fields(xid)`\n\nGet list of all available profile fields for a fund.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n\n**Returns:** List of all field names available\n\n```python\nxid = get_xid('SPY')\nfields = get_available_fields(xid)\nprint(\"Available fields:\")\nfor field in fields:\n print(f\" - {field}\")\n```\n\n#### `search_profile_field(xid, search_term)`\n\nSearch for specific fields in the fund profile data.\n\n**Parameters:**\n- `xid` (str): The FT Markets XID\n- `search_term` (str): Term to search for in field names (case-insensitive)\n\n**Returns:** pandas.DataFrame with matching fields and values\n\n```python\nxid = get_xid('SPY')\nfees = search_profile_field(xid, 'fee')\ninception = search_profile_field(xid, 'inception')\n```\n\n## Complete Example\n\n```python\nfrom ftgo import get_xid, get_historical_prices, get_holdings, get_fund_profile\nimport matplotlib.pyplot as plt\n\n# Search for QQQ ETF\nqqq_xid = get_xid('QQQ')\n\n# Get 1 year of historical data\nhistorical_data = get_historical_prices(qqq_xid, \"01012023\", \"31122023\")\n\n# Get fund information\nprofile = get_fund_profile(qqq_xid)\ntop_holdings = get_holdings(qqq_xid, \"top_holdings\")\nasset_allocation = get_holdings(qqq_xid, \"asset_allocation\")\n\n# Plot price chart\nhistorical_data.set_index('date')['close'].plot(title='QQQ Price History')\nplt.show()\n\n# Display fund information\nprint(\"Fund Profile:\")\nprint(profile.head(10))\n\nprint(\"\\nTop 10 Holdings:\")\nprint(top_holdings.head(10))\n\nprint(\"\\nAsset Allocation:\")\nprint(asset_allocation)\n```\n\n## Error Handling\n\nThe library includes logging and error handling, but you should wrap calls in try-except blocks for production use:\n\n```python\ntry:\n xid = get_xid('INVALID_TICKER')\n data = get_historical_prices(xid, \"01012024\", \"31012024\")\nexcept ValueError as e:\n print(f\"Error: {e}\")\nexcept Exception as e:\n print(f\"Unexpected error: {e}\")\n```\n\n## Requirements\n\n- Python 3.7+\n- cloudscraper >= 1.2.68\n- pandas >= 1.3.0\n- beautifulsoup4 >= 4.11.0\n\n## Contributing\n\nContributions are welcome! Please feel free to submit a Pull Request.\n\n## Disclaimer\n\nThis library is for educational and research purposes.\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n",
"bugtrack_url": null,
"license": null,
"summary": "A Python library for fetching financial data from FT Markets",
"version": "1.0.0",
"project_urls": {
"Bug Reports": "https://github.com/gohibiki/ftgo/issues",
"Changelog": "https://github.com/gohibiki/ftgo/blob/main/CHANGELOG.md",
"Documentation": "https://github.com/gohibiki/ftgo#readme",
"Homepage": "https://github.com/gohibiki/ftgo",
"Repository": "https://github.com/gohibiki/ftgo"
},
"split_keywords": [
"finance",
" stocks",
" etf",
" historical-data",
" financial-analysis",
" market-data",
" ft-markets",
" financial-times"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "90d997ca37c1b12ff8f7d156bd10c6faa4d4b0845b49f140b64a0d1b29b3a00d",
"md5": "1add449dfb53138132fe975792510a5b",
"sha256": "465d515f73161c41cde3de9174fc1fc31773c3f0ae05b01086ddc457d9d0aae9"
},
"downloads": -1,
"filename": "ftgo-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "1add449dfb53138132fe975792510a5b",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 14638,
"upload_time": "2025-09-09T01:53:15",
"upload_time_iso_8601": "2025-09-09T01:53:15.266860Z",
"url": "https://files.pythonhosted.org/packages/90/d9/97ca37c1b12ff8f7d156bd10c6faa4d4b0845b49f140b64a0d1b29b3a00d/ftgo-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "98d806ab954883963cd3c922f699d9ee4f43bf1766344d93a42bb21b0724d245",
"md5": "3b0d09fb77743e66c534cce780b04f40",
"sha256": "5f6da93f3e672f661c3a134948f92c8ddb9be0cbe125c740eee1095acadbb469"
},
"downloads": -1,
"filename": "ftgo-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "3b0d09fb77743e66c534cce780b04f40",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 15206,
"upload_time": "2025-09-09T01:53:16",
"upload_time_iso_8601": "2025-09-09T01:53:16.712041Z",
"url": "https://files.pythonhosted.org/packages/98/d8/06ab954883963cd3c922f699d9ee4f43bf1766344d93a42bb21b0724d245/ftgo-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-09-09 01:53:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "gohibiki",
"github_project": "ftgo",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"requirements": [],
"lcname": "ftgo"
}