Esempio n. 1
0
def find_opt_rates(args: EvalArgs, actual: np.ndarray) -> dict:
    best_rates = {"heston": 0, "vg": 0, "ls": 0}
    best_fun = {"heston": 1000, "vg": 1000, "ls": 1000}

    if args.is_call:
        postfix = "call"
    else:
        postfix = "put"

    metric = "RMR"
    step = .001
    upper = 1

    with open(f"params/opt_rate_{postfix}.txt", "a+") as f:
        try:
            last = f.readlines()[-1]
            last_rate = float(re.search(r"Rate: (.+?), ", last).group(1))
            start_from = int(last_rate / step)
        except IndexError or ValueError or AttributeError:
            start_from = 1

        for rate in [
                i * step for i in range(start_from,
                                        int(upper / step) + 1)
        ]:
            for model in ("heston", "vg", "ls"):
                args.r = rate
                args.q = rate
                res = tune_model(eval_args=args,
                                 bounds=par_bounds[model],
                                 model=model,
                                 local=False,
                                 metric=metric,
                                 prices=actual,
                                 polish=True,
                                 maxiter=50)

                if best_fun[model] > res.fun:
                    best_rates[model] = rate
                    best_fun[model] = res.fun
                msg = f"Rate: {rate}, model: {model}, metric: {metric}, pars: {array2str(res.x)}, " \
                      f"res.fun: {res.fun}, best: {best_rates[model]}"
                print(msg)
                f.write(msg + "\n")
                f.flush()
            f.write("\n")

        res = dict()
        vals = tuple(zip(best_rates, best_fun))
        for i in range(len(best_rates.keys())):
            res[list(best_rates.keys())[i]] = vals[i]

    return res
Esempio n. 2
0
def optimize_model(model: str, info: List[Info], data: Data, metric: str,
                   day: int, rate: float, local: bool, use_fft: bool,
                   **kwargs) -> opt.OptimizeResult:
    print(f"Optimizing {model} with {metric} on day {day}")

    actual_calls = data.prices[True][day]
    actual_puts = data.prices[False][day]
    pricer = GenPricer(model=model,
                       market=EvalArgs.from_structure(data=data,
                                                      info=info,
                                                      rate=rate,
                                                      day=day),
                       use_fft=use_fft)
    optimizer = opt.minimize if local else opt.differential_evolution

    t0 = time()
    result = pricer.optimize_pars(metric=metric,
                                  actual_calls=actual_calls,
                                  actual_puts=actual_puts,
                                  bounds=par_bounds[model],
                                  optimizer=optimizer,
                                  **kwargs)
    with open(hf.get_log_file_name(model=model, metric=metric), 'a+') as log:
        hf.log_print(
            f"Time spent for {model}, day {day}: {timedelta(seconds=(time() - t0))}\n",
            out1=log)

    return result
Esempio n. 3
0
def model_prices(pars: tuple,
                 args: EvalArgs,
                 model: str,
                 strict=False,
                 check=False,
                 bounds_only=True) -> np.ndarray:
    return optimization.models[model](pars=pars,
                                      args=args.as_tuple(),
                                      strict=strict,
                                      check=check,
                                      bounds_only=bounds_only)
Esempio n. 4
0
def estimate_model(pars: tuple, args: EvalArgs, model: str, metric: str, prices: np.ndarray) -> float:
    """

    :param pars: model parameters
    :param args: market parameters with strikes as args[1]
    :param model: pricing model
    :param metric: quality metric
    :param prices: actual prices

    :return: value of quality metric on passed parameters
    """

    k = args.get_strikes()

    if model not in models.keys():
        raise Exception("Cannot use model " + model)

    if metric not in metrics.keys():
        raise Exception("Cannot use metric " + metric)

    if (type(prices) is not np.ndarray) | (type(k) is not np.ndarray) | (len(prices) != len(k)):
        raise Exception("strikes and prices should be np.arrays with same length")

    return apply_metric(models[model](pars=pars, args=args.as_tuple()), prices, metric)
Esempio n. 5
0
def tuning():
    times = 5
    metric = 'RMSE'
    optimizer = differential_evolution
    actual_puts = np.ndarray([])

    spot = 1200
    t = .76
    r = .008
    q = r
    is_call = True

    logfile = open(f'{root_dir}/params/time_benchmark_{datetime.now()}.log', 'w')

    for n in [1, 10, 25, 50, 100, 200]:
        strikes = np.array([i * 50 + 500 for i in range(n)])
        args = (spot, strikes, t, r, q, is_call)
        market = EvalArgs.from_tuple((spot, strikes, t, r, q, is_call))
        call_prices = FFT(model='vg', args=args).price((0.838288226409, -0.188041460262, 0.179096605713))

        def bs_func():
            GenPricer(model='bs', market=market, use_fft=False) \
                .optimize_pars(metric=metric, optimizer=optimizer, bounds=par_bounds['bs'],
                               actual_puts=actual_puts, actual_calls=call_prices,
                               polish=True)

        t0 = time()
        unit = td_decorator(func=bs_func, times=times, seconds=True, log_each=True)()
        hf.log_print(f'BS unit time for {n} strike(s): {unit}, real time: {(time() - t0) / times}', logfile)
        for model in ['heston', 'vg', 'ls']:
            def func():
                GenPricer(model=model, market=market, use_fft=True) \
                    .optimize_pars(metric=metric, optimizer=optimizer, bounds=par_bounds[model],
                                   actual_puts=actual_puts, actual_calls=call_prices,
                                   polish=True, disp=True, maxiter=50)
            t0 = time()
            hf.log_print(f"{model}: {td_decorator(func=func, times=times, seconds=True, log_each=True)() / unit}"
                         f" units, real time: {time() - t0}", logfile)
        hf.log_print("\n", logfile)

    logfile.close()
