Coder Social home page Coder Social logo

qlnet's Introduction

QLNet

QLNet C# library official repository. QLNet is a financial library written in C# derived primarily from its C++ counterpart, Quantlib, which has been used as a base reference for modelling various financial instruments. QLNet also contains new developments on the bond market like MBS, Amortized Cost, PSA Curve and others.

Build status NuGet Donate

Quality Gate Status Bugs Vulnerabilities Code Smells Duplicated Lines (%) Lines of Code Maintainability Rating Reliability Rating Security Rating Technical Debt

Development workflow

QLNet use git flow workflow.

Instead of a single master branch, this workflow uses two branches to record the history of the project. The master branch stores the official release history, and the develop branch serves as an integration branch for features. The develop branch will also contain the complete history of the project.

Features

To contribute features, you should clone the repository, create a tracking branch for develop and create the feature:

git clone https://github.com/amaggiulli/qlnet.git
git checkout -b develop origin/develop
git checkout -b some-feature develop

When the feature is ready, you can make a pull request to merge that feature into develop. Note that features will never be merged directly into master.

Releases

When a release is ready, we fork a release branch from develop. Creating this branch starts the next release cycle, so no new features can be added after this point; only bug fixes, documentation generation, and other release-oriented tasks go in this branch. Once it's ready to ship, the release gets merged into master and tagged with a version number.

HotFix

Maintenance or “hotfix” branches are used to quickly patch production releases. This is the only branch that fork directly off of master. As soon as the fix is complete, it will be merged into both master and develop, and master will be tagged with an updated version number.

Acknowledgements

Thanks to all Quantlib creators and contributors. Thanks to all QLNet contributors. Special thanks to JetBrains for their support of open source projects; QLNet makes extensive use of Resharper.

qlnet's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

qlnet's Issues

Vanilla Swap Pricer Ignores Index Fixing Days

Hi @amaggiulli

I think I have found a bug becuase the vanilla swap pricer ignores fixing days of the index - it always uses the default which is 2. See my code below. If you value for 20 April 2015 you get an exception for a the fixing of 17 April 2015. Since the index has 0 fixing days I should not need the 17 April fixing.

I have looked through the source code. I am not sure why this line is commented out in the VanillaSwap.cs class but it appears to fix the problem if I uncomment it.

  legs_[1] = new IborLeg(floatSchedule, iborIndex)
                                 .withPaymentDayCounter(floatingDayCount)
        //.withFixingDays(iborIndex.fixingDays())
                                 .withSpreads(spread)
                                 .withNotionals(nominal)
                                 .withPaymentAdjustment(paymentConvention_);

Without this, what happens is that in the constructor of FloatingRateCoupon.cs class fixingDays is passed in with the default value of 2 and this line:

fixingDays_ = fixingDays == default(int) ? index.fixingDays() : fixingDays;

subsequently always returns 2.

Code to reproduce issue:

Date tradeDate = new Date(17, Month.April, 2015);
Calendar calendar = new UnitedKingdom();
Date settlementDate = calendar.advance(tradeDate, 2, TimeUnit.Days, BusinessDayConvention.Following);
Date maturityDate = calendar.advance(settlementDate, 5, TimeUnit.Years, BusinessDayConvention.Following);
Date valueDate = new Date(20, Month.April, 2015);
Settings.setEvaluationDate(valueDate);

        List<Date> dates = new List<Date>();
        dates.Add(valueDate);
        dates.Add(valueDate + new Period(1,TimeUnit.Years));
        dates.Add(valueDate + new Period(2,TimeUnit.Years));
        dates.Add(valueDate + new Period(5,TimeUnit.Years));
        dates.Add(valueDate + new Period(10,TimeUnit.Years));
        dates.Add(valueDate + new Period(20,TimeUnit.Years));

        List<double> rates = new List<double>();
        rates.Add(0.01);
        rates.Add(0.01);
        rates.Add(0.01);
        rates.Add(0.01);
        rates.Add(0.01);
        rates.Add(0.01);

        var discountCurveHandle = new RelinkableHandle<YieldTermStructure>();

        var forecastCurveHandle = new RelinkableHandle<YieldTermStructure>();

        GBPLibor index = new GBPLibor(new Period(6, TimeUnit.Months), forecastCurveHandle);

        InterpolatedZeroCurve<Linear> zeroCurve = new InterpolatedZeroCurve<Linear>(dates,rates,new Actual360() , new Linear());

        var fixedSchedule =  new Schedule(settlementDate, maturityDate, new Period(1,TimeUnit.Years), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false);

        var floatSchedule = new Schedule(settlementDate, maturityDate, index.tenor(), calendar, BusinessDayConvention.Following, BusinessDayConvention.Following, DateGeneration.Rule.Forward, false);

        VanillaSwap swap = new VanillaSwap(VanillaSwap.Type.Payer, 1000000, fixedSchedule, 0.01, new Actual360(), floatSchedule, index, 0, new Actual360());

        discountCurveHandle.linkTo(zeroCurve);

        forecastCurveHandle.linkTo(zeroCurve);

        var swapEngine = new DiscountingSwapEngine(discountCurveHandle, false, null);

        swap.setPricingEngine(swapEngine);

        Console.WriteLine("Settlement Date is: " + settlementDate);
        Console.WriteLine("Fixing days of index is: " + index.fixingDays());
        Console.WriteLine("Therefore, we do not need a fixing for 17/04/2015 when we value on " + valueDate + " but we get this error");


        try
        {
           swap.NPV();  
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }

Thanks
Ofir

InterpolatedZeroCurve construction using tenor dates, rates, and reference date

