Heston校准quantlib python中的最大曲线时间误差

2024-09-28 01:23:46 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在运行从源代码编译的SWIG python 1.16版QuantLib。

我一直在尝试按照this example校准赫斯顿模型。 我目前只使用QL校准来测试它,然后再尝试其他校准。 我需要依赖于时间的参数,所以我使用PiecewiseTimeDependentHestonModel。你知道吗

这是我代码的相关部分。你知道吗

助手函数:

def tenor2date(s, base_date=None,ql=False):
    # returns a date from a tenor and a base date
    if base_date is None:
        base_date = datetime.today()
    num = float(s[:-1])
    period = s[-1].upper()
    if period == "Y":
        return_date = base_date + relativedelta(years=num)
    elif period == "M":
        return_date = base_date + relativedelta(months=num)
    elif period == "W":
        return_date = base_date + relativedelta(weeks=num)
    elif period == "D":
        return_date = base_date + relativedelta(days=num)
    else:
        return_date = base_date
    if ql:
        return Date(return_date.strftime("%F"),"yyyy-mm-dd")
    else:
        return return_date

def setup_model(yield_ts, dividend_ts, spot, times,init_condition=(0.02, 0.2, 0.5, 0.1, 0.01)):
    theta, kappa, sigma, rho, v0 = init_condition

    model = ql.PiecewiseTimeDependentHestonModel(yield_ts, dividend_ts, ql.QuoteHandle(ql.SimpleQuote(spot)), v0, ql.Parameter(), ql.Parameter(),
                                                   ql.Parameter(), ql.Parameter(), ql.TimeGrid(times))
    engine = ql.AnalyticPTDHestonEngine(model)
    return model, engine

def setup_helpers(engine, vol_surface, ref_date, spot, yield_ts, dividend_ts):
    heston_helpers = []
    grid_data = []
    for tenor in vol_surface:
        expiry_date = tenor2date(tenor, datetime(ref_date.year(), ref_date.month(), ref_date.dayOfMonth()), True)
        t = (expiry_date - ref_date)
        print(f"{tenor} : {t / 365}")
        p = ql.Period(t, ql.Days)
        for strike, vol in zip(vol_surface[tenor]["strikes"], vol_surface[tenor]["volatilities"]):
            print((strike, vol))
            helper = ql.HestonModelHelper(p, calendar, spot, strike, ql.QuoteHandle(ql.SimpleQuote(vol / 100)), yield_ts, dividend_ts)
            helper.setPricingEngine(engine)
            heston_helpers.append(helper)
            grid_data.append((expiry_date, strike))
    return heston_helpers, grid_data

市场数据:

