quantmod 0.0.4__tar.gz → 0.0.6__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.
Files changed (50) hide show
  1. {quantmod-0.0.4 → quantmod-0.0.6}/PKG-INFO +25 -11
  2. {quantmod-0.0.4 → quantmod-0.0.6}/README.md +8 -8
  3. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/__init__.py +3 -10
  4. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/derivatives/__init__.py +2 -4
  5. quantmod-0.0.6/quantmod/derivatives/nse.py +274 -0
  6. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/indicators/indicators.py +27 -22
  7. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/markets/yahoo.py +30 -15
  8. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/models/__init__.py +5 -1
  9. quantmod-0.0.6/quantmod/models/binomial.py +184 -0
  10. quantmod-0.0.6/quantmod/models/blackscholes.py +393 -0
  11. quantmod-0.0.6/quantmod/models/montecarlo.py +152 -0
  12. quantmod-0.0.6/quantmod/models/optioninputs.py +49 -0
  13. quantmod-0.0.6/quantmod/risk/__init__.py +26 -0
  14. quantmod-0.0.6/quantmod/risk/var.py +108 -0
  15. quantmod-0.0.6/quantmod/risk/varbacktest.py +124 -0
  16. quantmod-0.0.6/quantmod/risk/varinputs.py +62 -0
  17. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/timeseries/performance.py +56 -49
  18. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/timeseries/timeseries.py +12 -15
  19. quantmod-0.0.6/quantmod/version.py +1 -0
  20. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/PKG-INFO +25 -11
  21. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/SOURCES.txt +4 -3
  22. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/requires.txt +3 -0
  23. {quantmod-0.0.4 → quantmod-0.0.6}/setup.py +9 -10
  24. quantmod-0.0.4/quantmod/derivatives/options.py +0 -47
  25. quantmod-0.0.4/quantmod/models/blackscholes.py +0 -156
  26. quantmod-0.0.4/quantmod/models/montecarlo.py +0 -115
  27. quantmod-0.0.4/quantmod/models/optioninputs.py +0 -44
  28. quantmod-0.0.4/quantmod/risk/__init__.py +0 -27
  29. quantmod-0.0.4/quantmod/risk/riskinputs.py +0 -36
  30. quantmod-0.0.4/quantmod/risk/var.py +0 -103
  31. quantmod-0.0.4/quantmod/risk/varbacktester.py +0 -85
  32. quantmod-0.0.4/quantmod/version.py +0 -1
  33. {quantmod-0.0.4 → quantmod-0.0.6}/LICENSE.txt +0 -0
  34. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/_version.py +0 -0
  35. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/datasets/__init__.py +0 -0
  36. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/datasets/data/__init__.py +0 -0
  37. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/datasets/data/nifty50.csv +0 -0
  38. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/datasets/data/spx.csv +0 -0
  39. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/datasets/dataloader.py +0 -0
  40. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/indicators/__init__.py +0 -0
  41. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/main.py +0 -0
  42. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/markets/__init__.py +0 -0
  43. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/markets/bb.py +0 -0
  44. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/timeseries/__init__.py +0 -0
  45. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod/utils.py +0 -0
  46. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/dependency_links.txt +0 -0
  47. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/entry_points.txt +0 -0
  48. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/not-zip-safe +0 -0
  49. {quantmod-0.0.4 → quantmod-0.0.6}/quantmod.egg-info/top_level.txt +0 -0
  50. {quantmod-0.0.4 → quantmod-0.0.6}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.2
2
2
  Name: quantmod
3
- Version: 0.0.4
3
+ Version: 0.0.6
4
4
  Summary: Quantmod Python Package
5
5
  Home-page: https://kannansingaravelu.com/
6
6
  Author: Kannan Singaravelu
@@ -9,7 +9,6 @@ License: Apache License 2.0
9
9
  Keywords: python,quant,quantmod,quantmod-python
10
10
  Platform: any
11
11
  Classifier: License :: OSI Approved :: Apache Software License
12
- Classifier: Programming Language :: Python :: 3
13
12
  Classifier: Programming Language :: Python :: 3.10
14
13
  Classifier: Operating System :: OS Independent
15
14
  Classifier: Intended Audience :: Developers
@@ -20,13 +19,28 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
19
  Requires-Python: >=3.10
21
20
  Description-Content-Type: text/markdown
