예제 #1
0
    double EuropeanOptionBlack76::getRhoNumeric(double absoluteChangeInNominalInterestRate)
    {
        double df = discountFactor;
        double df1 = exp((log(discountFactor) / yearsToSettlement - absoluteChangeInNominalInterestRate) * yearsToSettlement);

        setDiscountFactor(df1);
        double price1 = getPremium();
        setDiscountFactor(df);
        double price = getPremium();
        return price1 - price;
    }
예제 #2
0
    BlackScholesGreeks EuropeanOptionBlack76::getOptionPriceAndGreeksNumeric(double dF, double dV, double dY, double dR) 
    {
        double F = forward;
        double sd = standardDeviation;
        double df = discountFactor;
        double yte = yearsToExpiry;
        double yts = yearsToSettlement;
        double X = strike;
        double sqrtdt = sqrt(yte);

        double price = getPremium();
        // Delta
        setForward(F + dF);
        double deltaPremium = getPremium();
        double delta = deltaPremium - price;
        // Gamma
        setForward(F - dF);
        double gammaPremium = getPremium();
        double gamma = (deltaPremium - 2 * price + gammaPremium);        
        setForward(F);
        // Vega
        double originalVol = sd / sqrtdt;
        double sd1 = (originalVol + dV) * sqrtdt;
        setStandardDeviation(sd1);
        double priceVega = getPremium();
        double vega = priceVega - price;
        // setStandardDeviation(sd1); will do a setParamters in Theta
        // Theta
        sd1 = (sd / sqrt(yte)) * sqrt(yte - dY);
        double df1 = exp(log(df) / yts * (yts - dY));
        setParameters(F, X, yte - dY, yts - dY, sd1, df1);
        double priceTheta = getPremium();
        double theta = priceTheta - price;
        setParameters(F, X, yte, yts, sd, df);
        // Rho
        df1 = exp((log(df) / yts - dR) * yts);
        setDiscountFactor(df1);
        double priceRho = getPremium();
        double rho = priceRho - price;
        setParameters(F, X, yte, yts, sd, df);
        return BlackScholesGreeks(price, delta, gamma, theta, vega, rho);
    }