When I create an InterpolatedZeroCurve using a specific set of dates, set of yields, day counter, interpolator, compounding, and frequency, my first date always gets anchored to time zero, which is expected. Unfortunately I'm not allowed to add a reference date within that specific overload, so any interpolations that are performed must first have the difference between the true reference date and the first tenor date subtracted from the input to the interpolation method... I need to be able to properly interpolated across the curve as well as extrapolate to the reference rate (which is one of the main reasons I need this object), which means I must include the reference date in some way without performing this reference date-first tenor date difference.

Is there be another way to supply a reference date using the above information to create an interpolated zero curve? I could use all the help I could get at this point.

QLNet Location: https://github.com/amaggiulli/qlnet/blob/master/QLNet/Termstructures/Yield/ZeroCurve.cs

Constructor:
public InterpolatedZeroCurve(List<Date> dates, List<double> yields, DayCounter dayCounter, Interpolator interpolator, Compounding compounding = Compounding.Continuous, Frequency frequency = Frequency.Annual)

request: example with MaxBasketPayoff

First I would like to thanks the developer for that quality project, it is really much appreciated.
I was looking for pricing European option on the max of two assets. I can see that in the class payoff there is mention of a MaxBasketPayoff. Is it usuable? If it is the case would you mind to add an example of how to use it? I am currently developing in csharp an implementation of Stulz and I wanted to check the result with a MonteCarlo.
Thank you for your help and thank again for the great work.

AmortizingBond

Hi @amaggiulli

in QLNet we have 4 classes for amortizing bonds: AmortizingBond, AmortizingCMSRateBond, AmortizingFixedRateBond and AmortizingFloatingRateBond.

In QuantLib the AmortingBond class doesn't exist. What is the purpose of this class if the other 3 already exist? If it's important, I want to backport it.

InterpolatedZeroInflationCurve

Hi,

I see InterpolatedZeroInflationCurve hasn't been implemented yet. I'll try to implement it, but I'm just checking first that you don't perhaps have a semi-completed version. If so, please let me know.

Convex-Monotone interpolation gives bad results

Has somebody tested the Convex-Monotone interpolation looking at the data points vs the interpolant?

I find that the interpolant does not even go through the data points. I'm wrapping around it in a simple way from my code, and the wrapping code is the same as for the Cubic Spline but the Cubic Spline works fine. I can see this problem even with very simple data points from a polynomial.

How to calculate volatility input for option pricing

I'd like to do simple american option pricing calculations.

How do I go about calculating the volatility value?

SPECIFICALLY: there is a value .20 provided below. How is that calculated?

My belief is I need to get prices for a period and do a volatility calculation on the series of prices. Does anyone have a sample? how many periods are required?

Thanks in advance.

