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.
Files changed (44) hide show
  1. {quantmod-0.1.0 → quantmod-0.1.2}/PKG-INFO +1 -1
  2. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/plotting.py +2 -2
  3. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/derivatives/nse.py +88 -101
  4. quantmod-0.1.2/quantmod/version.py +1 -0
  5. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/PKG-INFO +1 -1
  6. quantmod-0.1.0/quantmod/version.py +0 -1
  7. {quantmod-0.1.0 → quantmod-0.1.2}/LICENSE.txt +0 -0
  8. {quantmod-0.1.0 → quantmod-0.1.2}/README.md +0 -0
  9. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/__init__.py +0 -0
  10. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/_version.py +0 -0
  11. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/__init__.py +0 -0
  12. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/charts/themes.py +0 -0
  13. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/__init__.py +0 -0
  14. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/data/nifty50.csv +0 -0
  15. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/data/spx.csv +0 -0
  16. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/datasets/dataloader.py +0 -0
  17. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/derivatives/__init__.py +0 -0
  18. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/indicators/__init__.py +0 -0
  19. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/indicators/indicators.py +0 -0
  20. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/main.py +0 -0
  21. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/__init__.py +0 -0
  22. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/bb.py +0 -0
  23. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/markets/yahoo.py +0 -0
  24. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/__init__.py +0 -0
  25. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/binomial.py +0 -0
  26. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/blackscholes.py +0 -0
  27. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/montecarlo.py +0 -0
  28. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/models/optioninputs.py +0 -0
  29. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/__init__.py +0 -0
  30. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/var.py +0 -0
  31. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/varbacktest.py +0 -0
  32. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/risk/varinputs.py +0 -0
  33. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/__init__.py +0 -0
  34. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/performance.py +0 -0
  35. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/timeseries/timeseries.py +0 -0
  36. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod/utils.py +0 -0
  37. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/SOURCES.txt +0 -0
  38. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/dependency_links.txt +0 -0
  39. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/entry_points.txt +0 -0
  40. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/not-zip-safe +0 -0
  41. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/requires.txt +0 -0
  42. {quantmod-0.1.0 → quantmod-0.1.2}/quantmod.egg-info/top_level.txt +0 -0
  43. {quantmod-0.1.0 → quantmod-0.1.2}/setup.cfg +0 -0
  44. {quantmod-0.1.0 → quantmod-0.1.2}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: quantmod
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Quantmod Python Package
5
5
  Home-page: https://kannansingaravelu.com/
6
6
  Author: Kannan Singaravelu
@@ -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] * 100,
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] * 100,
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
- # improvised from nsepython
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
- # Constants
16
- indices = ["NIFTY", "FINNIFTY", "BANKNIFTY"]
17
-
18
- headers = {
19
- "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",
20
- "accept-language": "en-US,en;q=0.9,en-IN;q=0.8,en-GB;q=0.7",
21
- "cache-control": "max-age=0",
22
- "priority": "u=0, i",
23
- "sec-ch-ua": '"Microsoft Edge";v="129", "Not=A?Brand";v="8", "Chromium";v="129"',
24
- "sec-ch-ua-mobile": "?0",
25
- "sec-ch-ua-platform": '"Windows"',
26
- "sec-fetch-dest": "document",
27
- "sec-fetch-mode": "navigate",
28
- "sec-fetch-site": "none",
29
- "sec-fetch-user": "?1",
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
- # Curl headers
35
- 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"""
36
-
37
- # https://ipapi.co/json
38
- # https://ipinfo.io/json
39
-
40
- try:
41
- # Try ipapi.co
42
- response = requests.get("https://ipapi.co/json/", timeout=5)
43
- if response.status_code == 200:
44
- data = response.json()
45
- country_code = data.get('country_code', '').upper()
46
- mode = "local" if country_code == "IN" else "vpn"
47
- else:
48
- # Fallback to ipinfo.io
49
- response = requests.get("https://ipinfo.io/json", timeout=5)
50
- if response.status_code == 200:
51
- data = response.json()
52
- country_code = data.get('country', '').upper()
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
- output = os.popen(payload_var).read()
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
- s = requests.Session()
52
+ refresh_cookies()
53
+ raw = os.popen(cmd).read()
87
54
  try:
88
- output = s.get("http://nseindia.com/option-chain", headers=headers)
89
- output = s.get(payload, headers=headers).json()
55
+ return json.loads(raw)
90
56
  except ValueError:
91
- output = s.get("https://www.nseindia.com", headers=headers)
92
- output = output.json()
93
- # output = s.get("https://www.nseindia.com/option-chain", headers=headers) # replaced http://nseindia.com with https://www.nseindia.com/option-chain
94
- output = s.get(payload, headers=headers).json()
95
- return output
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-indices?symbol="
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-equities?symbol="
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) for last traded price
186
- - 'sell' for bid price
187
- - 'buy' for ask price
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]["bidprice"]
185
+ return self.payload["records"]["data"][x][optionType]["sellPrice1"]
202
186
  if intent == "buy":
203
- return self.payload["records"]["data"][x][optionType]["askPrice"]
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
- if i["expiryDate"] == self.expiry_dt:
218
- try:
219
- ce_oi += i["CE"]["openInterest"]
220
- pe_oi += i["PE"]["openInterest"]
221
- except KeyError:
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,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: quantmod
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Quantmod Python Package
5
5
  Home-page: https://kannansingaravelu.com/
6
6
  Author: Kannan Singaravelu
@@ -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