quantmod 0.1.0__tar.gz → 0.1.2__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.1.0 → quantmod-0.1.2}/PKG-INFO +1 -1
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/plotting.py +2 -2
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/derivatives/nse.py +88 -101
- quantmod-0.1.2/quantmod/version.py +1 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/PKG-INFO +1 -1
- quantmod-0.1.0/quantmod/version.py +0 -1
- {quantmod-0.1.0 → quantmod-0.1.2}/LICENSE.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/README.md +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/_version.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/themes.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/data/nifty50.csv +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/data/spx.csv +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/dataloader.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/derivatives/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/indicators/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/indicators/indicators.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/main.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/bb.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/yahoo.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/binomial.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/blackscholes.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/montecarlo.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/optioninputs.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/var.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/varbacktest.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/varinputs.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/__init__.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/performance.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/timeseries.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/utils.py +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/SOURCES.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/dependency_links.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/entry_points.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/not-zip-safe +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/requires.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/top_level.txt +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/setup.cfg +0 -0
- {quantmod-0.1.0 → quantmod-0.1.2}/setup.py +0 -0
|
@@ -235,7 +235,7 @@ def _plot_histogram(df, columns=None, **kwargs):
|
|
|
235
235
|
for i, col in enumerate(columns):
|
|
236
236
|
fig.add_trace(
|
|
237
237
|
go.Histogram(
|
|
238
|
-
x=df[col]
|
|
238
|
+
x=df[col],
|
|
239
239
|
nbinsx=kwargs.get("nbinsx", 50),
|
|
240
240
|
name=col,
|
|
241
241
|
opacity=0.75,
|
|
@@ -249,7 +249,7 @@ def _plot_histogram(df, columns=None, **kwargs):
|
|
|
249
249
|
r, c = divmod(i, ncols)
|
|
250
250
|
fig.add_trace(
|
|
251
251
|
go.Histogram(
|
|
252
|
-
x=df[col]
|
|
252
|
+
x=df[col],
|
|
253
253
|
nbinsx=kwargs.get("nbinsx", 50),
|
|
254
254
|
name=col,
|
|
255
255
|
opacity=0.75,
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
#
|
|
2
|
-
# to be used only for tutorial purposes
|
|
3
|
-
# for production use, please reach out to NSE India
|
|
1
|
+
# updated to new nse api changes on 10th Dec 2025
|
|
4
2
|
import os, sys
|
|
5
3
|
import requests
|
|
6
4
|
import numpy as np
|
|
@@ -12,87 +10,76 @@ import logging
|
|
|
12
10
|
import re
|
|
13
11
|
import urllib.parse
|
|
14
12
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
headers = {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
"upgrade-insecure-requests": "1",
|
|
31
|
-
"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",
|
|
13
|
+
# --- Configuration ---
|
|
14
|
+
mode = "auto" # can be "local", "vpn", or "auto"
|
|
15
|
+
|
|
16
|
+
headers = {"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",
|
|
17
|
+
"accept-language": "en-US,en;q=0.9,en-IN;q=0.8,en-GB;q=0.7",
|
|
18
|
+
"cache-control": "max-age=0",
|
|
19
|
+
"priority": "u=0, i",
|
|
20
|
+
"sec-ch-ua": '"Microsoft Edge";v="129", "Not=A?Brand";v="8", "Chromium";v="129"', "sec-ch-ua-mobile": "?0",
|
|
21
|
+
"sec-ch-ua-platform": '"Windows"',
|
|
22
|
+
"sec-fetch-dest": "document",
|
|
23
|
+
"sec-fetch-mode": "navigate",
|
|
24
|
+
"sec-fetch-site": "none",
|
|
25
|
+
"sec-fetch-user": "?1",
|
|
26
|
+
"upgrade-insecure-requests": "1",
|
|
27
|
+
"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",
|
|
32
28
|
}
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
mode = "local" if country_code == "IN" else "vpn"
|
|
54
|
-
else:
|
|
55
|
-
mode = "local"
|
|
56
|
-
|
|
57
|
-
except Exception:
|
|
58
|
-
mode = "local"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def nsefetch(payload):
|
|
62
|
-
if mode == "vpn":
|
|
63
|
-
if ("%26" in payload) or ("%20" in payload):
|
|
64
|
-
encoded_url = payload
|
|
65
|
-
else:
|
|
66
|
-
encoded_url = urllib.parse.quote(payload, safe=":/?&=")
|
|
67
|
-
payload_var = 'curl -b cookies.txt "' + encoded_url + '"' + curl_headers + ""
|
|
30
|
+
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'''
|
|
31
|
+
|
|
32
|
+
# --- Main function ---
|
|
33
|
+
def nsefetch(payload: str):
|
|
34
|
+
def encode(url: str) -> str:
|
|
35
|
+
if "%26" in url or "%20" in url:
|
|
36
|
+
return url
|
|
37
|
+
return urllib.parse.quote(url, safe=":/?&=")
|
|
38
|
+
|
|
39
|
+
def refresh_cookies():
|
|
40
|
+
os.popen(f'curl -c cookies.txt "https://www.nseindia.com" {curl_headers}').read()
|
|
41
|
+
os.popen(f'curl -b cookies.txt -c cookies.txt "https://www.nseindia.com/option-chain" {curl_headers}').read()
|
|
42
|
+
|
|
43
|
+
def curl_fetch(url: str):
|
|
44
|
+
encoded_url = encode(url)
|
|
45
|
+
if not os.path.exists("cookies.txt"):
|
|
46
|
+
refresh_cookies()
|
|
47
|
+
cmd = f'curl -b cookies.txt "{encoded_url}" {curl_headers}'
|
|
48
|
+
raw = os.popen(cmd).read()
|
|
68
49
|
try:
|
|
69
|
-
|
|
70
|
-
output = json.loads(output)
|
|
71
|
-
except ValueError: # includes simplejson.decoder.JSONDecodeError:
|
|
72
|
-
payload2 = "https://www.nseindia.com"
|
|
73
|
-
output2 = os.popen(
|
|
74
|
-
'curl -c cookies.txt "' + payload2 + '"' + curl_headers + ""
|
|
75
|
-
).read()
|
|
76
|
-
|
|
77
|
-
output = os.popen(payload_var).read()
|
|
78
|
-
output = json.loads(output)
|
|
79
|
-
return output
|
|
80
|
-
|
|
81
|
-
else: # mode == "local":
|
|
82
|
-
try:
|
|
83
|
-
output = requests.get(payload, headers=headers).json()
|
|
84
|
-
# print(output)
|
|
50
|
+
return json.loads(raw)
|
|
85
51
|
except ValueError:
|
|
86
|
-
|
|
52
|
+
refresh_cookies()
|
|
53
|
+
raw = os.popen(cmd).read()
|
|
87
54
|
try:
|
|
88
|
-
|
|
89
|
-
output = s.get(payload, headers=headers).json()
|
|
55
|
+
return json.loads(raw)
|
|
90
56
|
except ValueError:
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
57
|
+
return {}
|
|
58
|
+
|
|
59
|
+
def requests_fetch(url: str):
|
|
60
|
+
try:
|
|
61
|
+
s = requests.Session()
|
|
62
|
+
s.get("https://www.nseindia.com", headers=headers, timeout=10)
|
|
63
|
+
s.get("https://www.nseindia.com/option-chain", headers=headers, timeout=10)
|
|
64
|
+
return s.get(url, headers=headers, timeout=10).json()
|
|
65
|
+
except Exception:
|
|
66
|
+
return {}
|
|
67
|
+
|
|
68
|
+
# --- Auto / Mode selection ---
|
|
69
|
+
if mode == "local":
|
|
70
|
+
return requests_fetch(payload)
|
|
71
|
+
elif mode == "vpn":
|
|
72
|
+
return curl_fetch(payload)
|
|
73
|
+
else:
|
|
74
|
+
# Auto mode: try requests first, fallback to curl
|
|
75
|
+
data = requests_fetch(payload)
|
|
76
|
+
if not data:
|
|
77
|
+
print("⚠️ Local fetch failed — switching to curl + cookies.")
|
|
78
|
+
data = curl_fetch(payload)
|
|
79
|
+
return data
|
|
80
|
+
|
|
81
|
+
# --- Utility constants ---
|
|
82
|
+
indices = ["NIFTY", "FINNIFTY", "BANKNIFTY"]
|
|
96
83
|
|
|
97
84
|
|
|
98
85
|
class OptionData:
|
|
@@ -160,16 +147,15 @@ class OptionData:
|
|
|
160
147
|
"""
|
|
161
148
|
if any(x in self.symbol for x in indices):
|
|
162
149
|
payload = nsefetch(
|
|
163
|
-
"https://www.nseindia.com/api/option-chain-
|
|
164
|
-
+ self.symbol
|
|
150
|
+
f"https://www.nseindia.com/api/option-chain-v3?type=Indices&symbol={self.symbol}&expiry={self.expiry_dt}"
|
|
165
151
|
)
|
|
166
152
|
else:
|
|
167
153
|
payload = nsefetch(
|
|
168
|
-
"https://www.nseindia.com/api/option-chain-
|
|
169
|
-
+ self.symbol
|
|
154
|
+
f"https://www.nseindia.com/api/option-chain-v3?type=Equity&symbol={self.symbol}&expiry={self.expiry_dt}"
|
|
170
155
|
)
|
|
171
156
|
return payload
|
|
172
157
|
|
|
158
|
+
|
|
173
159
|
def get_option_quote(self, strikePrice, optionType, intent=""):
|
|
174
160
|
"""
|
|
175
161
|
Get option quote for specific strike price and option type.
|
|
@@ -182,9 +168,9 @@ class OptionData:
|
|
|
182
168
|
Type of option, either 'CE' (Call) or 'PE' (Put)
|
|
183
169
|
intent : str, optional
|
|
184
170
|
Quote type:
|
|
185
|
-
- '' (default)
|
|
186
|
-
- 'sell' for
|
|
187
|
-
- 'buy' for
|
|
171
|
+
- '' (default) lastPrice
|
|
172
|
+
- 'sell' for sellPrice1
|
|
173
|
+
- 'buy' for buyPrice1
|
|
188
174
|
|
|
189
175
|
Returns
|
|
190
176
|
-------
|
|
@@ -192,16 +178,15 @@ class OptionData:
|
|
|
192
178
|
Option price based on the specified intent
|
|
193
179
|
"""
|
|
194
180
|
for x in range(len(self.payload["records"]["data"])):
|
|
195
|
-
if (self.payload["records"]["data"][x]["strikePrice"] == strikePrice)
|
|
196
|
-
self.payload["records"]["data"][x]["expiryDate"] == self.expiry_dt
|
|
197
|
-
):
|
|
181
|
+
if (self.payload["records"]["data"][x]["strikePrice"] == strikePrice):
|
|
198
182
|
if intent == "":
|
|
199
183
|
return self.payload["records"]["data"][x][optionType]["lastPrice"]
|
|
200
184
|
if intent == "sell":
|
|
201
|
-
return self.payload["records"]["data"][x][optionType]["
|
|
185
|
+
return self.payload["records"]["data"][x][optionType]["sellPrice1"]
|
|
202
186
|
if intent == "buy":
|
|
203
|
-
return self.payload["records"]["data"][x][optionType]["
|
|
187
|
+
return self.payload["records"]["data"][x][optionType]["buyPrice1"]
|
|
204
188
|
|
|
189
|
+
|
|
205
190
|
def _get_option_pcr(self):
|
|
206
191
|
"""
|
|
207
192
|
Calculate Put-Call Ratio based on open interest.
|
|
@@ -214,14 +199,14 @@ class OptionData:
|
|
|
214
199
|
ce_oi = 0
|
|
215
200
|
pe_oi = 0
|
|
216
201
|
for i in self.payload["records"]["data"]:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pass
|
|
202
|
+
try:
|
|
203
|
+
ce_oi += i["CE"]["openInterest"]
|
|
204
|
+
pe_oi += i["PE"]["openInterest"]
|
|
205
|
+
except KeyError:
|
|
206
|
+
pass
|
|
223
207
|
return round(pe_oi / ce_oi, 2)
|
|
224
208
|
|
|
209
|
+
|
|
225
210
|
def get_synthetic_future_price(self, strike):
|
|
226
211
|
"""
|
|
227
212
|
Calculate synthetic futures price using put-call parity.
|
|
@@ -243,6 +228,7 @@ class OptionData:
|
|
|
243
228
|
)
|
|
244
229
|
return synthetic_futures
|
|
245
230
|
|
|
231
|
+
|
|
246
232
|
def _get_call_option_data(self):
|
|
247
233
|
"""
|
|
248
234
|
Get call options data for current expiry.
|
|
@@ -255,10 +241,11 @@ class OptionData:
|
|
|
255
241
|
ce_values = [
|
|
256
242
|
data["CE"]
|
|
257
243
|
for data in self.payload["records"]["data"]
|
|
258
|
-
if "CE" in data and data["expiryDate"] == self.expiry_dt
|
|
259
244
|
]
|
|
260
245
|
return pd.DataFrame(ce_values).sort_values(["strikePrice"])
|
|
261
|
-
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
262
249
|
def _get_put_option_data(self):
|
|
263
250
|
"""
|
|
264
251
|
Get put options data for current expiry.
|
|
@@ -271,10 +258,10 @@ class OptionData:
|
|
|
271
258
|
pe_values = [
|
|
272
259
|
data["PE"]
|
|
273
260
|
for data in self.payload["records"]["data"]
|
|
274
|
-
if "PE" in data and data["expiryDate"] == self.expiry_dt
|
|
275
261
|
]
|
|
276
262
|
return pd.DataFrame(pe_values).sort_values(["strikePrice"])
|
|
277
|
-
|
|
263
|
+
|
|
264
|
+
|
|
278
265
|
def _get_maximum_pain_strike(self):
|
|
279
266
|
"""
|
|
280
267
|
Calculate maximum pain strike price.
|
|
@@ -295,4 +282,4 @@ class OptionData:
|
|
|
295
282
|
for expiry_price in strikes
|
|
296
283
|
]
|
|
297
284
|
|
|
298
|
-
return strikes[np.argmin(total_pain)]
|
|
285
|
+
return strikes[np.argmin(total_pain)]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
version = "0.1.2"
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
version = "0.1.0"
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|