AmericanOptionData[] juValues = new AmericanOptionData[] {
// type, strike, spot, q, r, t, vol, value, tol
// These values are from Exhibit 3 - Short dated Put Options
new AmericanOptionData( Option.Type.Put, 35.00, 40.00, 0.0, 0.0488, 0.0833, 0.2, 0.006 ),

Swap example unhandled exception

I tried the swap example on both Win7 (VS213) and XP (VS2010), but kept getting the following exception: "Unhandled Exception: System.ApplicationException: 1 iteration: failed at 1 alive instrument, maturity 2004/09/29, reference date 2004/09/22: invalid value (-3) at index 1".

I tried debugging it but couldn't figure out what the root cause is because I am not very familiar with QuantLib and qlnet seems to be implemented quite differently from QuantLib C++ as well. I copied the Swap example code from qlnet to QuantLib-SWIG\CSharp\examples and got it to work with minimal change. Therefore the example itself is not the issue.

I tried changing line 77 from: double s5yQuote = 0.0443; to double s5yQuote = 0.0460; and surprisingly it ran through the end without exception, but it produced two sets of identical numbers.

In addition, I found that Bootstraptraits.cs has the following code and line 110 (return -3.0) seems to be the issue, but I don't understand why it reaches that line. Could you please take a look when you get a chance? Thanks a lot in advance!

public double minValueAfter( int i, InterpolatedCurve c, bool validData, int f )
{
    //return Const.QL_Epsilon;

    if ( validData )
    {
        #if QL_NEGATIVE_RATES
            // no constraints.
            // We choose as min a value very unlikely to be exceeded.
            return -3.0;
        #else
            return c.data().Last() / 2.0;
        #endif
    }
    double dt = c.times()[i] - c.times()[i - 1];
    return c.data()[i - 1] * System.Math.Exp( -maxRate * dt );
}

Complete console output:

Today: Monday, 2004/09/20
Settlement date: Wednesday, 2004/09/22
====================================================================
5-year market swap-rate = 4.43%
====================================================================
        5-years swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          19065.88 |      -0.42% |           4.43% |
 depo-fut-swap |          19076.14 |      -0.42% |           4.43% |
 depo-FRA-swap |          19056.02 |      -0.42% |           4.43% |
--------------------------------------------------------------------
        5-years, 1-year forward swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          40049.46 |      -0.92% |           4.95% |
 depo-fut-swap |          40092.79 |      -0.92% |           4.95% |
 depo-FRA-swap |          37238.92 |      -0.86% |           4.88% |
====================================================================
5-year market swap-rate = 4.60%
====================================================================
        5-years swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------

Unhandled Exception: System.ApplicationException: 1 iteration: failed at 1 alive instrument, maturity 2004/09/29, reference date 2004/09/22: invalid value (-3) at index 1
   at QLNet.Utils.QL_FAIL(String message) in C:\GitHub\qlnet\QLNet\Utils.cs:line 85
   at QLNet.IterativeBootstrap`2.calculate() in C:\GitHub\qlnet\QLNet\Termstructures\Iterativebootstrap.cs:line 223
   at QLNet.PiecewiseYieldCurve`3.performCalculations() in C:\GitHub\qlnet\QLNet\Termstructures\Yield\PiecewiseYieldCurv
e.cs:line 233
   at QLNet.LazyObject.calculate() in C:\GitHub\qlnet\QLNet\Patterns\LazyObject.cs:line 112
   at QLNet.PiecewiseYieldCurve.maxDate() in C:\GitHub\qlnet\QLNet\Termstructures\Yield\PiecewiseYieldCurve.cs:line 68
   at QLNet.TermStructure.maxTime() in C:\GitHub\qlnet\QLNet\Termstructures\TermStructure.cs:line 98
   at QLNet.TermStructure.checkRange(Double t, Boolean extrapolate) in C:\GitHub\qlnet\QLNet\Termstructures\TermStructur
e.cs:line 155
   at QLNet.YieldTermStructure.discount(Double t, Boolean extrapolate) in C:\GitHub\qlnet\QLNet\Termstructures\YieldTerm
Structure.cs:line 122
   at QLNet.YieldTermStructure.discount(Date d, Boolean extrapolate) in C:\GitHub\qlnet\QLNet\Termstructures\YieldTermSt
ructure.cs:line 114
   at QLNet.DiscountingSwapEngine.calculate() in C:\GitHub\qlnet\QLNet\Pricingengines\Swap\Discountingswapengine.cs:line
 77
   at QLNet.Instrument.performCalculations() in C:\GitHub\qlnet\QLNet\Instruments\Instrument.cs:line 78
   at QLNet.LazyObject.calculate() in C:\GitHub\qlnet\QLNet\Patterns\LazyObject.cs:line 112
   at QLNet.Instrument.calculate() in C:\GitHub\qlnet\QLNet\Instruments\Instrument.cs:line 65
   at QLNet.Instrument.NPV() in C:\GitHub\qlnet\QLNet\Instruments\Instrument.cs:line 100
   at Swap.SwapValuation.Main(String[] args) in C:\GitHub\qlnet\Examples\Swap\swapvaluation.cs:line 480
Press any key to continue . . .

Output for changing line 77 to set 5yr swap rate to 4.60%

Today: Monday, 2004/09/20
Settlement date: Wednesday, 2004/09/22
====================================================================
5-year market swap-rate = 4.60%
====================================================================
        5-years swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          26539.06 |      -0.58% |           4.60% |
 depo-fut-swap |          26553.34 |      -0.58% |           4.60% |
 depo-FRA-swap |          26525.34 |      -0.58% |           4.60% |
--------------------------------------------------------------------
        5-years, 1-year forward swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          45736.04 |      -1.06% |           5.09% |
 depo-fut-swap |          45782.40 |      -1.06% |           5.09% |
 depo-FRA-swap |          42922.60 |      -0.99% |           5.02% |
====================================================================
5-year market swap-rate = 4.60%
====================================================================
        5-years swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          26539.06 |      -0.58% |           4.60% |
 depo-fut-swap |          26553.34 |      -0.58% |           4.60% |
 depo-FRA-swap |          26525.34 |      -0.58% |           4.60% |
--------------------------------------------------------------------
        5-years, 1-year forward swap paying 4.00%
term structure | net present value | fair spread | fair fixed rate |
--------------------------------------------------------------------
     depo-swap |          45736.04 |      -1.06% |           5.09% |
 depo-fut-swap |          45782.40 |      -1.06% |           5.09% |
 depo-FRA-swap |          42922.60 |      -0.99% |           5.02% |

Run completed in 00:00:00.3749976
Press any key to continue ...

American Option pricing with Discrete Dividend

I am looking for American option pricing with discrete dividend via Monte Carlo or Binomial option. While quantlib/qlnet has the finite difference implementation for the same, I am curios if quantlib has functionalities in this regards.

MultiAssetOption greeks are scalar

I am writing an instrument derived from MultiAssetOption class. The problem I have is that the greeks are declared as scalars in the MultiAssetOption while I need them to all the underlyings. Any suggestions on how to allow them to be vectors in my subclass - apart from effectively overriding entire MultiAssetOption class?

Assertions failing in EquityOption sample on timeSteps==null || timeStepsPerYear==null

Hi,

I am new to QLNet and was trying to run the EquityOption sample. It now fails on an assertion in the MCVanillaEngine:

     Utils.QL_REQUIRE( timeSteps == null || timeStepsPerYear == null, () =>
                "both time steps and time steps per year were provided" );

The variables are declared as int and not as int? meaning they can never have the null value.

I think MakeMCEuropeanEngine should be modified to declare steps_, stepsPerYear_, samples_ and maxSamples_ as int?.

Am I right, should I modify the library like this?

Tomislav

CashFlow / IRR and YTM

Just starting with this library, and wondering if someone can help with this use case question

I need to calculate the internal rate of return (IRR) , both for the reporting period (Period IRR) as well as the Annualized IRR for a portfolio. I have already prepared as SimpleCashFlows the

  • intial Value of the portfolio,
  • the contributions / withdrawals,
  • end Value of the portfolio.

Can I simply use CashFlows.yield(), i.e. the same method I would typically used for calculating YTM on a bond ? If yes, what option should I use for compounding / frequency ?

Indentation: tab = 3 spaces

Hi,

I noticed that the indentation setting is mostly 3 spaces. Isn't this a bit odd? The default Visual Studio settings for a .NET project is 4 spaces for indentation. Is there any specific reason for using 3 spaces or will you consider moving to 4 spaces for indentation?

Also, I see that there are a mixture of tabs and spaces in some files. I'll fix this later.

See attached screenshot of default Visual Studio tab settings.

image

Calculation of CASH

Hi @amaggiulli

In revision 361 in the old SVN project, I see that support for calculation of CASH values were added. However, I can't find any reference to these calculations in the QuantLib project. I'd like to keep the 2 projects in line as much as possible, so can you please explain what these CASH calculations are for? They don't seem to be used that much. If they really serve a purpose, I'll backport it to QuantLib.

QLNet Current State

I have been trying to use both QLNet and Quantlib (C++) library. I find that QLNet is not updated with all functionalities and features as available in Quantlib. Is there an active development effort for QLNet? If yes, then I have a few questions to ask regarding QLNet, else it might be better to raise these questions on Quantlib forum. Thank you

NuGet

Would it be possible to place official releases of QLNet on NuGet? That'd streamline the process of using the library and of updating it.

I'm willing to work on this if you want, just let me know. I could configure the project for NuGet publishing and send you a pull request.

Improvement idea: Use specific type for exceptions

Hi,

It would be very useful for exception handling if the following utils:

Utils.QL_REQUIRE

throws a dedicated type of exception instead of the generic System.Exception. C#6 and C#7 have lots of goodies to handle exceptions by type and QLNet ones cannot be differentiate easily.

Change is minor:

  • Create an exception class that inherits System.Exception
  • Change the "Utils.QL_REQUIRE" code to generate this new type instead

What do you think?

PS: having two new Exception types would be even better. One for QL_REQUIRE and another for QL_FAIL.

.NET Core Support

I want to use this app in an .NET Core application. Can you please add support for it?

testFdGreeks support for theta approximation

Hello Andrea,

Thank you for your work on QLNet. Really appreciate it. Wanted to clarify one moment with testFdGreeks test. I have noticed that theta approximation in the test is commented out. I stumbled upon this test while trying to figure out why my theta approximation code returns zeros (effectively the same code you have commented in your test). Seems like if I set new evaluationDate up for reevaluation, it is not picked up by the QLNet on my next call .NPV(). Is this a known issue?

Thank you,
Pavel

Performance issue

I have upgraded the QLNet from a very old version (1.0.0.1) to 1.3.0.0 and noted a huge performance drop. To give an idea: the total execution time of an application moved from 2.5 to 10 minutes. And this is ONLY upgrading the QLNet library. After spending some time, with profiling the library and comparing the code, I found that the cause of the issue is in using the Utils.QL_REQUIRE() call all over the places. Even though, it may look innocent, but having for example a date or some other data type comparison, impacts the performance, if called MANY times.
For testing purposes, I have commented out EVERY usage of Utils.QL_REQUIRE(), and the performance returned back.
I think, in a quant/math libraries should be as less "unnecessary" checks / validations. Users of the library should do some work for their own protection. We should not compromise the performance, so just to be nice to the user :)
I would like to recommend someone to remove / comment / put under some define those entries, having it disabled by default.