RQ_EXPORT rq_yield_curve_t
rq_bootstrap_yield_curve_simple(
    const char *curve_id,
    const rq_system_t system,
    const rq_market_t market,
    double *rate_adjust_factors,
    rq_date last_date_to_bootstrap
    )
{
    unsigned int i;
    rq_date date = rq_market_get_market_date(market);
    const rq_rate_mgr_t rate_mgr = rq_market_get_rate_mgr(market);
    const rq_asset_mgr_t asset_mgr = rq_system_get_asset_mgr(system); 
    rq_calendar_t cal;
    const rq_bootstrap_config_t config = rq_bootstrap_config_mgr_find(rq_system_get_bootstrap_config_mgr(system), curve_id, RQ_TERMSTRUCT_TYPE_YIELD_CURVE); 

    rq_date last_date_bootstrapped = 0;
    double last_swap_rate = 0.0;
    rq_date last_swap_date = 0;
    double last_swap_period = 0.0;
    rq_calendar_t cals[2];
    unsigned short num_cals = 0;
    const char *underlying_asset_id = NULL;
	double r=0;
	rq_asset_t lastFutureAsset = NULL;
	rq_rate_t lastFutureRate = NULL;
    double lastFutureDF = 0;

#ifdef DEBUG_BOOTSTRAP
#ifdef DEBUG_BOOTSTRAP_FH
    FILE *fh = fopen(debugFile, "a");
#else
	FILE *fh = stdout;
#endif
#endif

    /* 
       Add one to the number of discount factors because we are
       going to create a discount factor of 1.0  at the zero days
       point 
    */
    /* int max_factors = (config->num_rate_class_ids + 1) * 2; */

    rq_yield_curve_t ts;

    if (!config)
        return NULL;

    //first try curve calendar
    cal = rq_calendar_mgr_get(rq_system_get_calendar_mgr(system), curve_id);
    if (cal)
    {
        cals[num_cals++] = cal;
    }
    else
    {
        //no curve calendar, so try curve asset
        cal = rq_calendar_mgr_get(rq_system_get_calendar_mgr(system), rq_bootstrap_config_get_asset_id(config));
        if (cal)
            cals[num_cals++] = cal;
    }

    ts = rq_yield_curve_init(
        rq_bootstrap_config_get_curve_id(config),
//        config,
		rq_bootstrap_config_get_interpolation_method(config),
		rq_bootstrap_config_get_extrapolation_method_start(config),
		rq_bootstrap_config_get_extrapolation_method_end(config),
		rq_bootstrap_config_get_zero_method(config),
		rq_bootstrap_config_get_zero_method_compound_frequency(config),
		rq_bootstrap_config_get_default_day_count_convention(config),
        date
        );

    underlying_asset_id = rq_bootstrap_config_get_asset_id(config);
    if (underlying_asset_id)
    {
        rq_asset_t a = rq_asset_mgr_get(asset_mgr, underlying_asset_id);

        rq_yield_curve_set_underlying_asset_id(ts, underlying_asset_id);

        /* Set the default day count convention to be ACT/360 if the 
           underlying currency has a 360 day basis.
        */
        if (a && !strcmp(rq_asset_get_asset_type_id(a), rq_asset_type_id_ccy))
        {
            if (rq_asset_ccy_get_days_per_year(a) == 360)
                rq_yield_curve_set_default_day_count_convention(
                    ts,
                    RQ_DAY_COUNT_ACTUAL_360
                    );
        }
    }

#ifdef DEBUG_BOOTSTRAP
    fprintf(fh, "Building %s %s yield curve simple\n", curve_id, rq_bootstrap_config_get_asset_id(config));
	fflush(fh);
#endif

	// need to sort the rate classes by tenor, to ensure points are bootstrapped in correct order

    for (i = 0; i < rq_bootstrap_config_get_num_rate_class_ids(config); i++)
    {
        const rq_rate_t rate = rq_rate_mgr_find(
            rate_mgr, 
            rq_bootstrap_config_get_rate_class_id_at(config, i)
            );
        if (rate)
        {
            /* find the asset */
			const char *asset_id = rq_rate_get_asset_id(rate);
            const rq_asset_t asset = rq_asset_mgr_get(
                asset_mgr, 
                asset_id
                );

            /* Note these are not actually applied !! */
            if (rate_adjust_factors && rate_adjust_factors[i] != 0.0)
                r *= rate_adjust_factors[i];

            if (asset)
            {
#ifdef DEBUG_BOOTSTRAP
                    {
                        short d1, m1, y1;
                        short d2, m2, y2;
                        rq_date_to_dmy(rq_rate_get_observation_date(rate), &d1, &m1, &y1);
                        rq_date_to_dmy(rq_rate_get_value_date(rate), &d2, &m2, &y2);
						fprintf(fh, "\tBootstrap: %i\trate_class_id=%s \tasset=%s \trate=%f \tobs_date=%d/%d/%d \tvalue_date=%d/%d/%d\n", i, rq_rate_get_rate_class_id(rate), asset_id, rq_rate_get_value(rate), d1, m1, y1, d2, m2, y2);
						fflush(fh);
                    }
#endif
                if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_ccy))
                {
                    double df = bootstrapAssetCcy(asset, rate, &last_date_bootstrapped);
                    setDiscountFactor(ts, last_date_bootstrapped, df);
#ifdef DEBUG_BOOTSTRAP
{
    char buf[40];
    fprintf(fh, " %g %s ", df, rq_date_to_string(buf, "dd/mm/yy", last_date_bootstrapped));
}
#endif
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irovernight))
                {
                    double df = bootstrapAssetIROvernight(asset, rate, &last_date_bootstrapped);
                    setDiscountFactor(ts, last_date_bootstrapped, df);
#ifdef DEBUG_BOOTSTRAP
{
    char buf[40];
    fprintf(fh, " %g %s ", df, rq_date_to_string(buf, "dd/mm/yy", last_date_bootstrapped));
}
#endif
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irdiscount))
                {
                    double df = bootstrapAssetIRDiscount(asset, rate, &last_date_bootstrapped, cals, num_cals, ts);
                    setDiscountFactor(ts, last_date_bootstrapped, df);
#ifdef DEBUG_BOOTSTRAP
{
    char buf[40];
    fprintf(fh, " %g %s ", df, rq_date_to_string(buf, "dd/mm/yy", last_date_bootstrapped));
}
#endif
				}
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irfuture))
                {
                    double df;
                    switch(config->billFuture_method)
                    {
                    case RQ_BILL_FUTURE_TENOR:
                        df = bootstrapAssetIRFutureTenor(asset, rate, &last_date_bootstrapped, ts, cals, num_cals);
                        break;
                    case RQ_BILL_FUTURE_STRIP:
                    default:
                        df = bootstrapAssetIRFutureStrip(asset, rate, &last_date_bootstrapped, ts, cals, num_cals, lastFutureRate, lastFutureAsset, lastFutureDF);
                        lastFutureDF = df;
                        break;
                    }
                    setDiscountFactor(ts, last_date_bootstrapped, df);
                    lastFutureAsset = asset;
                    lastFutureRate = rate;
#ifdef DEBUG_BOOTSTRAP
{
    char buf[40];
    fprintf(fh, " %g %s ", df, rq_date_to_string(buf, "dd/mm/yy", last_date_bootstrapped));
}
#endif
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irswap))
                {
					processSwapsDCF(asset, rate, &last_date_bootstrapped, ts, cals, num_cals, rq_system_get_calendar_mgr(system), &last_swap_date, &last_swap_rate, &last_swap_period, RQ_SWAP_DAY_COUNT_SIMPLE, rq_bootstrap_config_get_swapParInterpolation_method(config), 0, 0, 0);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irbond))
                {
					bootstrapAssetIRBond(asset, rate, &last_date_bootstrapped, ts, cals, num_cals);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_credit_spread))
                {
					double df = bootstrapAssetCreditSpread(asset, rate, &last_date_bootstrapped);
                    rq_yield_curve_set_discount_factor(ts, last_date_bootstrapped, df);
#ifdef DEBUG_BOOTSTRAP
{
    char buf[40];
    fprintf(fh, " %g %s ", df, rq_date_to_string(buf, "dd/mm/yy", last_date_bootstrapped));
}
#endif
                }

				if (last_date_to_bootstrap > 0 && last_date_bootstrapped > last_date_to_bootstrap)
                    break; /* break out of for loop, we've bootstrapped enough */
            }
            else
            {
                /* printf("Couldn't find asset\n"); */
            }
		}
        else
        {
            /* printf("Couldn't find rate\n"); */
        }
    }

