openbb-oilpriceapi 0.1.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.
- openbb_oilpriceapi-0.1.0/LICENSE +21 -0
- openbb_oilpriceapi-0.1.0/PKG-INFO +205 -0
- openbb_oilpriceapi-0.1.0/README.md +182 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/__init__.py +55 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/models/__init__.py +29 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/models/oil_historical.py +208 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/models/oil_price.py +234 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/utils/__init__.py +9 -0
- openbb_oilpriceapi-0.1.0/openbb_oilpriceapi/utils/constants.py +44 -0
- openbb_oilpriceapi-0.1.0/pyproject.toml +36 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 OilPriceAPI
|
|
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,205 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: openbb-oilpriceapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenBB provider for OilPriceAPI - Real-time oil and commodity prices (WTI, Brent, Urals, Natural Gas, Coal)
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: openbb,oil,commodity,api,energy,prices,wti,brent,urals
|
|
8
|
+
Author: OilPriceAPI
|
|
9
|
+
Author-email: support@oilpriceapi.com
|
|
10
|
+
Requires-Python: >=3.10,<3.14
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
18
|
+
Requires-Dist: openbb-core (>=1.5.1,<2.0.0)
|
|
19
|
+
Requires-Dist: tenacity (>=8.2.0,<9.0.0)
|
|
20
|
+
Project-URL: Repository, https://github.com/OilpriceAPI/openbb-oilpriceapi
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# openbb-oilpriceapi
|
|
24
|
+
|
|
25
|
+
[](https://badge.fury.io/py/openbb-oilpriceapi)
|
|
26
|
+
[](https://opensource.org/licenses/MIT)
|
|
27
|
+
|
|
28
|
+
OpenBB provider for [OilPriceAPI](https://oilpriceapi.com) - Real-time oil and commodity prices.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install openbb-oilpriceapi
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
from openbb import obb
|
|
40
|
+
|
|
41
|
+
# Configure your API key (get free key at https://oilpriceapi.com/signup)
|
|
42
|
+
obb.user.credentials.oilpriceapi_api_key = "your_api_key"
|
|
43
|
+
|
|
44
|
+
# Get all commodity prices
|
|
45
|
+
prices = obb.commodity.oil.price(provider="oilpriceapi")
|
|
46
|
+
df = prices.to_dataframe()
|
|
47
|
+
print(df)
|
|
48
|
+
|
|
49
|
+
# Get specific commodity (WTI crude)
|
|
50
|
+
wti = obb.commodity.oil.price(symbol="WTI", provider="oilpriceapi")
|
|
51
|
+
print(f"WTI Price: ${wti.results[0].price}/barrel")
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Supported Commodities
|
|
55
|
+
|
|
56
|
+
| Symbol | Name | Description |
|
|
57
|
+
|--------|------|-------------|
|
|
58
|
+
| `WTI` | WTI Crude Oil | West Texas Intermediate benchmark |
|
|
59
|
+
| `BRENT` | Brent Crude Oil | North Sea benchmark |
|
|
60
|
+
| `URALS` | Urals Crude Oil | Russian export blend |
|
|
61
|
+
| `DUBAI` | Dubai Crude Oil | Middle East benchmark |
|
|
62
|
+
| `NG` | Natural Gas (US) | Henry Hub |
|
|
63
|
+
| `NG_EU` | Natural Gas (EU) | TTF |
|
|
64
|
+
| `NG_UK` | Natural Gas (UK) | NBP |
|
|
65
|
+
| `COAL` | Coal | Thermal coal |
|
|
66
|
+
| `DIESEL_US` | US Diesel | National average |
|
|
67
|
+
| `GASOLINE_US` | US Gasoline | National average |
|
|
68
|
+
|
|
69
|
+
## Configuration
|
|
70
|
+
|
|
71
|
+
### Set Credentials
|
|
72
|
+
|
|
73
|
+
You can set your API key in multiple ways:
|
|
74
|
+
|
|
75
|
+
**Option 1: In Python**
|
|
76
|
+
```python
|
|
77
|
+
obb.user.credentials.oilpriceapi_api_key = "your_key"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Option 2: Via settings file**
|
|
81
|
+
Add to `~/.openbb_platform/user_settings.json`:
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"credentials": {
|
|
85
|
+
"oilpriceapi_api_key": "your_key"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**Option 3: Environment variable**
|
|
91
|
+
```bash
|
|
92
|
+
export OPENBB_OILPRICEAPI_API_KEY="your_key"
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Examples
|
|
96
|
+
|
|
97
|
+
### Get Price History
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
# Get WTI prices for the past week
|
|
101
|
+
history = obb.commodity.oil.historical(
|
|
102
|
+
symbol="WTI",
|
|
103
|
+
period="past_week",
|
|
104
|
+
provider="oilpriceapi"
|
|
105
|
+
)
|
|
106
|
+
df = history.to_dataframe()
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Compare Commodities
|
|
110
|
+
|
|
111
|
+
```python
|
|
112
|
+
import pandas as pd
|
|
113
|
+
|
|
114
|
+
# Get all prices and compare
|
|
115
|
+
prices = obb.commodity.oil.price(provider="oilpriceapi")
|
|
116
|
+
df = prices.to_dataframe()
|
|
117
|
+
|
|
118
|
+
# Filter for crude oils
|
|
119
|
+
crude = df[df['symbol'].isin(['WTI', 'BRENT', 'URALS'])]
|
|
120
|
+
print(crude[['symbol', 'price', 'change_percent']])
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Visualize Prices
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
import matplotlib.pyplot as plt
|
|
127
|
+
|
|
128
|
+
history = obb.commodity.oil.historical(
|
|
129
|
+
symbol="BRENT",
|
|
130
|
+
period="past_month",
|
|
131
|
+
provider="oilpriceapi"
|
|
132
|
+
)
|
|
133
|
+
df = history.to_dataframe()
|
|
134
|
+
|
|
135
|
+
plt.figure(figsize=(10, 6))
|
|
136
|
+
plt.plot(df['date'], df['price'])
|
|
137
|
+
plt.title('Brent Crude - Past Month')
|
|
138
|
+
plt.ylabel('Price (USD/barrel)')
|
|
139
|
+
plt.show()
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## API Reference
|
|
143
|
+
|
|
144
|
+
### OilPrice
|
|
145
|
+
|
|
146
|
+
Fetch latest commodity prices.
|
|
147
|
+
|
|
148
|
+
**Parameters:**
|
|
149
|
+
- `symbol` (str, optional): Commodity symbol. If not provided, returns all commodities.
|
|
150
|
+
- `provider` (str): Must be "oilpriceapi"
|
|
151
|
+
|
|
152
|
+
**Returns:**
|
|
153
|
+
- `symbol`: Commodity symbol
|
|
154
|
+
- `name`: Commodity name
|
|
155
|
+
- `price`: Current price
|
|
156
|
+
- `currency`: Price currency
|
|
157
|
+
- `unit`: Unit of measurement
|
|
158
|
+
- `updated_at`: Last update timestamp
|
|
159
|
+
- `change`: Price change (absolute)
|
|
160
|
+
- `change_percent`: Price change (percentage)
|
|
161
|
+
|
|
162
|
+
### OilHistorical
|
|
163
|
+
|
|
164
|
+
Fetch historical price data.
|
|
165
|
+
|
|
166
|
+
**Parameters:**
|
|
167
|
+
- `symbol` (str, required): Commodity symbol
|
|
168
|
+
- `period` (str): Historical period - `past_day` (24h hourly), `past_week` (7d daily), `past_month` (30d daily). Default: `past_week`
|
|
169
|
+
- `provider` (str): Must be "oilpriceapi"
|
|
170
|
+
|
|
171
|
+
**Returns:**
|
|
172
|
+
- `date`: Price timestamp
|
|
173
|
+
- `symbol`: Commodity symbol
|
|
174
|
+
- `price`: Price at timestamp
|
|
175
|
+
- `currency`: Price currency
|
|
176
|
+
- `unit`: Unit of measurement
|
|
177
|
+
|
|
178
|
+
## Development
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
# Clone the repository
|
|
182
|
+
git clone https://github.com/OilpriceAPI/openbb-oilpriceapi.git
|
|
183
|
+
cd openbb-oilpriceapi
|
|
184
|
+
|
|
185
|
+
# Install dependencies
|
|
186
|
+
poetry install
|
|
187
|
+
|
|
188
|
+
# Run tests
|
|
189
|
+
poetry run pytest
|
|
190
|
+
|
|
191
|
+
# Run tests with coverage
|
|
192
|
+
poetry run pytest --cov=openbb_oilpriceapi
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Links
|
|
196
|
+
|
|
197
|
+
- [OilPriceAPI Website](https://oilpriceapi.com)
|
|
198
|
+
- [OilPriceAPI Documentation](https://docs.oilpriceapi.com)
|
|
199
|
+
- [OpenBB Platform](https://openbb.co)
|
|
200
|
+
- [GitHub Repository](https://github.com/OilpriceAPI/openbb-oilpriceapi)
|
|
201
|
+
|
|
202
|
+
## License
|
|
203
|
+
|
|
204
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
205
|
+
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
# openbb-oilpriceapi
|
|
2
|
+
|
|
3
|
+
[](https://badge.fury.io/py/openbb-oilpriceapi)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
OpenBB provider for [OilPriceAPI](https://oilpriceapi.com) - Real-time oil and commodity prices.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
pip install openbb-oilpriceapi
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```python
|
|
17
|
+
from openbb import obb
|
|
18
|
+
|
|
19
|
+
# Configure your API key (get free key at https://oilpriceapi.com/signup)
|
|
20
|
+
obb.user.credentials.oilpriceapi_api_key = "your_api_key"
|
|
21
|
+
|
|
22
|
+
# Get all commodity prices
|
|
23
|
+
prices = obb.commodity.oil.price(provider="oilpriceapi")
|
|
24
|
+
df = prices.to_dataframe()
|
|
25
|
+
print(df)
|
|
26
|
+
|
|
27
|
+
# Get specific commodity (WTI crude)
|
|
28
|
+
wti = obb.commodity.oil.price(symbol="WTI", provider="oilpriceapi")
|
|
29
|
+
print(f"WTI Price: ${wti.results[0].price}/barrel")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Supported Commodities
|
|
33
|
+
|
|
34
|
+
| Symbol | Name | Description |
|
|
35
|
+
|--------|------|-------------|
|
|
36
|
+
| `WTI` | WTI Crude Oil | West Texas Intermediate benchmark |
|
|
37
|
+
| `BRENT` | Brent Crude Oil | North Sea benchmark |
|
|
38
|
+
| `URALS` | Urals Crude Oil | Russian export blend |
|
|
39
|
+
| `DUBAI` | Dubai Crude Oil | Middle East benchmark |
|
|
40
|
+
| `NG` | Natural Gas (US) | Henry Hub |
|
|
41
|
+
| `NG_EU` | Natural Gas (EU) | TTF |
|
|
42
|
+
| `NG_UK` | Natural Gas (UK) | NBP |
|
|
43
|
+
| `COAL` | Coal | Thermal coal |
|
|
44
|
+
| `DIESEL_US` | US Diesel | National average |
|
|
45
|
+
| `GASOLINE_US` | US Gasoline | National average |
|
|
46
|
+
|
|
47
|
+
## Configuration
|
|
48
|
+
|
|
49
|
+
### Set Credentials
|
|
50
|
+
|
|
51
|
+
You can set your API key in multiple ways:
|
|
52
|
+
|
|
53
|
+
**Option 1: In Python**
|
|
54
|
+
```python
|
|
55
|
+
obb.user.credentials.oilpriceapi_api_key = "your_key"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Option 2: Via settings file**
|
|
59
|
+
Add to `~/.openbb_platform/user_settings.json`:
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"credentials": {
|
|
63
|
+
"oilpriceapi_api_key": "your_key"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**Option 3: Environment variable**
|
|
69
|
+
```bash
|
|
70
|
+
export OPENBB_OILPRICEAPI_API_KEY="your_key"
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Examples
|
|
74
|
+
|
|
75
|
+
### Get Price History
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
# Get WTI prices for the past week
|
|
79
|
+
history = obb.commodity.oil.historical(
|
|
80
|
+
symbol="WTI",
|
|
81
|
+
period="past_week",
|
|
82
|
+
provider="oilpriceapi"
|
|
83
|
+
)
|
|
84
|
+
df = history.to_dataframe()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Compare Commodities
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
import pandas as pd
|
|
91
|
+
|
|
92
|
+
# Get all prices and compare
|
|
93
|
+
prices = obb.commodity.oil.price(provider="oilpriceapi")
|
|
94
|
+
df = prices.to_dataframe()
|
|
95
|
+
|
|
96
|
+
# Filter for crude oils
|
|
97
|
+
crude = df[df['symbol'].isin(['WTI', 'BRENT', 'URALS'])]
|
|
98
|
+
print(crude[['symbol', 'price', 'change_percent']])
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Visualize Prices
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
import matplotlib.pyplot as plt
|
|
105
|
+
|
|
106
|
+
history = obb.commodity.oil.historical(
|
|
107
|
+
symbol="BRENT",
|
|
108
|
+
period="past_month",
|
|
109
|
+
provider="oilpriceapi"
|
|
110
|
+
)
|
|
111
|
+
df = history.to_dataframe()
|
|
112
|
+
|
|
113
|
+
plt.figure(figsize=(10, 6))
|
|
114
|
+
plt.plot(df['date'], df['price'])
|
|
115
|
+
plt.title('Brent Crude - Past Month')
|
|
116
|
+
plt.ylabel('Price (USD/barrel)')
|
|
117
|
+
plt.show()
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## API Reference
|
|
121
|
+
|
|
122
|
+
### OilPrice
|
|
123
|
+
|
|
124
|
+
Fetch latest commodity prices.
|
|
125
|
+
|
|
126
|
+
**Parameters:**
|
|
127
|
+
- `symbol` (str, optional): Commodity symbol. If not provided, returns all commodities.
|
|
128
|
+
- `provider` (str): Must be "oilpriceapi"
|
|
129
|
+
|
|
130
|
+
**Returns:**
|
|
131
|
+
- `symbol`: Commodity symbol
|
|
132
|
+
- `name`: Commodity name
|
|
133
|
+
- `price`: Current price
|
|
134
|
+
- `currency`: Price currency
|
|
135
|
+
- `unit`: Unit of measurement
|
|
136
|
+
- `updated_at`: Last update timestamp
|
|
137
|
+
- `change`: Price change (absolute)
|
|
138
|
+
- `change_percent`: Price change (percentage)
|
|
139
|
+
|
|
140
|
+
### OilHistorical
|
|
141
|
+
|
|
142
|
+
Fetch historical price data.
|
|
143
|
+
|
|
144
|
+
**Parameters:**
|
|
145
|
+
- `symbol` (str, required): Commodity symbol
|
|
146
|
+
- `period` (str): Historical period - `past_day` (24h hourly), `past_week` (7d daily), `past_month` (30d daily). Default: `past_week`
|
|
147
|
+
- `provider` (str): Must be "oilpriceapi"
|
|
148
|
+
|
|
149
|
+
**Returns:**
|
|
150
|
+
- `date`: Price timestamp
|
|
151
|
+
- `symbol`: Commodity symbol
|
|
152
|
+
- `price`: Price at timestamp
|
|
153
|
+
- `currency`: Price currency
|
|
154
|
+
- `unit`: Unit of measurement
|
|
155
|
+
|
|
156
|
+
## Development
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
# Clone the repository
|
|
160
|
+
git clone https://github.com/OilpriceAPI/openbb-oilpriceapi.git
|
|
161
|
+
cd openbb-oilpriceapi
|
|
162
|
+
|
|
163
|
+
# Install dependencies
|
|
164
|
+
poetry install
|
|
165
|
+
|
|
166
|
+
# Run tests
|
|
167
|
+
poetry run pytest
|
|
168
|
+
|
|
169
|
+
# Run tests with coverage
|
|
170
|
+
poetry run pytest --cov=openbb_oilpriceapi
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Links
|
|
174
|
+
|
|
175
|
+
- [OilPriceAPI Website](https://oilpriceapi.com)
|
|
176
|
+
- [OilPriceAPI Documentation](https://docs.oilpriceapi.com)
|
|
177
|
+
- [OpenBB Platform](https://openbb.co)
|
|
178
|
+
- [GitHub Repository](https://github.com/OilpriceAPI/openbb-oilpriceapi)
|
|
179
|
+
|
|
180
|
+
## License
|
|
181
|
+
|
|
182
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""OpenBB OilPriceAPI Provider Module.
|
|
2
|
+
|
|
3
|
+
This provider enables access to real-time oil and commodity prices
|
|
4
|
+
from OilPriceAPI through the OpenBB Platform.
|
|
5
|
+
|
|
6
|
+
Supported commodities:
|
|
7
|
+
- WTI Crude Oil (WTI)
|
|
8
|
+
- Brent Crude Oil (BRENT)
|
|
9
|
+
- Urals Crude Oil (URALS)
|
|
10
|
+
- Dubai Crude Oil (DUBAI)
|
|
11
|
+
- Natural Gas US (NG)
|
|
12
|
+
- Natural Gas EU (NG_EU)
|
|
13
|
+
- Natural Gas UK (NG_UK)
|
|
14
|
+
- Coal (COAL)
|
|
15
|
+
- Diesel US (DIESEL_US)
|
|
16
|
+
- Gasoline US (GASOLINE_US)
|
|
17
|
+
|
|
18
|
+
Usage:
|
|
19
|
+
from openbb import obb
|
|
20
|
+
|
|
21
|
+
# Configure credentials
|
|
22
|
+
obb.user.credentials.oilpriceapi_api_key = "your_api_key"
|
|
23
|
+
|
|
24
|
+
# Get all prices
|
|
25
|
+
prices = obb.commodity.oil.price(provider="oilpriceapi")
|
|
26
|
+
|
|
27
|
+
# Get specific commodity
|
|
28
|
+
wti = obb.commodity.oil.price(symbol="WTI", provider="oilpriceapi")
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
from openbb_core.provider.abstract.provider import Provider
|
|
32
|
+
from openbb_oilpriceapi.models.oil_price import OilPriceAPIFetcher
|
|
33
|
+
from openbb_oilpriceapi.models.oil_historical import OilHistoricalFetcher
|
|
34
|
+
|
|
35
|
+
oilpriceapi_provider = Provider(
|
|
36
|
+
name="oilpriceapi",
|
|
37
|
+
website="https://oilpriceapi.com",
|
|
38
|
+
description=(
|
|
39
|
+
"OilPriceAPI provides real-time and historical oil and commodity prices "
|
|
40
|
+
"including WTI, Brent, Urals crude oil, natural gas, coal, and diesel. "
|
|
41
|
+
"Get your free API key at https://oilpriceapi.com"
|
|
42
|
+
),
|
|
43
|
+
credentials=["api_key"],
|
|
44
|
+
fetcher_dict={
|
|
45
|
+
"OilPrice": OilPriceAPIFetcher,
|
|
46
|
+
"OilHistorical": OilHistoricalFetcher,
|
|
47
|
+
},
|
|
48
|
+
repr_name="OilPriceAPI",
|
|
49
|
+
instructions=(
|
|
50
|
+
"Get your free API key at https://oilpriceapi.com/signup\n"
|
|
51
|
+
"Set credentials: obb.user.credentials.oilpriceapi_api_key = 'your_key'"
|
|
52
|
+
),
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
__all__ = ["oilpriceapi_provider"]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""OilPriceAPI models."""
|
|
2
|
+
|
|
3
|
+
from openbb_oilpriceapi.models.oil_price import (
|
|
4
|
+
OilPriceAPIFetcher,
|
|
5
|
+
OilPriceAPIQueryParams,
|
|
6
|
+
OilPriceAPIData,
|
|
7
|
+
OilPriceAPIError,
|
|
8
|
+
AuthenticationError,
|
|
9
|
+
RateLimitError,
|
|
10
|
+
NotFoundError,
|
|
11
|
+
)
|
|
12
|
+
from openbb_oilpriceapi.models.oil_historical import (
|
|
13
|
+
OilHistoricalFetcher,
|
|
14
|
+
OilHistoricalQueryParams,
|
|
15
|
+
OilHistoricalData,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__all__ = [
|
|
19
|
+
"OilPriceAPIFetcher",
|
|
20
|
+
"OilPriceAPIQueryParams",
|
|
21
|
+
"OilPriceAPIData",
|
|
22
|
+
"OilPriceAPIError",
|
|
23
|
+
"AuthenticationError",
|
|
24
|
+
"RateLimitError",
|
|
25
|
+
"NotFoundError",
|
|
26
|
+
"OilHistoricalFetcher",
|
|
27
|
+
"OilHistoricalQueryParams",
|
|
28
|
+
"OilHistoricalData",
|
|
29
|
+
]
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"""OilPriceAPI Historical Price model and fetcher."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any, Literal
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from openbb_core.provider.abstract.fetcher import Fetcher
|
|
8
|
+
from openbb_core.provider.abstract.query_params import QueryParams
|
|
9
|
+
from openbb_core.provider.abstract.data import Data
|
|
10
|
+
from pydantic import Field, field_validator
|
|
11
|
+
from tenacity import (
|
|
12
|
+
retry,
|
|
13
|
+
stop_after_attempt,
|
|
14
|
+
wait_exponential,
|
|
15
|
+
retry_if_exception_type,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from openbb_oilpriceapi.utils.constants import (
|
|
19
|
+
SYMBOL_MAPPING,
|
|
20
|
+
AVAILABLE_SYMBOLS,
|
|
21
|
+
OILPRICEAPI_BASE_URL,
|
|
22
|
+
REVERSE_SYMBOL_MAPPING,
|
|
23
|
+
)
|
|
24
|
+
from openbb_oilpriceapi.models.oil_price import (
|
|
25
|
+
AuthenticationError,
|
|
26
|
+
RateLimitError,
|
|
27
|
+
NotFoundError,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
# Supported historical periods
|
|
32
|
+
HISTORICAL_PERIODS = ["past_day", "past_week", "past_month"]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class OilHistoricalQueryParams(QueryParams):
|
|
36
|
+
"""OilPriceAPI Historical Query Parameters.
|
|
37
|
+
|
|
38
|
+
Source: https://oilpriceapi.com
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
__json_schema_extra__ = {
|
|
42
|
+
"symbol": {
|
|
43
|
+
"multiple_items_allowed": False,
|
|
44
|
+
"choices": AVAILABLE_SYMBOLS,
|
|
45
|
+
},
|
|
46
|
+
"period": {
|
|
47
|
+
"multiple_items_allowed": False,
|
|
48
|
+
"choices": HISTORICAL_PERIODS,
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
symbol: str = Field(
|
|
53
|
+
description="The commodity symbol to fetch historical data for. "
|
|
54
|
+
f"Available symbols: {', '.join(AVAILABLE_SYMBOLS)}",
|
|
55
|
+
)
|
|
56
|
+
period: Literal["past_day", "past_week", "past_month"] = Field(
|
|
57
|
+
default="past_week",
|
|
58
|
+
description="Historical period: past_day (24h hourly), past_week (7d daily), past_month (30d daily).",
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
@field_validator("symbol", mode="before")
|
|
62
|
+
@classmethod
|
|
63
|
+
def validate_symbol(cls, v: str) -> str:
|
|
64
|
+
"""Validate that symbol is in the list of available symbols."""
|
|
65
|
+
v_upper = v.upper()
|
|
66
|
+
if v_upper not in AVAILABLE_SYMBOLS:
|
|
67
|
+
raise ValueError(
|
|
68
|
+
f"Invalid symbol '{v}'. Available symbols: {', '.join(AVAILABLE_SYMBOLS)}"
|
|
69
|
+
)
|
|
70
|
+
return v_upper
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class OilHistoricalData(Data):
|
|
74
|
+
"""OilPriceAPI Historical Price Data Model."""
|
|
75
|
+
|
|
76
|
+
date: datetime = Field(description="The timestamp of the price data point.")
|
|
77
|
+
symbol: str = Field(description="The commodity symbol/code.")
|
|
78
|
+
price: float = Field(description="The price at this timestamp.")
|
|
79
|
+
currency: str = Field(default="USD", description="The price currency.")
|
|
80
|
+
unit: str = Field(default="barrel", description="The unit of measurement.")
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class OilHistoricalFetcher(Fetcher[OilHistoricalQueryParams, list[OilHistoricalData]]):
|
|
84
|
+
"""OilPriceAPI Historical Price Fetcher."""
|
|
85
|
+
|
|
86
|
+
require_credentials = True
|
|
87
|
+
|
|
88
|
+
@staticmethod
|
|
89
|
+
def transform_query(params: dict[str, Any]) -> OilHistoricalQueryParams:
|
|
90
|
+
"""Transform the query parameters."""
|
|
91
|
+
return OilHistoricalQueryParams(**params)
|
|
92
|
+
|
|
93
|
+
@staticmethod
|
|
94
|
+
@retry(
|
|
95
|
+
stop=stop_after_attempt(3),
|
|
96
|
+
wait=wait_exponential(multiplier=1, min=1, max=10),
|
|
97
|
+
retry=retry_if_exception_type(RateLimitError),
|
|
98
|
+
reraise=True,
|
|
99
|
+
)
|
|
100
|
+
async def _fetch_with_retry(
|
|
101
|
+
client: httpx.AsyncClient,
|
|
102
|
+
url: str,
|
|
103
|
+
headers: dict[str, str],
|
|
104
|
+
) -> dict[str, Any]:
|
|
105
|
+
"""Fetch data with retry logic for rate limits."""
|
|
106
|
+
response = await client.get(url, headers=headers)
|
|
107
|
+
|
|
108
|
+
if response.status_code == 401:
|
|
109
|
+
raise AuthenticationError(
|
|
110
|
+
"Invalid API key. Check your OilPriceAPI credentials."
|
|
111
|
+
)
|
|
112
|
+
if response.status_code == 429:
|
|
113
|
+
raise RateLimitError(
|
|
114
|
+
"Rate limit exceeded. Retrying with exponential backoff..."
|
|
115
|
+
)
|
|
116
|
+
if response.status_code == 404:
|
|
117
|
+
raise NotFoundError("Commodity not found.")
|
|
118
|
+
|
|
119
|
+
response.raise_for_status()
|
|
120
|
+
return response.json()
|
|
121
|
+
|
|
122
|
+
@staticmethod
|
|
123
|
+
async def aextract_data(
|
|
124
|
+
query: OilHistoricalQueryParams,
|
|
125
|
+
credentials: dict[str, str] | None,
|
|
126
|
+
**kwargs: Any,
|
|
127
|
+
) -> list[dict[str, Any]]:
|
|
128
|
+
"""Extract historical data from OilPriceAPI."""
|
|
129
|
+
api_key = credentials.get("api_key") if credentials else None
|
|
130
|
+
if not api_key:
|
|
131
|
+
raise AuthenticationError(
|
|
132
|
+
"OilPriceAPI API key is required. "
|
|
133
|
+
"Get a free key at https://oilpriceapi.com"
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
headers = {
|
|
137
|
+
"Authorization": f"Token {api_key}",
|
|
138
|
+
"Accept": "application/json",
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
# Map OpenBB symbol to OilPriceAPI code
|
|
142
|
+
oilpriceapi_code = SYMBOL_MAPPING.get(query.symbol, query.symbol)
|
|
143
|
+
url = f"{OILPRICEAPI_BASE_URL}/prices/{query.period}?by_code={oilpriceapi_code}"
|
|
144
|
+
|
|
145
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
146
|
+
try:
|
|
147
|
+
data = await OilHistoricalFetcher._fetch_with_retry(
|
|
148
|
+
client, url, headers
|
|
149
|
+
)
|
|
150
|
+
except RateLimitError:
|
|
151
|
+
raise RateLimitError(
|
|
152
|
+
"Rate limit exceeded after 3 retries. "
|
|
153
|
+
"Please wait before making more requests."
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
# Handle response structure
|
|
157
|
+
if "data" in data:
|
|
158
|
+
if "prices" in data["data"]:
|
|
159
|
+
return data["data"]["prices"]
|
|
160
|
+
elif isinstance(data["data"], list):
|
|
161
|
+
return data["data"]
|
|
162
|
+
|
|
163
|
+
return []
|
|
164
|
+
|
|
165
|
+
@staticmethod
|
|
166
|
+
def transform_data(
|
|
167
|
+
query: OilHistoricalQueryParams,
|
|
168
|
+
data: list[dict[str, Any]],
|
|
169
|
+
**kwargs: Any,
|
|
170
|
+
) -> list[OilHistoricalData]:
|
|
171
|
+
"""Transform API response to OilHistoricalData models."""
|
|
172
|
+
results = []
|
|
173
|
+
|
|
174
|
+
for item in data:
|
|
175
|
+
# Parse the timestamp
|
|
176
|
+
date_str = item.get("created_at") or item.get("date") or item.get("timestamp")
|
|
177
|
+
if date_str:
|
|
178
|
+
if isinstance(date_str, str):
|
|
179
|
+
date_str = date_str.replace("Z", "+00:00")
|
|
180
|
+
try:
|
|
181
|
+
date = datetime.fromisoformat(date_str)
|
|
182
|
+
except ValueError:
|
|
183
|
+
continue # Skip invalid dates
|
|
184
|
+
else:
|
|
185
|
+
date = date_str
|
|
186
|
+
else:
|
|
187
|
+
continue # Skip entries without dates
|
|
188
|
+
|
|
189
|
+
# Get symbol from query (historical data is for specific symbol)
|
|
190
|
+
symbol = query.symbol
|
|
191
|
+
|
|
192
|
+
# Clean up unit string
|
|
193
|
+
unit = item.get("unit", "").replace("per ", "").strip() or "barrel"
|
|
194
|
+
|
|
195
|
+
results.append(
|
|
196
|
+
OilHistoricalData(
|
|
197
|
+
date=date,
|
|
198
|
+
symbol=symbol,
|
|
199
|
+
price=float(item.get("price", 0)),
|
|
200
|
+
currency=item.get("currency", "USD"),
|
|
201
|
+
unit=unit,
|
|
202
|
+
)
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
# Sort by date ascending
|
|
206
|
+
results.sort(key=lambda x: x.date)
|
|
207
|
+
|
|
208
|
+
return results
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""OilPriceAPI Oil Price model and fetcher."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
from openbb_core.provider.abstract.fetcher import Fetcher
|
|
8
|
+
from openbb_core.provider.abstract.query_params import QueryParams
|
|
9
|
+
from openbb_core.provider.abstract.data import Data
|
|
10
|
+
from pydantic import Field, field_validator
|
|
11
|
+
from tenacity import (
|
|
12
|
+
retry,
|
|
13
|
+
stop_after_attempt,
|
|
14
|
+
wait_exponential,
|
|
15
|
+
retry_if_exception_type,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from openbb_oilpriceapi.utils.constants import (
|
|
19
|
+
SYMBOL_MAPPING,
|
|
20
|
+
AVAILABLE_SYMBOLS,
|
|
21
|
+
OILPRICEAPI_BASE_URL,
|
|
22
|
+
REVERSE_SYMBOL_MAPPING,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OilPriceAPIError(Exception):
|
|
27
|
+
"""Base exception for OilPriceAPI errors."""
|
|
28
|
+
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class AuthenticationError(OilPriceAPIError):
|
|
33
|
+
"""Raised when API key is invalid or missing."""
|
|
34
|
+
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class RateLimitError(OilPriceAPIError):
|
|
39
|
+
"""Raised when rate limit is exceeded."""
|
|
40
|
+
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class NotFoundError(OilPriceAPIError):
|
|
45
|
+
"""Raised when commodity is not found."""
|
|
46
|
+
|
|
47
|
+
pass
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class OilPriceAPIQueryParams(QueryParams):
|
|
51
|
+
"""OilPriceAPI Query Parameters.
|
|
52
|
+
|
|
53
|
+
Source: https://oilpriceapi.com
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
__json_schema_extra__ = {
|
|
57
|
+
"symbol": {
|
|
58
|
+
"multiple_items_allowed": False,
|
|
59
|
+
"choices": AVAILABLE_SYMBOLS,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
symbol: str | None = Field(
|
|
64
|
+
default=None,
|
|
65
|
+
description="The commodity symbol to fetch. If None, returns all available commodities. "
|
|
66
|
+
f"Available symbols: {', '.join(AVAILABLE_SYMBOLS)}",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@field_validator("symbol", mode="before")
|
|
70
|
+
@classmethod
|
|
71
|
+
def validate_symbol(cls, v: str | None) -> str | None:
|
|
72
|
+
"""Validate that symbol is in the list of available symbols."""
|
|
73
|
+
if v is None:
|
|
74
|
+
return v
|
|
75
|
+
v_upper = v.upper()
|
|
76
|
+
if v_upper not in AVAILABLE_SYMBOLS:
|
|
77
|
+
raise ValueError(
|
|
78
|
+
f"Invalid symbol '{v}'. Available symbols: {', '.join(AVAILABLE_SYMBOLS)}"
|
|
79
|
+
)
|
|
80
|
+
return v_upper
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class OilPriceAPIData(Data):
|
|
84
|
+
"""OilPriceAPI Oil Price Data Model."""
|
|
85
|
+
|
|
86
|
+
symbol: str = Field(description="The commodity symbol/code.")
|
|
87
|
+
name: str = Field(description="The commodity name.")
|
|
88
|
+
price: float = Field(description="The current price.")
|
|
89
|
+
currency: str = Field(description="The price currency (e.g., USD).")
|
|
90
|
+
unit: str = Field(description="The unit of measurement (e.g., barrel, therm).")
|
|
91
|
+
updated_at: datetime = Field(description="The timestamp of the last price update.")
|
|
92
|
+
change: float | None = Field(
|
|
93
|
+
default=None, description="The absolute price change."
|
|
94
|
+
)
|
|
95
|
+
change_percent: float | None = Field(
|
|
96
|
+
default=None, description="The percentage price change."
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class OilPriceAPIFetcher(Fetcher[OilPriceAPIQueryParams, list[OilPriceAPIData]]):
|
|
101
|
+
"""OilPriceAPI Oil Price Fetcher."""
|
|
102
|
+
|
|
103
|
+
require_credentials = True
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def transform_query(params: dict[str, Any]) -> OilPriceAPIQueryParams:
|
|
107
|
+
"""Transform the query parameters."""
|
|
108
|
+
return OilPriceAPIQueryParams(**params)
|
|
109
|
+
|
|
110
|
+
@staticmethod
|
|
111
|
+
@retry(
|
|
112
|
+
stop=stop_after_attempt(3),
|
|
113
|
+
wait=wait_exponential(multiplier=1, min=1, max=10),
|
|
114
|
+
retry=retry_if_exception_type(RateLimitError),
|
|
115
|
+
reraise=True,
|
|
116
|
+
)
|
|
117
|
+
async def _fetch_with_retry(
|
|
118
|
+
client: httpx.AsyncClient,
|
|
119
|
+
url: str,
|
|
120
|
+
headers: dict[str, str],
|
|
121
|
+
) -> dict[str, Any]:
|
|
122
|
+
"""Fetch data with retry logic for rate limits."""
|
|
123
|
+
response = await client.get(url, headers=headers)
|
|
124
|
+
|
|
125
|
+
if response.status_code == 401:
|
|
126
|
+
raise AuthenticationError(
|
|
127
|
+
"Invalid API key. Check your OilPriceAPI credentials."
|
|
128
|
+
)
|
|
129
|
+
if response.status_code == 429:
|
|
130
|
+
raise RateLimitError(
|
|
131
|
+
"Rate limit exceeded. Retrying with exponential backoff..."
|
|
132
|
+
)
|
|
133
|
+
if response.status_code == 404:
|
|
134
|
+
raise NotFoundError("Commodity not found.")
|
|
135
|
+
|
|
136
|
+
response.raise_for_status()
|
|
137
|
+
return response.json()
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
async def aextract_data(
|
|
141
|
+
query: OilPriceAPIQueryParams,
|
|
142
|
+
credentials: dict[str, str] | None,
|
|
143
|
+
**kwargs: Any,
|
|
144
|
+
) -> list[dict[str, Any]]:
|
|
145
|
+
"""Extract data from OilPriceAPI."""
|
|
146
|
+
api_key = credentials.get("api_key") if credentials else None
|
|
147
|
+
if not api_key:
|
|
148
|
+
raise AuthenticationError(
|
|
149
|
+
"OilPriceAPI API key is required. "
|
|
150
|
+
"Get a free key at https://oilpriceapi.com"
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
headers = {
|
|
154
|
+
"Authorization": f"Token {api_key}",
|
|
155
|
+
"Accept": "application/json",
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
async with httpx.AsyncClient(timeout=30.0) as client:
|
|
159
|
+
# Determine endpoint based on symbol
|
|
160
|
+
if query.symbol:
|
|
161
|
+
# Map OpenBB symbol to OilPriceAPI code
|
|
162
|
+
oilpriceapi_code = SYMBOL_MAPPING.get(query.symbol, query.symbol)
|
|
163
|
+
url = f"{OILPRICEAPI_BASE_URL}/prices/latest?by_code={oilpriceapi_code}"
|
|
164
|
+
else:
|
|
165
|
+
url = f"{OILPRICEAPI_BASE_URL}/prices/latest"
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
data = await OilPriceAPIFetcher._fetch_with_retry(client, url, headers)
|
|
169
|
+
except RateLimitError:
|
|
170
|
+
# Re-raise with user-friendly message after retries exhausted
|
|
171
|
+
raise RateLimitError(
|
|
172
|
+
"Rate limit exceeded after 3 retries. "
|
|
173
|
+
"Please wait before making more requests."
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Handle different response structures
|
|
177
|
+
if "data" in data:
|
|
178
|
+
if "prices" in data["data"]:
|
|
179
|
+
# Multiple prices response
|
|
180
|
+
return data["data"]["prices"]
|
|
181
|
+
elif "price" in data["data"]:
|
|
182
|
+
# Single price response
|
|
183
|
+
return [data["data"]["price"]]
|
|
184
|
+
else:
|
|
185
|
+
return [data["data"]]
|
|
186
|
+
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
@staticmethod
|
|
190
|
+
def transform_data(
|
|
191
|
+
query: OilPriceAPIQueryParams,
|
|
192
|
+
data: list[dict[str, Any]],
|
|
193
|
+
**kwargs: Any,
|
|
194
|
+
) -> list[OilPriceAPIData]:
|
|
195
|
+
"""Transform API response to OilPriceAPIData models."""
|
|
196
|
+
results = []
|
|
197
|
+
|
|
198
|
+
for item in data:
|
|
199
|
+
# Parse the timestamp
|
|
200
|
+
updated_at_str = item.get("created_at") or item.get("updated_at")
|
|
201
|
+
if updated_at_str:
|
|
202
|
+
if isinstance(updated_at_str, str):
|
|
203
|
+
# Handle ISO format with or without Z suffix
|
|
204
|
+
updated_at_str = updated_at_str.replace("Z", "+00:00")
|
|
205
|
+
try:
|
|
206
|
+
updated_at = datetime.fromisoformat(updated_at_str)
|
|
207
|
+
except ValueError:
|
|
208
|
+
updated_at = datetime.now()
|
|
209
|
+
else:
|
|
210
|
+
updated_at = updated_at_str
|
|
211
|
+
else:
|
|
212
|
+
updated_at = datetime.now()
|
|
213
|
+
|
|
214
|
+
# Get the symbol - use OpenBB symbol if available
|
|
215
|
+
raw_symbol = item.get("code", item.get("symbol", "UNKNOWN"))
|
|
216
|
+
symbol = REVERSE_SYMBOL_MAPPING.get(raw_symbol, raw_symbol)
|
|
217
|
+
|
|
218
|
+
# Clean up unit string
|
|
219
|
+
unit = item.get("unit", "").replace("per ", "").strip()
|
|
220
|
+
|
|
221
|
+
results.append(
|
|
222
|
+
OilPriceAPIData(
|
|
223
|
+
symbol=symbol,
|
|
224
|
+
name=item.get("name", ""),
|
|
225
|
+
price=float(item.get("price", 0)),
|
|
226
|
+
currency=item.get("currency", "USD"),
|
|
227
|
+
unit=unit or "barrel",
|
|
228
|
+
updated_at=updated_at,
|
|
229
|
+
change=item.get("change"),
|
|
230
|
+
change_percent=item.get("change_percent"),
|
|
231
|
+
)
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
return results
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"""OilPriceAPI constants and symbol mappings."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
# Base URL for OilPriceAPI
|
|
6
|
+
OILPRICEAPI_BASE_URL = "https://api.oilpriceapi.com/v1"
|
|
7
|
+
|
|
8
|
+
# Mapping from OpenBB symbols to OilPriceAPI commodity codes
|
|
9
|
+
SYMBOL_MAPPING: dict[str, str] = {
|
|
10
|
+
# Crude Oil
|
|
11
|
+
"WTI": "WTI_USD",
|
|
12
|
+
"BRENT": "BRENT_CRUDE_USD",
|
|
13
|
+
"URALS": "URALS_USD",
|
|
14
|
+
"DUBAI": "DUBAI_CRUDE_USD",
|
|
15
|
+
# Natural Gas
|
|
16
|
+
"NG": "NATURAL_GAS_USD",
|
|
17
|
+
"NG_EU": "NATURAL_GAS_EU",
|
|
18
|
+
"NG_UK": "NATURAL_GAS_GBP",
|
|
19
|
+
# Coal
|
|
20
|
+
"COAL": "COAL_USD",
|
|
21
|
+
# Diesel/Gasoline
|
|
22
|
+
"DIESEL_US": "DIESEL_US_NATIONAL",
|
|
23
|
+
"GASOLINE_US": "GASOLINE_US_NATIONAL",
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Reverse mapping for transforming API responses
|
|
27
|
+
REVERSE_SYMBOL_MAPPING: dict[str, str] = {v: k for k, v in SYMBOL_MAPPING.items()}
|
|
28
|
+
|
|
29
|
+
# List of available symbols for validation
|
|
30
|
+
AVAILABLE_SYMBOLS: list[str] = list(SYMBOL_MAPPING.keys())
|
|
31
|
+
|
|
32
|
+
# Type for symbol literals (for type hints)
|
|
33
|
+
SymbolType = Literal[
|
|
34
|
+
"WTI",
|
|
35
|
+
"BRENT",
|
|
36
|
+
"URALS",
|
|
37
|
+
"DUBAI",
|
|
38
|
+
"NG",
|
|
39
|
+
"NG_EU",
|
|
40
|
+
"NG_UK",
|
|
41
|
+
"COAL",
|
|
42
|
+
"DIESEL_US",
|
|
43
|
+
"GASOLINE_US",
|
|
44
|
+
]
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "openbb-oilpriceapi"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "OpenBB provider for OilPriceAPI - Real-time oil and commodity prices (WTI, Brent, Urals, Natural Gas, Coal)"
|
|
5
|
+
authors = ["OilPriceAPI <support@oilpriceapi.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
packages = [{ include = "openbb_oilpriceapi" }]
|
|
9
|
+
repository = "https://github.com/OilpriceAPI/openbb-oilpriceapi"
|
|
10
|
+
keywords = ["openbb", "oil", "commodity", "api", "energy", "prices", "wti", "brent", "urals"]
|
|
11
|
+
|
|
12
|
+
[tool.poetry.dependencies]
|
|
13
|
+
python = ">=3.10,<3.14"
|
|
14
|
+
openbb-core = "^1.5.1"
|
|
15
|
+
httpx = "^0.27.0"
|
|
16
|
+
tenacity = "^8.2.0"
|
|
17
|
+
|
|
18
|
+
[tool.poetry.group.dev.dependencies]
|
|
19
|
+
pytest = "^8.0.0"
|
|
20
|
+
pytest-asyncio = "^0.23.0"
|
|
21
|
+
pytest-cov = "^4.1.0"
|
|
22
|
+
respx = "^0.21.0"
|
|
23
|
+
|
|
24
|
+
[build-system]
|
|
25
|
+
requires = ["poetry-core"]
|
|
26
|
+
build-backend = "poetry.core.masonry.api"
|
|
27
|
+
|
|
28
|
+
[tool.poetry.plugins."openbb_provider_extension"]
|
|
29
|
+
oilpriceapi = "openbb_oilpriceapi:oilpriceapi_provider"
|
|
30
|
+
|
|
31
|
+
[tool.pytest.ini_options]
|
|
32
|
+
asyncio_mode = "auto"
|
|
33
|
+
testpaths = ["tests"]
|
|
34
|
+
|
|
35
|
+
[tool.coverage.run]
|
|
36
|
+
source = ["openbb_oilpriceapi"]
|