Design flaw in how polymorphism and generics work

I'm not sure whether this is a major problem, but I struggled for a long time and couldn't solve it. I'm trying to implement the default probability curves. The design pattern is similar in how the yield term structures work.

To illustrate the problem, look at the testLinearDiscountConsistency test. It uses a PiecewiseYieldCurve to build a curve and interpolates the Discount curve using Linear interpolator. When the interpolation occurs, this piece of the codebase is executed:

In QuantLib:

 DiscountFactor PiecewiseYieldCurve<C,I,B>::discountImpl(Time t) const {
     calculate();
     return base_curve::discountImpl(t);
 }

The discountImpl that is executed is then InterpolatedDiscountCurve<T>::discountImpl :

DiscountFactor InterpolatedDiscountCurve<T>::discountImpl(Time t) const {
     if (t <= this->times_.back())
        return this->interpolation_(t, true);

    // flat fwd extrapolation
    Time tMax = this->times_.back();
    DiscountFactor dMax = this->data_.back();
    Rate instFwdMax = - this->interpolation_.derivative(tMax) / dMax;
    return dMax * std::exp(- instFwdMax * (t-tMax));
}

What happens in QLNet is this. In PiecewiseYieldCurve:

protected override double discountImpl(double t) {
   calculate();
   return traits_.discountImpl(interpolation_, t);
}

But _traits is defined as the Discount class, not InterpolatedDiscountCurve as in QuantLib and the code that is then executed is:

public double discountImpl( Interpolation i, double t ) { return i.value( t, true ); }

This is because of the difference in how the generics and polymorphism work. We are "lucky" in the sense that InterpolatedDiscountCurve.discountImpl and Discount.discountImpl do almost the same thing and that is why the tests pass.

When I started implementing the Default Curves, I noticed the same problem, except we aren't so lucky anymore. Refer to the testLinearDensityConsistency, which is very similar to the discount curve test I discussed above. The test wants to calculate a swap fair value and in doing so, needs the survival probability. In QuantLib: PiecewiseDefaultCurve::survivalProbabilityImpl would call InterpolatedDefaultDensityCurve<T>::survivalProbabilityImpl. But in QLNet, PiecewiseDefaultCurve.survivalProbabilityImpl would call DefaultDensity.survivalProbabilityImpl:

public double survivalProbabilityImpl(Interpolation i, double t) { throw new NotSupportedException(); }

And then the test fails. There must be a way to make the call to InterpolatedDefaultDensityCurve instead of DefaultDensity, but I can't figure how how. C++ has typenames and typedefs which help here, but that's not possible in C#. Maybe there is a solution using reflection?

