|
From: Luigi B. <lui...@gm...> - 2022-05-20 09:17:00
|
It would be the sum of past fixings; for three past fixings of 100.2, 101.3 and 94.6 it would be 296.1. Luigi On Thu, May 19, 2022 at 12:37 PM Ashish Bansal <ash...@gm...> wrote: > Thanks, Luigi for the suggestion. After taking the running accumulator, we > are able to generate the numbers. What exactly should be passed here? The > average price of past fixings or just 1 when the trade is priced during > averaging period? > > Thanks for help. > > Ashish > > On Wed, 18 May 2022 at 21:17, Luigi Ballabio <lui...@gm...> > wrote: > >> I don't have a 1.7 version to try it, but the check is the one at < >> https://github.com/lballabio/QuantLib/blob/QuantLib-v1.7/ql/pricingengines/asian/fdblackscholesasianengine.cpp#L51-L53>, >> suggesting that your running accumulator should be 0 (which makes sense, >> because you're using arithmetic average, i.e., a sum, and if you don't have >> any fixings yet the sum should be 0.) >> Your default seems to be 1 instead. >> >> Luigi >> >> >> On Wed, May 18, 2022 at 5:17 PM Ashish Bansal <ash...@gm...> >> wrote: >> >>> Luigi, >>> >>> Our code is not too much but we are using deprecated functions like >>> FDEuropeanEngine and FDAmericanEngine. Not sure if using new function >>> called FdBlackScholesVanillaEngine has any change in the calculation >>> that our code will have an impact. >>> >>> Can we use the DiscreteAveragingAsianOption without the overloaded >>> parameter of pastfixings under 1.7? >>> >>> Ashish >>> >>> On Wed, 18 May 2022 at 20:00, Luigi Ballabio <lui...@gm...> >>> wrote: >>> >>>> Hi — it could be. Any particular reason you're still using a version >>>> from 4 years ago? If you have a substantial amount of code that depends on >>>> QuantLib, it might require some work to update because some methods were >>>> deprecated and then removed in the meantime; and of course you'll probably >>>> have some validation process in place when updating, so that's work too. >>>> But on the other hand, you're missing 4 years worth of bug fixings... >>>> >>>> Luigi >>>> >>>> >>>> On Wed, May 18, 2022 at 4:19 PM Ashish Bansal <ash...@gm...> >>>> wrote: >>>> >>>>> We tried again and got the same error. >>>>> >>>>> Could it be due to the old version (1.7) we are using? I see in the >>>>> release notes of Apr-2021 that the overload for past fixing was added: >>>>> >>>>> - Added an overloaded constructor for Asian options that takes all >>>>> past fixings and thus allows to reprice them correctly when the evaluation >>>>> date changes (thanks to Jack Gillett). >>>>> >>>>> Ashish >>>>> >>>>> On Wed, 18 May 2022 at 19:14, Jack G <jac...@gm...> wrote: >>>>> >>>>>> Hi Ashish, >>>>>> >>>>>> I have a better answer for you with a screenshot awaiting moderation >>>>>> as it's quite large, but in the meantime, I was able to run your code >>>>>> without problems using the python at the bottom of this email (although I >>>>>> didn't check the numbers). >>>>>> >>>>>> If there is something you're doing specifically to generate the >>>>>> error, could you please attach a minimal reproduction of it? >>>>>> >>>>>> Best, >>>>>> Jack >>>>>> >>>>>> >>>>>> >>>>>> >>>>>> import QuantLib as ql >>>>>> from copy import deepcopy >>>>>> from datetime import datetime >>>>>> from datetime import timedelta >>>>>> >>>>>> >>>>>> # DEFAULT_PERIODS = [ql.Period(f"{i}d") for i in range(0,31)] >>>>>> DEFAULT_PERIODS = [ql.Period("6M"), ql.Period("12M"), >>>>>> ql.Period("18M"), ql.Period("24M")] >>>>>> DEFAULT_tGRID = 100 >>>>>> DEFAULT_xGRID = 100 >>>>>> DEFAULT_aGRID = 50 >>>>>> DEFAULT_aRA = 1 # arithmeticRunningAccumulator >>>>>> DEFAULT_PASTFIXINGS = 1 >>>>>> >>>>>> >>>>>> class AsianOptionPrice: >>>>>> def __init__(self, **x): >>>>>> for k, v in x.items(): >>>>>> setattr(self, k, v) >>>>>> self.tGrid = x.get("tGrid", DEFAULT_tGRID) >>>>>> self.xGrid = x.get("xGrid", DEFAULT_xGRID) >>>>>> self.aGrid = x.get("aGrid", DEFAULT_aGRID) >>>>>> self.periods = x.get("periods", DEFAULT_PERIODS) >>>>>> self.pastFixings = x.get("pastFixings", DEFAULT_PASTFIXINGS) >>>>>> self.aRA = x.get("arithmeticRunningAccumulator", DEFAULT_aRA) >>>>>> self.keyList = [k for k, v in x.items()] >>>>>> self.dist = 10**(-2) >>>>>> self.date_format = "%d-%m-%Y" >>>>>> self.value_date = ql.DateParser.parseFormatted( >>>>>> self.valueDate, '%d-%m-%Y') >>>>>> self.expiry_date = ql.DateParser.parseFormatted( >>>>>> self.expiryDate, '%d-%m-%Y') >>>>>> ql.Settings.instance().evaluationDate = self.value_date >>>>>> self.exDay = ql.DateParser.parseFormatted(self.expiryDate, >>>>>> '%d-%m-%Y') >>>>>> # Volatility input is required for running the computing >>>>>> implied volatility function. This volatility is NOT used in the implied >>>>>> volatility calculation. >>>>>> self.vol_for_iv_calc = 0.10 >>>>>> self.IV = None >>>>>> >>>>>> def generate_fixture_dates(self,start_date,end_date,period): >>>>>> schedule = ql.MakeSchedule(start_date, end_date, period) >>>>>> fixture_dates = [_date for _date in schedule if >>>>>> _date.weekday() not in [1,7]] >>>>>> return fixture_dates >>>>>> def asian(self): >>>>>> """ >>>>>> arithmeticRunningAccumulator(aRA) >>>>>> """ >>>>>> arithmeticRunningAccumulator = self.aRA >>>>>> pastFixings = self.pastFixings >>>>>> print(pastFixings) >>>>>> option_type = self.optionType.lower() >>>>>> if option_type not in ["call", "put"]: >>>>>> raise Exception( >>>>>> f"Option Type is Neither Call nor Put, Option type is >>>>>> {option_type}") >>>>>> option_type = ql.Option.Call if option_type == "call" else >>>>>> ql.Option.Put >>>>>> strike = self.strikePrice >>>>>> today = self.value_date >>>>>> print(today) >>>>>> fixingStartDate >>>>>> =ql.DateParser.parseFormatted(self.fixingStartDate, '%d-%m-%Y') >>>>>> print("#"*40,fixingStartDate) >>>>>> periods = self.periods >>>>>> asianFutureFixingDates = >>>>>> self.generate_fixture_dates(fixingStartDate,self.expiry_date,ql.Period("1d")) >>>>>> print("#"*40,asianFutureFixingDates) >>>>>> asianExpiryDate = self.expiry_date >>>>>> vanillaPayoff = ql.PlainVanillaPayoff(option_type, strike) >>>>>> europeanExercise = ql.EuropeanExercise(asianExpiryDate) >>>>>> arithmeticAverage = ql.Average().Arithmetic >>>>>> discreteArithmeticAsianOption = >>>>>> ql.DiscreteAveragingAsianOption( >>>>>> arithmeticAverage, arithmeticRunningAccumulator, >>>>>> pastFixings, asianFutureFixingDates, vanillaPayoff, europeanExercise) >>>>>> return discreteArithmeticAsianOption >>>>>> >>>>>> def create_arg_list(self, Option=None, compute_implied_vol=None, >>>>>> implied_vol_am_put=None): >>>>>> ''' >>>>>> The arguments with disturbances added. Will be used for >>>>>> calculation of Greeks >>>>>> using numerical differentiation. >>>>>> Creating a dictionary of arguments that will be used for >>>>>> option price and greeks calculation. >>>>>> ''' >>>>>> self.riskFreeRate = self.riskFreeRate/100 >>>>>> originalDict_ = {k: getattr(self, k) for k in self.keyList} >>>>>> ListDict = [] >>>>>> for i in range(4): >>>>>> ListDict.append(deepcopy(originalDict_)) >>>>>> ListDict[1]['riskFreeRate'] = self.riskFreeRate + self.dist >>>>>> ListDict[2]['volatility'] = self.volatility + self.dist >>>>>> ListDict[3]['expiryDate'] = (datetime.strptime( >>>>>> self.expiryDate, self.date_format) - >>>>>> timedelta(days=1)).strftime(self.date_format) >>>>>> print(ListDict) >>>>>> return(ListDict) >>>>>> >>>>>> def bs_process(self, create_process_for_iv=None, use_IV=None): >>>>>> """ >>>>>> Creating the Black-Scholes process for option valuation. >>>>>> """ >>>>>> riskFreeTS = ql.YieldTermStructureHandle( >>>>>> ql.FlatForward(self.value_date, self.riskFreeRate, >>>>>> ql.Actual365Fixed())) >>>>>> dividendTS = ql.YieldTermStructureHandle( >>>>>> ql.FlatForward(self.value_date, 0, ql.Actual365Fixed())) >>>>>> volatility = >>>>>> ql.BlackVolTermStructureHandle(ql.BlackConstantVol( >>>>>> self.value_date, ql.NullCalendar(), self.volatility, >>>>>> ql.Actual365Fixed())) >>>>>> initialValue = >>>>>> ql.QuoteHandle(ql.SimpleQuote(self.underlyingPrice)) >>>>>> process = ql.BlackScholesMertonProcess( >>>>>> initialValue, dividendTS, riskFreeTS, volatility) >>>>>> return(process) >>>>>> >>>>>> def evaluate(self, Option=None, compute_implied_vol=None): >>>>>> """ >>>>>> Call the relevant option based on the input. >>>>>> """ >>>>>> self.riskFreeRate = self.riskFreeRate/100 >>>>>> res = None >>>>>> option = AsianOptionPrice.asian(self) >>>>>> if compute_implied_vol == True: >>>>>> # create Black Scholes process using IV. >>>>>> process = AsianOptionPrice.bs_process( >>>>>> self, create_process_for_iv=False, use_IV=True) >>>>>> engine = ql.FdBlackScholesAsianEngine( >>>>>> process, tGrid=self.tGrid, xGrid=self.xGrid, >>>>>> aGrid=self.aGrid) >>>>>> option.setPricingEngine(engine) >>>>>> res = {'value': option.NPV(), 'impliedVolatility': >>>>>> self.IV} >>>>>> else: >>>>>> # Create Black Scholes process using HV. >>>>>> process = AsianOptionPrice.bs_process( >>>>>> self, create_process_for_iv=False, use_IV=False) >>>>>> engine = ql.FdBlackScholesAsianEngine( >>>>>> process, tGrid=self.tGrid, xGrid=self.xGrid, >>>>>> aGrid=self.aGrid) >>>>>> option.setPricingEngine(engine) >>>>>> res = {'value': option.NPV()} >>>>>> return res >>>>>> >>>>>> def evaluate_asian_npv(self): >>>>>> Option = AsianOptionPrice.asian(self) >>>>>> process = AsianOptionPrice.bs_process( >>>>>> self, create_process_for_iv=False, use_IV=False) >>>>>> engine = ql.FdBlackScholesAsianEngine( >>>>>> process, tGrid=self.tGrid, xGrid=self.xGrid, >>>>>> aGrid=self.aGrid) >>>>>> Option.setPricingEngine(engine) >>>>>> res = Option.NPV() >>>>>> return(res) >>>>>> >>>>>> def calculate_greeks(self, Option=None, compute_implied_vol=None): >>>>>> today = self.value_date >>>>>> Option = AsianOptionPrice.asian(self) >>>>>> if compute_implied_vol == True: >>>>>> process = AsianOptionPrice.bs_process( >>>>>> self, create_process_for_iv=False, use_IV=True) >>>>>> else: >>>>>> process = AsianOptionPrice.bs_process( >>>>>> self, create_process_for_iv=False, use_IV=False) >>>>>> engine = ql.FdBlackScholesAsianEngine( >>>>>> process, tGrid=self.tGrid, xGrid=self.xGrid, >>>>>> aGrid=self.aGrid) >>>>>> Option.setPricingEngine(engine) >>>>>> option_greeks_ = {"delta": Option.delta(), "gamma": >>>>>> Option.gamma( >>>>>> )} >>>>>> ArgmntList = AsianOptionPrice.create_arg_list( >>>>>> self, Option, compute_implied_vol=True, >>>>>> implied_vol_am_put=self.volatility) >>>>>> DisturbedPrices = [] >>>>>> arg_keys = ['Price', 'PRup', 'PVup', 'PTup'] >>>>>> for i in range(4): >>>>>> DisturbedPrices.append(eval( >>>>>> >>>>>> "AsianOptionPrice(**ArgmntList[i]).evaluate_asian_npv()")) >>>>>> print(DisturbedPrices) >>>>>> PricesDistrbd = dict(zip(arg_keys, DisturbedPrices)) >>>>>> Rho = (PricesDistrbd['PRup'] - >>>>>> PricesDistrbd['Price'])/(self.dist*100) >>>>>> vega = (PricesDistrbd['PVup'] - >>>>>> PricesDistrbd['Price'])/(self.dist*100) >>>>>> thetaDay = (PricesDistrbd['PTup'] - PricesDistrbd['Price']) >>>>>> option_greeks_.update({'rho': Rho, 'vega': vega, 'theta': >>>>>> thetaDay}) >>>>>> return option_greeks_ >>>>>> >>>>>> >>>>>> settings = { >>>>>> "computeHistoricalVolatiltiy": False, >>>>>> "tenantId": "380", >>>>>> "gridPoints": 149, >>>>>> "computeImpliedVolatiltiy": False, >>>>>> "runId": 3735, >>>>>> "timeSteps": 150, >>>>>> "optionTrades": [ >>>>>> { >>>>>> "underlyingPrice": 98.69, >>>>>> "refNo": "OPT-1135-GVA", >>>>>> "underlyingPriceUnit": "US cents/LB", >>>>>> "valueDate": "17-03-2022", >>>>>> "fixingStartDate":"01-05-2022", >>>>>> "pastFixings":0, >>>>>> "volatility": 0.6015, >>>>>> "openQuantity": 1, >>>>>> "strikePriceUnit": "US cents/LB", >>>>>> "optionType": "Call", >>>>>> "expiryDate": "31-05-2022", >>>>>> "exType": "asian", >>>>>> "riskFreeRate": 0.8080374999999999, >>>>>> "premium": 1, >>>>>> "portfolioId": 18209, >>>>>> "marketPremium": 11.42, >>>>>> "longShort": "Long", >>>>>> "optionInstrument": "EURO USD 1.105 Call", >>>>>> "asset": "EURO USD 1.105 Call", >>>>>> "portfolioName": "Option Trades", >>>>>> "scenarioId": 8356, >>>>>> "scenarioName": "Option Valuation - Greeks", >>>>>> "strikePrice": 95, >>>>>> "maturityInYears": 0.205479452 >>>>>> } >>>>>> ], >>>>>> "userId": "5263", >>>>>> "americanOptionsEngine": "CrankNicolson" >>>>>> } >>>>>> >>>>>> opt = AsianOptionPrice(**settings["optionTrades"][0]) >>>>>> opt.evaluate_asian_npv() >>>>>> >>>>>> On Wed, May 18, 2022 at 9:25 PM Ashish Bansal < >>>>>> ash...@gm...> wrote: >>>>>> >>>>>>> Hi Jack, >>>>>>> >>>>>>> Please find attached the Asian option python code and the option >>>>>>> trade payload. >>>>>>> >>>>>>> Thanks for your help, >>>>>>> Regards, >>>>>>> Ashish >>>>>>> >>>>>>> On Wed, 18 May 2022 at 12:12, Jack G <jac...@gm...> >>>>>>> wrote: >>>>>>> >>>>>>>> Hi Ashish, >>>>>>>> >>>>>>>> I've just lifted the examples from your references directly for a >>>>>>>> discrete arithmetic Asian using the FD Asian engine and it is working for >>>>>>>> me - can you share the code you are using that breaks please? >>>>>>>> >>>>>>>> Best, >>>>>>>> Jack >>>>>>>> >>>>>>>> On Wed, 18 May 2022, 13:55 Ashish Bansal, <ash...@gm...> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> Hi all, >>>>>>>>> >>>>>>>>> Could somebody help with the asian options? We are using >>>>>>>>> FdBlackScholesAsianengine with DiscreteAveragingAsianOption. Online >>>>>>>>> references are given below. In DiscreteAveragingAsianOption, we need to >>>>>>>>> pass the past fixing which is suggested to be 0 for new trade. Whereas when >>>>>>>>> we are passing it as 0, we are getting the following error: >>>>>>>>> "QuantLib Error - Running average requires at least one past >>>>>>>>> fixing" >>>>>>>>> ref: >>>>>>>>> >>>>>>>>> https://quantlib-python-docs.readthedocs.io/en/latest/pricing_engines.html#fdblackscholesasianengine >>>>>>>>> >>>>>>>>> >>>>>>>>> https://quantlib-python-docs.readthedocs.io/en/latest/instruments/options.html?highlight=DiscreteAveragingAsianOption#ql.DiscreteAveragingAsianOption >>>>>>>>> >>>>>>>>> Queries: >>>>>>>>> 1. What is to be passed here for new trade if not 0? >>>>>>>>> 2. For trade which is mid of averaging and has few past fixings, >>>>>>>>> do we need to pass the count of past fixing or the actual rates of the >>>>>>>>> pastfixing as an array? >>>>>>>>> >>>>>>>>> Any help will be appreciated. >>>>>>>>> >>>>>>>>> Thanks in advance >>>>>>>>> Ashish >>>>>>>>> _______________________________________________ >>>>>>>>> QuantLib-users mailing list >>>>>>>>> Qua...@li... >>>>>>>>> https://lists.sourceforge.net/lists/listinfo/quantlib-users >>>>>>>>> >>>>>>>> _______________________________________________ >>>>> QuantLib-users mailing list >>>>> Qua...@li... >>>>> https://lists.sourceforge.net/lists/listinfo/quantlib-users >>>>> >>>> |