fmp-stable-api 0.0.1__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.
- fmp_stable_api-0.0.1/LICENSE.txt +21 -0
- fmp_stable_api-0.0.1/MANIFEST.in +3 -0
- fmp_stable_api-0.0.1/PKG-INFO +152 -0
- fmp_stable_api-0.0.1/README.md +119 -0
- fmp_stable_api-0.0.1/fmp/__init__.py +35 -0
- fmp_stable_api-0.0.1/fmp/config_manager.py +34 -0
- fmp_stable_api-0.0.1/fmp/dynamic.py +26 -0
- fmp_stable_api-0.0.1/fmp/fmp_client.py +118 -0
- fmp_stable_api-0.0.1/fmp/fmp_websockets/__init__.py +9 -0
- fmp_stable_api-0.0.1/fmp/fmp_websockets/base_websocket_client.py +58 -0
- fmp_stable_api-0.0.1/fmp/fmp_websockets/crypto_websocket.py +7 -0
- fmp_stable_api-0.0.1/fmp/fmp_websockets/forex_websocket.py +7 -0
- fmp_stable_api-0.0.1/fmp/fmp_websockets/stock_websocket.py +7 -0
- fmp_stable_api-0.0.1/fmp/logger.py +29 -0
- fmp_stable_api-0.0.1/fmp/session.py +30 -0
- fmp_stable_api-0.0.1/fmp_stable_api.egg-info/PKG-INFO +152 -0
- fmp_stable_api-0.0.1/fmp_stable_api.egg-info/SOURCES.txt +21 -0
- fmp_stable_api-0.0.1/fmp_stable_api.egg-info/dependency_links.txt +1 -0
- fmp_stable_api-0.0.1/fmp_stable_api.egg-info/requires.txt +7 -0
- fmp_stable_api-0.0.1/fmp_stable_api.egg-info/top_level.txt +1 -0
- fmp_stable_api-0.0.1/pyproject.toml +3 -0
- fmp_stable_api-0.0.1/setup.cfg +4 -0
- fmp_stable_api-0.0.1/setup.py +36 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Vimal Seshadri Raguraman
|
|
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.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: fmp-stable-api
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Python client library for the Financial Modeling Prep API
|
|
5
|
+
Home-page: https://github.com/Vimal-Seshadri-Raguraman/FMP
|
|
6
|
+
Author: Vimal Seshadri Raguraman
|
|
7
|
+
Project-URL: GitHub, https://github.com/Vimal-Seshadri-Raguraman/FMP
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
14
|
+
Requires-Python: >=3.6
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE.txt
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: ratelimit
|
|
19
|
+
Requires-Dist: websockets
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: twine; extra == "dev"
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: project-url
|
|
29
|
+
Dynamic: provides-extra
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
# FMP Client Library
|
|
35
|
+
A Python client library for the [Financial Modeling Prep (FMP) API](https://financialmodelingprep.com/). This library provides both synchronous REST API and asynchronous WebSocket support, all in a modular, easy-to-use package.
|
|
36
|
+
|
|
37
|
+
The client is built to work with the [**Stable** version](https://site.financialmodelingprep.com/developer/docs/stable) of the Financial Modeling Prep (FMP) API. All endpoints are configured to use the stable base URL:
|
|
38
|
+
```arduino
|
|
39
|
+
https://financialmodelingprep.com/stable/
|
|
40
|
+
```
|
|
41
|
+
The endpoints available in this stable version are defined in the [fmp_endpoints.json](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/FMP/fmp_endpoints.json) file
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Unified API Client:**
|
|
46
|
+
Dynamically access FMP endpoints using Pythonic method names.
|
|
47
|
+
|
|
48
|
+
- **Rate-Limited HTTP Session:**
|
|
49
|
+
Built-in rate limiting using the `ratelimit` library and robust error handling with logging.
|
|
50
|
+
|
|
51
|
+
- **Dynamic Endpoint Methods:**
|
|
52
|
+
Automatically attaches methods based on your configuration file (`fmp_endpoints.json`).
|
|
53
|
+
|
|
54
|
+
- **Asynchronous WebSocket Clients:**
|
|
55
|
+
Separate clients for stocks, crypto, and forex data available in the `fmp_websockets` subpackage.
|
|
56
|
+
|
|
57
|
+
- **Flexible Configuration and Logging:**
|
|
58
|
+
Easily configure your endpoints with a JSON file and log messages to a file in the same directory as your main script.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Clone the repository and install the dependencies:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
66
|
+
cd FMP
|
|
67
|
+
pip install -r requirements.txt
|
|
68
|
+
python setup.py install
|
|
69
|
+
```
|
|
70
|
+
Alternatively, install directly from Github:
|
|
71
|
+
```bash
|
|
72
|
+
pip install git+https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
### API Client
|
|
77
|
+
Initialize the client with your API Key and call any endpoint dynmically:
|
|
78
|
+
```python
|
|
79
|
+
from fmp import FMP
|
|
80
|
+
|
|
81
|
+
# Initialize client with your API Key
|
|
82
|
+
client = fmp(api_key = "YOUR_API_KEY")
|
|
83
|
+
|
|
84
|
+
# Call an endpoint (e.g., "Profile")
|
|
85
|
+
response = client.profile(symbol = "AAPL")
|
|
86
|
+
print("Status Code:", response.status_code)
|
|
87
|
+
print("Profile Data:", response.json())
|
|
88
|
+
```
|
|
89
|
+
#### Dynmic Methods and Help
|
|
90
|
+
The client automatically attaches methods based on the JSON configuration. To see available endpoints and their parameters:
|
|
91
|
+
```python
|
|
92
|
+
# General help for all endpoints
|
|
93
|
+
print(client.help())
|
|
94
|
+
|
|
95
|
+
# Detailed help for a specific endpoint (e.g., "profile")
|
|
96
|
+
print(client.help("profile"))
|
|
97
|
+
|
|
98
|
+
# Generate a manual page of endpoints
|
|
99
|
+
man_doc = client.man_page() # Create a text file
|
|
100
|
+
print(man_doc)
|
|
101
|
+
```
|
|
102
|
+
### WebSocket Clients
|
|
103
|
+
The library includes asynchronous WebSocket clients for real-time data.
|
|
104
|
+
#### Stock WebSocket Example
|
|
105
|
+
```python
|
|
106
|
+
import asyncio
|
|
107
|
+
from fmp import StockWebsockets
|
|
108
|
+
|
|
109
|
+
async def run_stock_ws():
|
|
110
|
+
stock_ws = StockWebsockets(tickers=["AAPL", "MSFT"], api_key="YOUR_API_KEY")
|
|
111
|
+
async for message in stock_ws.run():
|
|
112
|
+
print("Stock WebSocket Message:", message)
|
|
113
|
+
|
|
114
|
+
asyncio.run(run_stock_ws())
|
|
115
|
+
```
|
|
116
|
+
#### Crypto and Forex WebSocket Example
|
|
117
|
+
```python
|
|
118
|
+
import asyncio
|
|
119
|
+
from fmp import CryptoWebsockets, ForexWebsockets
|
|
120
|
+
|
|
121
|
+
async def run_crypto_ws():
|
|
122
|
+
crypto_ws = CryptoWebsockets(tickers=["BTCUSD", "ETHUSD"], api_key="YOUR_API_KEY")
|
|
123
|
+
async for message in crypto_ws.run():
|
|
124
|
+
print("Crypto WebSocket Message:", message)
|
|
125
|
+
|
|
126
|
+
async def run_forex_ws():
|
|
127
|
+
forex_ws = ForexWebsockets(pairs=["EURUSD", "GBPUSD"], api_key="YOUR_API_KEY")
|
|
128
|
+
async for message in forex_ws.run():
|
|
129
|
+
print("Forex WebSocket Message:", message)
|
|
130
|
+
|
|
131
|
+
# Run one example at a time:
|
|
132
|
+
asyncio.run(run_crypto_ws())
|
|
133
|
+
# asyncio.run(run_forex_ws())
|
|
134
|
+
```
|
|
135
|
+
## Configuration
|
|
136
|
+
By default, the client loads endpoint configuration from ```fmp_endpoints.json``` located in the same directory as ```fmp_client.py```. To use a custom configuration file:
|
|
137
|
+
```python
|
|
138
|
+
client = FMP(api_key="YOUR_API_KEY", config_file="path/to/your_config.json")
|
|
139
|
+
```
|
|
140
|
+
If you update the configuration file during runtime, force a reload with:
|
|
141
|
+
```python
|
|
142
|
+
client.config_manager.reload()
|
|
143
|
+
```
|
|
144
|
+
## Logging
|
|
145
|
+
Logging is enabled by default and creates a log file (```fmp.log```) in the directory where your main script is located. To disable logging:
|
|
146
|
+
```python
|
|
147
|
+
client = FMP(api_key="YOUR_API_KEY", log_enabled=False)
|
|
148
|
+
```
|
|
149
|
+
## Contributing
|
|
150
|
+
Contributions, bug reports, and feature requests are welcome. Please open an issue or submit a pull request.
|
|
151
|
+
## License
|
|
152
|
+
This project is licensed under the MIT License. See the [```LICENSE.md```](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/LICENSE) file for details.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# FMP Client Library
|
|
2
|
+
A Python client library for the [Financial Modeling Prep (FMP) API](https://financialmodelingprep.com/). This library provides both synchronous REST API and asynchronous WebSocket support, all in a modular, easy-to-use package.
|
|
3
|
+
|
|
4
|
+
The client is built to work with the [**Stable** version](https://site.financialmodelingprep.com/developer/docs/stable) of the Financial Modeling Prep (FMP) API. All endpoints are configured to use the stable base URL:
|
|
5
|
+
```arduino
|
|
6
|
+
https://financialmodelingprep.com/stable/
|
|
7
|
+
```
|
|
8
|
+
The endpoints available in this stable version are defined in the [fmp_endpoints.json](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/FMP/fmp_endpoints.json) file
|
|
9
|
+
|
|
10
|
+
## Features
|
|
11
|
+
|
|
12
|
+
- **Unified API Client:**
|
|
13
|
+
Dynamically access FMP endpoints using Pythonic method names.
|
|
14
|
+
|
|
15
|
+
- **Rate-Limited HTTP Session:**
|
|
16
|
+
Built-in rate limiting using the `ratelimit` library and robust error handling with logging.
|
|
17
|
+
|
|
18
|
+
- **Dynamic Endpoint Methods:**
|
|
19
|
+
Automatically attaches methods based on your configuration file (`fmp_endpoints.json`).
|
|
20
|
+
|
|
21
|
+
- **Asynchronous WebSocket Clients:**
|
|
22
|
+
Separate clients for stocks, crypto, and forex data available in the `fmp_websockets` subpackage.
|
|
23
|
+
|
|
24
|
+
- **Flexible Configuration and Logging:**
|
|
25
|
+
Easily configure your endpoints with a JSON file and log messages to a file in the same directory as your main script.
|
|
26
|
+
|
|
27
|
+
## Installation
|
|
28
|
+
|
|
29
|
+
Clone the repository and install the dependencies:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
git clone https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
33
|
+
cd FMP
|
|
34
|
+
pip install -r requirements.txt
|
|
35
|
+
python setup.py install
|
|
36
|
+
```
|
|
37
|
+
Alternatively, install directly from Github:
|
|
38
|
+
```bash
|
|
39
|
+
pip install git+https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
### API Client
|
|
44
|
+
Initialize the client with your API Key and call any endpoint dynmically:
|
|
45
|
+
```python
|
|
46
|
+
from fmp import FMP
|
|
47
|
+
|
|
48
|
+
# Initialize client with your API Key
|
|
49
|
+
client = fmp(api_key = "YOUR_API_KEY")
|
|
50
|
+
|
|
51
|
+
# Call an endpoint (e.g., "Profile")
|
|
52
|
+
response = client.profile(symbol = "AAPL")
|
|
53
|
+
print("Status Code:", response.status_code)
|
|
54
|
+
print("Profile Data:", response.json())
|
|
55
|
+
```
|
|
56
|
+
#### Dynmic Methods and Help
|
|
57
|
+
The client automatically attaches methods based on the JSON configuration. To see available endpoints and their parameters:
|
|
58
|
+
```python
|
|
59
|
+
# General help for all endpoints
|
|
60
|
+
print(client.help())
|
|
61
|
+
|
|
62
|
+
# Detailed help for a specific endpoint (e.g., "profile")
|
|
63
|
+
print(client.help("profile"))
|
|
64
|
+
|
|
65
|
+
# Generate a manual page of endpoints
|
|
66
|
+
man_doc = client.man_page() # Create a text file
|
|
67
|
+
print(man_doc)
|
|
68
|
+
```
|
|
69
|
+
### WebSocket Clients
|
|
70
|
+
The library includes asynchronous WebSocket clients for real-time data.
|
|
71
|
+
#### Stock WebSocket Example
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
from fmp import StockWebsockets
|
|
75
|
+
|
|
76
|
+
async def run_stock_ws():
|
|
77
|
+
stock_ws = StockWebsockets(tickers=["AAPL", "MSFT"], api_key="YOUR_API_KEY")
|
|
78
|
+
async for message in stock_ws.run():
|
|
79
|
+
print("Stock WebSocket Message:", message)
|
|
80
|
+
|
|
81
|
+
asyncio.run(run_stock_ws())
|
|
82
|
+
```
|
|
83
|
+
#### Crypto and Forex WebSocket Example
|
|
84
|
+
```python
|
|
85
|
+
import asyncio
|
|
86
|
+
from fmp import CryptoWebsockets, ForexWebsockets
|
|
87
|
+
|
|
88
|
+
async def run_crypto_ws():
|
|
89
|
+
crypto_ws = CryptoWebsockets(tickers=["BTCUSD", "ETHUSD"], api_key="YOUR_API_KEY")
|
|
90
|
+
async for message in crypto_ws.run():
|
|
91
|
+
print("Crypto WebSocket Message:", message)
|
|
92
|
+
|
|
93
|
+
async def run_forex_ws():
|
|
94
|
+
forex_ws = ForexWebsockets(pairs=["EURUSD", "GBPUSD"], api_key="YOUR_API_KEY")
|
|
95
|
+
async for message in forex_ws.run():
|
|
96
|
+
print("Forex WebSocket Message:", message)
|
|
97
|
+
|
|
98
|
+
# Run one example at a time:
|
|
99
|
+
asyncio.run(run_crypto_ws())
|
|
100
|
+
# asyncio.run(run_forex_ws())
|
|
101
|
+
```
|
|
102
|
+
## Configuration
|
|
103
|
+
By default, the client loads endpoint configuration from ```fmp_endpoints.json``` located in the same directory as ```fmp_client.py```. To use a custom configuration file:
|
|
104
|
+
```python
|
|
105
|
+
client = FMP(api_key="YOUR_API_KEY", config_file="path/to/your_config.json")
|
|
106
|
+
```
|
|
107
|
+
If you update the configuration file during runtime, force a reload with:
|
|
108
|
+
```python
|
|
109
|
+
client.config_manager.reload()
|
|
110
|
+
```
|
|
111
|
+
## Logging
|
|
112
|
+
Logging is enabled by default and creates a log file (```fmp.log```) in the directory where your main script is located. To disable logging:
|
|
113
|
+
```python
|
|
114
|
+
client = FMP(api_key="YOUR_API_KEY", log_enabled=False)
|
|
115
|
+
```
|
|
116
|
+
## Contributing
|
|
117
|
+
Contributions, bug reports, and feature requests are welcome. Please open an issue or submit a pull request.
|
|
118
|
+
## License
|
|
119
|
+
This project is licensed under the MIT License. See the [```LICENSE.md```](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/LICENSE) file for details.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Financial Modeling Prep Client Library
|
|
3
|
+
|
|
4
|
+
Exposes:
|
|
5
|
+
FMP: Unified REST API client.
|
|
6
|
+
Logger: Logging utility.
|
|
7
|
+
ConfigManager: Configuration loader.
|
|
8
|
+
Session: HTTP session with rate limiting.
|
|
9
|
+
StockWebsockets: WebSocket client for stock data.
|
|
10
|
+
CryptoWebsockets: WebSocket client for crypto data.
|
|
11
|
+
ForexWebsockets: WebSocket client for forex data.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .logger import Logger
|
|
15
|
+
from .config_manager import ConfigManager
|
|
16
|
+
from .dynamic import create_endpoint_method, attach_dynamic_functions
|
|
17
|
+
from .session import Session
|
|
18
|
+
from .fmp_client import FMP
|
|
19
|
+
|
|
20
|
+
from .fmp_websockets.stock_websocket import StockWebsockets
|
|
21
|
+
from .fmp_websockets.crypto_websocket import CryptoWebsockets
|
|
22
|
+
from .fmp_websockets.forex_websocket import ForexWebsockets
|
|
23
|
+
|
|
24
|
+
__all__ = [
|
|
25
|
+
"FMP",
|
|
26
|
+
"Logger",
|
|
27
|
+
"ConfigManager",
|
|
28
|
+
"Session",
|
|
29
|
+
"StockWebsockets",
|
|
30
|
+
"CryptoWebsockets",
|
|
31
|
+
"ForexWebsockets",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
__version__ = "0.0.1"
|
|
35
|
+
__author__ = "Vimal Seshadri Raguraman"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from typing import Dict, Any, Optional
|
|
3
|
+
import importlib.resources as pkg_resources
|
|
4
|
+
|
|
5
|
+
class ConfigManager:
|
|
6
|
+
"""
|
|
7
|
+
Loads and caches a JSON configuration file.
|
|
8
|
+
If no config_file is provided, loads the default configuration
|
|
9
|
+
from the package resource fmp_endpoints.json.
|
|
10
|
+
"""
|
|
11
|
+
def __init__(self, config_file: Optional[str] = None) -> None:
|
|
12
|
+
self.config_file = config_file
|
|
13
|
+
self._config: Optional[Dict[str, Any]] = None
|
|
14
|
+
|
|
15
|
+
def get(self) -> Dict[str, Any]:
|
|
16
|
+
if self._config is None:
|
|
17
|
+
if self.config_file is None:
|
|
18
|
+
# Load default configuration from package resources.
|
|
19
|
+
with pkg_resources.open_text("fmp", "fmp_endpoints.json") as f:
|
|
20
|
+
self._config = json.load(f)
|
|
21
|
+
else:
|
|
22
|
+
with open(self.config_file, "r") as f:
|
|
23
|
+
self._config = json.load(f)
|
|
24
|
+
return self._config
|
|
25
|
+
|
|
26
|
+
def reload(self) -> Dict[str, Any]:
|
|
27
|
+
"""Force reload of the configuration file."""
|
|
28
|
+
if self.config_file is None:
|
|
29
|
+
with pkg_resources.open_text("fmp", "fmp_endpoints.json") as f:
|
|
30
|
+
self._config = json.load(f)
|
|
31
|
+
else:
|
|
32
|
+
with open(self.config_file, "r") as f:
|
|
33
|
+
self._config = json.load(f)
|
|
34
|
+
return self._config
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from typing import Callable, Any
|
|
2
|
+
|
|
3
|
+
def create_endpoint_method(ep: str) -> Callable:
|
|
4
|
+
"""
|
|
5
|
+
Returns an endpoint method bound to a specific API endpoint.
|
|
6
|
+
Renames parameters (e.g. 'start_date' to 'from') before calling the client.
|
|
7
|
+
"""
|
|
8
|
+
def method(self, *args, **kwargs):
|
|
9
|
+
if 'start_date' in kwargs:
|
|
10
|
+
kwargs['from'] = kwargs.pop('start_date')
|
|
11
|
+
elif 'from_' in kwargs:
|
|
12
|
+
kwargs['from'] = kwargs.pop('from_')
|
|
13
|
+
if 'end_date' in kwargs:
|
|
14
|
+
kwargs['to'] = kwargs.pop('end_date')
|
|
15
|
+
elif 'to_' in kwargs:
|
|
16
|
+
kwargs['to'] = kwargs.pop('to_')
|
|
17
|
+
return self.call(ep, **kwargs)
|
|
18
|
+
return method
|
|
19
|
+
|
|
20
|
+
def attach_dynamic_functions(client: Any) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Attaches dynamic endpoint methods to the client.
|
|
23
|
+
"""
|
|
24
|
+
for ep in client.endpoints.keys():
|
|
25
|
+
func_name = ep.replace("-", "_")
|
|
26
|
+
setattr(client.__class__, func_name, create_endpoint_method(ep))
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import urllib.parse
|
|
4
|
+
from typing import Optional, Dict, Any
|
|
5
|
+
import requests
|
|
6
|
+
|
|
7
|
+
from .config_manager import ConfigManager
|
|
8
|
+
from .logger import Logger
|
|
9
|
+
from .session import Session
|
|
10
|
+
from .dynamic import attach_dynamic_functions
|
|
11
|
+
|
|
12
|
+
class FMP:
|
|
13
|
+
"""
|
|
14
|
+
Unified Financial Modeling Prep API client.
|
|
15
|
+
|
|
16
|
+
Combines configuration management, HTTP session handling, dynamic endpoint methods,
|
|
17
|
+
and helper functions into one class.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
client = FMP(api_key="YOUR_API_KEY")
|
|
21
|
+
response = client.profile(symbol="AAPL")
|
|
22
|
+
print(response.json())
|
|
23
|
+
"""
|
|
24
|
+
def __init__(self,
|
|
25
|
+
api_key: str,
|
|
26
|
+
config_file: Optional[str] = None,
|
|
27
|
+
base_url: Optional[str] = None,
|
|
28
|
+
logger: Optional[Logger] = None,
|
|
29
|
+
log_enabled: bool = True) -> None:
|
|
30
|
+
self.api_key = api_key
|
|
31
|
+
# Let ConfigManager load the default config from package resources if config_file is None.
|
|
32
|
+
self.config_manager = ConfigManager(config_file)
|
|
33
|
+
self.config = self.config_manager.get()
|
|
34
|
+
self.base_url = base_url or self.config.get("base_url")
|
|
35
|
+
if logger is None:
|
|
36
|
+
logger = Logger("FMP", enabled=log_enabled)
|
|
37
|
+
self.logger = logger
|
|
38
|
+
self.session = Session(api_key, logger=logger)
|
|
39
|
+
self.endpoints: Dict[str, Any] = self.config.get("endpoints", {})
|
|
40
|
+
attach_dynamic_functions(self)
|
|
41
|
+
|
|
42
|
+
def call(self, endpoint_name: str, **kwargs) -> requests.Response:
|
|
43
|
+
if endpoint_name not in self.endpoints:
|
|
44
|
+
raise ValueError(f"Endpoint '{endpoint_name}' not found in configuration.")
|
|
45
|
+
endpoint_info = self.endpoints[endpoint_name]
|
|
46
|
+
url = urllib.parse.urljoin(self.base_url, endpoint_info["path"])
|
|
47
|
+
allowed = endpoint_info.get("params", {}).keys()
|
|
48
|
+
params = {k: v for k, v in kwargs.items() if k in allowed}
|
|
49
|
+
params["apikey"] = self.api_key
|
|
50
|
+
return self.session.get(url, params=params)
|
|
51
|
+
|
|
52
|
+
def help(self, endpoint: Optional[str] = None) -> str:
|
|
53
|
+
"""
|
|
54
|
+
Returns help information for endpoints.
|
|
55
|
+
"""
|
|
56
|
+
doc = ("FMP API Client Help\n\nUsage:\n client.endpoint_name(param1=value1, ...)\n"
|
|
57
|
+
"Example:\n client.profile(symbol='AAPL')\n\n")
|
|
58
|
+
if endpoint:
|
|
59
|
+
target = next((key for key in self.endpoints if key.replace("-", "_") == endpoint), None)
|
|
60
|
+
if not target:
|
|
61
|
+
doc += f"Endpoint '{endpoint}' not found.\n"
|
|
62
|
+
else:
|
|
63
|
+
config = self.endpoints[target]
|
|
64
|
+
doc += f"Help for endpoint '{target}':\n Path: {config.get('path')}\n"
|
|
65
|
+
params = config.get("params", {})
|
|
66
|
+
if params:
|
|
67
|
+
doc += " Allowed parameters:\n"
|
|
68
|
+
for param, details in params.items():
|
|
69
|
+
required = details.get("required", False)
|
|
70
|
+
param_type = details.get("type", "unknown")
|
|
71
|
+
example = details.get("example", "")
|
|
72
|
+
doc += f" - {param} (required: {required}, type: {param_type}, example: {example})\n"
|
|
73
|
+
else:
|
|
74
|
+
doc += " No parameters defined.\n"
|
|
75
|
+
else:
|
|
76
|
+
for ep, config in self.endpoints.items():
|
|
77
|
+
func_name = ep.replace("-", "_")
|
|
78
|
+
doc += f"\nEndpoint: {func_name}\n Path: {config.get('path')}\n"
|
|
79
|
+
params = config.get("params", {})
|
|
80
|
+
if params:
|
|
81
|
+
doc += " Allowed parameters:\n"
|
|
82
|
+
for param, details in params.items():
|
|
83
|
+
required = details.get("required", False)
|
|
84
|
+
param_type = details.get("type", "unknown")
|
|
85
|
+
example = details.get("example", "")
|
|
86
|
+
doc += f" - {param} (required: {required}, type: {param_type}, example: {example})\n"
|
|
87
|
+
else:
|
|
88
|
+
doc += " No parameters defined.\n"
|
|
89
|
+
doc += "\n"
|
|
90
|
+
return doc
|
|
91
|
+
|
|
92
|
+
def man_page(self, just_name: bool = False, filename: str = "FMP_man_page.txt") -> str:
|
|
93
|
+
main_dir = (os.path.dirname(sys.modules["__main__"].__file__)
|
|
94
|
+
if "__main__" in sys.modules and hasattr(sys.modules["__main__"], "__file__")
|
|
95
|
+
else os.getcwd())
|
|
96
|
+
doc_file = os.path.join(main_dir, filename)
|
|
97
|
+
if os.path.exists(doc_file):
|
|
98
|
+
os.remove(doc_file)
|
|
99
|
+
output = "Manual Page for FMP API Client Endpoints:\n"
|
|
100
|
+
for ep, config in self.endpoints.items():
|
|
101
|
+
func_name = ep.replace("-", "_")
|
|
102
|
+
if just_name:
|
|
103
|
+
output += f"\n\t{func_name}"
|
|
104
|
+
else:
|
|
105
|
+
output += f"\n\nEndpoint: {func_name}\n Path: {config.get('path')}\n"
|
|
106
|
+
params = config.get("params", {})
|
|
107
|
+
if params:
|
|
108
|
+
output += " Allowed parameters:\n"
|
|
109
|
+
for param, details in params.items():
|
|
110
|
+
required = details.get("required", False)
|
|
111
|
+
param_type = details.get("type", "unknown")
|
|
112
|
+
example = details.get("example", "")
|
|
113
|
+
output += f" - {param} (required: {required}, type: {param_type}, example: {example})\n"
|
|
114
|
+
else:
|
|
115
|
+
output += " No parameters defined.\n"
|
|
116
|
+
with open(doc_file, "w") as f:
|
|
117
|
+
f.write(output)
|
|
118
|
+
return output
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import asyncio
|
|
3
|
+
from typing import List, Optional, AsyncGenerator
|
|
4
|
+
import websockets
|
|
5
|
+
|
|
6
|
+
class BaseWebsocketClient:
|
|
7
|
+
"""
|
|
8
|
+
Base class for FinancialModelingPrep WebSocket clients.
|
|
9
|
+
Handles connection, login, subscription, and yields messages.
|
|
10
|
+
"""
|
|
11
|
+
def __init__(self, tickers: List[str], api_key: str, uri: str) -> None:
|
|
12
|
+
self.tickers = tickers if isinstance(tickers, list) else [tickers]
|
|
13
|
+
self.api_key = api_key
|
|
14
|
+
self.uri = uri
|
|
15
|
+
self.websocket: Optional[websockets.WebSocketClientProtocol] = None
|
|
16
|
+
|
|
17
|
+
async def connect(self) -> None:
|
|
18
|
+
self.websocket = await websockets.connect(self.uri)
|
|
19
|
+
print(f"Connected to {self.uri}")
|
|
20
|
+
|
|
21
|
+
async def login(self) -> None:
|
|
22
|
+
login_msg = {"event": "login", "data": {"apiKey": self.api_key}}
|
|
23
|
+
await self.websocket.send(json.dumps(login_msg))
|
|
24
|
+
print("Sent login message")
|
|
25
|
+
|
|
26
|
+
async def subscribe(self) -> None:
|
|
27
|
+
subscribe_msg = {"event": "subscribe", "data": {"ticker": self.tickers}}
|
|
28
|
+
await self.websocket.send(json.dumps(subscribe_msg))
|
|
29
|
+
print(f"Subscribed to tickers: {self.tickers}")
|
|
30
|
+
|
|
31
|
+
async def run(self) -> AsyncGenerator[dict, None]:
|
|
32
|
+
"""
|
|
33
|
+
Connects, logs in, waits for confirmation, subscribes,
|
|
34
|
+
and yields messages continuously.
|
|
35
|
+
"""
|
|
36
|
+
await self.connect()
|
|
37
|
+
await self.login()
|
|
38
|
+
while True:
|
|
39
|
+
response = await self.websocket.recv()
|
|
40
|
+
message = json.loads(response)
|
|
41
|
+
if message.get("event") == "login":
|
|
42
|
+
if message.get("status") == 200:
|
|
43
|
+
print("Login successful")
|
|
44
|
+
break
|
|
45
|
+
else:
|
|
46
|
+
raise Exception("Login failed: " + message.get("message", "Unknown error"))
|
|
47
|
+
else:
|
|
48
|
+
print("Received (before login confirmation):", message)
|
|
49
|
+
await self.subscribe()
|
|
50
|
+
try:
|
|
51
|
+
while True:
|
|
52
|
+
response = await self.websocket.recv()
|
|
53
|
+
data = json.loads(response)
|
|
54
|
+
yield data
|
|
55
|
+
except websockets.ConnectionClosed:
|
|
56
|
+
print("Connection closed by the server.")
|
|
57
|
+
finally:
|
|
58
|
+
await self.websocket.close()
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from .base_websocket_client import BaseWebsocketClient
|
|
3
|
+
|
|
4
|
+
class CryptoWebsockets(BaseWebsocketClient):
|
|
5
|
+
def __init__(self, tickers: List[str], api_key: str,
|
|
6
|
+
uri: str = "wss://crypto.financialmodelingprep.com") -> None:
|
|
7
|
+
super().__init__(tickers, api_key, uri)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from .base_websocket_client import BaseWebsocketClient
|
|
3
|
+
|
|
4
|
+
class ForexWebsockets(BaseWebsocketClient):
|
|
5
|
+
def __init__(self, pairs: List[str], api_key: str,
|
|
6
|
+
uri: str = "wss://forex.financialmodelingprep.com") -> None:
|
|
7
|
+
super().__init__(pairs, api_key, uri)
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from typing import List
|
|
2
|
+
from .base_websocket_client import BaseWebsocketClient
|
|
3
|
+
|
|
4
|
+
class StockWebsockets(BaseWebsocketClient):
|
|
5
|
+
def __init__(self, tickers: List[str], api_key: str,
|
|
6
|
+
uri: str = "wss://websockets.financialmodelingprep.com") -> None:
|
|
7
|
+
super().__init__(tickers, api_key, uri)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
class Logger:
|
|
7
|
+
def __init__(self, name: str = "FMPLogger", log_file: Optional[str] = None,
|
|
8
|
+
level: int = logging.INFO, enabled: bool = True) -> None:
|
|
9
|
+
self.logger = logging.getLogger(name)
|
|
10
|
+
self.logger.setLevel(level)
|
|
11
|
+
if log_file is None:
|
|
12
|
+
if "__main__" in sys.modules and hasattr(sys.modules["__main__"], "__file__"):
|
|
13
|
+
main_dir = os.path.dirname(sys.modules["__main__"].__file__)
|
|
14
|
+
else:
|
|
15
|
+
main_dir = os.getcwd()
|
|
16
|
+
log_file = os.path.join(main_dir, "fmp.log")
|
|
17
|
+
if enabled:
|
|
18
|
+
handler = logging.FileHandler(log_file)
|
|
19
|
+
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
20
|
+
handler.setFormatter(formatter)
|
|
21
|
+
self.logger.addHandler(handler)
|
|
22
|
+
else:
|
|
23
|
+
self.logger.addHandler(logging.NullHandler())
|
|
24
|
+
|
|
25
|
+
def info(self, message: str) -> None:
|
|
26
|
+
self.logger.info(message)
|
|
27
|
+
|
|
28
|
+
def error(self, message: str) -> None:
|
|
29
|
+
self.logger.error(message)
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import requests
|
|
2
|
+
from typing import Optional, Dict, Any
|
|
3
|
+
from ratelimit import limits, sleep_and_retry
|
|
4
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
5
|
+
from .logger import Logger
|
|
6
|
+
|
|
7
|
+
REQUEST_RATE = {"calls": 3000, "seconds": 60}
|
|
8
|
+
|
|
9
|
+
class Session:
|
|
10
|
+
"""
|
|
11
|
+
Provides a persistent HTTP session with rate limiting.
|
|
12
|
+
"""
|
|
13
|
+
def __init__(self, api_key: str, logger: Optional[Logger] = None) -> None:
|
|
14
|
+
self.api_key = api_key
|
|
15
|
+
self.session = requests.Session()
|
|
16
|
+
self.logger = logger if logger is not None else Logger("FMP.Session", enabled=True)
|
|
17
|
+
self.executor = ThreadPoolExecutor(max_workers=5)
|
|
18
|
+
|
|
19
|
+
@sleep_and_retry
|
|
20
|
+
@limits(calls=REQUEST_RATE["calls"], period=REQUEST_RATE["seconds"])
|
|
21
|
+
def get(self, url: str, params: Optional[Dict[str, Any]] = None) -> requests.Response:
|
|
22
|
+
self.logger.info(f"HTTP GET: {url} with params {params}")
|
|
23
|
+
try:
|
|
24
|
+
response = self.session.get(url, params=params)
|
|
25
|
+
response.raise_for_status()
|
|
26
|
+
self.logger.info(f"Response: {response.status_code}")
|
|
27
|
+
return response
|
|
28
|
+
except Exception as e:
|
|
29
|
+
self.logger.error(f"HTTP GET error: {e}")
|
|
30
|
+
raise
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: fmp-stable-api
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Python client library for the Financial Modeling Prep API
|
|
5
|
+
Home-page: https://github.com/Vimal-Seshadri-Raguraman/FMP
|
|
6
|
+
Author: Vimal Seshadri Raguraman
|
|
7
|
+
Project-URL: GitHub, https://github.com/Vimal-Seshadri-Raguraman/FMP
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
14
|
+
Requires-Python: >=3.6
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE.txt
|
|
17
|
+
Requires-Dist: requests
|
|
18
|
+
Requires-Dist: ratelimit
|
|
19
|
+
Requires-Dist: websockets
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: pytest; extra == "dev"
|
|
22
|
+
Requires-Dist: twine; extra == "dev"
|
|
23
|
+
Dynamic: author
|
|
24
|
+
Dynamic: classifier
|
|
25
|
+
Dynamic: description
|
|
26
|
+
Dynamic: description-content-type
|
|
27
|
+
Dynamic: home-page
|
|
28
|
+
Dynamic: project-url
|
|
29
|
+
Dynamic: provides-extra
|
|
30
|
+
Dynamic: requires-dist
|
|
31
|
+
Dynamic: requires-python
|
|
32
|
+
Dynamic: summary
|
|
33
|
+
|
|
34
|
+
# FMP Client Library
|
|
35
|
+
A Python client library for the [Financial Modeling Prep (FMP) API](https://financialmodelingprep.com/). This library provides both synchronous REST API and asynchronous WebSocket support, all in a modular, easy-to-use package.
|
|
36
|
+
|
|
37
|
+
The client is built to work with the [**Stable** version](https://site.financialmodelingprep.com/developer/docs/stable) of the Financial Modeling Prep (FMP) API. All endpoints are configured to use the stable base URL:
|
|
38
|
+
```arduino
|
|
39
|
+
https://financialmodelingprep.com/stable/
|
|
40
|
+
```
|
|
41
|
+
The endpoints available in this stable version are defined in the [fmp_endpoints.json](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/FMP/fmp_endpoints.json) file
|
|
42
|
+
|
|
43
|
+
## Features
|
|
44
|
+
|
|
45
|
+
- **Unified API Client:**
|
|
46
|
+
Dynamically access FMP endpoints using Pythonic method names.
|
|
47
|
+
|
|
48
|
+
- **Rate-Limited HTTP Session:**
|
|
49
|
+
Built-in rate limiting using the `ratelimit` library and robust error handling with logging.
|
|
50
|
+
|
|
51
|
+
- **Dynamic Endpoint Methods:**
|
|
52
|
+
Automatically attaches methods based on your configuration file (`fmp_endpoints.json`).
|
|
53
|
+
|
|
54
|
+
- **Asynchronous WebSocket Clients:**
|
|
55
|
+
Separate clients for stocks, crypto, and forex data available in the `fmp_websockets` subpackage.
|
|
56
|
+
|
|
57
|
+
- **Flexible Configuration and Logging:**
|
|
58
|
+
Easily configure your endpoints with a JSON file and log messages to a file in the same directory as your main script.
|
|
59
|
+
|
|
60
|
+
## Installation
|
|
61
|
+
|
|
62
|
+
Clone the repository and install the dependencies:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
66
|
+
cd FMP
|
|
67
|
+
pip install -r requirements.txt
|
|
68
|
+
python setup.py install
|
|
69
|
+
```
|
|
70
|
+
Alternatively, install directly from Github:
|
|
71
|
+
```bash
|
|
72
|
+
pip install git+https://github.com/Vimal-Seshadri-Raguraman/FMP.git
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
### API Client
|
|
77
|
+
Initialize the client with your API Key and call any endpoint dynmically:
|
|
78
|
+
```python
|
|
79
|
+
from fmp import FMP
|
|
80
|
+
|
|
81
|
+
# Initialize client with your API Key
|
|
82
|
+
client = fmp(api_key = "YOUR_API_KEY")
|
|
83
|
+
|
|
84
|
+
# Call an endpoint (e.g., "Profile")
|
|
85
|
+
response = client.profile(symbol = "AAPL")
|
|
86
|
+
print("Status Code:", response.status_code)
|
|
87
|
+
print("Profile Data:", response.json())
|
|
88
|
+
```
|
|
89
|
+
#### Dynmic Methods and Help
|
|
90
|
+
The client automatically attaches methods based on the JSON configuration. To see available endpoints and their parameters:
|
|
91
|
+
```python
|
|
92
|
+
# General help for all endpoints
|
|
93
|
+
print(client.help())
|
|
94
|
+
|
|
95
|
+
# Detailed help for a specific endpoint (e.g., "profile")
|
|
96
|
+
print(client.help("profile"))
|
|
97
|
+
|
|
98
|
+
# Generate a manual page of endpoints
|
|
99
|
+
man_doc = client.man_page() # Create a text file
|
|
100
|
+
print(man_doc)
|
|
101
|
+
```
|
|
102
|
+
### WebSocket Clients
|
|
103
|
+
The library includes asynchronous WebSocket clients for real-time data.
|
|
104
|
+
#### Stock WebSocket Example
|
|
105
|
+
```python
|
|
106
|
+
import asyncio
|
|
107
|
+
from fmp import StockWebsockets
|
|
108
|
+
|
|
109
|
+
async def run_stock_ws():
|
|
110
|
+
stock_ws = StockWebsockets(tickers=["AAPL", "MSFT"], api_key="YOUR_API_KEY")
|
|
111
|
+
async for message in stock_ws.run():
|
|
112
|
+
print("Stock WebSocket Message:", message)
|
|
113
|
+
|
|
114
|
+
asyncio.run(run_stock_ws())
|
|
115
|
+
```
|
|
116
|
+
#### Crypto and Forex WebSocket Example
|
|
117
|
+
```python
|
|
118
|
+
import asyncio
|
|
119
|
+
from fmp import CryptoWebsockets, ForexWebsockets
|
|
120
|
+
|
|
121
|
+
async def run_crypto_ws():
|
|
122
|
+
crypto_ws = CryptoWebsockets(tickers=["BTCUSD", "ETHUSD"], api_key="YOUR_API_KEY")
|
|
123
|
+
async for message in crypto_ws.run():
|
|
124
|
+
print("Crypto WebSocket Message:", message)
|
|
125
|
+
|
|
126
|
+
async def run_forex_ws():
|
|
127
|
+
forex_ws = ForexWebsockets(pairs=["EURUSD", "GBPUSD"], api_key="YOUR_API_KEY")
|
|
128
|
+
async for message in forex_ws.run():
|
|
129
|
+
print("Forex WebSocket Message:", message)
|
|
130
|
+
|
|
131
|
+
# Run one example at a time:
|
|
132
|
+
asyncio.run(run_crypto_ws())
|
|
133
|
+
# asyncio.run(run_forex_ws())
|
|
134
|
+
```
|
|
135
|
+
## Configuration
|
|
136
|
+
By default, the client loads endpoint configuration from ```fmp_endpoints.json``` located in the same directory as ```fmp_client.py```. To use a custom configuration file:
|
|
137
|
+
```python
|
|
138
|
+
client = FMP(api_key="YOUR_API_KEY", config_file="path/to/your_config.json")
|
|
139
|
+
```
|
|
140
|
+
If you update the configuration file during runtime, force a reload with:
|
|
141
|
+
```python
|
|
142
|
+
client.config_manager.reload()
|
|
143
|
+
```
|
|
144
|
+
## Logging
|
|
145
|
+
Logging is enabled by default and creates a log file (```fmp.log```) in the directory where your main script is located. To disable logging:
|
|
146
|
+
```python
|
|
147
|
+
client = FMP(api_key="YOUR_API_KEY", log_enabled=False)
|
|
148
|
+
```
|
|
149
|
+
## Contributing
|
|
150
|
+
Contributions, bug reports, and feature requests are welcome. Please open an issue or submit a pull request.
|
|
151
|
+
## License
|
|
152
|
+
This project is licensed under the MIT License. See the [```LICENSE.md```](https://github.com/Vimal-Seshadri-Raguraman/FMP/blob/main/LICENSE) file for details.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
LICENSE.txt
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
setup.py
|
|
6
|
+
fmp/__init__.py
|
|
7
|
+
fmp/config_manager.py
|
|
8
|
+
fmp/dynamic.py
|
|
9
|
+
fmp/fmp_client.py
|
|
10
|
+
fmp/logger.py
|
|
11
|
+
fmp/session.py
|
|
12
|
+
fmp/fmp_websockets/__init__.py
|
|
13
|
+
fmp/fmp_websockets/base_websocket_client.py
|
|
14
|
+
fmp/fmp_websockets/crypto_websocket.py
|
|
15
|
+
fmp/fmp_websockets/forex_websocket.py
|
|
16
|
+
fmp/fmp_websockets/stock_websocket.py
|
|
17
|
+
fmp_stable_api.egg-info/PKG-INFO
|
|
18
|
+
fmp_stable_api.egg-info/SOURCES.txt
|
|
19
|
+
fmp_stable_api.egg-info/dependency_links.txt
|
|
20
|
+
fmp_stable_api.egg-info/requires.txt
|
|
21
|
+
fmp_stable_api.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
fmp
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="fmp-stable-api",
|
|
5
|
+
version="0.0.1",
|
|
6
|
+
description="Python client library for the Financial Modeling Prep API",
|
|
7
|
+
long_description=open("README.md").read(),
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="Vimal Seshadri Raguraman",
|
|
10
|
+
url="https://github.com/Vimal-Seshadri-Raguraman/FMP",
|
|
11
|
+
packages=find_packages(),
|
|
12
|
+
include_package_data=True,
|
|
13
|
+
install_requires=[
|
|
14
|
+
"requests",
|
|
15
|
+
"ratelimit",
|
|
16
|
+
"websockets",
|
|
17
|
+
],
|
|
18
|
+
classifiers=[
|
|
19
|
+
"Development Status :: 3 - Alpha",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Operating System :: OS Independent",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"Intended Audience :: Financial and Insurance Industry",
|
|
24
|
+
"Topic :: Office/Business :: Financial"
|
|
25
|
+
],
|
|
26
|
+
extras_require={
|
|
27
|
+
"dev": [
|
|
28
|
+
"pytest",
|
|
29
|
+
"twine"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
python_requires='>=3.6',
|
|
33
|
+
project_urls={
|
|
34
|
+
"GitHub":"https://github.com/Vimal-Seshadri-Raguraman/FMP",
|
|
35
|
+
}
|
|
36
|
+
)
|