validation of bond risk analytics calculations

i am wondering if anyone has encountered any accuracy problems in using the quantlib for computing bond risk analytic metrics including modified duration, Macaulay duration and convexity.
the result do not match a reference those obtained from an industry-standard 3rd party commercial library used on our production system and i was wondering if anyone has encountered any such issues

clone() in OvernightIndex

Hello,

i think there is an issue with the return value in overnightindex.clone(..):

This prevents the downcast after the clone (i.e.: oi.clone(yts) as OvernightIndex will not work):
public new IborIndex clone( Handle<YieldTermStructure> h ) { return new OvernightIndex( familyName(), fixingDays(), currency(), fixingCalendar(), dayCounter(), h ); }

this should fix it:

public new OvernightIndex clone( Handle<YieldTermStructure> h ) { return new OvernightIndex( familyName(), fixingDays(), currency(), fixingCalendar(), dayCounter(), h ); }

Serialisation

Hi
Firstly thanks for your great work! In the future would it be possible to add serialisation attributes to the classes. I would like the ability to be able to serialise term structures for later use.
Thanks
Sean

CallableBond example does not work

in class CallableFixedRateBond, the method setupArguments put the prices twice in the collection arguments.callabilityPrices, this makes the validation fail when it tries to match the size os collections arguments.callabilityPrices and arguments.callabilityDates.

File:CallableBond.cs (QLNet-> Instruments -> Bonds)
Line 271: setup bug
Line 63: validation

public override void validate()
{
Utils.QL_REQUIRE(settlementDate != null,"null settlement date");

        //Utils.QL_REQUIRE(redemption != null, "null redemption");
        Utils.QL_REQUIRE(redemption >= 0.0, "positive redemption required: " + redemption + " not allowed");

        Utils.QL_REQUIRE(callabilityDates.Count == callabilityPrices.Count, "different number of callability dates and prices");
        Utils.QL_REQUIRE(couponDates.Count == couponAmounts.Count, "different number of coupon dates and amounts");
     }

if (!putCallSchedule_[i].hasOccurred(settlement, false))
{
arguments.callabilityDates.Add(putCallSchedule_[i].date());
arguments.callabilityPrices.Add(putCallSchedule_[i].price().amount());

           if (putCallSchedule_[i].price().type() == Callability.Price.Type.Clean)
           {
              /* calling accrued() forces accrued interest to be zero
                 if future option date is also coupon date, so that dirty
                 price = clean price. Use here because callability is
                 always applied before coupon in the tree engine.
              */
              arguments.callabilityPrices.Add(putCallSchedule_[i].price().amount() +
                                              this.accrued(putCallSchedule_[i].date()));
           }
           else
              arguments.callabilityPrices.Add(putCallSchedule_[i].price().amount());

        }

how to pricing American option with volatility surface?

In the option examples, QLNet uses the flat term structures for r, q and volatility. how to use the curve term structures? in particular, how to set up a volatility surface and use the surface as input for the pricing engines? In QuantLib C++, you can create a wrapper:

boost::shared_ptr ForwardImpliedVolSurface(Date todaysDate, Date forwardDate, Calendar calendar, std::vector maturityArray, std::vector strikeArray, Matrix volatilityMatrix)
{
// Handle to boost::shared_ptr
DayCounter dayCounter = Actual365Fixed();
boost::shared_ptr volatilitySurface(new BlackVarianceSurface(todaysDate, calendar, maturityArray, strikeArray, volatilityMatrix, dayCounter));
Handle volatilitySurfaceH(volatilitySurface);

// Volatility surface interpolation
volatilitySurface->enableExtrapolation(true);

// Change interpolator to bicubic splines
volatilitySurface->setInterpolation(Bicubic());

// Forward implied volatility surface
boost::shared_ptr forwardVolSurface(new ImpliedVolTermStructure(volatilitySurfaceH, forwardDate));

return(forwardVolSurface);
}

how does QLNet achieve this?

Thanks
Mike

Error running the example in swapvaluation.cs

Hi I was trying to get up to speed with qlnet but hit a problem when I ran the supplied example in the "Swap" project. After the 5year swap rate is changed and the depoSwaptermStructure relinked I get the error :
"Additional information: 1 iteration: failed at 1 alive instrument, maturity 29/09/2004, reference date 22/09/2004: invalid value (-3) at index 1"

when it tries to recalculate the NPV.

Can't price simple fixed coupon bond

Hi all,

I am trying to extract the clean price, dirty price, accrued amount, and cash flows from a FixedRateBond object after setting it with a DiscountingBondEngine object. I can get back the accrued amount and cash flows but not the clean price and dirty price. Instead an exception is thrown:

An unhandled exception of type 'System.ApplicationException' occurred in QLNet.dll

Additional information: 1 iteration: failed at 3 alive instrument, maturity 1/8/2018, reference date 2/23/2015: root not bracketed: f[0.316514877920835,0.865103973410519] -> [0.612424282783745,0.0100000000000001]

The weird thing is I'm running essentially the same code using NQuantLib64 (NuGet package containing QuantLib-SWIG for C# x64) and everything works fine, including matching outputs (for those in QLNet being outputted). I'm also using QLNet version 1.4.0.27.

Would you know what I'm doing wrong? Or maybe there's some issue with QLNet? See code below.

