quantmod 0.0.6__tar.gz → 0.0.7__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.
- {quantmod-0.0.6 → quantmod-0.0.7}/PKG-INFO +4 -2
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/__init__.py +1 -0
- {quantmod-0.0.6/quantmod/datasets/data → quantmod-0.0.7/quantmod/charts}/__init__.py +4 -1
- quantmod-0.0.7/quantmod/charts/plotting.py +463 -0
- quantmod-0.0.7/quantmod/charts/themes.py +142 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/datasets/dataloader.py +19 -12
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/derivatives/nse.py +7 -1
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/risk/varbacktest.py +2 -1
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/timeseries/performance.py +15 -5
- quantmod-0.0.7/quantmod/version.py +1 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/PKG-INFO +4 -2
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/SOURCES.txt +3 -1
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/requires.txt +3 -1
- quantmod-0.0.6/quantmod/version.py +0 -1
- {quantmod-0.0.6 → quantmod-0.0.7}/LICENSE.txt +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/README.md +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/_version.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/datasets/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/datasets/data/nifty50.csv +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/datasets/data/spx.csv +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/derivatives/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/indicators/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/indicators/indicators.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/main.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/markets/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/markets/bb.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/markets/yahoo.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/models/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/models/binomial.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/models/blackscholes.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/models/montecarlo.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/models/optioninputs.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/risk/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/risk/var.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/risk/varinputs.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/timeseries/__init__.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/timeseries/timeseries.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod/utils.py +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/dependency_links.txt +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/entry_points.txt +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/not-zip-safe +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/quantmod.egg-info/top_level.txt +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/setup.cfg +0 -0
- {quantmod-0.0.6 → quantmod-0.0.7}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: quantmod
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Quantmod Python Package
|
|
5
5
|
Home-page: https://kannansingaravelu.com/
|
|
6
6
|
Author: Kannan Singaravelu
|
|
@@ -21,14 +21,16 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
22
|
Requires-Dist: joblib
|
|
23
23
|
Requires-Dist: matplotlib
|
|
24
|
+
Requires-Dist: nbformat>=5.10.4
|
|
24
25
|
Requires-Dist: numpy>=2.0.2
|
|
25
26
|
Requires-Dist: pandas>=2.2.2
|
|
27
|
+
Requires-Dist: plotly>=6.1.2
|
|
26
28
|
Requires-Dist: pydantic>=2.8.2
|
|
27
29
|
Requires-Dist: scipy>=1.13.1
|
|
28
30
|
Requires-Dist: sqlalchemy>=2.0.38
|
|
29
31
|
Requires-Dist: tabulate>=0.9.0
|
|
30
32
|
Requires-Dist: urllib3==1.26.15
|
|
31
|
-
Requires-Dist: yfinance
|
|
33
|
+
Requires-Dist: yfinance==0.2.58
|
|
32
34
|
Dynamic: author
|
|
33
35
|
Dynamic: author-email
|
|
34
36
|
Dynamic: classifier
|
|
@@ -14,4 +14,7 @@
|
|
|
14
14
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
15
|
# See the License for the specific language governing permissions and
|
|
16
16
|
# limitations under the License.
|
|
17
|
-
#
|
|
17
|
+
#
|
|
18
|
+
|
|
19
|
+
# Import plotlytools to enable the monkey-patching of pandas objects
|
|
20
|
+
from . import plotting
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
"""
|
|
2
|
+
quantmod.charts.plotting
|
|
3
|
+
|
|
4
|
+
Interactive Plotting Utilities for Quantmod
|
|
5
|
+
|
|
6
|
+
Usage Notes:
|
|
7
|
+
- In **Jupyter notebooks**, interactive plots display inline automatically when you call `df.iplot(...)`.
|
|
8
|
+
- In **Python scripts**, interactive plots open in your default web browser. For best results, set:
|
|
9
|
+
import plotly.io as pio
|
|
10
|
+
pio.renderers.default = "browser"
|
|
11
|
+
fig = df.iplot(...)
|
|
12
|
+
fig.show()
|
|
13
|
+
- In **headless environments** (e.g., servers), save plots to HTML files:
|
|
14
|
+
fig = df.iplot(...)
|
|
15
|
+
fig.write_html("plot.html")
|
|
16
|
+
print("Plot saved to plot.html. Open this file in your browser to view the plot.")
|
|
17
|
+
|
|
18
|
+
Available Chart Types:
|
|
19
|
+
- "line": Line chart
|
|
20
|
+
- "scatter": Scatter plot
|
|
21
|
+
- "ohlc": OHLC (Open-High-Low-Close) chart
|
|
22
|
+
- "candlestick": Candlestick chart
|
|
23
|
+
- "subplots": Multiple line charts as subplots
|
|
24
|
+
- "histogram": Histogram of daily returns
|
|
25
|
+
- "bar": Bar chart
|
|
26
|
+
- "heatmap": Heatmap
|
|
27
|
+
- "box": Box plot
|
|
28
|
+
- "pie": Pie chart
|
|
29
|
+
- "treemap": Treemap chart
|
|
30
|
+
- "overlay": Overlay multiple series with secondary y-axis
|
|
31
|
+
- "normalized": Normalized line chart (base=100)
|
|
32
|
+
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
import pandas as pd
|
|
36
|
+
import plotly.graph_objects as go
|
|
37
|
+
import plotly.express.colors as pc
|
|
38
|
+
from plotly.subplots import make_subplots
|
|
39
|
+
import plotly.io as pio
|
|
40
|
+
from .themes import THEMES, COLOR_SCALES, create_template
|
|
41
|
+
|
|
42
|
+
# Set global Plotly theme and dimensions
|
|
43
|
+
# pio.templates["pearl"] = create_pearl_template()
|
|
44
|
+
# pio.templates.default = "pearl"
|
|
45
|
+
# DEFAULT_THEME = "pearl"
|
|
46
|
+
|
|
47
|
+
# Register all available themes
|
|
48
|
+
for theme_name in THEMES.keys():
|
|
49
|
+
pio.templates[theme_name] = create_template(theme_name)
|
|
50
|
+
|
|
51
|
+
# Set default template
|
|
52
|
+
pio.templates.default = "pearl"
|
|
53
|
+
|
|
54
|
+
DEFAULT_THEME = "pearl"
|
|
55
|
+
DEFAULT_WIDTH = 1000
|
|
56
|
+
DEFAULT_HEIGHT = 600
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# Main plot dispatcher
|
|
60
|
+
def _iplot(self, kind="line", **kwargs):
|
|
61
|
+
if kind == "normalized":
|
|
62
|
+
return _plot_normalized(self, **kwargs)
|
|
63
|
+
if kind == "overlay":
|
|
64
|
+
return _plot_overlay(self, **kwargs)
|
|
65
|
+
if isinstance(self, pd.Series):
|
|
66
|
+
df = self.to_frame()
|
|
67
|
+
else:
|
|
68
|
+
df = self.copy()
|
|
69
|
+
|
|
70
|
+
# Create a lowercase column mapping
|
|
71
|
+
colmap = {col.lower(): col for col in df.columns}
|
|
72
|
+
|
|
73
|
+
if kind == "line":
|
|
74
|
+
fig = _plot_line(df, **kwargs)
|
|
75
|
+
elif kind == "scatter":
|
|
76
|
+
fig = _plot_scatter(df, **kwargs)
|
|
77
|
+
elif kind == "ohlc":
|
|
78
|
+
fig = _plot_ohlc(df, colmap, **kwargs)
|
|
79
|
+
elif kind == "candlestick":
|
|
80
|
+
fig = _plot_candlestick(df, colmap, **kwargs)
|
|
81
|
+
elif kind == "subplots":
|
|
82
|
+
fig = _plot_subplots(df, **kwargs)
|
|
83
|
+
elif kind == "histogram":
|
|
84
|
+
fig = _plot_histogram(df, **kwargs)
|
|
85
|
+
elif kind == "bar":
|
|
86
|
+
fig = _plot_bar(df, **kwargs)
|
|
87
|
+
elif kind == "heatmap":
|
|
88
|
+
fig = _plot_heatmap(df, **kwargs)
|
|
89
|
+
elif kind == "box":
|
|
90
|
+
fig = _plot_box(df, **kwargs)
|
|
91
|
+
elif kind == "pie":
|
|
92
|
+
fig = _plot_pie(df, **kwargs)
|
|
93
|
+
elif kind == "treemap":
|
|
94
|
+
fig = _plot_treemap(df, **kwargs)
|
|
95
|
+
else:
|
|
96
|
+
raise ValueError(f"Plot type '{kind}' not supported.")
|
|
97
|
+
|
|
98
|
+
return fig
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _get_colors(theme_name):
|
|
102
|
+
"""Get colors for the specified theme - FIXED"""
|
|
103
|
+
colorscale_name = THEMES.get(theme_name, {}).get("colorscale", "original")
|
|
104
|
+
colors = COLOR_SCALES.get(colorscale_name, COLOR_SCALES["original"])
|
|
105
|
+
return colors
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _plot_line(df, x=None, y=None, **kwargs):
|
|
109
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
110
|
+
colors = _get_colors(theme_name)
|
|
111
|
+
|
|
112
|
+
trace_kwargs = {}
|
|
113
|
+
if "color" in kwargs:
|
|
114
|
+
trace_kwargs["line"] = {"color": kwargs.pop("color")}
|
|
115
|
+
else:
|
|
116
|
+
# Use theme colors if no specific color provided
|
|
117
|
+
trace_kwargs["line"] = {"color": colors[0]}
|
|
118
|
+
|
|
119
|
+
for k in ["line", "name", "hoverinfo", "opacity"]:
|
|
120
|
+
if k in kwargs:
|
|
121
|
+
if k == "line" and "line" in trace_kwargs:
|
|
122
|
+
trace_kwargs["line"].update(kwargs.pop(k))
|
|
123
|
+
else:
|
|
124
|
+
trace_kwargs[k] = kwargs.pop(k)
|
|
125
|
+
|
|
126
|
+
x_data = df.index if x is None else df[x]
|
|
127
|
+
y_data = df[y] if isinstance(y, str) else df.iloc[:, 0]
|
|
128
|
+
|
|
129
|
+
fig = go.Figure(
|
|
130
|
+
go.Scatter(x=x_data, y=y_data, mode="lines", name="", **trace_kwargs)
|
|
131
|
+
)
|
|
132
|
+
_update_layout(fig, kwargs, default_title="Stock Prices", yaxis_title="")
|
|
133
|
+
return fig
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
def _plot_scatter(df, x=None, y=None, **kwargs):
|
|
137
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
138
|
+
colors = _get_colors(theme_name)
|
|
139
|
+
|
|
140
|
+
trace_kwargs = {}
|
|
141
|
+
if "color" in kwargs:
|
|
142
|
+
trace_kwargs["marker"] = {"color": kwargs.pop("color")}
|
|
143
|
+
else:
|
|
144
|
+
trace_kwargs["marker"] = {"color": colors[0]}
|
|
145
|
+
|
|
146
|
+
for k in ["marker", "line", "name", "hoverinfo", "opacity"]:
|
|
147
|
+
if k in kwargs:
|
|
148
|
+
if k == "marker" and "marker" in trace_kwargs:
|
|
149
|
+
trace_kwargs["marker"].update(kwargs.pop(k))
|
|
150
|
+
else:
|
|
151
|
+
trace_kwargs[k] = kwargs.pop(k)
|
|
152
|
+
|
|
153
|
+
x_data = df.index if x is None else df[x]
|
|
154
|
+
y_data = df[y] if isinstance(y, str) else df.iloc[:, 0]
|
|
155
|
+
|
|
156
|
+
fig = go.Figure(
|
|
157
|
+
go.Scatter(x=x_data, y=y_data, mode="markers", name="", **trace_kwargs)
|
|
158
|
+
)
|
|
159
|
+
_update_layout(fig, kwargs, default_title="Scatter Plot", yaxis_title="")
|
|
160
|
+
return fig
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def _plot_ohlc(df, colmap, **kwargs):
|
|
164
|
+
# df = df[-30:] if len(df) > 30 else df
|
|
165
|
+
fig = go.Figure(
|
|
166
|
+
go.Ohlc(
|
|
167
|
+
x=df.index,
|
|
168
|
+
open=df[colmap.get("open")],
|
|
169
|
+
high=df[colmap.get("high")],
|
|
170
|
+
low=df[colmap.get("low")],
|
|
171
|
+
close=df[colmap.get("close")],
|
|
172
|
+
name="",
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
_update_layout(fig, kwargs, default_title="OHLC Chart", yaxis_title="")
|
|
176
|
+
return fig
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def _plot_candlestick(df, colmap, **kwargs):
|
|
180
|
+
# df = df[-30:] if len(df) > 30 else df
|
|
181
|
+
fig = go.Figure(
|
|
182
|
+
go.Candlestick(
|
|
183
|
+
x=df.index,
|
|
184
|
+
open=df[colmap.get("open")],
|
|
185
|
+
high=df[colmap.get("high")],
|
|
186
|
+
low=df[colmap.get("low")],
|
|
187
|
+
close=df[colmap.get("close")],
|
|
188
|
+
name="",
|
|
189
|
+
)
|
|
190
|
+
)
|
|
191
|
+
_update_layout(fig, kwargs, default_title="Candlestick Chart", yaxis_title="")
|
|
192
|
+
return fig
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _plot_subplots(df, cols=None, **kwargs):
|
|
196
|
+
ncols = kwargs.pop("ncols", 2)
|
|
197
|
+
shared_yaxes = kwargs.pop("shared_yaxes", False)
|
|
198
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
199
|
+
colors = _get_colors(theme_name)
|
|
200
|
+
|
|
201
|
+
cols = df.columns if cols is None else cols
|
|
202
|
+
n = len(cols)
|
|
203
|
+
rows = (n - 1) // ncols + 1
|
|
204
|
+
fig = make_subplots(rows=rows, cols=ncols, shared_yaxes=shared_yaxes)
|
|
205
|
+
|
|
206
|
+
for i, col in enumerate(cols):
|
|
207
|
+
r, c = divmod(i, ncols)
|
|
208
|
+
fig.add_trace(
|
|
209
|
+
go.Scatter(
|
|
210
|
+
x=df.index,
|
|
211
|
+
y=df[col],
|
|
212
|
+
mode="lines",
|
|
213
|
+
name=col,
|
|
214
|
+
line=dict(color=colors[i % len(colors)]),
|
|
215
|
+
),
|
|
216
|
+
row=r + 1,
|
|
217
|
+
col=c + 1,
|
|
218
|
+
)
|
|
219
|
+
_update_layout(fig, kwargs, default_title="Subplots", yaxis_title="")
|
|
220
|
+
return fig
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _plot_histogram(df, columns=None, **kwargs):
|
|
224
|
+
overlap = kwargs.pop("overlap", True)
|
|
225
|
+
ncols = kwargs.pop("ncols", 2)
|
|
226
|
+
shared_yaxes = kwargs.pop("shared_yaxes", False)
|
|
227
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
228
|
+
colors = _get_colors(theme_name)
|
|
229
|
+
|
|
230
|
+
columns = df.columns if columns is None else columns
|
|
231
|
+
|
|
232
|
+
if overlap:
|
|
233
|
+
fig = go.Figure()
|
|
234
|
+
for i, col in enumerate(columns):
|
|
235
|
+
fig.add_trace(
|
|
236
|
+
go.Histogram(
|
|
237
|
+
x=df[col] * 100,
|
|
238
|
+
nbinsx=kwargs.get("nbinsx", 50),
|
|
239
|
+
name=col,
|
|
240
|
+
opacity=0.75,
|
|
241
|
+
marker_color=colors[i % len(colors)],
|
|
242
|
+
)
|
|
243
|
+
)
|
|
244
|
+
else:
|
|
245
|
+
rows = (len(columns) - 1) // ncols + 1
|
|
246
|
+
fig = make_subplots(rows=rows, cols=ncols, shared_yaxes=shared_yaxes)
|
|
247
|
+
for i, col in enumerate(columns):
|
|
248
|
+
r, c = divmod(i, ncols)
|
|
249
|
+
fig.add_trace(
|
|
250
|
+
go.Histogram(
|
|
251
|
+
x=df[col] * 100,
|
|
252
|
+
nbinsx=kwargs.get("nbinsx", 50),
|
|
253
|
+
name=col,
|
|
254
|
+
opacity=0.75,
|
|
255
|
+
marker_color=colors[i % len(colors)],
|
|
256
|
+
),
|
|
257
|
+
row=r + 1,
|
|
258
|
+
col=c + 1,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
_update_layout(
|
|
262
|
+
fig,
|
|
263
|
+
kwargs,
|
|
264
|
+
default_title="Histogram of Daily Returns",
|
|
265
|
+
xaxis_title="",
|
|
266
|
+
yaxis_title="Frequency",
|
|
267
|
+
)
|
|
268
|
+
return fig
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def _plot_bar(df, x=None, y=None, scale=False, **kwargs):
|
|
272
|
+
if scale:
|
|
273
|
+
df = df * 100
|
|
274
|
+
|
|
275
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
276
|
+
colors = kwargs.pop("colors", _get_colors(theme_name))
|
|
277
|
+
fig = go.Figure()
|
|
278
|
+
|
|
279
|
+
if df.shape[0] == 1: # single-row DataFrame
|
|
280
|
+
y_vals = df.iloc[0] if y is None else df[y]
|
|
281
|
+
x_vals = df.columns if x is None else x
|
|
282
|
+
for i, (xi, yi) in enumerate(zip(x_vals, y_vals)):
|
|
283
|
+
fig.add_trace(
|
|
284
|
+
go.Bar(
|
|
285
|
+
x=[xi], y=[yi], name=str(xi), marker_color=colors[i % len(colors)]
|
|
286
|
+
)
|
|
287
|
+
)
|
|
288
|
+
else: # multi-row DataFrame — use index as x, columns as series
|
|
289
|
+
columns_to_plot = (
|
|
290
|
+
df.columns if y is None else ([y] if isinstance(y, str) else y)
|
|
291
|
+
)
|
|
292
|
+
for i, col in enumerate(columns_to_plot):
|
|
293
|
+
fig.add_trace(
|
|
294
|
+
go.Bar(
|
|
295
|
+
x=df.index,
|
|
296
|
+
y=df[col],
|
|
297
|
+
name=col,
|
|
298
|
+
marker_color=colors[i % len(colors)],
|
|
299
|
+
)
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
_update_layout(fig, kwargs, default_title="Bar Chart", yaxis_title="")
|
|
303
|
+
return fig
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def _plot_heatmap(df, matrix=False, **kwargs):
|
|
307
|
+
colorscale = kwargs.pop("colorscale", "Viridis")
|
|
308
|
+
if matrix:
|
|
309
|
+
cols = df.columns
|
|
310
|
+
n = len(cols)
|
|
311
|
+
rows = (n - 1) // 2 + 1
|
|
312
|
+
fig = make_subplots(rows=rows, cols=2)
|
|
313
|
+
for i, col in enumerate(cols):
|
|
314
|
+
r, c = divmod(i, 2)
|
|
315
|
+
fig.add_trace(
|
|
316
|
+
go.Heatmap(
|
|
317
|
+
z=df[[col]].values, x=[col], y=df.index, colorscale=colorscale
|
|
318
|
+
),
|
|
319
|
+
row=r + 1,
|
|
320
|
+
col=c + 1,
|
|
321
|
+
)
|
|
322
|
+
else:
|
|
323
|
+
fig = go.Figure(
|
|
324
|
+
data=go.Heatmap(
|
|
325
|
+
z=df.values, x=df.columns, y=df.index, colorscale=colorscale
|
|
326
|
+
)
|
|
327
|
+
)
|
|
328
|
+
_update_layout(fig, kwargs, default_title="Heatmap", xaxis_title="", yaxis_title="")
|
|
329
|
+
return fig
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
def _plot_box(df, columns=None, **kwargs):
|
|
333
|
+
columns = df.columns if columns is None else columns
|
|
334
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
335
|
+
colors = _get_colors(theme_name)
|
|
336
|
+
|
|
337
|
+
fig = go.Figure()
|
|
338
|
+
for i, col in enumerate(columns):
|
|
339
|
+
fig.add_trace(go.Box(y=df[col], name=col, marker_color=colors[i % len(colors)]))
|
|
340
|
+
_update_layout(
|
|
341
|
+
fig, kwargs, default_title="Box Plot", xaxis_title="", yaxis_title=""
|
|
342
|
+
)
|
|
343
|
+
return fig
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
def _plot_pie(df, names=None, values=None, **kwargs):
|
|
347
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
348
|
+
colors = _get_colors(theme_name)
|
|
349
|
+
|
|
350
|
+
names_data = df.index if names is None else df[names]
|
|
351
|
+
values_data = df.iloc[:, 0] if values is None else df[values]
|
|
352
|
+
|
|
353
|
+
fig = go.Figure(
|
|
354
|
+
data=[
|
|
355
|
+
go.Pie(
|
|
356
|
+
labels=names_data,
|
|
357
|
+
values=values_data,
|
|
358
|
+
marker_colors=colors[: len(names_data)],
|
|
359
|
+
)
|
|
360
|
+
]
|
|
361
|
+
)
|
|
362
|
+
_update_layout(fig, kwargs, default_title="Pie Chart")
|
|
363
|
+
return fig
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
def _plot_overlay(df, secondary_y=None, **kwargs):
|
|
367
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
368
|
+
colors = _get_colors(theme_name)
|
|
369
|
+
|
|
370
|
+
fig = make_subplots(specs=[[{"secondary_y": True}]])
|
|
371
|
+
cols = df.columns
|
|
372
|
+
for i, col in enumerate(cols):
|
|
373
|
+
fig.add_trace(
|
|
374
|
+
go.Scatter(
|
|
375
|
+
x=df.index,
|
|
376
|
+
y=df[col],
|
|
377
|
+
mode="lines",
|
|
378
|
+
name=col,
|
|
379
|
+
line=dict(color=colors[i % len(colors)]),
|
|
380
|
+
),
|
|
381
|
+
secondary_y=(col == secondary_y),
|
|
382
|
+
)
|
|
383
|
+
_update_layout(fig, kwargs, default_title="Overlay Chart", yaxis_title="")
|
|
384
|
+
return fig
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _plot_normalized(df, **kwargs):
|
|
388
|
+
theme_name = kwargs.get("theme", DEFAULT_THEME)
|
|
389
|
+
colors = _get_colors(theme_name)
|
|
390
|
+
|
|
391
|
+
norm_df = (df / df.iloc[0]) * 100
|
|
392
|
+
fig = go.Figure()
|
|
393
|
+
for i, col in enumerate(norm_df.columns):
|
|
394
|
+
fig.add_trace(
|
|
395
|
+
go.Scatter(
|
|
396
|
+
x=norm_df.index,
|
|
397
|
+
y=norm_df[col],
|
|
398
|
+
mode="lines",
|
|
399
|
+
name=col,
|
|
400
|
+
line=dict(color=colors[i % len(colors)]),
|
|
401
|
+
)
|
|
402
|
+
)
|
|
403
|
+
_update_layout(
|
|
404
|
+
fig,
|
|
405
|
+
kwargs,
|
|
406
|
+
default_title="Normalized Prices",
|
|
407
|
+
yaxis_title="Normalized (Base = 100)",
|
|
408
|
+
)
|
|
409
|
+
return fig
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def _plot_treemap(df, path=None, values=None, labels=None, parents=None, **kwargs):
|
|
413
|
+
if path is not None:
|
|
414
|
+
df = df.copy()
|
|
415
|
+
for p in path:
|
|
416
|
+
if p not in df.columns:
|
|
417
|
+
raise ValueError(f"Column '{p}' not in DataFrame")
|
|
418
|
+
labels = df[path[-1]]
|
|
419
|
+
parents = df[path[-2]] if len(path) > 1 else [""] * len(df)
|
|
420
|
+
values = df[values or df.columns[0]]
|
|
421
|
+
elif labels is not None and parents is not None and values is not None:
|
|
422
|
+
labels = df[labels] if isinstance(labels, str) else labels
|
|
423
|
+
parents = df[parents] if isinstance(parents, str) else parents
|
|
424
|
+
values = df[values] if isinstance(values, str) else values
|
|
425
|
+
else:
|
|
426
|
+
raise ValueError(
|
|
427
|
+
"Must provide either 'path' or all of 'labels', 'parents', and 'values'"
|
|
428
|
+
)
|
|
429
|
+
|
|
430
|
+
fig = go.Figure(
|
|
431
|
+
go.Treemap(
|
|
432
|
+
labels=labels,
|
|
433
|
+
parents=parents,
|
|
434
|
+
values=values,
|
|
435
|
+
hoverinfo="label+value+percent parent",
|
|
436
|
+
marker=dict(colors=_get_colors(DEFAULT_THEME)),
|
|
437
|
+
)
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
_update_layout(fig, kwargs, default_title="Treemap")
|
|
441
|
+
return fig
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
def _update_layout(fig, user_kwargs, default_title="", xaxis_title="", yaxis_title=""):
|
|
445
|
+
theme_name = user_kwargs.pop("theme", DEFAULT_THEME)
|
|
446
|
+
theme_layout = THEMES.get(theme_name, {}).get("layout", {})
|
|
447
|
+
|
|
448
|
+
layout_defaults = dict(
|
|
449
|
+
title=default_title,
|
|
450
|
+
xaxis_title=xaxis_title,
|
|
451
|
+
yaxis_title=yaxis_title,
|
|
452
|
+
width=user_kwargs.pop("width", DEFAULT_WIDTH),
|
|
453
|
+
height=user_kwargs.pop("height", DEFAULT_HEIGHT),
|
|
454
|
+
showlegend=user_kwargs.pop("showlegend", False),
|
|
455
|
+
)
|
|
456
|
+
layout_defaults.update(theme_layout)
|
|
457
|
+
layout_defaults.update(user_kwargs) # allow override
|
|
458
|
+
fig.update_layout(**layout_defaults)
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
# Attach iplot method to both DataFrame and Series
|
|
462
|
+
pd.DataFrame.iplot = _iplot
|
|
463
|
+
pd.Series.iplot = _iplot
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import plotly.graph_objects as go
|
|
2
|
+
|
|
3
|
+
THEMES = {
|
|
4
|
+
"pearl": {
|
|
5
|
+
"colorscale": "original",
|
|
6
|
+
"linewidth": 1.3,
|
|
7
|
+
"bargap": 0.01,
|
|
8
|
+
"layout": {
|
|
9
|
+
"legend": {"bgcolor": "#F5F6F9", "font": {"color": "#4D5663"}},
|
|
10
|
+
"paper_bgcolor": "#F5F6F9",
|
|
11
|
+
"plot_bgcolor": "#F5F6F9",
|
|
12
|
+
"title": {"font": {"color": "#4D5663"}, "x": 0.5},
|
|
13
|
+
"yaxis": {
|
|
14
|
+
"tickfont": {"color": "#4D5663"},
|
|
15
|
+
"gridcolor": "#E1E5ED",
|
|
16
|
+
"title": {"font": {"color": "#4D5663"}},
|
|
17
|
+
"zerolinecolor": "#E1E5ED",
|
|
18
|
+
"showgrid": True,
|
|
19
|
+
},
|
|
20
|
+
"xaxis": {
|
|
21
|
+
"tickfont": {"color": "#4D5663"},
|
|
22
|
+
"gridcolor": "#E1E5ED",
|
|
23
|
+
"title": {"font": {"color": "#4D5663"}},
|
|
24
|
+
"zerolinecolor": "#E1E5ED",
|
|
25
|
+
"showgrid": True,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
"annotations": {"fontcolor": "#4D5663", "arrowcolor": "#9499A3"},
|
|
29
|
+
"3d": {
|
|
30
|
+
"scene": {
|
|
31
|
+
"yaxis": {
|
|
32
|
+
"gridcolor": "#9499A3",
|
|
33
|
+
"zerolinecolor": "#9499A3",
|
|
34
|
+
"title": {"font": {"color": "#4D5663"}},
|
|
35
|
+
},
|
|
36
|
+
"xaxis": {
|
|
37
|
+
"gridcolor": "#9499A3",
|
|
38
|
+
"zerolinecolor": "#9499A3",
|
|
39
|
+
"title": {"font": {"color": "#4D5663"}},
|
|
40
|
+
},
|
|
41
|
+
"zaxis": {
|
|
42
|
+
"gridcolor": "#9499A3",
|
|
43
|
+
"zerolinecolor": "#9499A3",
|
|
44
|
+
"title": {"font": {"color": "#4D5663"}},
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
"henanigans": {
|
|
50
|
+
"colorscale": "original",
|
|
51
|
+
"linewidth": 1.3,
|
|
52
|
+
"bargap": 0.01,
|
|
53
|
+
"layout": {
|
|
54
|
+
"legend": {"bgcolor": "#242424", "font": {"color": "#F4F4F4"}},
|
|
55
|
+
"paper_bgcolor": "#242424",
|
|
56
|
+
"plot_bgcolor": "#242424",
|
|
57
|
+
"title": {"font": {"color": "#F4F4F4"}, "x": 0.5},
|
|
58
|
+
"yaxis": {
|
|
59
|
+
"tickfont": {"color": "#A4A4A4"},
|
|
60
|
+
"gridcolor": "#343434",
|
|
61
|
+
"title": {"font": {"color": "#A4A4A4"}},
|
|
62
|
+
"zerolinecolor": "#444444",
|
|
63
|
+
"showgrid": True,
|
|
64
|
+
},
|
|
65
|
+
"xaxis": {
|
|
66
|
+
"tickfont": {"color": "#A4A4A4"},
|
|
67
|
+
"gridcolor": "#343434",
|
|
68
|
+
"title": {"font": {"color": "#A4A4A4"}},
|
|
69
|
+
"zerolinecolor": "#444444",
|
|
70
|
+
"showgrid": True,
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
"annotations": {"fontcolor": "#EBB483", "arrowcolor": "#EBB483"},
|
|
74
|
+
"3d": {
|
|
75
|
+
"scene": {
|
|
76
|
+
"yaxis": {
|
|
77
|
+
"gridcolor": "#343434",
|
|
78
|
+
"zerolinecolor": "#343434",
|
|
79
|
+
"title": {"font": {"color": "#A4A4A4"}},
|
|
80
|
+
},
|
|
81
|
+
"xaxis": {
|
|
82
|
+
"gridcolor": "#343434",
|
|
83
|
+
"zerolinecolor": "#343434",
|
|
84
|
+
"title": {"font": {"color": "#A4A4A4"}},
|
|
85
|
+
},
|
|
86
|
+
"zaxis": {
|
|
87
|
+
"gridcolor": "#343434",
|
|
88
|
+
"zerolinecolor": "#343434",
|
|
89
|
+
"title": {"font": {"color": "#A4A4A4"}},
|
|
90
|
+
},
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Custom color scales
|
|
97
|
+
COLOR_SCALES = {
|
|
98
|
+
"original": [
|
|
99
|
+
"#FF6B35",
|
|
100
|
+
"#004E89",
|
|
101
|
+
"#00A896",
|
|
102
|
+
"#7209B7",
|
|
103
|
+
"#E63946",
|
|
104
|
+
"#2A9D8F",
|
|
105
|
+
"#F4A261",
|
|
106
|
+
"#6A994E",
|
|
107
|
+
"#FA8072",
|
|
108
|
+
"#87CEEB",
|
|
109
|
+
]
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Create pearl template
|
|
114
|
+
def create_pearl_template():
|
|
115
|
+
"""Create a proper Plotly template from the theme configuration"""
|
|
116
|
+
theme_config = THEMES["pearl"]["layout"]
|
|
117
|
+
|
|
118
|
+
template = go.layout.Template(layout=go.Layout(**theme_config))
|
|
119
|
+
|
|
120
|
+
return template
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# Create henanigans template
|
|
124
|
+
def create_henanigans_template():
|
|
125
|
+
"""Create a proper Plotly template from the theme configuration"""
|
|
126
|
+
theme_config = THEMES["henanigans"]["layout"]
|
|
127
|
+
|
|
128
|
+
template = go.layout.Template(layout=go.Layout(**theme_config))
|
|
129
|
+
|
|
130
|
+
return template
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
# Function to create any template
|
|
134
|
+
def create_template(theme_name):
|
|
135
|
+
"""Create a template for any theme"""
|
|
136
|
+
if theme_name not in THEMES:
|
|
137
|
+
raise ValueError(f"Theme '{theme_name}' not found in THEMES")
|
|
138
|
+
|
|
139
|
+
theme_config = THEMES[theme_name]["layout"]
|
|
140
|
+
template = go.layout.Template(layout=go.Layout(**theme_config))
|
|
141
|
+
|
|
142
|
+
return template
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
2
|
from quantmod.utils import convert_date_format
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
# import importlib.resources as pkg_resources
|
|
5
|
+
from importlib.resources import files
|
|
4
6
|
from . import data
|
|
5
7
|
|
|
6
8
|
|
|
7
|
-
def fetch_historical_data(
|
|
9
|
+
def fetch_historical_data(
|
|
10
|
+
symbol: str, start_date: str = None, end_date: str = None
|
|
11
|
+
) -> pd.DataFrame:
|
|
8
12
|
"""
|
|
9
13
|
Load historical data for a given symbol
|
|
10
14
|
|
|
@@ -26,15 +30,19 @@ def fetch_historical_data(symbol: str, start_date: str=None, end_date: str=None)
|
|
|
26
30
|
------
|
|
27
31
|
ValueError
|
|
28
32
|
If the symbol is invalid or the start date is greater than the end date
|
|
29
|
-
If the start date is less than the first date in the dataset or the end date is greater than the last date in the dataset
|
|
33
|
+
If the start date is less than the first date in the dataset or the end date is greater than the last date in the dataset
|
|
30
34
|
If the start date is greater than the last date in the dataset or the end date is less than the first date in the dataset
|
|
31
35
|
"""
|
|
32
36
|
|
|
37
|
+
# def read_csv_file(filename):
|
|
38
|
+
# with pkg_resources.path(data, filename) as file_path:
|
|
39
|
+
# return pd.read_csv(file_path)
|
|
40
|
+
|
|
33
41
|
def read_csv_file(filename):
|
|
34
|
-
with
|
|
35
|
-
return pd.read_csv(
|
|
42
|
+
with files(data).joinpath(filename).open("r") as f:
|
|
43
|
+
return pd.read_csv(f)
|
|
36
44
|
|
|
37
|
-
if symbol.lower() == "spx":
|
|
45
|
+
if symbol.lower() == "spx":
|
|
38
46
|
df = read_csv_file("spx.csv")
|
|
39
47
|
# df = pd.read_csv("./data/spx.csv")
|
|
40
48
|
elif symbol.lower() == "nifty":
|
|
@@ -42,24 +50,23 @@ def fetch_historical_data(symbol: str, start_date: str=None, end_date: str=None)
|
|
|
42
50
|
# df = pd.read_csv("./data/nifty50.csv")
|
|
43
51
|
else:
|
|
44
52
|
raise ValueError("Invalid symbol. Only SPX & NIFTY is supported")
|
|
45
|
-
|
|
53
|
+
|
|
46
54
|
df = df.rename(columns=str.lower)
|
|
47
|
-
df = convert_date_format(df,
|
|
55
|
+
df = convert_date_format(df, "date")
|
|
48
56
|
|
|
49
57
|
if start_date is None or end_date is None:
|
|
50
58
|
return df
|
|
51
59
|
|
|
52
60
|
elif start_date > end_date:
|
|
53
61
|
raise ValueError("Start date should be less than or equal to end date")
|
|
54
|
-
|
|
62
|
+
|
|
55
63
|
elif start_date < df.date.iloc[0] or end_date < df.date.iloc[0]:
|
|
56
64
|
raise ValueError(f"Date should be greater than or equal to {df.date.iloc[0]}")
|
|
57
|
-
|
|
65
|
+
|
|
58
66
|
elif start_date > df.date.iloc[-1] or end_date > df.date.iloc[-1]:
|
|
59
67
|
raise ValueError(f"Date should be less than or equal to {df.date.iloc[-1]}")
|
|
60
|
-
|
|
68
|
+
|
|
61
69
|
else:
|
|
62
70
|
# Use query method for filtering based on date range
|
|
63
71
|
query_str = f"date >= '{start_date}' and date <= '{end_date}'"
|
|
64
72
|
return df.query(query_str)
|
|
65
|
-
|
|
@@ -47,7 +47,13 @@ if mode == "local":
|
|
|
47
47
|
# print(output)
|
|
48
48
|
except ValueError:
|
|
49
49
|
s = requests.Session()
|
|
50
|
-
|
|
50
|
+
try:
|
|
51
|
+
output = s.get("http://nseindia.com/option-chain", headers=headers)
|
|
52
|
+
output = s.get(payload, headers=headers).json()
|
|
53
|
+
except ValueError:
|
|
54
|
+
output = s.get("https://www.nseindia.com", headers=headers)
|
|
55
|
+
output = output.json()
|
|
56
|
+
# output = s.get("https://www.nseindia.com/option-chain", headers=headers) # replaced http://nseindia.com with https://www.nseindia.com/option-chain
|
|
51
57
|
output = s.get(payload, headers=headers).json()
|
|
52
58
|
return output
|
|
53
59
|
|
|
@@ -73,7 +73,7 @@ class VaRAnalyzer:
|
|
|
73
73
|
data["shifted_returns"].rolling(window=self.window_forward).sum()
|
|
74
74
|
)
|
|
75
75
|
data["shifted_forward_returns"] = data["forward_returns"].shift(
|
|
76
|
-
-self.window_forward +
|
|
76
|
+
-self.window_forward + 2
|
|
77
77
|
)
|
|
78
78
|
|
|
79
79
|
# Identify breaches
|
|
@@ -121,4 +121,5 @@ class VaRAnalyzer:
|
|
|
121
121
|
["Conditional Probability of Breaches", conditional_probability * 100],
|
|
122
122
|
]
|
|
123
123
|
|
|
124
|
+
# return data
|
|
124
125
|
return tabulate(table, headers=header, floatfmt=(".2f"))
|
|
@@ -18,7 +18,7 @@ def periodReturn(
|
|
|
18
18
|
|
|
19
19
|
Returns
|
|
20
20
|
-------
|
|
21
|
-
pd.
|
|
21
|
+
pd.Series
|
|
22
22
|
resampled dataframe series of log returns
|
|
23
23
|
"""
|
|
24
24
|
|
|
@@ -27,7 +27,10 @@ def periodReturn(
|
|
|
27
27
|
raise ValueError("Input must be a pandas DataFrame or Series")
|
|
28
28
|
|
|
29
29
|
# Initialize variable to hold log returns
|
|
30
|
-
|
|
30
|
+
if isinstance(data, pd.DataFrame):
|
|
31
|
+
temp = pd.DataFrame(dtype=float)
|
|
32
|
+
else:
|
|
33
|
+
temp = pd.Series(dtype=float)
|
|
31
34
|
|
|
32
35
|
if period is None:
|
|
33
36
|
temp = np.log(data).diff()
|
|
@@ -92,11 +95,18 @@ def annualReturn(data: pd.DataFrame | pd.Series) -> pd.DataFrame | pd.Series:
|
|
|
92
95
|
return periodReturn(data, period="A")
|
|
93
96
|
|
|
94
97
|
|
|
95
|
-
def allReturn(data: pd.
|
|
98
|
+
def allReturn(data: pd.Series) -> pd.Series:
|
|
96
99
|
"""Calculates annual returns for the specified inputs."""
|
|
97
100
|
return periodReturn(data, period="all")
|
|
98
101
|
|
|
99
102
|
|
|
103
|
+
def rollingReturn(
|
|
104
|
+
data: pd.DataFrame | pd.Series, window: int = 10
|
|
105
|
+
) -> pd.DataFrame | pd.Series:
|
|
106
|
+
"""Calculates rolling returns for the specified inputs."""
|
|
107
|
+
return dailyReturn(data).rolling(window).sum()
|
|
108
|
+
|
|
109
|
+
|
|
100
110
|
def cagr(returns: pd.Series, intra_period: int = 1, is_log: bool = False) -> float:
|
|
101
111
|
"""
|
|
102
112
|
Compounded Annual Growth Rate (CAGR) is the annual rate of return
|
|
@@ -127,12 +137,12 @@ def cagr(returns: pd.Series, intra_period: int = 1, is_log: bool = False) -> flo
|
|
|
127
137
|
if is_log:
|
|
128
138
|
cumulative_returns = np.exp(returns.sum()) # for log returns
|
|
129
139
|
years = len(returns) / (252 * intra_period)
|
|
130
|
-
return (cumulative_returns[-1]) ** (1 / years) - 1
|
|
140
|
+
return (cumulative_returns.iloc[-1]) ** (1 / years) - 1
|
|
131
141
|
else:
|
|
132
142
|
cumulative_returns = (1 + returns).cumprod() # for simple returns
|
|
133
143
|
|
|
134
144
|
years = len(returns) / (252 * intra_period)
|
|
135
|
-
return (cumulative_returns[-1]) ** (1 / years) - 1
|
|
145
|
+
return (cumulative_returns.iloc[-1]) ** (1 / years) - 1
|
|
136
146
|
|
|
137
147
|
|
|
138
148
|
def volatility(returns: pd.Series, intra_period: int = 1) -> float:
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.0.7"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: quantmod
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Quantmod Python Package
|
|
5
5
|
Home-page: https://kannansingaravelu.com/
|
|
6
6
|
Author: Kannan Singaravelu
|
|
@@ -21,14 +21,16 @@ Description-Content-Type: text/markdown
|
|
|
21
21
|
License-File: LICENSE.txt
|
|
22
22
|
Requires-Dist: joblib
|
|
23
23
|
Requires-Dist: matplotlib
|
|
24
|
+
Requires-Dist: nbformat>=5.10.4
|
|
24
25
|
Requires-Dist: numpy>=2.0.2
|
|
25
26
|
Requires-Dist: pandas>=2.2.2
|
|
27
|
+
Requires-Dist: plotly>=6.1.2
|
|
26
28
|
Requires-Dist: pydantic>=2.8.2
|
|
27
29
|
Requires-Dist: scipy>=1.13.1
|
|
28
30
|
Requires-Dist: sqlalchemy>=2.0.38
|
|
29
31
|
Requires-Dist: tabulate>=0.9.0
|
|
30
32
|
Requires-Dist: urllib3==1.26.15
|
|
31
|
-
Requires-Dist: yfinance
|
|
33
|
+
Requires-Dist: yfinance==0.2.58
|
|
32
34
|
Dynamic: author
|
|
33
35
|
Dynamic: author-email
|
|
34
36
|
Dynamic: classifier
|
|
@@ -14,9 +14,11 @@ quantmod.egg-info/entry_points.txt
|
|
|
14
14
|
quantmod.egg-info/not-zip-safe
|
|
15
15
|
quantmod.egg-info/requires.txt
|
|
16
16
|
quantmod.egg-info/top_level.txt
|
|
17
|
+
quantmod/charts/__init__.py
|
|
18
|
+
quantmod/charts/plotting.py
|
|
19
|
+
quantmod/charts/themes.py
|
|
17
20
|
quantmod/datasets/__init__.py
|
|
18
21
|
quantmod/datasets/dataloader.py
|
|
19
|
-
quantmod/datasets/data/__init__.py
|
|
20
22
|
quantmod/datasets/data/nifty50.csv
|
|
21
23
|
quantmod/datasets/data/spx.csv
|
|
22
24
|
quantmod/derivatives/__init__.py
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "0.0.6"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|