def main_fun(now_date, now_time, percent): vol_sr = pd.Series() try: vol_sr['percent'] = percent part_result_dict = deal_fun(now_date=now_date, now_time=now_time, percent=percent) F = part_result_dict['spot_px'] vol_sr['S'] = F r = part_result_dict['rate_weight'] vol_sr['r'] = r tran_dict = {1: 'first', 2: 'second'} for i in range(1, 3): t = part_result_dict['opt_ttm_1'] / 365 for ii in range(1, 3): K = part_result_dict[f'opt_k_{i}_{ii}'] vol_sr[f'{tran_dict[i]}_K_{ii}'] = K # 计算 vol # if F >= K: # flag = 'call' # price = part_result_dict[f'{flag}_px_{i}_{ii}'] # vol_sr[f'{tran_dict[i]}_{flag}_px_{ii}'] = price # sigma = implied_volatility(price, F, K, t, r, flag[0]) # vol_sr[f'{tran_dict[i]}_{flag}_vol_{ii}'] = sigma # vol_sr[f'{tran_dict[i]}_vol_{ii}'] = vol_sr[f'{tran_dict[i]}_call_vol_{ii}'] # else: # flag = 'put' # price = part_result_dict[f'{flag}_px_{i}_{ii}'] # vol_sr[f'{tran_dict[i]}_{flag}_px_{ii}'] = price # sigma = implied_volatility(price, F, K, t, r, flag[0]) # vol_sr[f'{tran_dict[i]}_{flag}_vol_{ii}'] = sigma # vol_sr[f'{tran_dict[i]}_vol_{ii}'] = vol_sr[f'{tran_dict[i]}_put_vol_{ii}'] # 计算希腊字母 for flag in ['call', 'put']: price = result_dict[now_date][f'{flag}_px_{i}_{ii}'] vol_sr[f'{tran_dict[i]}_{flag}_px_{ii}'] = price sigma = implied_volatility(price, F, K, t, r, flag[0]) vol_sr[f'{tran_dict[i]}_{flag}_vol_{ii}'] = sigma vol_sr[f'{tran_dict[i]}_{flag}_delta_{ii}'] = delta(flag[0], F, K, t, r, sigma) vol_sr[f'{tran_dict[i]}_{flag}_gamma_{ii}'] = gamma(flag[0], F, K, t, r, sigma) vol_sr[f'{tran_dict[i]}_{flag}_rho_{ii}'] = rho(flag[0], F, K, t, r, sigma) vol_sr[f'{tran_dict[i]}_{flag}_theta_{ii}'] = theta(flag[0], F, K, t, r, sigma) vol_sr[f'{tran_dict[i]}_{flag}_vega_{ii}'] = vega(flag[0], F, K, t, r, sigma) vol_sr[f'{tran_dict[i]}_K_weight'] = (F - vol_sr[f'{tran_dict[i]}_K_2']) / \ (vol_sr[f'{tran_dict[i]}_K_1'] - vol_sr[f'{tran_dict[i]}_K_2']) vol_sr[f'{tran_dict[i]}_vol'] = vol_sr[f'{tran_dict[i]}_K_weight'] * \ vol_sr[f'{tran_dict[i]}_vol_1'] + \ (1 - vol_sr[f'{tran_dict[i]}_K_weight']) * \ vol_sr[f'{tran_dict[i]}_vol_2'] x = (30 - part_result_dict['opt_ttm_2']) / \ (part_result_dict['opt_ttm_1'] - part_result_dict['opt_ttm_2']) vol_sr[f'opt_ttm_1'] = part_result_dict['opt_ttm_1'] vol_sr[f'opt_ttm_2'] = part_result_dict['opt_ttm_2'] vol_sr[f'time_weight'] = x vol_sr[f'target_vol'] = x * vol_sr[f'first_vol'] + (1 - x) * vol_sr[f'second_vol'] except Exception as error: print(error) vol_sr.name = pd.to_datetime(f'{now_date} {now_time}') return vol_sr
def get_iv(row): try: return implied_volatility(row.Matched_price * row.CVN, row.Price, row.Excercise, row.Date / 360, risk_free, 'c') except: return np.nan
def test_implied_volatility(self): while self.tdi.has_next(): row = self.tdi.next_row() S, K, t, r, sigma = row['S'], row['K'], row['t'], row['R'], row[ 'v'] C, P = black_scholes('c', S, K, t, r, sigma), black_scholes('p', S, K, t, r, sigma) try: iv = implied_volatility(C, S, K, t, r, 'c') self.assertAlmostEqual(sigma, iv, delta=0.0001) except: print('could not calculate iv for ', C, S, K, t, r, 'c') iv = implied_volatility(P, S, K, t, r, 'p') self.assertTrue( iv == 0.0) if iv == 0.0 else self.assertAlmostEqual( sigma, iv, delta=0.001)
def get_vol(option_price, spot, strike, T, r=0, option_type='p'): """ Calculates the implied volatility of an option. Parameters ------------- option_price: int The market price of the option spot: int The current price of the underlying asset (in this case ETH) strike: int The strike price of the option contract T: int The time to maturity of the option in years r: int The current interest rate (assuming zero by default) option_type: str Option can be either a call ('c') or put ('p') Returns ------------- int: Returns the annualised implied volatility of the option Example ------------- >>> get_vol(option_price=1.1031, spot=200, strike=150, T=0.034, r=0, option_type='p') 1.0713281006448705 """ return iv.implied_volatility(option_price, spot, strike, T, r, option_type)
def get_implied_volatility(Option, underlying_price, option_price, interest_rate = 0, reference_date = dt.date.today()): price = option_price S = underlying_price K = Option.Strike r = interest_rate flag = Option.Option_Type.lower()[0] t = get_time_to_expiry(Option.Expiry) return implied_volatility(price, S, K, t, r, flag)
def Implied_Vol(price, S, K, RemainingTerm, RisklessRate): try: val = BSImpVol.implied_volatility(price, S, K, RemainingTerm, RisklessRate, 'c') except Exception as e: # raise e val = 0 return val
def vol_example(): ul_price = 60200 strike = 60000 dte = 4.5 option_price_mid = 2200 iv = implied_volatility(option_price_mid, ul_price, strike, dte/365, interest, 'p') print(f'Put iv:{iv}')
def iv_with_exception_handling(price, S, K, t, r, flag): if t < 0: return np.nan else: try: return implied_volatility(price, S, K, t, r, flag) except BelowIntrinsicException: return np.nan except AboveMaximumException: return np.nan
def precompute(underlying): print "precompute: " + str(underlying) print db = MySQLdb.connect(host="localhost", user=settings.db_username, passwd=settings.db_password, db="optiondata") cur2 = db.cursor() query = "SELECT id, quote_date, underlying_bid_1545, underlying_ask_1545, bid_1545, ask_1545, expiration, strike, option_type FROM optiondata WHERE underlying_symbol = '" + underlying + "' AND iv IS NULL ORDER BY id asc" cur2.execute(query) for row in cur2: rowid = row[0] quote_date = row[1] underlying_bid_1545 = row[2] underlying_ask_1545 = row[3] bid_1545 = row[4] ask_1545 = row[5] expiration = row[6] strike = float(row[7]) option_type = row[8].lower() current_quote = float((underlying_bid_1545 + underlying_ask_1545) / 2) midprice = float((bid_1545 + ask_1545) / 2) expiration_time = datetime.combine(expiration, time(16, 00)) remaining_time_in_years = util.remaining_time(quote_date, expiration_time) iv = 0.001 delta = 0.001 theta = 0.001 if remaining_time_in_years > 0: try: iv = implied_volatility.implied_volatility(midprice, current_quote, int(strike), remaining_time_in_years, util.interest, option_type) except: iv = 0.001 delta = analytical.delta(option_type, current_quote, strike, remaining_time_in_years, util.interest, iv) * 100 theta = analytical.theta(option_type, current_quote, strike, remaining_time_in_years, util.interest, iv) * 100 updateQuery = "UPDATE optiondata SET iv=%s, delta=%s, theta=%s WHERE id=%s" % (iv, delta, theta, rowid) try: cur2.execute(updateQuery) db.commit() except: print rowid print current_quote print midprice print iv print delta print theta print updateQuery db.close()
def pd_apply(N): from py_vollib.black_scholes.implied_volatility import implied_volatility from py_vollib.black_scholes import black_scholes tt = big_test_df.iloc[:N] tt["price"] = tt.apply(lambda row: black_scholes(row["flag"], row[ "S"], row["K"], row["t"], row["R"], row["v"]), axis=1) tt.apply(lambda row: implied_volatility(row["price"], row["S"], row["K"], row["t"], row["R"], row["flag"]), axis=1)
def _calculate_iv(price: float, S: float, K: float, t: float, r: float, flag: str, ticker: str): iv_value = float('NaN') if price > 0.0 and t > 0.0: # Otherwise makes no sense try: iv_value = iv.implied_volatility(price, S, K, t, r, flag.lower()) except BelowIntrinsicException as e: # Option price is below the intrinsic value (distance between current underlying price and strike). If true (including fees), this is a free # risk opportunity, but it is more likely an error in data (probably underlying asset price is not updated) iv_value = float('NaN') except Exception as e: exception_type = type(e).__name__ print('ERROR {} while calculating IV(price, S, K, t, r, right)->({}, {}, {}, {}, {}, {}) for ticker {} : {}'.format(exception_type, price, S, K, t, r, flag, ticker, e)) return iv_value
def test_implied_volatility_vs_py_vollib(self): for sigma, r, s0, tm, sk, call in itertools.product( self.sigmas, self.rates, self.spots, self.maturities, self.strikes, self.call): with self.subTest(): price = BlackScholes._option_price(sigma, r, s0, tm, sk, True) np.testing.assert_almost_equal( BlackScholes._implied_volatility(r, s0, tm, sk, call, price), implied_volatility(price=price, S=s0, K=sk, t=tm, r=r, flag='c' if call else 'p'))
def get_vol(attrs): option_price = attrs['price'] ul_price = attrs['ul_price'] dte = attrs['dte'] strike = attrs['strike'] flag = attrs['flag'] try: # print(option_price, ul_price, strike, dte, interest, flag) iv = implied_volatility(option_price, ul_price, strike, dte/365, interest, flag) except BelowIntrinsicException: # print('Below Intrinsic: return NaN') iv = np.nan except AboveMaximumException: # print('Vol above max value') iv = np.nan return iv
def iterrows(N): from py_vollib.black_scholes.implied_volatility import implied_volatility from py_vollib.black_scholes import black_scholes tt = big_test_df.iloc[:N] prices = [] for _, row in tt.iterrows(): prices.append( black_scholes(row["flag"], row["S"], row["K"], row["t"], row["R"], row["v"])) tt["price"] = prices ivs = [] for _, row in tt.iterrows(): ivs.append( implied_volatility(row["price"], row["S"], row["K"], row["t"], row["R"], row["flag"]))
def listcomp(N): from py_vollib.black_scholes.implied_volatility import implied_volatility from py_vollib.black_scholes import black_scholes tt = big_test_df.iloc[:N] prices = [ black_scholes(tt.iloc[i]["flag"], tt.iloc[i]["S"], tt.iloc[i]["K"], tt.iloc[i]["t"], tt.iloc[i]["R"], tt.iloc[i]["v"]) for i in range(len(tt)) ] tt["price"] = prices ivs = [ implied_volatility(tt.iloc[i]["price"], tt.iloc[i]["S"], tt.iloc[i]["K"], tt.iloc[i]["t"], tt.iloc[i]["R"], tt.iloc[i]["flag"]) for i in range(len(tt)) ]
def for_loop(N): from py_vollib.black_scholes.implied_volatility import implied_volatility from py_vollib.black_scholes import black_scholes tt = big_test_df.iloc[:N] prices = [] for i in range(len(tt)): prices.append( black_scholes(tt.iloc[i]["flag"], tt.iloc[i]["S"], tt.iloc[i]["K"], tt.iloc[i]["t"], tt.iloc[i]["R"], tt.iloc[i]["v"])) tt["price"] = prices ivs = [] for i in range(len(tt)): ivs.append( implied_volatility(tt.iloc[i]["price"], tt.iloc[i]["S"], tt.iloc[i]["K"], tt.iloc[i]["t"], tt.iloc[i]["R"], tt.iloc[i]["flag"]))
def get_implied_volatility(Option, option_price, underlying_price=None, interest_rate=None, reference_date=None): if underlying_price is None: underlying_price = 1 if interest_rate is None: interest_rate = 0 if reference_date is None: reference_date = dt.date.today() price = option_price S = underlying_price K = Option.Strike r = interest_rate flag = Option.Option_Type.lower()[0] t = get_time_to_expiry(Option.Expiry) if S <= .05: print('Stock price is below 5 cents. Check stock price') return 0 # If the option price is below the specified threshold, return volatility of 0 if price < .01: return 0 # If the intrinsic value is below the specified threshold, return volatility of 0 if flag == 'c': intrinsic_value = max((S - K), 0) elif flag == 'p': intrinsic_value = max((K - S), 0) if price - intrinsic_value < .01: return 0 # print('Type: {}, S: {:.2f}, K: {:.2f}, price: {:.2f}'.format(flag, S, K, price)) return implied_volatility(price, S, K, t, r, flag)
def on_update(msg, order): now = time.time() global tick ms = msg['market_state'] tck = ms['ticker'] last_price = msg['market_state']['last_price'] tickers[tck]['price'].append(last_price) tick += 1 if tck == fut: return S = tickers[fut]['price'][-1] if len(tickers[fut]['price']) > 0 else None K = int(tck[1:4]) if len(tck) == 5 else int(tck[1:3]) t = (450 - tick) / 450 * 1 / 12 flag = 'c' if tck[-1] == 'C' else 'p' if S is not None: try: iv = implied_volatility.implied_volatility(last_price, S, K, t, r, flag) theo_p = black_scholes.black_scholes(flag, S, K, t, r, iv) delta = analytical.delta(flag, S, K, t, r, iv) gamma = analytical.gamma(flag, S, K, t, r, iv) # vega = analytical.vega(flag,S,K,t,r,iv) tickers[tck]['vol'].append(vol) tickers[tck]['delta'].append(delta) tickers[tck]['gamma'].append(gamma) # tickers[tck]['vega'].append(vega) if len(tickers[tck]['vol']) > 5: vol_sma = np.mean(np.array(ticker[tck]['vol'][-6:-1])) if abs(iv - vol_sma) / vol_sma > .015: if iv > vol_sma: order.addSell(tck, 10, last_price + dx) else: order.addBuy(tck, 10, last_price - dx) except: print(S, K, last_price, flag)
def get_implied_volatility(Option, option_price, underlying_price=None, interest_rate=None, reference_date=None): if underlying_price is None: underlying_price = 1 if interest_rate is None: interest_rate = 0 if reference_date is None: reference_date = dt.date.today() price = option_price S = underlying_price K = Option.Strike r = interest_rate flag = Option.Option_Type.lower()[0] t = get_time_to_expiry(Option.Expiry) if S <= .05: return 0 if flag == 'c': if S - K > price or price / S > .9: return 0 else: if K - S > price or price / S > .9: return 0 if price < .01: return 0 #print("Strike: {}{}, Underlying: {:.2f}, Option: {:.2f}".format(K, flag, S, price)) #print(price, S, K, t, r, flag) return implied_volatility(price, S, K, t, r, flag)
def getExpectedValue(connector, underlying, combo, current_date, expiration): current_quote = connector.query_midprice_underlying( underlying, current_date) expiration_time = datetime.combine(expiration, time(16)) remaining_time_in_years = util.remaining_time(current_date, expiration_time) ul_for_ew = [] sum_legs = [] prob_touch = [] if (current_quote % 10) < 5: atm_strike = int(current_quote / 10) * 10 else: atm_strike = int((current_quote + 10) / 10) * 10 try: atm_option = util.Option(connector, current_date, underlying, atm_strike, expiration, "p") except ValueError: return "missing data" midprice = connector.query_midprice(current_date, atm_option) try: atm_iv = implied_volatility.implied_volatility( midprice, current_quote, atm_strike, remaining_time_in_years, util.interest, atm_option.type) except pyex.BelowIntrinsicException: atm_iv = 0.01 if (atm_iv == 0): atm_iv = 0.01 # print atm_iv one_sd = (atm_iv / math.sqrt( util.yeartradingdays / (remaining_time_in_years * util.yeartradingdays))) * current_quote lower_ul = current_quote - e_spanne * one_sd upper_ul = current_quote + e_spanne * one_sd step = (upper_ul - lower_ul) / 24 # war 1000 for i in range(25): # war 1001 ul_for_ew.insert(i, lower_ul + (i * step)) sum_legs_i = 0 positions = combo.getPositions() for position in positions: # param sigma: annualized standard deviation, or volatility # https://www.etfreplay.com/etf/iwm.aspx value = black_scholes.black_scholes(position.option.type, ul_for_ew[i], position.option.strike, remaining_time_in_years, util.interest, 0) guv = (value - position.entry_price) * ratio * position.amount sum_legs_i += guv sum_legs.insert(i, sum_legs_i) prob = util.prob_hit(current_quote, ul_for_ew[i], remaining_time_in_years, 0, atm_iv) prob_touch.insert(i, prob) sumproduct = sum([a * b for a, b in zip(sum_legs, prob_touch)]) expected_value = round((sumproduct / sum(prob_touch)), 2) return expected_value
def precompute(table, computedate, underlying, include_riskfree): # start = time.time() db = psycopg2.connect(host="localhost", user=settings.db_username, password=settings.db_password, database="optiondata") cur2 = db.cursor() underlying_fragment = "" if (underlying != "*"): underlying_fragment = "underlying_symbol = '" + underlying + "' AND " date_fragment = "" if (computedate != "*"): date_fragment = "quote_date = '" + str(computedate) + "' AND " query = "SELECT id, quote_date, underlying_mid_1545, mid_1545, expiration, strike, option_type FROM " + table + " WHERE " + underlying_fragment + date_fragment + "bs_price_bid_ask IS NULL" cur2.execute(query) result = cur2.fetchall() print (str(computedate) + " " + str(underlying) + ": " + str(len(result)) + " results") bulkrows = [] if (len(result) > 0): for row in result: rowid = row[0] quote_date = row[1] underlying_mid_1545 = float(row[2]) mid_1545 = float(row[3]) expiration = row[4] strike = float(row[5]) option_type = row[6] expiration_time = datetime.datetime.combine(expiration, datetime.time(16, 0)) remaining_time_in_years = util.remaining_time(quote_date, expiration_time) rf = util.interest if include_riskfree: rf = util.get_riskfree_libor(quote_date, remaining_time_in_years) try: iv = implied_volatility.implied_volatility(mid_1545, underlying_mid_1545, int(strike), remaining_time_in_years, rf, option_type) except: iv = 0.001 if underlying_mid_1545 == 0: underlying_mid_1545 = 0.01 bs_price_bid_ask = black_scholes(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) # print (bs_price_bid_ask) bulkrows.append({'bs_price_bid_ask': bs_price_bid_ask, 'rowid': rowid}) try: psycopg2.extras.execute_batch(cur2, """UPDATE """ + table + """ SET bs_price_bid_ask=%(bs_price_bid_ask)s WHERE id=%(rowid)s""", bulkrows, page_size=100) db.commit() except Exception as e: print("an exception occurred") print(e) print (query) # end = time.time() # print (end - start) print () db.close()
def getExpectedValue(underlying, combo, current_date, expiration, use_precomputed=True, include_riskfree=True): current_quote_original = util.connector.query_midprice_underlying( underlying, current_date) if (current_quote_original is None): return None current_quote = float(current_quote_original) if (current_quote == 0.0): return None expiration_time = datetime.combine(expiration, time(16)) remaining_time_in_years = util.remaining_time(current_date, expiration_time) ul_for_ew = [] sum_legs = [] prob_touch = [] if (current_quote % 10) < 5: atm_strike = int(current_quote / 10) * 10 else: atm_strike = int((current_quote + 10) / 10) * 10 if use_precomputed: try: atm_iv = float( util.connector.select_iv(current_date, underlying, expiration, "p", atm_strike)) except: atm_iv = 0.01 else: try: atm_option = util.Option(current_date, underlying, atm_strike, expiration, "p") except ValueError: return None midprice = util.connector.query_midprice(current_date, atm_option) rf = util.interest if include_riskfree: rf = util.get_riskfree_libor(current_date, remaining_time_in_years) try: atm_iv = float( implied_volatility.implied_volatility(midprice, current_quote, atm_strike, remaining_time_in_years, rf, atm_option.type)) except: atm_iv = 0.01 if (atm_iv == 0): atm_iv = 0.01 one_sd = (atm_iv / math.sqrt( util.yeartradingdays / (remaining_time_in_years * util.yeartradingdays))) * current_quote lower_ul = current_quote - e_spanne * one_sd upper_ul = current_quote + e_spanne * one_sd step = (upper_ul - lower_ul) / 24 # war 1000 for i in range(25): # war 1001 ul_for_ew.insert(i, lower_ul + (i * step)) sum_legs_i = 0 positions = combo.getPositions() for position in positions: # param sigma: annualized standard deviation, or volatility # https://www.etfreplay.com/etf/iwm.aspx rf = util.interest if include_riskfree: rf = util.get_riskfree_libor(current_date, remaining_time_in_years) value = black_scholes.black_scholes(position.option.type, ul_for_ew[i], position.option.strike, remaining_time_in_years, rf, 0) guv = (value - position.entry_price) * ratio * position.amount sum_legs_i += guv sum_legs.insert(i, sum_legs_i) prob = util.prob_hit(current_quote, ul_for_ew[i], remaining_time_in_years, 0, atm_iv) prob_touch.insert(i, prob) sumproduct = sum([a * b for a, b in zip(sum_legs, prob_touch)]) expected_value = round((sumproduct / sum(prob_touch)), 2) return expected_value
def precompute(underlying, include_riskfree): done = False bulksize = 100000 counter = 0 print("precompute: " + str(underlying)) print() while not done: db = psycopg2.connect(host="localhost", user=settings.db_username, password=settings.db_password, database="optiondata") cur2 = db.cursor() print("Query for next " + str(bulksize) + " items to precompute ") query = "SELECT id, quote_date, underlying_mid_1545, mid_1545, expiration, strike, option_type FROM optiondata WHERE underlying_symbol = '" + underlying + "' AND iv IS NULL LIMIT " + str( bulksize) cur2.execute(query) result = cur2.fetchall() print(str(len(result)) + " items to precompute") if len(result) == 0: done = True print("Done precomputing") print() bulkrows = [] for row in result: rowid = row[0] quote_date = row[1] underlying_mid_1545 = float(row[2]) mid_1545 = float(row[3]) expiration = row[4] strike = float(row[5]) option_type = row[6] expiration_time = datetime.datetime.combine( expiration, datetime.time(16, 0)) remaining_time_in_years = util.remaining_time( quote_date, expiration_time) rf = util.interest if include_riskfree: rf = util.get_riskfree_libor(quote_date, remaining_time_in_years) try: iv = implied_volatility.implied_volatility( mid_1545, underlying_mid_1545, int(strike), remaining_time_in_years, rf, option_type) delta = analytical.delta(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 theta = analytical.theta(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 vega = analytical.vega(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 except: iv = 0.001 delta = 0.001 theta = 0.001 vega = 0.001 bulkrows.append({ 'iv': iv, 'delta': delta, 'theta': theta, 'vega': vega, 'rowid': rowid }) counter += 1 if (((counter % 1000) == 0) or ((len(result) < bulksize) and (counter == len(result)))): try: cur2.executemany( """UPDATE optiondata SET iv=%(iv)s, delta=%(delta)s, theta=%(theta)s, vega=%(vega)s WHERE id=%(rowid)s""", bulkrows) db.commit() print("inserted: " + str(counter)) bulkrows = [] time.sleep(1) except Exception as e: print("an exception occurred") print(e) if (len(result) < bulksize) and (counter == len(result)): done = True print("Done precomputing") print() db.close()
def plot_risk_graph(options_data, S, r, save_png=False): ''' Creates a risk graph for the combination of options provided in the input list of options for the different times to expiration provided inputs: options_data -> options data composing the strategy. It is important to provide this list ordered by near-term expiries first S -> current underlying price r -> interest rate on a 3-month U.S. Treasury bill or similar save_png -> determines if the plot is saved as a PNG file (default False) returns: list of tuples (x, (datetime, y)) ''' # Get the list of options from options_data options_list = options_data['options'] # First get the graph bounds, 10% apart from the min and max strikes min_strike = None max_strike = None for opt in options_list: if (min_strike is None) or (opt['strike'] < min_strike): min_strike = opt['strike'] if (max_strike is None) or (opt['strike'] > max_strike): max_strike = opt['strike'] # Make sure current underlying price is into the range if min_strike > S: min_strike = S if max_strike < S: max_strike = S # Determine front expiration date front_expiration = None back_expiration = None for opt in options_list: aux_date = datetime.strptime(opt['expiration_date'], '%d/%m/%Y') if (front_expiration is None) or (aux_date < front_expiration): front_expiration = aux_date if (back_expiration is None) or (aux_date > back_expiration): back_expiration = aux_date # Prices vector strike_spread = max_strike - min_strike x_vector = np.linspace(min_strike - strike_spread * 0.1, max_strike + strike_spread * 0.1, 500) # Now plot the risk graph for the different time values provided return_values = [] y = [] for t in [datetime.today(), front_expiration, back_expiration]: y_vector = np.zeros(len(x_vector)) y_vector.fill(options_data['meta']['amount'] * options_data['meta']['multiplier'] * options_data['meta']['premium'] - options_data['meta']['commisions']) y.append(y_vector) # Create the discrete values of P/L to plot against xrange for opt in options_list: # Get time to expiration in years days_to_expire = ( datetime.strptime(opt['expiration_date'], '%d/%m/%Y') - t).days t_exp = days_to_expire / 365. if t_exp >= 0: # Calculate IV from latest option price iv = bsiv.implied_volatility(opt['last_price'], S, opt['strike'], t_exp, r, opt['right'].lower()) # Calculate option price using black-scholes given that IV y[-1] += np.array([ options_data['meta']['amount'] * options_data['meta']['multiplier'] * opt['amount'] * bs.black_scholes(opt['right'].lower(), x, opt['strike'], t_exp, r, iv) for x in x_vector ]) # Get the number of days to expiration from today for plot's legend plt.plot(x_vector, y[-1], label='t: ' + str(days_to_expire)) return_values.append((t, y[-1])) # Plot a vertical line where the underlying is currently trading at plt.axvline(S, color='r') # Plot zero horizontal line plt.axhline(0, color='k', linestyle='dashed') plt.legend() plt.xlabel('Price') plt.ylabel('P/L') # Save the plot as a PNG if required, or show plot in a window if save_png: plt.savefig(datetime.today().strftime(options_data.meta.ticker + '_%d%b%y.png')) else: # Show the plot plt.show() # Return the values calculated TODO for what? to calculate breakevens? return (x_vector, return_values)
rng_u = real_vol + 0.01 else: rng_d = real_vol - 0.15 rng_u = real_vol + 0.15 if now_tick in rng_time: range_news = api.news_kind("News", is_last=True)["body"] rng_d = int(re.findall(r"\d+", range_news.values[0])[0]) / 100 rng_u = int(re.findall(r"\d+", range_news.values[0])[1]) / 100 # computation -- implied vol vol_dict = {} for call in call_list: K = int("".join(re.findall(r'\d', call))[1:]) flag = 'c' try: iv = implied_volatility(prc_last[call], S_last, K, t, r, flag) except Exception: iv = np.nan vol_dict[call] = iv for put in put_list: K = int("".join(re.findall(r'\d', call))[1:]) flag = 'p' try: iv = implied_volatility(prc_last[put], S_last, K, t, r, flag) except Exception: iv = np.nan vol_dict[put] = iv iv_s = pd.Series(vol_dict) # print(iv_s) # find at-the-money option and its iv at_money_opt = []
def precompute(table, computedate, underlying, include_riskfree): db = psycopg2.connect(host="localhost", user=settings.db_username, password=settings.db_password, database="optiondata") cur2 = db.cursor() underlying_fragment = "" if (underlying != "*"): underlying_fragment = "underlying_symbol = '" + underlying + "' AND " date_fragment = "" if (computedate != "*"): date_fragment = "quote_date = '" + str(computedate) + "' AND " query = "SELECT id, quote_date, underlying_mid_1545, mid_1545, expiration, strike, option_type FROM " + \ table + " WHERE " + underlying_fragment + date_fragment + "iv IS NULL" cur2.execute(query) result = cur2.fetchall() print( str(computedate) + " " + str(underlying) + ": " + str(len(result)) + " results") bulkrows = [] if (len(result) > 0): for row in result: rowid = row[0] quote_date = row[1] underlying_mid_1545 = float(row[2]) mid_1545 = float(row[3]) expiration = row[4] strike = float(row[5]) option_type = row[6] expiration_time = datetime.datetime.combine( expiration, datetime.time(16, 0)) remaining_time_in_years = util.remaining_time( quote_date, expiration_time) rf = util.interest if include_riskfree: rf = util.get_riskfree_libor(quote_date, remaining_time_in_years) try: iv = implied_volatility.implied_volatility( mid_1545, underlying_mid_1545, int(strike), remaining_time_in_years, rf, option_type) except: iv = 0.001 try: bs_price_bid_ask = black_scholes(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) except: bs_price_bid_ask = 0.001 try: delta = analytical.delta(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 except: delta = 0.001 try: theta = analytical.theta(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 except: theta = 0.001 try: vega = analytical.vega(option_type, underlying_mid_1545, strike, remaining_time_in_years, rf, iv) * 100 except: vega = 0.001 bulkrows.append({ 'iv': iv, 'bs_price_bid_ask': bs_price_bid_ask, 'delta': delta, 'theta': theta, 'vega': vega, 'rowid': rowid }) psycopg2.extras.execute_batch( cur2, """UPDATE """ + table + """ SET iv=%(iv)s, bs_price_bid_ask=%(bs_price_bid_ask)s, delta=%(delta)s, theta=%(theta)s, vega=%(vega)s WHERE id=%(rowid)s""", bulkrows, page_size=100) db.commit() db.close()
def black_scholes_run(iterations): for i in range(iterations): price = black_scholes(flag, S, K, t, r, sigma) iv = implied_volatility(price, S, K, t, r, flag) return (price, iv)