My Main file:

    public class Program
    {
        public static void Main(string[] args)
        {
            double faceValue = 100;
            double coupon = 0.01;
            int settleDays = 3;
            DateTime issueDate = DateTime.Parse("2015-01-06");
            DateTime settleDate = DateTime.Parse("2015-02-23");
            DateTime maturityDate = DateTime.Parse("2019-01-08");
            Dictionary<DateTime, double> termStructure = new Dictionary<DateTime, double>
            {
                { DateTime.Parse("2015-01-06"), 1.0},
                { DateTime.Parse("2016-01-06"), 0.98},
                { DateTime.Parse("2017-01-06"), 0.95},
                { DateTime.Parse("2018-01-08"), 0.96},
                { DateTime.Parse("2019-01-08"), 0.97}
            };

            // Initialize and price QLNet fixed coupon bond
            QLNetFixedCouponBond qlnFixedCouponBond = new QLNetFixedCouponBond(faceValue, coupon, settleDays, termStructure, settleDate, issueDate, maturityDate);
            qlnFixedCouponBond.Price();

            // Display QLNet fixed coupon bond price info
            Console.WriteLine("QLNet Fixed Coupon Bond Pricing Info");
            Console.WriteLine("  Clean price:       {0}", qlnFixedCouponBond.CleanPrice);
            Console.WriteLine("  Dirty price:       {0}", qlnFixedCouponBond.DirtyPrice);
            Console.WriteLine("  Accrued amount:    {0}", qlnFixedCouponBond.AccruedAmount);
            Console.WriteLine("  Cash flows:");
            foreach (var cf in qlnFixedCouponBond.CashFlow)
            {
                Console.WriteLine("                     {0}", cf.amount());
            }
        }
    }

And my custom fixed coupon bond class:

    public class QLNetFixedCouponBond
    {
        public double FaceValue { get; set; }
        public double Coupon { get; set; }
        public Calendar Calendar { set; get; }
        public int SettleDays { get; set; }
        public List<Date> Dates { get; set; }
        public List<double> DiscountFactors { get; set; }
        public Date SettleDate { get; set; }
        public Date IssueDate { get; set; }
        public Date MaturityDate { get; set; }

        public double CleanPrice { get; set; }
        public double DirtyPrice { get; set; }
        public double AccruedAmount { get; set; }
        public List<CashFlow> CashFlow { get; set; }

        public QLNetFixedCouponBond(double faceValue, double coupon, int settleDays, Dictionary<DateTime, double> termStructure, DateTime settleDate, DateTime issueDate, DateTime maturityDate)
        {
            FaceValue = faceValue;
            Coupon = coupon;
            SettleDays = settleDays;
            Calendar = new Germany();
            IssueDate = new Date(issueDate.Day, (Month)issueDate.Month, issueDate.Year);
            SettleDate = new Date(settleDate.Day, (Month)settleDate.Month, settleDate.Year);
            MaturityDate = new Date(maturityDate.Day, (Month)maturityDate.Month, maturityDate.Year);

            Dates = new List<Date>();
            DiscountFactors = new List<double>();
            foreach (var t in termStructure)
            {
                Dates.Add(new Date(t.Key.Day, (Month)t.Key.Month, t.Key.Year));
                DiscountFactors.Add(t.Value);
            }
        }

        public void Price()
        {
            // Prepare QLNet objects for initialization of fixed coupon bond object
            BusinessDayConvention dayCountConvention = BusinessDayConvention.Unadjusted;

            Schedule schedule = new Schedule(
                effectiveDate: SettleDate,
                terminationDate: MaturityDate,
                tenor: new Period(Frequency.Semiannual),
                calendar: new NullCalendar(),
                convention: dayCountConvention,
                terminationDateConvention: dayCountConvention,
                rule: DateGeneration.Rule.Backward,
                endOfMonth: false);

            // Initialize QLNet bond pricing engine
            Handle<YieldTermStructure> discountCurve = CreateZeroCouponTermstructure(SettleDate, Dates, DiscountFactors);
            IPricingEngine bondEngine = new DiscountingBondEngine(discountCurve);

            // Initialize QLNet fixed coupon bond and set pricing engine
            FixedRateBond fixedCouponBond = new FixedRateBond(
                settlementDays: SettleDays,
                faceAmount: FaceValue,
                schedule: schedule,
                coupons: new List<double> { Coupon },
                accrualDayCounter: new ActualActual(ActualActual.Convention.Bond),
                paymentConvention: dayCountConvention,
                redemption: FaceValue,
                issueDate: IssueDate);
            fixedCouponBond.setPricingEngine(bondEngine);

            // Get price info from QLNet fixed coupon bond
            //CleanPrice = fixedCouponBond.cleanPrice();
            DirtyPrice = fixedCouponBond.dirtyPrice();
            AccruedAmount = fixedCouponBond.accruedAmount();
            CashFlow = fixedCouponBond.cashflows();
        }

        private Handle<YieldTermStructure> CreateZeroCouponTermstructure(Date settleDate, List<Date> dates, List<double> discountfactors)
        {
            var bondInstruments = new List<RateHelper>();

            for (var i = 0; i < discountfactors.Count; i++)
            {
                if (dates[i] <= settleDate) continue;

                var df = new Handle<Quote>(new SimpleQuote(discountfactors[i]));
                var matu = dates[i];

                var schedule = new Schedule(
                    effectiveDate: settleDate,
                    terminationDate: matu,
                    tenor: new Period(Frequency.Once),
                    calendar: new NullCalendar(),
                    convention: BusinessDayConvention.Unadjusted,
                    terminationDateConvention: BusinessDayConvention.Unadjusted,
                    rule: DateGeneration.Rule.Backward,
                    endOfMonth: true);

                var coupons = new List<double> { 0.0 };

                var helper = new FixedRateBondHelper(
                    price: df,
                    settlementDays: 0,
                    faceAmount: 1.0,
                    schedule: schedule,
                    coupons: coupons,
                    dayCounter: new ActualActual(),
                    paymentConvention: BusinessDayConvention.Unadjusted,
                    redemption: 1.0,
                    issueDate: settleDate);

                bondInstruments.Add(helper);
            }

            // Cubic interpolation of discount factors
            YieldTermStructure bondDiscountingTermStructure = new PiecewiseYieldCurve<Discount, Cubic>(settleDate, bondInstruments, new ActualActual());

            return new Handle<YieldTermStructure>(bondDiscountingTermStructure);
        }
    }

