import pickle import re import signal import sys import time from collections import OrderedDict from selenium.webdriver import Firefox from selenium.webdriver.firefox.options import Options from utils import * BNF_SYMBOL = "" NF_SYMBOL = "" STRIKE_PRICE_INDEX = 11 OC_BASE_URL = "" INDEX_URL = OC_BASE_URL + "&instrument=OPTIDX&symbol={}" STOCK_URL = OC_BASE_URL + "&instrument=OPTSTK&symbol={}" MONTHLY_EXPIRY_SUFFIX = "&date={}" INDIA_VIX_URL = "https://in.investing.com/indices/india-vix" value_time_pattern = re.compile(".*Underlying [a-zA-Z]+: [A-Z]+ ([0-9.]+) As on (.*)") date_today = datetime.now().date() def parse_tr_for_elements(tr, tag_name="td"): sub_elements = tr.find_elements_by_tag_name(tag_name) return [tag.text for tag in sub_elements] def compute_max_pain(trs): print(" Computing Max Pain ...", end="") all_expiry_loss = {} for index, exp_trdata in enumerate(trs): exp_strike_price = int(float(exp_trdata[STRIKE_PRICE_INDEX])) expiry_loss = 0 for trdata in trs: strike_price = int(float(trdata[STRIKE_PRICE_INDEX])) call_oi = int(trdata[1].replace(",", "").replace("-", "0")) put_oi = int(trdata[21].replace(",", "").replace("-", "0")) if strike_price == exp_strike_price: continue elif strike_price > exp_strike_price: expiry_loss += abs(strike_price - exp_strike_price) * put_oi else: expiry_loss += abs(strike_price - exp_strike_price) * call_oi all_expiry_loss[exp_strike_price] = expiry_loss max_pain = min(list(all_expiry_loss.keys()), key=all_expiry_loss.get) print(max_pain) return max_pain def get_oc_for_symbol(symbol, browser, india_vix_value, expiry_date, monthly=False): print("Running {} for symbol: {}".format("monthly" if monthly else "weekly", symbol)) print(" Reloading page ...") browser.refresh() trs = browser.find_elements_by_tag_name("tr") value, stime = value_time_pattern.findall(trs[0].text)[0] total_oi_line = trs[-2].text.split(" ") pcr_ratio = float(total_oi_line[-2].replace(",", "")) / float(total_oi_line[1].replace(",", "")) stime = str(datetime.strptime(stime, "%b %d, %Y %H:%M:%S %Z")) print(" PCR: {}".format(pcr_ratio)) print(" Parsing oc table ...") trs = [parse_tr_for_elements(tr) for tr in trs[10:-7]] filepath = "{}/trool/data/{}/{}/{}".format(get_home_directory(), symbol, "monthly" if monthly else "weekly", expiry_date) if not os.path.exists(filepath): create_dir_if_not_exist(os.path.dirname(filepath)) octable = OrderedDict() else: with open(filepath, "rb") as ocfile: octable = pickle.load(ocfile) octable[stime] = { "value": value, "india_vix": india_vix_value, "max_pain": compute_max_pain(trs), "pcr": round(pcr_ratio, 2), "oc": {}} for trdata in trs: octable[stime]["oc"][int(float(trdata[STRIKE_PRICE_INDEX]))] = { "Call": { "OI": trdata[1], "ChangeInOI": trdata[2], "Volume": trdata[3], "IV": trdata[4], "LTP": trdata[5], "NetChange": trdata[6], "BidQty": trdata[7], "BidPrice": trdata[8], "AskPrice": trdata[9], "AskQty": trdata[10] }, "Put": { "OI": trdata[21], "ChangeInOI": trdata[20], "Volume": trdata[19], "IV": trdata[18], "LTP": trdata[17], "NetChange": trdata[16], "BidQty": trdata[12], "BidPrice": trdata[13], "AskPrice": trdata[14], "AskQty": trdata[15] } } with open(filepath, "wb") as ocfile: pickle.dump(octable, ocfile) def get_browser_for_url(url): opts = Options() opts.headless = True try: browser = Firefox(options=opts) browser.get(url) except: print("Error initing browser. Sleeping before retrying ...") time.sleep(120) browser = Firefox(options=opts) browser.get(url) return browser def cleanup(signal=None, frame=None): print("Closing open browser sessions before exit ...") try: bnf_weekly_browser.close() nf_weekly_browser.close() bnf_monthly_browser.close() nf_monthly_browser.close() india_vix_browser.close() except: pass sys.exit() def get_value_for_india_vix(): india_vix_browser.refresh() return india_vix_browser.find_element_by_id("last_last").text def main(): while True: now = datetime.now() if is_market_closed(): print("Market closed. Exiting.") break try: print("Running at {}".format(now)) india_vix_value = get_value_for_india_vix() get_oc_for_symbol(BNF_SYMBOL, bnf_monthly_browser, india_vix_value, monthly_expiry_date, monthly=True) get_oc_for_symbol(NF_SYMBOL, nf_monthly_browser, india_vix_value, monthly_expiry_date, monthly=True) if not is_expiry_week: get_oc_for_symbol(BNF_SYMBOL, bnf_weekly_browser, india_vix_value, weekly_expiry_date) get_oc_for_symbol(NF_SYMBOL, nf_weekly_browser, india_vix_value, weekly_expiry_date) except Exception as e: print("Failed to fetch. Error: {}".format(e)) print("Sleeping ...") time.sleep(180) if __name__ == "__main__": if is_market_closed(): print("Market closed. Exiting.") sys.exit() signal.signal(signal.SIGINT, cleanup) monthly_expiry_date = get_expiry_date() is_expiry_week = False if int(monthly_expiry_date[:2]) < date_today.day: # This month's expiry date has passed. Should pick next month's. monthly_expiry_date = get_expiry_date(date_today.year, date_today.month + 1) elif (int(monthly_expiry_date[:2]) - date_today.day) < 7: # This is expiry week. No need to fetch for two separate dates. print("Is expiry week. Will skip fetching weekly option chain.") is_expiry_week = True print("Initing monthly BNF Browser ...") bnf_monthly_browser = get_browser_for_url(INDEX_URL.format(BNF_SYMBOL) + MONTHLY_EXPIRY_SUFFIX.format(monthly_expiry_date)) print("Initing monthly NF Browser ...") nf_monthly_browser = get_browser_for_url(INDEX_URL.format(NF_SYMBOL) + MONTHLY_EXPIRY_SUFFIX.format(monthly_expiry_date)) if not is_expiry_week: print("Initing weekly BNF Browser ...") bnf_weekly_browser = get_browser_for_url(INDEX_URL.format(BNF_SYMBOL)) print("Initing weekly NF Browser ...") nf_weekly_browser = get_browser_for_url(INDEX_URL.format(NF_SYMBOL)) weekly_expiry_date = bnf_weekly_browser.find_element_by_id("date").text.split("\n")[1] print("Fetching value for india vix ...") india_vix_browser = get_browser_for_url(INDIA_VIX_URL) main() cleanup()