Esempio n. 6
0
def cut_by_bs_delta(data: Data,
                    info: List[Info],
                    rate=0.008,
                    disp=False) -> Tuple[Data, List[Info]]:
    for day, is_call in [(d, c) for d in range(len(info))
                         for c in [True, False]]:
        pricer = gp.GenPricer(model='bs',
                              market=EvalArgs.from_structure(data=data,
                                                             info=info,
                                                             rate=rate,
                                                             day=day),
                              use_fft=False)

        result: opt.OptimizeResult = pricer.optimize_pars(
            metric='MAE',
            actual_calls=data.prices[True][day],
            actual_puts=data.prices[False][day],
            bounds=config.par_bounds['bs'],
            optimizer=opt.differential_evolution,
            polish=True,
            disp=disp)
        bs_sigma = result.x[0]
        bs_sigma = bs_sigma

        deltas = bs.bs_delta(spot=info[day].spot,
                             strikes=data.strikes[is_call][day],
                             r=rate,
                             q=rate,
                             t=info[day].mat,
                             bs_sigma=bs_sigma,
                             is_call=is_call)

        data.prices[is_call][day] = data.prices[is_call][day][
            np.abs(deltas) >= .1]
        data.strikes[is_call][day] = data.strikes[is_call][day][
            np.abs(deltas) >= .1]

    return data, info
Esempio n. 7
0
def main() -> None:

    # need to somehow work around with overflows
    np.seterr(all='warn')

    data, info = hf.read_new_data()

    print("Preparing data...")
    try:
        data = hf.get_prepared_data()
    except FileNotFoundError:
        data, info = dh.prepare_data(data=data, info=info)
    print("Done")

    day = 0
    metric = "RMSE"
    is_call = None
    market = EvalArgs(spot=info[day].spot,
                      k_call=data.strikes[True][day],
                      k_put=data.strikes[False][day],
                      tau=info[day].mat,
                      r=.008,
                      q=.008,
                      call=is_call)

    # models = ('heston', 'vg', 'ls', 'bs')
    # kwargs = [{
    #     'data': data,
    #     'rate': .008,
    #     'disp': False,
    #     'use_fft': True,
    #     'polish': True
    # }] * len(models)
    # all_args = zip(models, [metric] * len(models), [info] * len(models), [is_call] * len(models), kwargs)
    # pool = Pool()
    # pool.map(calibrate, all_args)

    tune_all_models(market=market, metric=metric)
Esempio n. 8
0
def test_r():

    # noinspection PyShadowingNames
    def prepare_args(a: List[str]) -> tuple:
        spot = float(a[0])
        strike = float(a[1])
        tau = float(a[2])
        r = float(a[3])
        q = float(a[4])
        is_call = True if a[5] == 'TRUE' else False
        return spot, strike, tau, r, q, is_call

    def params2tuple(params: tuple) -> tuple:
        return params + tuple(None for _ in range(5 - len(params)))

    cases = read_r_data()

    names = ['model', 'p1', 'p2', 'p3', 'p4', 'p5',
             'spot', 'strike', 't', 'r', 'q', 'is call',
             'R answer', 'Python answer', 'diff', 'rel diff', 'is correct']

    with open('sanity_log.txt', 'w') as log, open('sanity.csv', 'w') as out:
        out.write('; '.join(names) + "\n")

        for i, case in enumerate(cases):
            correct = True
            model = str(case[0])
            data = case[1:-1]
            answer = float(case[-1])
            if model.lower() == "heston":
                # func = he.price_heston
                pars = tuple(map(lambda x: float(x), data[:5]))
                args = prepare_args(data[5:])
            elif model.lower() == "vg":
                # func = vg.price_vg
                pars = tuple(map(lambda x: float(x), data[:3]))
                args = prepare_args(data[3:])
            elif model.lower() == "ls":
                # func = ls.price_ls
                pars = tuple(map(lambda x: float(x), data[:2]))
                args = prepare_args(data[2:])
            else:
                raise Exception(f"Can't recognise model {model}")
            market = EvalArgs.from_tuple(args)
            pricer = GenPricer(model=model.lower(), market=market, use_fft=True)
            # calculated = float(func(pars, args))
            calculated = pricer.price_call(pars) if market.is_call else pricer.price_put(pars)
            assert len(calculated) == 1
            diff = abs(answer - calculated)
            if diff > 1e-2 * answer and diff > 1e-3 and not (answer < 0 and calculated == 0):
                correct = False
                log.write(f"Sanity test failed with case: {', '.join(case)}\n"
                          f"\tR answer: {answer}\n"
                          f"\tPython answer: {calculated}\n"
                          f"\tDiff: {diff}\n\n")
                log.flush()

            p1, p2, p3, p4, p5 = params2tuple(params=pars)
            spot, strike, t, r, q, is_call = args
            row = f'{model};{p1};{p2};{p3};{p4};{p5};{spot};{strike};{t};{r};{q};' \
                  f'{is_call};{answer};{calculated};{diff};' \
                  f'{diff / answer if answer != 0 else "Inf"};{"+" if correct else "-"}\n'
            out.write(row)
            out.flush()

            if i % 1000 == 0:
                print(f"{i / len(cases):.{3}}")