Thanks in advance!

Best,

Grant

QLNet Thread Safe

Let's talk here about making QLNet thread safe , let's start with GarnikA comment :

on the thread-safe note; you mention that "evaluationDate is stored in a singleton". Are you referring to the static Settings class? If yes, should not [ThreadStatic] solve that problem?
From what I can see, there are only a few singletons and with very little change they can be turned to be thread-safe: IndexManager (protect the data_, actually I switch to ConcurrentDictionary and that solved the issue for me), ExchangeRateManager (already uses [ThreadStatic]) and SeedGenerator(we could just mark the instance_ with [ThreadStatic] as in the ExchangeRateManager). What do you think?

Garman Kohlagen Process ctor in BlackScholesProcess

There's probably an error in this ctor.
public class GarmanKohlagenProcess : GeneralizedBlackScholesProcess {
public GarmanKohlagenProcess(Handle x0,
Handle foreignRiskFreeTS,
Handle domesticRiskFreeTS,
Handle blackVolTS)
: this(x0, foreignRiskFreeTS, domesticRiskFreeTS, blackVolTS, new EulerDiscretization()) { }
public GarmanKohlagenProcess(Handle x0, Handle foreignRiskFreeTS,
Handle domesticRiskFreeTS,
Handle blackVolTS, IDiscretization1D d)
: base(x0, foreignRiskFreeTS, foreignRiskFreeTS, blackVolTS, d) { }
}
it should be.
public GarmanKohlagenProcess(Handle x0, Handle foreignRiskFreeTS,
Handle domesticRiskFreeTS,
Handle blackVolTS, IDiscretization1D d)
: base(x0, foreignRiskFreeTS, domesticRiskFreeTS, blackVolTS, d) { }
}

Documentation

Hi Andrea!

What's the current documentation tool you are using for the .net version of quantlib, as in 1.2 you had a doxygen folder in the distribution (but no instructions on how to use it). Do you still plan to use doxygen in the future and can you point me to some ways to use it with QLNet?

-regards,
ROland

linear least squares regression

In linearleastsquaresregression.cs,
public LinearRegression(List<List> x, List y) {
reg_ = new LinearLeastSquaresRegression<List>(x, y, linearFcts(x.Count));
}
linearFcts counts the number of explanatory variables, which shouldn't be the number of elements in x. It should be the number of elements in x[0].
x.count is actually the sample size.

Efficient option evaluations

Is there a quick way to evaluate an option over multiple dates and underlying prices? The QLNet examples show options being evaluated for one date/price. I was wondering if there was a more efficient way to do it without reinstantiating all those classes (like the engine and stochastic process) . I've included an abbreviated version of the function I'm trying to optimize to show what I'm doing. The jist of it is that I'm iterating over several dates/underlying prices to get option values. It assumes that other variables like IV and the risk free rate stay constant over the time period.
Any help would be appreciated.


public void SetOptionValues(OptionPricingInfo option)
{
    var riskFreeRate = RiskFreeRate.GetRiskFreeRate();

    //Convert StockData option type to QLnet option type
    Option.Type optionType = option.OptionType == OptionType.Call ? Option.Type.Call : Option.Type.Put;
    Date settlementDate = new Date(option.EvaluationCriteria.EvalStartDateTime.Date);
    Date expDate = new Date(option.ExpirationDate);

    //var values = new OptionValue[option.EvaluationCriteria.NumPriceSteps + 1, option.EvaluationCriteria.NumDateStep + 1];
    option.OptionValues = Matrix<double>.Build.Dense(option.EvaluationCriteria.NumDateStep + 1, option.EvaluationCriteria.NumPriceSteps + 1);

    Settings.setEvaluationDate(settlementDate);

    Calendar calendar = new TARGET();

    PlainVanillaPayoff payoff = new PlainVanillaPayoff(optionType, option.StrikePrice);
    DayCounter dayCounter = new Actual365Fixed();

    for (int dateIter = 0; dateIter <= option.EvaluationCriteria.NumDateStep; dateIter++)
    {
        //Reset Starting Price
        double evalPrice = EvaluationCriteria.EvalStartPrice;

        var flatTermStructure = new Handle<YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter));
        var flatDividendTs = new Handle<YieldTermStructure>(new FlatForward(settlementDate, option.OptionQuote.UnderlyingQuote.Stock.IndicatedAnnualDividend / 100.0, dayCounter));
        var flatVolTs = new Handle<BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, option.OptionQuote.ImpVol, dayCounter));
        AmericanExercise americanExercise = new AmericanExercise(settlementDate, expDate);
        VanillaOption americanOption = new VanillaOption(payoff, americanExercise);

        for (int spIter = 0; spIter <= option.EvaluationCriteria.NumPriceSteps; spIter++)
        {
            var underlyingQuoteH = new Handle<Quote>(new SimpleQuote(evalPrice));

            BlackScholesMertonProcess stochasticProcess = new BlackScholesMertonProcess(underlyingQuoteH, flatDividendTs, flatTermStructure, flatVolTs);

            // Barone-Adesi and Whaley approximation for American
            IPricingEngine myEngine = GetOptionEngine(EvaluationCriteria.EvalEngineType, stochasticProcess);

            americanOption.setPricingEngine(myEngine);

            option.OptionValues[dateIter, spIter] = americanOption.NPV();

            //Increment underlying Price
            evalPrice += option.EvaluationCriteria.PriceStepInc;
        }

        //Increment date
        settlementDate += option.EvaluationCriteria.DayInc;
        Settings.setEvaluationDate(settlementDate);
    }
}