22
21
  License-File: LICENSE.txt
22
+ Requires-Dist: joblib
23
+ Requires-Dist: matplotlib
23
24
  Requires-Dist: numpy>=2.0.2
24
25
  Requires-Dist: pandas>=2.2.2
25
26
  Requires-Dist: pydantic>=2.8.2
26
27
  Requires-Dist: scipy>=1.13.1
28
+ Requires-Dist: sqlalchemy>=2.0.38
27
29
  Requires-Dist: tabulate>=0.9.0
28
30
  Requires-Dist: urllib3==1.26.15
29
31
  Requires-Dist: yfinance>=0.2.43
32
+ Dynamic: author
33
+ Dynamic: author-email
34
+ Dynamic: classifier
35
+ Dynamic: description
36
+ Dynamic: description-content-type
37
+ Dynamic: home-page
38
+ Dynamic: keywords
39
+ Dynamic: license
40
+ Dynamic: platform
41
+ Dynamic: requires-dist
42
+ Dynamic: requires-python
43
+ Dynamic: summary
30
44
 
31
45
 
32
46
  Quantmod Python package is inspired by the quantmod package for R. This new tool is designed to assist quantitative traders and data analysts with the development, testing, and rapid prototyping of trading strategies. quantmod features a straightforward and intuitive interface aimed at simplifying workflows and boosting productivity.
@@ -42,13 +56,13 @@ pip install quantmod
42
56
 
43
57
  ## Modules
44
58
 