#ifdef DEBUG_BOOTSTRAP
/*	dumpYieldCurve(system, ts); */
	fprintf(fh, "\n\n");
#ifdef DEBUG_BOOTSTRAP_FH
    fclose(fh);
#endif
#endif

    if (rq_yield_curve_size(ts))
        return ts;

    rq_yield_curve_free(ts);
    return NULL;
}
RQ_EXPORT rq_yield_curve_t
rq_bootstrap_yield_curve_day_count(
    const char *curve_id,
    const rq_system_t system,
    const rq_market_t market,
    double *rate_adjust_factors,
    rq_date last_date_to_bootstrap,
    int force_backward_compatible_daycount,
	const char *debug_filename
    )
{
    unsigned int i;
    rq_date date = rq_market_get_market_date(market);
    const rq_rate_mgr_t rate_mgr = rq_market_get_rate_mgr(market);
    const rq_asset_mgr_t asset_mgr = rq_system_get_asset_mgr(system); 
    rq_calendar_t cal;
    const rq_bootstrap_config_t config = rq_bootstrap_config_mgr_find(rq_system_get_bootstrap_config_mgr(system), curve_id, RQ_TERMSTRUCT_TYPE_YIELD_CURVE); 

    rq_date last_date_bootstrapped = 0;
    double last_swap_rate = 0.0;
    rq_date last_swap_date = 0;
    double last_year_count_frac = 0.0;
    rq_calendar_t cals[2];
    unsigned short num_cals = 0;	
    const char *underlying_asset_id = NULL;
	double r=0;
	rq_asset_t lastAsset = NULL;
	rq_rate_t lastRate = NULL;
	rq_asset_t lastFutureAsset = NULL;
	rq_rate_t lastFutureRate = NULL;
	double lastDF = 0.0;
	double lastFutureDF = 0.0;
    rq_asset_t splineSwapAssets[RQ_MAX_SWAP_RATES];
    rq_rate_t splineSwapRates[RQ_MAX_SWAP_RATES];
    int numSplineSwaps = 0;
    enum rq_swapDayCount_method swapDayCount_method;
	enum rq_swapParInterpolation_method parInterp_method;

#ifdef DEBUG_BOOTSTRAP
#ifdef DEBUG_BOOTSTRAP_FH
    FILE *fh = fopen(debugFile, "a");
#else
	FILE *fh = stdout;
#endif
#endif
    rq_yield_curve_t ts;

    if (!config)
        return NULL;

    if(force_backward_compatible_daycount)
        swapDayCount_method = RQ_SWAP_DAY_COUNT_DAYCOUNT;
    else
        swapDayCount_method = rq_bootstrap_config_get_swapDayCount_method(config);

	parInterp_method = rq_bootstrap_config_get_swapParInterpolation_method(config);

    //first try curve calendar
    cal = rq_calendar_mgr_get(rq_system_get_calendar_mgr(system), curve_id);
    if (cal)
    {
        cals[num_cals++] = cal;
    }
    else
    {
        //no curve calendar, so try curve asset
        cal = rq_calendar_mgr_get(rq_system_get_calendar_mgr(system), rq_bootstrap_config_get_asset_id(config));
        if (cal)
            cals[num_cals++] = cal;
    }

    ts = rq_yield_curve_init(
        rq_bootstrap_config_get_curve_id(config),
		rq_bootstrap_config_get_interpolation_method(config),
		rq_bootstrap_config_get_extrapolation_method_start(config),
		rq_bootstrap_config_get_extrapolation_method_end(config),
		rq_bootstrap_config_get_zero_method(config),
		rq_bootstrap_config_get_zero_method_compound_frequency(config),
		rq_bootstrap_config_get_default_day_count_convention(config),
        date
        );
	rq_yield_curve_set_debug_filename(ts, debug_filename);

    underlying_asset_id = rq_bootstrap_config_get_asset_id(config);
    if (underlying_asset_id)
    {
        rq_asset_t a = rq_asset_mgr_get(asset_mgr, underlying_asset_id);

        rq_yield_curve_set_underlying_asset_id(ts, underlying_asset_id);

        /* Set the default day count convention to be ACT/360 if the 
           underlying currency has a 360 day basis.
        */
        if (a && !strcmp(rq_asset_get_asset_type_id(a), rq_asset_type_id_ccy))
        {
            if (rq_asset_ccy_get_days_per_year(a) == 360)
                rq_yield_curve_set_default_day_count_convention(
                    ts,
                    RQ_DAY_COUNT_ACTUAL_360
                    );
        }
    }

#ifdef DEBUG_BOOTSTRAP
    fprintf(fh, "Building %s curve\n", rq_bootstrap_config_get_asset_id(config));
	fflush(fh);
#endif

    // need to sort the rate classes by tenor, to ensure points are bootstrapped in correct order
    for (i = 0; i < rq_bootstrap_config_get_num_rate_class_ids(config); i++)
    {
        const rq_rate_t rate = rq_rate_mgr_find(
            rate_mgr, 
            rq_bootstrap_config_get_rate_class_id_at(config, i)
            );
        if (rate)
        {
            // find the asset
			const char *asset_id = rq_rate_get_asset_id(rate);
            const rq_asset_t asset = rq_asset_mgr_get(
                asset_mgr, 
                asset_id
                );

            if (rate_adjust_factors && rate_adjust_factors[i] != 0.0)
                r *= rate_adjust_factors[i];

            if (asset)
            {
#ifdef DEBUG_BOOTSTRAP
                    {
                        short d1, m1, y1;
                        short d2, m2, y2;
                        rq_date_to_dmy(rq_rate_get_observation_date(rate), &d1, &m1, &y1);
                        rq_date_to_dmy(rq_rate_get_value_date(rate), &d2, &m2, &y2);
						fprintf(fh, "\tBootstrap: \tasset=%s \trate=%f \tto_date=%d/%d/%d \tfrom_date=%d/%d/%d\n", asset_id, r, d1, m1, y1, d2, m2, y2);
						fflush(fh);
                    }
#endif
                if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_ccy))
                {
                    double df = bootstrapAssetCcy(asset, rate, &last_date_bootstrapped);
                    setDiscountFactor(ts, last_date_bootstrapped, df);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irovernight))
                {
                    double df = bootstrapAssetIROvernight(asset, rate, &last_date_bootstrapped);
                    setDiscountFactor(ts, last_date_bootstrapped, df);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irdiscount))
                {
                    double df = 0.0;
                    if (rq_rate_get_rate_type(rate) == RQ_RATE_TYPE_PAR)
                        df = bootstrapParDCF(asset, rate, &last_date_bootstrapped, ts, cals, num_cals, lastRate, lastAsset, lastDF);
                    else
                        df = bootstrapAssetIRDiscount(asset, rate, &last_date_bootstrapped, cals, num_cals, ts);
                    lastDF = df;
                    setDiscountFactor(ts, last_date_bootstrapped, df);
				}
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irfuture))
                {
                    double df;
                    switch(config->billFuture_method)
                    {
                    case RQ_BILL_FUTURE_TENOR:
                        df = bootstrapAssetIRFutureTenor(asset, rate, &last_date_bootstrapped, ts, cals, num_cals);
                        break;
                    case RQ_BILL_FUTURE_STRIP:
                    default:
                        df = bootstrapAssetIRFutureStrip(asset, rate, &last_date_bootstrapped, ts, cals, num_cals, lastFutureRate, lastFutureAsset, lastFutureDF);
                        break;
                    }
					lastDF = df;
					lastFutureDF = df;
                    lastFutureAsset = asset;
                    lastFutureRate = rate;
                    setDiscountFactor(ts, last_date_bootstrapped, df);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irswap))
                {

					// If using spline interpolation of swap par rates then we need to know all swaps before we can do any.
                    switch(parInterp_method)
                    {
					case RQ_SWAP_PAR_INTERPOLATION_CUBIC_SPLINE :
					case RQ_SWAP_PAR_INTERPOLATION_CUBIC_SPLINE_SWAPS_ONLY :
                        if(numSplineSwaps < RQ_MAX_SWAP_RATES)
                        {
                            splineSwapAssets[numSplineSwaps] = asset;
                            splineSwapRates[numSplineSwaps] = rate;
                            numSplineSwaps++;
                        }
						break;
					case RQ_SWAP_PAR_INTERPOLATION_LINEAR:
					default :
                        processSwapsDCF(asset,
                                    rate,
                                    &last_date_bootstrapped,
                                    ts,
                                    cals,
                                    num_cals,
									rq_system_get_calendar_mgr(system),
                                    &last_swap_date,
                                    &last_swap_rate,
                                    &last_year_count_frac,
                                    swapDayCount_method,
									parInterp_method,
									0,0,0);
						break;
					}
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_irbond))
                {
					bootstrapAssetIRBond(asset, rate, &last_date_bootstrapped, ts, cals, num_cals);
                }
                else if (!strcmp(rq_asset_get_asset_type_id(asset), rq_asset_type_id_credit_spread))
                {
					double df = bootstrapAssetCreditSpread(asset, rate, &last_date_bootstrapped);
                    rq_yield_curve_set_discount_factor(ts, last_date_bootstrapped, df);
                }
				lastAsset = asset;

				if (last_date_to_bootstrap > 0 && last_date_bootstrapped > last_date_to_bootstrap)
                    break; // enough bootstrapping, now get out of here, you bootstrapping cowboy.
			}
            else
            {
                // printf("Couldn't find asset\n");
            }
			lastRate = rate;
		}
        else
        {
            // printf("Couldn't find rate\n");
        }
    }
	for(i = 0; i < (unsigned int)numSplineSwaps; i++)
	{
        processSwapsDCF(splineSwapAssets[i],
                        splineSwapRates[i],
                        &last_date_bootstrapped,
                        ts,
                        cals,
                        num_cals,
                        rq_system_get_calendar_mgr(system),
                        &last_swap_date,
                        &last_swap_rate,
                        &last_year_count_frac,
                        swapDayCount_method,
						parInterp_method,
                        splineSwapAssets,
                        splineSwapRates,
                        numSplineSwaps);
		lastRate = splineSwapRates[i];
		lastAsset = splineSwapAssets[i];
	}

