ftgo 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ftgo-1.0.0/LICENSE +21 -0
- ftgo-1.0.0/MANIFEST.in +7 -0
- ftgo-1.0.0/PKG-INFO +353 -0
- ftgo-1.0.0/README.md +303 -0
- ftgo-1.0.0/ftgo/__init__.py +29 -0
- ftgo-1.0.0/ftgo/historical.py +237 -0
- ftgo-1.0.0/ftgo/holdings.py +292 -0
- ftgo-1.0.0/ftgo/infos.py +239 -0
- ftgo-1.0.0/ftgo/search.py +160 -0
- ftgo-1.0.0/ftgo.egg-info/PKG-INFO +353 -0
- ftgo-1.0.0/ftgo.egg-info/SOURCES.txt +18 -0
- ftgo-1.0.0/ftgo.egg-info/dependency_links.txt +1 -0
- ftgo-1.0.0/ftgo.egg-info/entry_points.txt +2 -0
- ftgo-1.0.0/ftgo.egg-info/requires.txt +15 -0
- ftgo-1.0.0/ftgo.egg-info/top_level.txt +1 -0
- ftgo-1.0.0/pyproject.toml +150 -0
- ftgo-1.0.0/requirements-dev.txt +30 -0
- ftgo-1.0.0/requirements.txt +3 -0
- ftgo-1.0.0/setup.cfg +4 -0
- ftgo-1.0.0/setup.py +35 -0
ftgo-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 gohibiki
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
ftgo-1.0.0/MANIFEST.in
ADDED
ftgo-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ftgo
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A Python library for fetching financial data from FT Markets
|
|
5
|
+
Home-page: https://github.com/gohibiki/ftgo
|
|
6
|
+
Author: gohibiki
|
|
7
|
+
Author-email: gohibiki <gohibiki@protonmail.com>
|
|
8
|
+
Maintainer-email: gohibiki <gohibiki@protonmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
Project-URL: Homepage, https://github.com/gohibiki/ftgo
|
|
11
|
+
Project-URL: Repository, https://github.com/gohibiki/ftgo
|
|
12
|
+
Project-URL: Documentation, https://github.com/gohibiki/ftgo#readme
|
|
13
|
+
Project-URL: Bug Reports, https://github.com/gohibiki/ftgo/issues
|
|
14
|
+
Project-URL: Changelog, https://github.com/gohibiki/ftgo/blob/main/CHANGELOG.md
|
|
15
|
+
Keywords: finance,stocks,etf,historical-data,financial-analysis,market-data,ft-markets,financial-times
|
|
16
|
+
Classifier: Development Status :: 4 - Beta
|
|
17
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
18
|
+
Classifier: Intended Audience :: Developers
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
27
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
28
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
29
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
30
|
+
Requires-Python: >=3.7
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: cloudscraper>=1.2.68
|
|
34
|
+
Requires-Dist: pandas>=1.3.0
|
|
35
|
+
Requires-Dist: beautifulsoup4>=4.11.0
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: flake8>=6.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
43
|
+
Provides-Extra: examples
|
|
44
|
+
Requires-Dist: matplotlib>=3.6.0; extra == "examples"
|
|
45
|
+
Requires-Dist: jupyter>=1.0.0; extra == "examples"
|
|
46
|
+
Dynamic: author
|
|
47
|
+
Dynamic: home-page
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
Dynamic: requires-python
|
|
50
|
+
|
|
51
|
+
# FTMarkets
|
|
52
|
+
|
|
53
|
+
[](https://badge.fury.io/py/ftgo)
|
|
54
|
+
[](https://www.python.org/downloads/)
|
|
55
|
+
[](https://opensource.org/licenses/MIT)
|
|
56
|
+
|
|
57
|
+
A Python library for fetching financial data from Financial Times Markets, including historical stock prices, ETF holdings, fund profiles, and allocation breakdowns.
|
|
58
|
+
|
|
59
|
+
## Features
|
|
60
|
+
|
|
61
|
+
- **Historical Data**: Fetch historical OHLCV data for stocks and ETFs
|
|
62
|
+
- **Holdings Data**: Get ETF/fund holdings, asset allocation, and sector breakdowns
|
|
63
|
+
- **Fund Profiles**: Access fund information, statistics, and investment details
|
|
64
|
+
- **Symbol Search**: Find FT Markets XIDs by ticker symbols
|
|
65
|
+
- **Concurrent Processing**: Fast data retrieval using multithreading
|
|
66
|
+
- **Pandas Integration**: Returns data as pandas DataFrames for easy analysis
|
|
67
|
+
|
|
68
|
+
## Installation
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install ftgo
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from ftgo import search_securities, get_xid, get_historical_prices, get_holdings
|
|
78
|
+
|
|
79
|
+
# Search for a security
|
|
80
|
+
results = search_securities('AAPL')
|
|
81
|
+
print(results)
|
|
82
|
+
|
|
83
|
+
# Get XID for a ticker
|
|
84
|
+
xid = get_xid('AAPL')
|
|
85
|
+
|
|
86
|
+
# Fetch historical data
|
|
87
|
+
df = get_historical_prices(xid, "01012024", "31012024")
|
|
88
|
+
print(df.head())
|
|
89
|
+
|
|
90
|
+
# Get ETF holdings
|
|
91
|
+
spy_xid = get_xid('SPY')
|
|
92
|
+
holdings = get_holdings(spy_xid, "top_holdings")
|
|
93
|
+
print(holdings)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## API Reference
|
|
97
|
+
|
|
98
|
+
### Search Functions
|
|
99
|
+
|
|
100
|
+
#### `search_securities(query)`
|
|
101
|
+
|
|
102
|
+
Search for securities on FT Markets.
|
|
103
|
+
|
|
104
|
+
**Parameters:**
|
|
105
|
+
- `query` (str): Search term for securities (ticker symbol or company name)
|
|
106
|
+
|
|
107
|
+
**Returns:** pandas.DataFrame with search results containing xid, name, symbol, asset_class, url
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
# Search for Apple
|
|
111
|
+
results = search_securities('Apple')
|
|
112
|
+
print(results)
|
|
113
|
+
|
|
114
|
+
# Search by ticker
|
|
115
|
+
results = search_securities('AAPL')
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### `get_xid(ticker, display_mode="first")`
|
|
119
|
+
|
|
120
|
+
Get FT Markets XID for given ticker symbol.
|
|
121
|
+
|
|
122
|
+
**Parameters:**
|
|
123
|
+
- `ticker` (str): Ticker symbol
|
|
124
|
+
- `display_mode` (str): "first" to return first match XID, "all" to return all matches
|
|
125
|
+
|
|
126
|
+
**Returns:** String XID (if display_mode="first") or DataFrame (if display_mode="all")
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
# Get XID for Apple
|
|
130
|
+
xid = get_xid('AAPL')
|
|
131
|
+
print(xid) # Returns XID string
|
|
132
|
+
|
|
133
|
+
# Get all matches
|
|
134
|
+
all_results = get_xid('AAPL', display_mode='all')
|
|
135
|
+
print(all_results)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Historical Data
|
|
139
|
+
|
|
140
|
+
#### `get_historical_prices(xid, date_from, date_to)`
|
|
141
|
+
|
|
142
|
+
Get historical price data for a security with full OHLCV data.
|
|
143
|
+
|
|
144
|
+
**Parameters:**
|
|
145
|
+
- `xid` (str): The FT Markets XID
|
|
146
|
+
- `date_from` (str): Start date in DDMMYYYY format (e.g., "01012024")
|
|
147
|
+
- `date_to` (str): End date in DDMMYYYY format (e.g., "31122024")
|
|
148
|
+
|
|
149
|
+
**Returns:** pandas.DataFrame with columns: date, open, high, low, close, volume
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
xid = get_xid('AAPL')
|
|
153
|
+
df = get_historical_prices(xid, "01012024", "31012024")
|
|
154
|
+
print(df.head())
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
#### `get_multiple_historical_prices(xids, date_from, date_to)`
|
|
158
|
+
|
|
159
|
+
Get historical data for multiple securities concurrently.
|
|
160
|
+
|
|
161
|
+
**Parameters:**
|
|
162
|
+
- `xids` (list): List of FT Markets XIDs
|
|
163
|
+
- `date_from` (str): Start date in DDMMYYYY format
|
|
164
|
+
- `date_to` (str): End date in DDMMYYYY format
|
|
165
|
+
|
|
166
|
+
**Returns:** pandas.DataFrame with concatenated data for all securities
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
xids = [get_xid('AAPL'), get_xid('MSFT')]
|
|
170
|
+
df = get_multiple_historical_prices(xids, "01012024", "31012024")
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Holdings Data
|
|
174
|
+
|
|
175
|
+
#### `get_holdings(xid, holdings_type="all")`
|
|
176
|
+
|
|
177
|
+
Get holdings and allocation data for ETFs and funds.
|
|
178
|
+
|
|
179
|
+
**Parameters:**
|
|
180
|
+
- `xid` (str): The FT Markets XID
|
|
181
|
+
- `holdings_type` (str): Type of holdings data:
|
|
182
|
+
- `"asset_allocation"`: Asset class breakdown (stocks, bonds, cash)
|
|
183
|
+
- `"sector_weights"`: Sector allocation
|
|
184
|
+
- `"geographic_allocation"`: Geographic allocation
|
|
185
|
+
- `"top_holdings"`: Top holdings by weight
|
|
186
|
+
- `"all"`: All holdings data types as a tuple
|
|
187
|
+
|
|
188
|
+
**Returns:** pandas.DataFrame or tuple of DataFrames
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
# Get top holdings for SPY ETF
|
|
192
|
+
spy_xid = get_xid('SPY')
|
|
193
|
+
top_holdings = get_holdings(spy_xid, "top_holdings")
|
|
194
|
+
|
|
195
|
+
# Get asset allocation
|
|
196
|
+
allocation = get_holdings(spy_xid, "asset_allocation")
|
|
197
|
+
|
|
198
|
+
# Get all holdings data
|
|
199
|
+
all_data = get_holdings(spy_xid, "all")
|
|
200
|
+
asset_alloc, sectors, regions, holdings = all_data
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
#### `get_fund_breakdown(xid)`
|
|
204
|
+
|
|
205
|
+
Get complete fund breakdown with all allocation data.
|
|
206
|
+
|
|
207
|
+
**Parameters:**
|
|
208
|
+
- `xid` (str): The FT Markets XID
|
|
209
|
+
|
|
210
|
+
**Returns:** Dictionary with all DataFrames
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
qqq_xid = get_xid('QQQ')
|
|
214
|
+
breakdown = get_fund_breakdown(qqq_xid)
|
|
215
|
+
print(breakdown['asset_allocation'])
|
|
216
|
+
print(breakdown['top_holdings'])
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Fund Profile Data
|
|
220
|
+
|
|
221
|
+
#### `get_fund_profile(xid)`
|
|
222
|
+
|
|
223
|
+
Get profile and investment information for ETFs and funds.
|
|
224
|
+
|
|
225
|
+
**Parameters:**
|
|
226
|
+
- `xid` (str): The FT Markets XID
|
|
227
|
+
|
|
228
|
+
**Returns:** pandas.DataFrame with Field and Value columns
|
|
229
|
+
|
|
230
|
+
```python
|
|
231
|
+
xid = get_xid('SPY')
|
|
232
|
+
profile = get_fund_profile(xid)
|
|
233
|
+
print(profile)
|
|
234
|
+
|
|
235
|
+
# Filter for specific information
|
|
236
|
+
fees = profile[profile['Field'].str.contains('fee', case=False)]
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
#### `get_fund_stats(xid)`
|
|
240
|
+
|
|
241
|
+
Get fund profile data as a dictionary for easy access.
|
|
242
|
+
|
|
243
|
+
**Parameters:**
|
|
244
|
+
- `xid` (str): The FT Markets XID
|
|
245
|
+
|
|
246
|
+
**Returns:** Dictionary with all available fund fields and values
|
|
247
|
+
|
|
248
|
+
```python
|
|
249
|
+
xid = get_xid('QQQ')
|
|
250
|
+
stats = get_fund_stats(xid)
|
|
251
|
+
|
|
252
|
+
# Access any available field safely
|
|
253
|
+
inception = stats.get('Inception date', 'Not available')
|
|
254
|
+
fees = stats.get('Ongoing charge', 'Not available')
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### `get_available_fields(xid)`
|
|
258
|
+
|
|
259
|
+
Get list of all available profile fields for a fund.
|
|
260
|
+
|
|
261
|
+
**Parameters:**
|
|
262
|
+
- `xid` (str): The FT Markets XID
|
|
263
|
+
|
|
264
|
+
**Returns:** List of all field names available
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
xid = get_xid('SPY')
|
|
268
|
+
fields = get_available_fields(xid)
|
|
269
|
+
print("Available fields:")
|
|
270
|
+
for field in fields:
|
|
271
|
+
print(f" - {field}")
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
#### `search_profile_field(xid, search_term)`
|
|
275
|
+
|
|
276
|
+
Search for specific fields in the fund profile data.
|
|
277
|
+
|
|
278
|
+
**Parameters:**
|
|
279
|
+
- `xid` (str): The FT Markets XID
|
|
280
|
+
- `search_term` (str): Term to search for in field names (case-insensitive)
|
|
281
|
+
|
|
282
|
+
**Returns:** pandas.DataFrame with matching fields and values
|
|
283
|
+
|
|
284
|
+
```python
|
|
285
|
+
xid = get_xid('SPY')
|
|
286
|
+
fees = search_profile_field(xid, 'fee')
|
|
287
|
+
inception = search_profile_field(xid, 'inception')
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Complete Example
|
|
291
|
+
|
|
292
|
+
```python
|
|
293
|
+
from ftgo import get_xid, get_historical_prices, get_holdings, get_fund_profile
|
|
294
|
+
import matplotlib.pyplot as plt
|
|
295
|
+
|
|
296
|
+
# Search for QQQ ETF
|
|
297
|
+
qqq_xid = get_xid('QQQ')
|
|
298
|
+
|
|
299
|
+
# Get 1 year of historical data
|
|
300
|
+
historical_data = get_historical_prices(qqq_xid, "01012023", "31122023")
|
|
301
|
+
|
|
302
|
+
# Get fund information
|
|
303
|
+
profile = get_fund_profile(qqq_xid)
|
|
304
|
+
top_holdings = get_holdings(qqq_xid, "top_holdings")
|
|
305
|
+
asset_allocation = get_holdings(qqq_xid, "asset_allocation")
|
|
306
|
+
|
|
307
|
+
# Plot price chart
|
|
308
|
+
historical_data.set_index('date')['close'].plot(title='QQQ Price History')
|
|
309
|
+
plt.show()
|
|
310
|
+
|
|
311
|
+
# Display fund information
|
|
312
|
+
print("Fund Profile:")
|
|
313
|
+
print(profile.head(10))
|
|
314
|
+
|
|
315
|
+
print("\nTop 10 Holdings:")
|
|
316
|
+
print(top_holdings.head(10))
|
|
317
|
+
|
|
318
|
+
print("\nAsset Allocation:")
|
|
319
|
+
print(asset_allocation)
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
## Error Handling
|
|
323
|
+
|
|
324
|
+
The library includes logging and error handling, but you should wrap calls in try-except blocks for production use:
|
|
325
|
+
|
|
326
|
+
```python
|
|
327
|
+
try:
|
|
328
|
+
xid = get_xid('INVALID_TICKER')
|
|
329
|
+
data = get_historical_prices(xid, "01012024", "31012024")
|
|
330
|
+
except ValueError as e:
|
|
331
|
+
print(f"Error: {e}")
|
|
332
|
+
except Exception as e:
|
|
333
|
+
print(f"Unexpected error: {e}")
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Requirements
|
|
337
|
+
|
|
338
|
+
- Python 3.7+
|
|
339
|
+
- cloudscraper >= 1.2.68
|
|
340
|
+
- pandas >= 1.3.0
|
|
341
|
+
- beautifulsoup4 >= 4.11.0
|
|
342
|
+
|
|
343
|
+
## Contributing
|
|
344
|
+
|
|
345
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
346
|
+
|
|
347
|
+
## Disclaimer
|
|
348
|
+
|
|
349
|
+
This library is for educational and research purposes.
|
|
350
|
+
|
|
351
|
+
## License
|
|
352
|
+
|
|
353
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
ftgo-1.0.0/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# FTMarkets
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/ftgo)
|
|
4
|
+
[](https://www.python.org/downloads/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
A Python library for fetching financial data from Financial Times Markets, including historical stock prices, ETF holdings, fund profiles, and allocation breakdowns.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Historical Data**: Fetch historical OHLCV data for stocks and ETFs
|
|
12
|
+
- **Holdings Data**: Get ETF/fund holdings, asset allocation, and sector breakdowns
|
|
13
|
+
- **Fund Profiles**: Access fund information, statistics, and investment details
|
|
14
|
+
- **Symbol Search**: Find FT Markets XIDs by ticker symbols
|
|
15
|
+
- **Concurrent Processing**: Fast data retrieval using multithreading
|
|
16
|
+
- **Pandas Integration**: Returns data as pandas DataFrames for easy analysis
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install ftgo
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
from ftgo import search_securities, get_xid, get_historical_prices, get_holdings
|
|
28
|
+
|
|
29
|
+
# Search for a security
|
|
30
|
+
results = search_securities('AAPL')
|
|
31
|
+
print(results)
|
|
32
|
+
|
|
33
|
+
# Get XID for a ticker
|
|
34
|
+
xid = get_xid('AAPL')
|
|
35
|
+
|
|
36
|
+
# Fetch historical data
|
|
37
|
+
df = get_historical_prices(xid, "01012024", "31012024")
|
|
38
|
+
print(df.head())
|
|
39
|
+
|
|
40
|
+
# Get ETF holdings
|
|
41
|
+
spy_xid = get_xid('SPY')
|
|
42
|
+
holdings = get_holdings(spy_xid, "top_holdings")
|
|
43
|
+
print(holdings)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Reference
|
|
47
|
+
|
|
48
|
+
### Search Functions
|
|
49
|
+
|
|
50
|
+
#### `search_securities(query)`
|
|
51
|
+
|
|
52
|
+
Search for securities on FT Markets.
|
|
53
|
+
|
|
54
|
+
**Parameters:**
|
|
55
|
+
- `query` (str): Search term for securities (ticker symbol or company name)
|
|
56
|
+
|
|
57
|
+
**Returns:** pandas.DataFrame with search results containing xid, name, symbol, asset_class, url
|
|
58
|
+
|
|
59
|
+
```python
|
|
60
|
+
# Search for Apple
|
|
61
|
+
results = search_securities('Apple')
|
|
62
|
+
print(results)
|
|
63
|
+
|
|
64
|
+
# Search by ticker
|
|
65
|
+
results = search_securities('AAPL')
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
#### `get_xid(ticker, display_mode="first")`
|
|
69
|
+
|
|
70
|
+
Get FT Markets XID for given ticker symbol.
|
|
71
|
+
|
|
72
|
+
**Parameters:**
|
|
73
|
+
- `ticker` (str): Ticker symbol
|
|
74
|
+
- `display_mode` (str): "first" to return first match XID, "all" to return all matches
|
|
75
|
+
|
|
76
|
+
**Returns:** String XID (if display_mode="first") or DataFrame (if display_mode="all")
|
|
77
|
+
|
|
78
|
+
```python
|
|
79
|
+
# Get XID for Apple
|
|
80
|
+
xid = get_xid('AAPL')
|
|
81
|
+
print(xid) # Returns XID string
|
|
82
|
+
|
|
83
|
+
# Get all matches
|
|
84
|
+
all_results = get_xid('AAPL', display_mode='all')
|
|
85
|
+
print(all_results)
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Historical Data
|
|
89
|
+
|
|
90
|
+
#### `get_historical_prices(xid, date_from, date_to)`
|
|
91
|
+
|
|
92
|
+
Get historical price data for a security with full OHLCV data.
|
|
93
|
+
|
|
94
|
+
**Parameters:**
|
|
95
|
+
- `xid` (str): The FT Markets XID
|
|
96
|
+
- `date_from` (str): Start date in DDMMYYYY format (e.g., "01012024")
|
|
97
|
+
- `date_to` (str): End date in DDMMYYYY format (e.g., "31122024")
|
|
98
|
+
|
|
99
|
+
**Returns:** pandas.DataFrame with columns: date, open, high, low, close, volume
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
xid = get_xid('AAPL')
|
|
103
|
+
df = get_historical_prices(xid, "01012024", "31012024")
|
|
104
|
+
print(df.head())
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### `get_multiple_historical_prices(xids, date_from, date_to)`
|
|
108
|
+
|
|
109
|
+
Get historical data for multiple securities concurrently.
|
|
110
|
+
|
|
111
|
+
**Parameters:**
|
|
112
|
+
- `xids` (list): List of FT Markets XIDs
|
|
113
|
+
- `date_from` (str): Start date in DDMMYYYY format
|
|
114
|
+
- `date_to` (str): End date in DDMMYYYY format
|
|
115
|
+
|
|
116
|
+
**Returns:** pandas.DataFrame with concatenated data for all securities
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
xids = [get_xid('AAPL'), get_xid('MSFT')]
|
|
120
|
+
df = get_multiple_historical_prices(xids, "01012024", "31012024")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Holdings Data
|
|
124
|
+
|
|
125
|
+
#### `get_holdings(xid, holdings_type="all")`
|
|
126
|
+
|
|
127
|
+
Get holdings and allocation data for ETFs and funds.
|
|
128
|
+
|
|
129
|
+
**Parameters:**
|
|
130
|
+
- `xid` (str): The FT Markets XID
|
|
131
|
+
- `holdings_type` (str): Type of holdings data:
|
|
132
|
+
- `"asset_allocation"`: Asset class breakdown (stocks, bonds, cash)
|
|
133
|
+
- `"sector_weights"`: Sector allocation
|
|
134
|
+
- `"geographic_allocation"`: Geographic allocation
|
|
135
|
+
- `"top_holdings"`: Top holdings by weight
|
|
136
|
+
- `"all"`: All holdings data types as a tuple
|
|
137
|
+
|
|
138
|
+
**Returns:** pandas.DataFrame or tuple of DataFrames
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
# Get top holdings for SPY ETF
|
|
142
|
+
spy_xid = get_xid('SPY')
|
|
143
|
+
top_holdings = get_holdings(spy_xid, "top_holdings")
|
|
144
|
+
|
|
145
|
+
# Get asset allocation
|
|
146
|
+
allocation = get_holdings(spy_xid, "asset_allocation")
|
|
147
|
+
|
|
148
|
+
# Get all holdings data
|
|
149
|
+
all_data = get_holdings(spy_xid, "all")
|
|
150
|
+
asset_alloc, sectors, regions, holdings = all_data
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### `get_fund_breakdown(xid)`
|
|
154
|
+
|
|
155
|
+
Get complete fund breakdown with all allocation data.
|
|
156
|
+
|
|
157
|
+
**Parameters:**
|
|
158
|
+
- `xid` (str): The FT Markets XID
|
|
159
|
+
|
|
160
|
+
**Returns:** Dictionary with all DataFrames
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
qqq_xid = get_xid('QQQ')
|
|
164
|
+
breakdown = get_fund_breakdown(qqq_xid)
|
|
165
|
+
print(breakdown['asset_allocation'])
|
|
166
|
+
print(breakdown['top_holdings'])
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Fund Profile Data
|
|
170
|
+
|
|
171
|
+
#### `get_fund_profile(xid)`
|
|
172
|
+
|
|
173
|
+
Get profile and investment information for ETFs and funds.
|
|
174
|
+
|
|
175
|
+
**Parameters:**
|
|
176
|
+
- `xid` (str): The FT Markets XID
|
|
177
|
+
|
|
178
|
+
**Returns:** pandas.DataFrame with Field and Value columns
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
xid = get_xid('SPY')
|
|
182
|
+
profile = get_fund_profile(xid)
|
|
183
|
+
print(profile)
|
|
184
|
+
|
|
185
|
+
# Filter for specific information
|
|
186
|
+
fees = profile[profile['Field'].str.contains('fee', case=False)]
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### `get_fund_stats(xid)`
|
|
190
|
+
|
|
191
|
+
Get fund profile data as a dictionary for easy access.
|
|
192
|
+
|
|
193
|
+
**Parameters:**
|
|
194
|
+
- `xid` (str): The FT Markets XID
|
|
195
|
+
|
|
196
|
+
**Returns:** Dictionary with all available fund fields and values
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
xid = get_xid('QQQ')
|
|
200
|
+
stats = get_fund_stats(xid)
|
|
201
|
+
|
|
202
|
+
# Access any available field safely
|
|
203
|
+
inception = stats.get('Inception date', 'Not available')
|
|
204
|
+
fees = stats.get('Ongoing charge', 'Not available')
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
#### `get_available_fields(xid)`
|
|
208
|
+
|
|
209
|
+
Get list of all available profile fields for a fund.
|
|
210
|
+
|
|
211
|
+
**Parameters:**
|
|
212
|
+
- `xid` (str): The FT Markets XID
|
|
213
|
+
|
|
214
|
+
**Returns:** List of all field names available
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
xid = get_xid('SPY')
|
|
218
|
+
fields = get_available_fields(xid)
|
|
219
|
+
print("Available fields:")
|
|
220
|
+
for field in fields:
|
|
221
|
+
print(f" - {field}")
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
#### `search_profile_field(xid, search_term)`
|
|
225
|
+
|
|
226
|
+
Search for specific fields in the fund profile data.
|
|
227
|
+
|
|
228
|
+
**Parameters:**
|
|
229
|
+
- `xid` (str): The FT Markets XID
|
|
230
|
+
- `search_term` (str): Term to search for in field names (case-insensitive)
|
|
231
|
+
|
|
232
|
+
**Returns:** pandas.DataFrame with matching fields and values
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
xid = get_xid('SPY')
|
|
236
|
+
fees = search_profile_field(xid, 'fee')
|
|
237
|
+
inception = search_profile_field(xid, 'inception')
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Complete Example
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
from ftgo import get_xid, get_historical_prices, get_holdings, get_fund_profile
|
|
244
|
+
import matplotlib.pyplot as plt
|
|
245
|
+
|
|
246
|
+
# Search for QQQ ETF
|
|
247
|
+
qqq_xid = get_xid('QQQ')
|
|
248
|
+
|
|
249
|
+
# Get 1 year of historical data
|
|
250
|
+
historical_data = get_historical_prices(qqq_xid, "01012023", "31122023")
|
|
251
|
+
|
|
252
|
+
# Get fund information
|
|
253
|
+
profile = get_fund_profile(qqq_xid)
|
|
254
|
+
top_holdings = get_holdings(qqq_xid, "top_holdings")
|
|
255
|
+
asset_allocation = get_holdings(qqq_xid, "asset_allocation")
|
|
256
|
+
|
|
257
|
+
# Plot price chart
|
|
258
|
+
historical_data.set_index('date')['close'].plot(title='QQQ Price History')
|
|
259
|
+
plt.show()
|
|
260
|
+
|
|
261
|
+
# Display fund information
|
|
262
|
+
print("Fund Profile:")
|
|
263
|
+
print(profile.head(10))
|
|
264
|
+
|
|
265
|
+
print("\nTop 10 Holdings:")
|
|
266
|
+
print(top_holdings.head(10))
|
|
267
|
+
|
|
268
|
+
print("\nAsset Allocation:")
|
|
269
|
+
print(asset_allocation)
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
## Error Handling
|
|
273
|
+
|
|
274
|
+
The library includes logging and error handling, but you should wrap calls in try-except blocks for production use:
|
|
275
|
+
|
|
276
|
+
```python
|
|
277
|
+
try:
|
|
278
|
+
xid = get_xid('INVALID_TICKER')
|
|
279
|
+
data = get_historical_prices(xid, "01012024", "31012024")
|
|
280
|
+
except ValueError as e:
|
|
281
|
+
print(f"Error: {e}")
|
|
282
|
+
except Exception as e:
|
|
283
|
+
print(f"Unexpected error: {e}")
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Requirements
|
|
287
|
+
|
|
288
|
+
- Python 3.7+
|
|
289
|
+
- cloudscraper >= 1.2.68
|
|
290
|
+
- pandas >= 1.3.0
|
|
291
|
+
- beautifulsoup4 >= 4.11.0
|
|
292
|
+
|
|
293
|
+
## Contributing
|
|
294
|
+
|
|
295
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
296
|
+
|
|
297
|
+
## Disclaimer
|
|
298
|
+
|
|
299
|
+
This library is for educational and research purposes.
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""
|
|
2
|
+
FTMarkets - A Python library for fetching financial data from FT Markets
|
|
3
|
+
|
|
4
|
+
This library provides easy access to historical stock prices and search
|
|
5
|
+
functionality for financial instruments from Financial Times Markets.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .search import search_securities, get_xid
|
|
9
|
+
from .historical import get_historical_prices, get_multiple_historical_prices
|
|
10
|
+
from .holdings import get_holdings, get_fund_breakdown
|
|
11
|
+
from .infos import get_fund_profile, get_fund_stats, get_available_fields, search_profile_field
|
|
12
|
+
|
|
13
|
+
__version__ = "1.0.0"
|
|
14
|
+
__author__ = "gohibiki"
|
|
15
|
+
__email__ = "gohibiki@protonmail.com"
|
|
16
|
+
__description__ = "A Python library for fetching financial data from FT Markets"
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"search_securities",
|
|
20
|
+
"get_xid",
|
|
21
|
+
"get_historical_prices",
|
|
22
|
+
"get_multiple_historical_prices",
|
|
23
|
+
"get_holdings",
|
|
24
|
+
"get_fund_breakdown",
|
|
25
|
+
"get_fund_profile",
|
|
26
|
+
"get_fund_stats",
|
|
27
|
+
"get_available_fields",
|
|
28
|
+
"search_profile_field"
|
|
29
|
+
]
|