45
- * [markets](https://kannansingaravelu.com/docs/site/markets/)
46
- * [models](https://kannansingaravelu.com/docs/site/models/)
47
- * [risk](https://kannansingaravelu.com/docs/site/risk/)
48
- * [timeseries](https://kannansingaravelu.com/docs/site/timeseries/)
49
- * [indicators](https://kannansingaravelu.com/docs/site/indicators/)
50
- * [derivatives](https://kannansingaravelu.com/docs/site/derivatives/)
51
- * [datasets](https://kannansingaravelu.com/docs/site/datasets/)
59
+ * [markets](https://kannansingaravelu.com/quantmod/markets/)
60
+ * [models](https://kannansingaravelu.com/quantmod/models/)
61
+ * [risk](https://kannansingaravelu.com/quantmod/risk/)
62
+ * [timeseries](https://kannansingaravelu.com/quantmod/timeseries/)
63
+ * [indicators](https://kannansingaravelu.com/quantmod/indicators/)
64
+ * [derivatives](https://kannansingaravelu.com/quantmod/derivatives/)
65
+ * [datasets](https://kannansingaravelu.com/quantmod/datasets/)
52
66
 
53
67
 
54
68
  ## Quickstart
@@ -84,7 +98,7 @@ Refer to the [examples](https://kannansingaravelu.com/) section for more details
84
98
 
85
99
 
86
100
  ## Changelog
87
- The list of changes to quantmod between each release can be found [here](https://kannansingaravelu.com/docs/site/changelog/)
101
+ The list of changes to quantmod between each release can be found [here](https://kannansingaravelu.com/quantmod/changelog/)
88
102
 
89
103
 
90
104
  ## Community
@@ -12,13 +12,13 @@ pip install quantmod
12
12
 
13
13
  ## Modules
14
14
 
15
- * [markets](https://kannansingaravelu.com/docs/site/markets/)
16
- * [models](https://kannansingaravelu.com/docs/site/models/)
17
- * [risk](https://kannansingaravelu.com/docs/site/risk/)
18
- * [timeseries](https://kannansingaravelu.com/docs/site/timeseries/)
19
- * [indicators](https://kannansingaravelu.com/docs/site/indicators/)
20
- * [derivatives](https://kannansingaravelu.com/docs/site/derivatives/)
21
- * [datasets](https://kannansingaravelu.com/docs/site/datasets/)
15
+ * [markets](https://kannansingaravelu.com/quantmod/markets/)
16
+ * [models](https://kannansingaravelu.com/quantmod/models/)
17
+ * [risk](https://kannansingaravelu.com/quantmod/risk/)
18
+ * [timeseries](https://kannansingaravelu.com/quantmod/timeseries/)
19
+ * [indicators](https://kannansingaravelu.com/quantmod/indicators/)
20
+ * [derivatives](https://kannansingaravelu.com/quantmod/derivatives/)
21
+ * [datasets](https://kannansingaravelu.com/quantmod/datasets/)
22
22
 
23
23
 
24
24
  ## Quickstart
@@ -54,7 +54,7 @@ Refer to the [examples](https://kannansingaravelu.com/) section for more details
54
54
 
55
55
 
56
56
  ## Changelog
57
- The list of changes to quantmod between each release can be found [here](https://kannansingaravelu.com/docs/site/changelog/)
57
+ The list of changes to quantmod between each release can be found [here](https://kannansingaravelu.com/quantmod/changelog/)
58
58
 
59
59
 
60
60
  ## Community
@@ -23,14 +23,7 @@
23
23
  from . import version
24
24
  from .main import hello
25
25
 
26
- from quantmod import (
27
- derivatives,
28
- indicators,
29
- markets,
30
- models,
31
- timeseries,
32
- datasets
33
- )
26
+ from quantmod import derivatives, indicators, markets, models, timeseries, datasets
34
27
 
35
28
 
36
29
  __all__ = [
@@ -40,8 +33,8 @@ __all__ = [
40
33
  "markets",
41
34
  "models",
42
35
  "timeseries",
43
- "datasets"
36
+ "datasets",
44
37
  ]
45
38
 
46
39
  __version__ = version.version
47
- __author__ = "Kannan Singaravelu"
40
+ __author__ = "Kannan Singaravelu"
@@ -16,8 +16,6 @@
16
16
  # limitations under the License.
17
17
  #
18
18
 
19
- from .options import maxpain
19
+ from .nse import OptionData
20
20
 
21
- __all__ = [
22
- "maxpain",
23
- ]
21
+ __all__ = ["OptionData"]
@@ -0,0 +1,274 @@
1
+ # improvised from nsepython
2
+ # to be used only for tutorial purposes
3
+ # for production use, please reach out to NSE India
4
+ import os, sys
5
+ import requests
6
+ import numpy as np
7
+ import pandas as pd
8
+ import json
9
+ import random
10
+ import datetime, time
11
+ import logging
12
+ import re
13
+ import urllib.parse
14
+
15
+ # Constants
16
+ indices = ["NIFTY", "FINNIFTY", "BANKNIFTY"]
17
+
18
+ mode = "local"
19
+
20
+ if mode == "vpn":
21
+
22
+ def nsefetch(payload):
23
+ if ("%26" in payload) or ("%20" in payload):
24
+ encoded_url = payload
25
+ else:
26
+ encoded_url = urllib.parse.quote(payload, safe=":/?&=")
27
+ payload_var = 'curl -b cookies.txt "' + encoded_url + '"' + curl_headers + ""
28
+ try:
29
+ output = os.popen(payload_var).read()
30
+ output = json.loads(output)
31
+ except ValueError: # includes simplejson.decoder.JSONDecodeError:
32
+ payload2 = "https://www.nseindia.com"
33
+ output2 = os.popen(
34
+ 'curl -c cookies.txt "' + payload2 + '"' + curl_headers + ""
35
+ ).read()
36
+
37
+ output = os.popen(payload_var).read()
38
+ output = json.loads(output)
39
+ return output
40
+
41
+
42
+ if mode == "local":
43
+
44
+ def nsefetch(payload):
45
+ try:
46
+ output = requests.get(payload, headers=headers).json()
47
+ # print(output)
48
+ except ValueError:
49
+ s = requests.Session()
50
+ output = s.get("http://nseindia.com", headers=headers)
51
+ output = s.get(payload, headers=headers).json()
52
+ return output
53
+
54
+
55
+ headers = {
56
+ "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
57
+ "accept-language": "en-US,en;q=0.9,en-IN;q=0.8,en-GB;q=0.7",
58
+ "cache-control": "max-age=0",
59
+ "priority": "u=0, i",
60
+ "sec-ch-ua": '"Microsoft Edge";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
61
+ "sec-ch-ua-mobile": "?0",
62
+ "sec-ch-ua-platform": '"Windows"',
63
+ "sec-fetch-dest": "document",
64
+ "sec-fetch-mode": "navigate",
65
+ "sec-fetch-site": "none",
66
+ "sec-fetch-user": "?1",
67
+ "upgrade-insecure-requests": "1",
68
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0",
69
+ }
70
+ # Curl headers
71
+ curl_headers = """ -H "authority: beta.nseindia.com" -H "cache-control: max-age=0" -H "dnt: 1" -H "upgrade-insecure-requests: 1" -H "user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.117 Safari/537.36" -H "sec-fetch-user: ?1" -H "accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" -H "sec-fetch-site: none" -H "sec-fetch-mode: navigate" -H "accept-encoding: gzip, deflate, br" -H "accept-language: en-US,en;q=0.9,hi;q=0.8" --compressed"""
72
+
73
+
74
+ class OptionData:
75
+ """
76
+ A class to fetch and analyze option chain data from NSE.
77
+
78
+ Parameters
79
+ ----------
80
+ symbol : str
81
+ Trading symbol of the stock/index (e.g., 'NIFTY', 'RELIANCE')
82
+ expiry_dt : str
83
+ Expiry date in format '%d-%b-%Y' (e.g., '27-Mar-2025')
84
+ Note: Month should be first 3 letters capitalized (Jan, Feb, Mar, etc.)
85
+
86
+ Attributes
87
+ ----------
88
+ get_put_call_ratio : float
89
+ Put-Call ratio based on open interest
90
+ get_maximum_pain_strike : float
91
+ Maximum pain strike price
92
+ get_call_option_data : pandas.DataFrame
93
+ Call option chain data
94
+ get_put_option_data : pandas.DataFrame
95
+ Put option chain data
96
+
97
+ Methods
98
+ -------
99
+ get_option_quote : float
100
+ Get option quote for specific strike price, option type and transaction intent
101
+ get_synthetic_future_price : float
102
+ Calculate synthetic futures price using put-call parity
103
+ """
104
+
105
+ def __init__(self, symbol, expiry_dt):
106
+ """
107
+ Initialize the OptionData class.
108
+
109
+ Parameters
110
+ ----------
111
+ symbol : str
112
+ Trading symbol of the stock/index (e.g., 'NIFTY', 'RELIANCE')
113
+ expiry_dt : str
114
+ Expiry date in format '%d-%b-%Y' (e.g., '27-Mar-2025')
115
+ Note: Month should be first 3 letters capitalized (Jan, Feb, Mar, etc.)
116
+ """
117
+ self.expiry_dt = expiry_dt
118
+ self.symbol = symbol.replace(
119
+ "&", "%26"
120
+ ) # URL Parse for Stocks Like M&M Finance
121
+ self.payload = self._nse_optionchain_scrapper()
122
+
123
+ self.get_put_call_ratio = self._get_option_pcr()
124
+ self.get_maximum_pain_strike = self._get_maximum_pain_strike()
125
+ self.get_call_option_data = self._get_call_option_data()
126
+ self.get_put_option_data = self._get_put_option_data()
127
+
128
+ def _nse_optionchain_scrapper(self):
129
+ """
130
+ Fetch option chain data from NSE website.
131
+
132
+ Returns
133
+ -------
134
+ dict
135
+ Raw option chain data from NSE API
136
+ """
137
+ if any(x in self.symbol for x in indices):
138
+ payload = nsefetch(
139
+ "https://www.nseindia.com/api/option-chain-indices?symbol="
140
+ + self.symbol
141
+ )
142
+ else:
143
+ payload = nsefetch(
144
+ "https://www.nseindia.com/api/option-chain-equities?symbol="
145
+ + self.symbol
146
+ )
147
+ return payload
148
+
149
+ def get_option_quote(self, strikePrice, optionType, intent=""):
150
+ """
151
+ Get option quote for specific strike price and option type.
152
+
153
+ Parameters
154
+ ----------
155
+ strikePrice : float
156
+ Strike price of the option
157
+ optionType : str
158
+ Type of option, either 'CE' (Call) or 'PE' (Put)
159
+ intent : str, optional
160
+ Quote type:
161
+ - '' (default) for last traded price
162
+ - 'sell' for bid price
163
+ - 'buy' for ask price
164
+
165
+ Returns
166
+ -------
167
+ float
168
+ Option price based on the specified intent
169
+ """
170
+ for x in range(len(self.payload["records"]["data"])):
171
+ if (self.payload["records"]["data"][x]["strikePrice"] == strikePrice) & (
172
+ self.payload["records"]["data"][x]["expiryDate"] == self.expiry_dt
173
+ ):
174
+ if intent == "":
175
+ return self.payload["records"]["data"][x][optionType]["lastPrice"]
176
+ if intent == "sell":
177
+ return self.payload["records"]["data"][x][optionType]["bidprice"]
178
+ if intent == "buy":
179
+ return self.payload["records"]["data"][x][optionType]["askPrice"]
180
+
181
+ def _get_option_pcr(self):
182
+ """
183
+ Calculate Put-Call Ratio based on open interest.
184
+
185
+ Returns
186
+ -------
187
+ float
188
+ Put-Call ratio rounded to 2 decimal places
189
+ """
190
+ ce_oi = 0
191
+ pe_oi = 0
192
+ for i in self.payload["records"]["data"]:
193
+ if i["expiryDate"] == self.expiry_dt:
194
+ try:
195
+ ce_oi += i["CE"]["openInterest"]
196
+ pe_oi += i["PE"]["openInterest"]
197
+ except KeyError:
198
+ pass
199
+ return round(pe_oi / ce_oi, 2)
200
+
201
+ def get_synthetic_future_price(self, strike):
202
+ """
203
+ Calculate synthetic futures price using put-call parity.
204
+
205
+ Parameters
206
+ ----------
207
+ strike : float
208
+ Strike price to use for calculation
209
+
210
+ Returns
211
+ -------
212
+ float
213
+ Synthetic futures price
214
+ """
215
+ synthetic_futures = (
216
+ strike
217
+ + self.get_option_quote(strike, "CE", "buy")
218
+ - self.get_option_quote(strike, "PE", "sell")
219
+ )
220
+ return synthetic_futures
221
+
222
+ def _get_call_option_data(self):
223
+ """
224
+ Get call options data for current expiry.
225
+
226
+ Returns
227
+ -------
228
+ pandas.DataFrame
229
+ DataFrame containing call options data sorted by strike price
230
+ """
231
+ ce_values = [
232
+ data["CE"]
233
+ for data in self.payload["records"]["data"]
234
+ if "CE" in data and data["expiryDate"] == self.expiry_dt
235
+ ]
236
+ return pd.DataFrame(ce_values).sort_values(["strikePrice"])
237
+
238
+ def _get_put_option_data(self):
239
+ """
240
+ Get put options data for current expiry.
241
+
242
+ Returns
243
+ -------
244
+ pandas.DataFrame
245
+ DataFrame containing put options data sorted by strike price
246
+ """
247
+ pe_values = [
248
+ data["PE"]
249
+ for data in self.payload["records"]["data"]
250
+ if "PE" in data and data["expiryDate"] == self.expiry_dt
251
+ ]
252
+ return pd.DataFrame(pe_values).sort_values(["strikePrice"])
253
+
254
+ def _get_maximum_pain_strike(self):
255
+ """
256
+ Calculate maximum pain strike price.
257
+
258
+ Returns
259
+ -------
260
+ float
261
+ Strike price where maximum pain occurs
262
+ """
263
+ calls = self._get_call_option_data()
264
+ strikes = calls["strikePrice"]
265
+ ce_oi = calls["openInterest"]
266
+ pe_oi = self._get_put_option_data()["openInterest"]
267
+
268
+ total_pain = [
269
+ sum(ce_oi * np.maximum(0, expiry_price - strikes))
270
+ + sum(pe_oi * np.maximum(0, strikes - expiry_price))
271
+ for expiry_price in strikes
272
+ ]
273
+
274
+ return strikes[np.argmin(total_pain)]
@@ -1,5 +1,6 @@
1
1
  import pandas as pd
2
2
 
3
+
3
4
  def ATR(df: pd.DataFrame, lookback: int = 14) -> pd.Series:
4
5
  """
5
6
  Calculate the Average True Range (ATR).
@@ -20,20 +21,20 @@ def ATR(df: pd.DataFrame, lookback: int = 14) -> pd.Series:
20
21
  pd.Series
21
22
  series containing the ATR values for each period
22
23
  """
23
-
24
+
24
25
  df = df.copy()
25
26
  df.rename(columns=str.lower, inplace=True)
26
-
27
- df['H-L']=abs(df['high']-df['low'])
28
- df['H-PC']=abs(df['high']-df['close'].shift(1))
29
- df['L-PC']=abs(df['low']-df['close'].shift(1))
30
-
31
- df['TR']=df[['H-L','H-PC','L-PC']].max(axis=1,skipna=False)
32
- df['ATR']=df['TR'].rolling(lookback).mean()
33
-
34
- data = df.drop(['H-L','H-PC','L-PC'],axis=1) # drop columns
35
-
36
- return data['ATR']
27
+
28
+ df["H-L"] = abs(df["high"] - df["low"])
29
+ df["H-PC"] = abs(df["high"] - df["close"].shift(1))
30
+ df["L-PC"] = abs(df["low"] - df["close"].shift(1))
31
+
32
+ df["TR"] = df[["H-L", "H-PC", "L-PC"]].max(axis=1, skipna=False)
33
+ df["ATR"] = df["TR"].rolling(lookback).mean()
34
+
35
+ data = df.drop(["H-L", "H-PC", "L-PC"], axis=1) # drop columns
36
+
37
+ return data["ATR"]
37
38
 
38
39
 
39
40
  def BBands(series: pd.Series, lookback: int, multiplier: float = 2) -> pd.Series:
@@ -77,7 +78,7 @@ def SMA(series: pd.Series, lookback: int) -> pd.Series:
77
78
  time series to calculate the Moving Average for
78
79
  lookback : int
79
80
  lookback period for the Moving Average
80
-
81
+
81
82
  Returns
82
83
  -------
83
84
  pd.Series
@@ -86,6 +87,7 @@ def SMA(series: pd.Series, lookback: int) -> pd.Series:
86
87
 
87
88
  return series.rolling(lookback).mean()
88
89
 
90
+
89
91
  def EMA(series: pd.Series, lookback: int) -> pd.Series:
90
92
  """
91
93
  Exponential Moving Average
@@ -96,7 +98,7 @@ def EMA(series: pd.Series, lookback: int) -> pd.Series:
96
98
  time series to calculate the Exponential Moving Average for
97
99
  lookback : int
98
100
  lookback period for the Exponential Moving Average
99
-
101
+
100
102
  Returns
101
103
  -------
102
104
  pd.Series
@@ -120,7 +122,7 @@ def MACD(series: pd.Series, lookback: int, fast: int, slow: int) -> pd.Series:
120
122
  fast period for the MACD
121
123
  slow : int
122
124
  slow period for the MACD
123
-
125
+
124
126
  Returns
125
127
  -------
126
128
  pd.Series
@@ -128,13 +130,17 @@ def MACD(series: pd.Series, lookback: int, fast: int, slow: int) -> pd.Series:
128
130
  """
129
131
 
130
132
  # Calculate MACD line
131
- macd = series.ewm(span=fast, adjust=False).mean() - series.ewm(span=slow, adjust=False).mean()
132
-
133
+ macd = (
134
+ series.ewm(span=fast, adjust=False).mean()
135
+ - series.ewm(span=slow, adjust=False).mean()
136
+ )
137
+
133
138
  # Calculate Signal line from the MACD line
134
139
  signal = macd.ewm(span=lookback, adjust=False).mean()
135
-
140
+
136
141
  return macd, signal
137
142
 
143
+
138
144
  def RSI(series: pd.Series, lookback: int) -> pd.Series:
139
145
  """
140
146
  Relative Strength Index
@@ -145,7 +151,7 @@ def RSI(series: pd.Series, lookback: int) -> pd.Series:
145
151
  time series to calculate the RSI for
146
152
  lookback : int
147
153
  lookback period for the RSI
148
-
154
+
149
155
  Returns
150
156
  -------
151
157
  pd.Series
@@ -158,10 +164,9 @@ def RSI(series: pd.Series, lookback: int) -> pd.Series:
158
164
  # Separate gains and losses
159
165
  gain = (delta.where(delta > 0, 0)).rolling(window=lookback).mean()
160
166
  loss = (-delta.where(delta < 0, 0)).rolling(window=lookback).mean()
161
-
167
+
162
168
  # Calculate the Relative Strength (RS)
163
169
  rs = gain / loss
164
-
170
+
165
171
  # Calculate RSI
166
172
  return 100 - (100 / (1 + rs))
167
-
@@ -46,32 +46,38 @@ from typing import Union, List
46
46
  # # Ensure cache directory exists
47
47
  # if not os.path.exists(CACHE_DIR):
48
48
  # os.makedirs(CACHE_DIR)
49
-
49
+
50
50
  # cache_file = _get_cache_file_name(tickers, start_date, end_date, period, interval)
51
-
51
+
52
52
  # # Check if cached file exists
53
53
  # if os.path.exists(cache_file):
54
54
  # # print(f"Loading data from cache: {cache_file}")
55
55
  # return joblib.load(cache_file)
56
-
56
+
57
57
  # try:
58
58
  # # Download data from yfinance
59
59
  # data = yf.download(tickers, start=start_date, end=end_date, auto_adjust=True, progress=False, period=period, interval=interval)
60
-
60
+
61
61
  # # Save data to cache
62
62
  # joblib.dump(data, cache_file)
63
63
  # # print(f"Data cached to: {cache_file}")
64
-
64
+
65
65
  # except Exception as e:
66
66
  # print(f"Error downloading data: {e}")
67
67
  # raise
68
-
68
+
69
69
  # return data
70
70
 
71
71
 
72
- def getData(tickers: Union[str, List[str]], start_date: str = None, end_date: str = None, period: str = '1mo', interval: str = '1d') -> pd.DataFrame:
72
+ def getData(
73
+ tickers: Union[str, List[str]],
74
+ start_date: str = None,
75
+ end_date: str = None,
76
+ period: str = "1mo",
77
+ interval: str = "1d",
78
+ ) -> pd.DataFrame:
73
79
  """
74
- Retrieve data from yfinance library for specified tickers.
80
+ Retrieve data using yfinance library for specified tickers.
75
81
 
76
82
  Parameters
77
83
  ----------
@@ -94,16 +100,25 @@ def getData(tickers: Union[str, List[str]], start_date: str = None, end_date: st
94
100
  DataFrame with OHLC[A]V (Open, High, Low, Close, Adj Close, Volume).
95
101
  """
96
102
 
97
- cols = ['Open', 'High', 'Low', 'Close', 'Volume']
98
- data = yf.download(tickers, start=None, end=None, auto_adjust=True, progress=False, multi_level_index=False, period=period, interval=interval)
99
-
103
+ cols = ["Open", "High", "Low", "Close", "Volume"]
104
+ data = yf.download(
105
+ tickers,
106
+ start=start_date,
107
+ end=end_date,
108
+ auto_adjust=True,
109
+ progress=False,
110
+ multi_level_index=False,
111
+ period=period,
112
+ interval=interval,
113
+ )
114
+
100
115
  return data[cols]
101
116
 
102
117
 
103
- # Retrieve ticker object from yfinance library
118
+ # Retrieve ticker object using yfinance library
104
119
  def getTicker(ticker: str) -> yf.Ticker:
105
120
  """
106
- Retrieve ticker object from yfinance library.
121
+ Retrieve ticker object using yfinance library.
107
122
 
108
123
  Parameters
109
124
  ----------
@@ -118,7 +133,7 @@ def getTicker(ticker: str) -> yf.Ticker:
118
133
 
119
134
  # for all available options, refer yfinance
120
135
  # .info
121
- # .history
136
+ # .history
122
137
  # .actions
123
138
  # .dividends
124
139
  # .splits
@@ -138,7 +153,7 @@ def getTicker(ticker: str) -> yf.Ticker:
138
153
  # .earnings_dates
139
154
  # .isin
140
155
  # .options
141
- #. option_chain('YYYY-MM-DD')
156
+ # . option_chain('YYYY-MM-DD')
142
157
  # .news
143
158
 
144
159
  return yf.Ticker(ticker)
@@ -19,10 +19,14 @@
19
19
  from .optioninputs import OptionInputs
20
20
  from .blackscholes import BlackScholesOptionPricing
21
21
  from .montecarlo import MonteCarloOptionPricing
22
+ from .binomial import OptionType, ExerciseStyle, BinomialOptionPricing
22
23
 
23
24
 
24
25
  __all__ = [
25
26
  "OptionInputs",
26
- "BlackScholesOptionPricing",
27
+ "OptionType",
28
+ "ExerciseStyle",
29
+ "BlackScholesOptionPricing",
27
30
  "MonteCarloOptionPricing",
31
+ "BinomialOptionPricing",
28
32
  ]