vol_surface = {'12M': {'strikes': [1.0030154025220293, 0.9840808634190958, 0.9589657270688433, 0.9408279805370683, 0.9174122318462831, 0.8963792435025802, 0.8787138822765832, 0.8538712672800733, 0.8355036501980958], 'volatilities': [6.7175, 6.5, 6.24375, 6.145, 6.195, 6.425, 6.72125, 7.21, 7.5625], 'forward': 0.919323}, '1M': {'strikes': [0.9369864196692815, 0.9324482223892986, 0.9261255003380027, 0.9213195223581382, 0.9150244003650484, 0.9088253068972495, 0.9038936313900919, 0.897245676067657, 0.8924388848562849], 'volatilities': [6.3475, 6.23375, 6.1075, 6.06, 6.09, 6.215, 6.3725, 6.63125, 6.8225], 'forward': 0.915169}, '1W': {'strikes': [0.9258809998009043, 0.9236526412979602, 0.920487656155217, 0.9180490618315417, 0.9148370595017086, 0.9116231311263782, 0.9090950947170667, 0.9057357691404444, 0.9033397443834199], 'volatilities': [6.7175, 6.63375, 6.53625, 6.5025, 6.53, 6.6425, 6.77875, 6.99625, 7.1525], 'forward': 0.914875}, '2M': {'strikes': [0.9456173410343232, 0.9392447942175677, 0.9304717860942596, 0.9238709412876663, 0.9152350197527926, 0.9068086964842931, 0.9000335970840222, 0.8908167643473346, 0.884110721680849], 'volatilities': [6.1575, 6.02625, 5.8825, 5.8325, 5.87, 6.0175, 6.1975, 6.48875, 6.7025], 'forward': 0.915506}, '3M': {'strikes': [0.9533543407827232, 0.945357456067501, 0.9343646071178692, 0.9261489737826977, 0.9154251386183144, 0.9050707394248945, 0.8966770979707913, 0.8851907303568785, 0.876803402158318], 'volatilities': [6.23, 6.09125, 5.93, 5.8725, 5.915, 6.0775, 6.28, 6.60375, 6.84], 'forward': 0.915841}, '4M': {'strikes': [0.9603950279333742, 0.9509237742916833, 0.9379657828957041, 0.928295643018581, 0.9156834006905108, 0.9036539552069216, 0.8938804229269658, 0.8804999196762403, 0.870730837142799], 'volatilities': [6.3175, 6.17125, 6.005, 5.94375, 5.985, 6.15125, 6.36, 6.69375, 6.9375], 'forward': 0.916255}, '6M': {'strikes': [0.9719887962018352, 0.9599837798239937, 0.943700651576822, 0.9316544554849711, 0.9159768970939797, 0.9013018796367052, 0.8892904835162911, 0.8727031923006017, 0.8605425787295339], 'volatilities': [6.3925, 6.22875, 6.04125, 5.9725, 6.01, 6.1875, 6.41375, 6.78625, 7.0575], 'forward': 0.916851}, '9M': {'strikes': [0.9879332225745909, 0.9724112749400833, 0.951642771321364, 0.936450663789222, 0.9167103888580063, 0.8985852649047051, 0.8835274087791912, 0.8625837214139542, 0.8472311260811375], 'volatilities': [6.54, 6.34875, 6.1325, 6.055, 6.11, 6.32, 6.5875, 7.01625, 7.32], 'forward': 0.918086}}
spotDates = [ql.Date(1,7,2019), ql.Date(8,7,2019), ql.Date(1,8,2019), ql.Date(1,9,2019), ql.Date(1,10,2019), ql.Date(1,11,2019), ql.Date(1,1,2020), ql.Date(1,4,2020), ql.Date(1,7,2020)]
spotRates = [0.9148, 0.914875, 0.915169, 0.915506, 0.915841, 0.916255, 0.916851, 0.918086, 0.919323]
udl_value = 0.9148
todaysDate = ql.Date("2019-07-01","yyyy-mm-dd")
settlementDate = ql.Date("2019-07-03","yyyy-mm-dd")

以及剧本本身:

ql.Settings.instance().evaluationDate = todaysDate

dayCounter = ql.Actual365Fixed()
interpolation = ql.Linear()
compounding = ql.Compounded
compoundingFrequency = ql.Annual
times = [(x - spotDates[0]) / 365 for x in spotDates][1:]
discountFactors = [-log(x / spotRates[0]) / (times[i]) for i, x in enumerate(spotRates[1:])]
fwdCurve = ql.ZeroCurve(spotDates, [0] + discountFactors, dayCounter, calendar, interpolation, compounding, compoundingFrequency)
fwdCurveHandle = ql.YieldTermStructureHandle(fwdCurve)

dividendCurveHandle = ql.YieldTermStructureHandle(ql.FlatForward(settlementDate, 0, dayCounter))

hestonModel, hestonEngine = setup_model(fwdCurveHandle, dividendCurveHandle, udl_value, times)
heston_helpers, grid_data = setup_helpers(hestonEngine, vol_surface, todaysDate, udl_value, fwdCurveHandle, dividendCurveHandle)
lm = ql.LevenbergMarquardt(1e-8, 1e-8, 1e-8)
hestonModel.calibrate(heston_helpers, lm, ql.EndCriteria(500, 300, 1.0e-8, 1.0e-8, 1.0e-8))

当我运行最后一行时,得到以下错误消息:

RuntimeError: time (1.42466) is past max curve time (1.00274)

我不明白它怎么能试图定价超过1Y的东西,因为helpers和forwards曲线都是在同一组日期上定义的。你知道吗


Tags: basedatereturnsurfacenumhelpersperiodforward
1条回答
网友
1楼 · 发布于 2024-09-28 01:23:46

如果对某人有帮助,请将我从quantlb邮件中得到的答案张贴在这里:

指定到期日(天)

    t = (expiry_date - ref_date)
    print(f"{tenor} : {t / 365}")
    p = ql.Period(t, ql.Days)

当使用指定的日历时,可能会产生违反直觉的效果 计算实际有效期。如果日历是。ql.美国 然后考虑到周末和假期

ql.UnitedStates().advance(ql.Date(1,1,2019),ql.Period(365, ql.Days))=>;Date(12,6,2020)

鉴于 ql.NullCalendar().advance(ql.Date(1,1,2019),ql.Period(365, ql.Days))=>;Date(1,1,2020)

因此,我猜利率曲线不够长,因此 错误消息。你知道吗

因此,解决方法是确保使用ql.NullCalendar()accross。你知道吗

相关问题 更多 >

    热门问题