Floating numbers equality

I have enabled another tool for code analysis , SonarQube , you can check it here https://sonarqube.com/dashboard/index?id=QLNet-develop. This tool, like Resharper , bother about floating point comparison so I developed a double extension to compare doubles (fcfbb62) , from my tests the overhead is very low but if someone know a fastest way to do it let me know . From now on to compare 2 double instead of

if ( val1 == val2 )
if ( val1 != val2 )
use
if ( val1.IsEqual(val2 )
if ( val1.IsNotEqual(val2 )

Error Casting QLNet.ArithmeticAPOPathPricer to QLNet.PathPricer<QLNet.IPath>

Hello,

I encountered a potential bug using MCDiscreteArithmeticAPEngine as follows:

DateTime timer = DateTime.Now;

// set up dates
Calendar calendar = new TARGET();
Date todaysDate = new Date(1, Month.January, 2017);
Date settlementDate = new Date(1, Month.January, 2017);
Date maturity = new Date(17, Month.May, 2018);
Settings.setEvaluationDate(todaysDate);

// our options
Option.Type type = Option.Type.Call;
double underlying = 100;
double strike = 100;
double dividendYield = 0.00;
double riskFreeRate = 0.06;
double volatility = 0.20;
            
DayCounter dayCounter = new Actual365Fixed();
Exercise europeanExercise = new EuropeanExercise(maturity);

double? accumulator = underlying;
int? pastfixingcount = 1;
List<Date> fixings = new List<Date>();
fixings.Add(new Date(1, 1, 2018));

Handle<Quote> underlyingH = new Handle<Quote>(new SimpleQuote(underlying));
// bootstrap the yield/dividend/vol curves
var flatTermStructure = new Handle<YieldTermStructure>(new FlatForward(settlementDate, riskFreeRate, dayCounter));
var flatDividendTS = new Handle<YieldTermStructure>(new FlatForward(settlementDate, dividendYield, dayCounter));
var flatVolTS = new Handle<BlackVolTermStructure>(new BlackConstantVol(settlementDate, calendar, volatility, dayCounter));
StrikedTypePayoff payoff = new PlainVanillaPayoff(type, strike);
var bsmProcess = new BlackScholesMertonProcess(underlyingH, flatDividendTS, flatTermStructure, flatVolTS);

// options
VanillaOption europeanOption = new VanillaOption(payoff, europeanExercise);
PlainVanillaPayoff callpayoff = new PlainVanillaPayoff(type, strike);

DiscreteAveragingAsianOption asianoption = new DiscreteAveragingAsianOption(
    Average.Type.Arithmetic,
    accumulator, 
    pastfixingcount, 
    fixings, 
    callpayoff, 
    europeanExercise);

int minSamples = 10000;
int maxSamples = 10000;
ulong seed = 42;
double tolerance = 1.0;

var pricingengine = new MCDiscreteArithmeticAPEngine<PseudoRandom, GeneralStatistics>(
    bsmProcess,
    252,
    false,
    false,
    false,
    minSamples,
    tolerance,
    maxSamples,
    seed);

asianoption.setPricingEngine(pricingengine);

double price = asianoption.NPV();

which gives me the following error:

System.InvalidCastException: Cannot convert object of type QLNet.ArithmeticAPOPathPricer to Type QLNet.PathPricer<QLNet.IPath>

and pops at the following line:
https://github.com/amaggiulli/QLNet/blob/develop/QLNet/Pricingengines/asian/mc_discr_arith_av_price.cs#L68
It seems that Upcasting generic types does not work in C# (you have to copy the object somehow) and thus is a language issue, also explained here:
http://stackoverflow.com/questions/23145117/upcasting-generics

Best,
Mario

Date.daysBetween return wrong result

Hi all,

In the file Date.cs at line 68, the current implementation of static method daysBetweenDate is

public static double daysBetween(Date d1, Date d2) 
{
    double days = d2 - d1;
    return days + d2.fractionOfDay() - d1.fractionOfDay();
}

In my opinion the correct implementation should be:

public static double daysBetween(Date d1, Date d2) 
{
    return (d2.date - d1.date).TotalDays;
}

To illustrate the error of the current implementation, here is a correction in the current implementation (same result as the one proposed above):

public static double daysBetween(Date d1, Date d2) 
{
    double days = d2 - d1;
    double fraction = d2.fractionOfDay() - d1.fractionOfDay();
    if (fraction < 0.0)
        days++;

    return days + d2.fractionOfDay() - d1.fractionOfDay();
}

Otherwise it won't work for dates where d2 time part is earlier in the day than d1 time part. A good example is:

d1 = new Date(new DateTime(2016, 1, 1, 18, 0, 0));
d2 = new Date(new DateTime(2016, 1, 2, 0, 0, 0));

Expected result is: 0.25 but we currently get -0.75

What do you think?

Cheers.

BackwardFlat interpolation

Hi,

In qlnet/QLNet/Math/Interpolations/backwardflatinterpolation.cs line 73
shouldn't that be:
return new BackwardFlatInterpolation(xBegin, size, yBegin);

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.