#ifdef DEBUG_BOOTSTRAP
	dumpYieldCurveSpline(system, ts);
	fprintf(fh, "\n\n");
#ifdef DEBUG_BOOTSTRAP_FH
    fclose(fh);
#endif
#endif

    if (rq_yield_curve_size(ts))
        return ts;

    rq_yield_curve_free(ts);
    return NULL;
}
void
processSwapsDCF(const rq_asset_t asset,
                const rq_rate_t rate,
                rq_date* last_date_bootstrapped,
                rq_yield_curve_t ts,
                const rq_calendar_t* base_cals,
                unsigned short base_num_cals,
				rq_calendar_mgr_t calendar_mgr,
                rq_date* last_swap_date,
                double* last_swap_rate,
                double* last_year_count_frac,
                enum rq_swapDayCount_method swapDayCount_method,
				enum rq_swapParInterpolation_method parInterpolation_method,
				const rq_asset_t *splineSwapAssets,
				const rq_rate_t *splineSwapRates,
				int numSwaps)
{
    /*
      Work out dates that the payments fall on for the swap.
      Calculate discount factors for all the dates except 
      the last date.
    */
    rq_date dates[RQ_YIELD_CURVE_MAX_FACTORS];
    double splineX[RQ_MAX_SPLINE_POINTS];
    double splineY[RQ_MAX_SPLINE_POINTS];
    double splineY2[RQ_MAX_SPLINE_POINTS];
    int splineNum;
	int num_cals;
	rq_calendar_t cals[3];
    int simple_daycount = swapDayCount_method == RQ_SWAP_DAY_COUNT_SIMPLE;
    FILE *debug_fp = 0;
	int no_interpolation;

    double r = rq_rate_get_value(rate);
    double df;

    rq_date start_date = ts->from_date; /* rq_rate_get_observation_date(rate); */
    double dfStart = 1.0;
    int num_dates;
    unsigned short num_discount_factors;
    double last_df = 1.0;
    unsigned short j;
    rq_date last_date_on_curve = rq_yield_curve_get_last_date(ts);
    double swap_period = rq_term_get_annualized_period(rq_asset_irswap_get_frequency(asset));
    double year_count_frac = swap_period;
    enum rq_day_count_convention day_count = rq_asset_irswap_get_day_count_convention(asset);
    double sum_dfs = 0.0;
    double x, x1, x2;
    rq_date lastDateStrapped;
	num_cals = base_num_cals;
	for(j=0; j < num_cals; j++)
		cals[j] = base_cals[j];
	if(rq_asset_irswap_get_additional_calendar(asset))
	{
		cals[num_cals] = rq_calendar_mgr_get(calendar_mgr, rq_asset_irswap_get_additional_calendar(asset));
		if(cals[num_cals])
			num_cals++;
	}

    start_date = rq_date_roll_offset_term(start_date,
                                          rq_asset_irswap_get_start_tenor_type(asset),
                                          rq_asset_irswap_get_start_tenor(asset),
                                          cals,
                                          num_cals,
                                          rq_asset_irswap_get_date_roll_convention(asset));

    if (start_date > ts->from_date)
        dfStart = rq_yield_curve_get_discount_factor(ts, start_date);

    lastDateStrapped = rq_date_roll_get_date(
        start_date,
        rq_asset_irswap_get_tenor(asset),
        RQ_ROLL_CONVENTION_NONE,
        rq_asset_irswap_get_date_roll_convention(asset),
        cals,
        num_cals
        );

    num_dates = rq_date_roll_generate_dates(
        dates,
        RQ_YIELD_CURVE_MAX_FACTORS,
        start_date,
        lastDateStrapped,
        rq_asset_irswap_get_frequency(asset),
        RQ_ROLL_CONVENTION_NONE,
        rq_asset_irswap_get_date_roll_convention(asset),
        cals,
        num_cals,
        RQ_DATE_ROLL_STUB_POSITION_NONE,
        15, /* allow 15 days error on date creation */
		NULL
        );

    /* ignore the first date */
    num_discount_factors = (unsigned short)(num_dates - 2);
    if(ts->debug_filename)
        debug_fp = fopen(ts->debug_filename, "a");

	if(debug_fp)
	{
		char buf[64];
		time_t ltime;
		time( &ltime );
		ctime_s(buf, 64, &ltime);
		fprintf(debug_fp, "%s : START bootstrapSwapAsset() ", buf);
		fprintf(debug_fp, "curve_id: %s asset_id: %s date: %s\n", rq_yield_curve_get_curve_id(ts), 
			rq_asset_get_asset_id(asset), rq_date_to_string(buf, "yyyymmdd", lastDateStrapped));
	}

    // If swap par rate interpolation method is cubic spline then setup spline points
    if(splineSwapRates)
    {
        splineNum = rq_generate_swap_splines(parInterpolation_method, dates, ts, splineSwapAssets, splineSwapRates, numSwaps,
			num_discount_factors, last_date_on_curve, start_date, dfStart, simple_daycount, 
			splineX, splineY, splineY2, swap_period, day_count, base_cals, base_num_cals, calendar_mgr);
        if(debug_fp)
        {
			fprintf(debug_fp, "Spline interpolation array X Y Y2 :\n");
			for(j = 1; j <= splineNum; j++)
				fprintf(debug_fp, "%d %.17lf %.17lf %.17lf\n", j, splineX[j], splineY[j], splineY2[j]);
        }
    }

	last_df = dfStart;
	// If 1 then no interpolation occurs and the swap par rate goes into each roll date.
	no_interpolation = ts->num_factors == 0;
    for (j = 0; j < num_discount_factors; j++)
    {
        if (dates[j+1] <= last_date_on_curve)
        {
			// This is wrong. The swap rate should be inserted before this.
            df = rq_yield_curve_get_discount_factor(ts, dates[j+1]);
        }
        else
        {
            /* need to imply a swap rate for this point */
            double par_rate_prev;
            double par_rate;
            rq_date date_prev;

            if (*last_swap_rate == 0.0 || *last_year_count_frac != year_count_frac)
            {
				if(sum_dfs == 0.0)
				{
					// First roll point is at ts->from_date so no par rate can be computed. Use first df point to calculate.
					df = ts->discount_factors[0].discount_factor;
					par_rate_prev = (1.0 - df) / (df * rq_day_count_get_year_fraction(day_count, ts->from_date, ts->discount_factors[0].date));
				}
				else
					par_rate_prev = (1.0 - last_df / dfStart) / (sum_dfs / dfStart);
                date_prev = dates[j];
            }
            else
            {
                par_rate_prev = *last_swap_rate;
                date_prev = *last_swap_date;
            }

            /* now linearly interpolate a new swap rate for
               the date we actually want */
            if(simple_daycount)
            {
                /* With BootstrapYieldCurveSimple each leg is assumed to have the same dcf. */
                x2 = lastDateStrapped;
                x1 = date_prev;
                x = dates[j+1];
                year_count_frac = swap_period;
            }
            else
            {
                /* This is inconsistent with the sum_df and will be raised a separate issue. For now no change to the functionality. Forge reference is: 178664 Enhanced bootstrap algorithm for swap. */
                /* Also in the forge case the example spreadsheet and spec differ, Spreadsheet uses start_date difference, spec uses relative dcf. */

                x2 = rq_day_count_get_year_fraction(day_count, start_date, lastDateStrapped);
                x1 = rq_day_count_get_year_fraction(day_count, start_date, date_prev);
                x = rq_day_count_get_year_fraction(day_count, start_date, dates[j+1]);
                year_count_frac = rq_day_count_get_year_fraction(day_count, start_date, dates[j+1])
                                - rq_day_count_get_year_fraction(day_count, start_date, dates[j]);
            }

			// ts->num_factors == 0 special case only swap points in curve so interpolation is not possible.
			// This allows us to bootstrap a curve containing only swaps.
			if(no_interpolation)
			{
				par_rate = r;
				// We also need to define dfStart or this will always be 1.
				if(start_date > ts->from_date)
				{
					dfStart = 1.0 / (1 + r * rq_day_count_get_year_fraction(day_count, ts->from_date, start_date));
					// And also add it into the curve.
					setDiscountFactor(ts, start_date, dfStart);
				}
			}
			else
				if(splineSwapRates)
					par_rate = rq_interpolate_splint(x, splineX, splineY, splineY2, splineNum);
				else
					par_rate = rq_interpolate_linear(x, x1, par_rate_prev, x2, r);

            /* now add the discount factor implied by this
               par rate to the yield curve */
            df = (dfStart - sum_dfs * par_rate) / (1 + par_rate * year_count_frac);
            setDiscountFactor(ts, dates[j+1], df);
			if(debug_fp)
			{
				char buf[16];
				fprintf(debug_fp, "interpolation %d date %s par_rate %.17lf x %.17lf df %.17lf dfStart %.17lf sum_dfs %.17lf year_count_frac %.17lf\n",
					j, rq_date_to_string(buf, "yyyymmdd", dates[j+1]), par_rate, x, df, dfStart, sum_dfs, year_count_frac);
			}
        }
        if(simple_daycount)
            sum_dfs += df * swap_period;
        else
            sum_dfs += df * rq_day_count_get_year_fraction(day_count, dates[j], dates[j+1]);
        last_df = df;
    }

    if(!simple_daycount)
        year_count_frac = rq_day_count_get_year_fraction(day_count, start_date, dates[num_discount_factors+1])
                        - rq_day_count_get_year_fraction(day_count, start_date, dates[num_discount_factors]);
    df = (dfStart - sum_dfs * r) / (1 + r * year_count_frac);

    setDiscountFactor(ts, lastDateStrapped, df);

    *last_swap_date = lastDateStrapped;
    *last_swap_rate = r;
    *last_year_count_frac = year_count_frac;
    *last_date_bootstrapped = lastDateStrapped;
	if(debug_fp)
	{
		char buf[64];
		time_t ltime;
		time( &ltime );
		ctime_s(buf, 64, &ltime);
		fprintf(debug_fp, "%s : END bootstrapSwapAsset() ", buf);
		fprintf(debug_fp, "curve_id: %s asset_id: %s\n\n",
			rq_yield_curve_get_curve_id(ts), rq_asset_get_asset_id(asset));
		fclose(debug_fp);
	}
}