Sunday 24 June 2012

QuantLib on iPad - a working example


I've posted a working copy of an xcode project on github that demonstrates using QuantLib in an Objective-C iPad application without exposing the C++ interface to the GUI. It uses the previously described PIMPL idiom built using the boost and QuantLib frameworks.
It's not pretty, but the objective of the project is to show how to interface an Objective-C GUI with QuantLib.

However, it's dull work. Writing an interface from scratch that converts between QuantLib types and Objective-C objects and types is time consuming. Fortunately, QuantLib defines a lot of types ultimately as native C++ types, so conversion is straightforward. There is just potentially a lot of it. Dates proved to be the most involved in the example, but I've always found date handling using NSDate and NSDateFormatters to be long-winded anyway. I expect anyone using QuantLib from another language without using SWIG will end up writing a lot of glue conversion code and putting it in a library.

The interface does not bear any resemblance to what is going on under the covers as it is very high level. I don't think that this is a bad thing, the interface provides mutators and a price method to price the FX Vanilla Swap that matches the GUI. Anything more complicated in would expose more of the QuantLib internals. This was just enough.

@interface FXVanillaSwapPricer : NSObject {
}


- (double) price;


// mutators - note that we don't create properties or mutators for the
// QuantLib data members else we will expose them to the rest of the
// Objective-C application that defeats the object of PIMPL.
//
// Instead we create use a facade-style interface and convert the
// Objective-C types to QuantLib types.
//
// For this example we do it in the maturity mutator only. See the .mm
// file for more information.


@property (nonatomic) double quote;
@property (nonatomic) double strikePrice;
@property (nonatomic) double foreignRate;
@property (nonatomic) double domesticRate;
@property (nonatomic) double volatility;
@property (strong, nonatomic) NSDate *today;
@property (strong, nonatomic) NSDate *settlement;


- (NSDate *) maturity;
- (void) setMaturity:(NSDate *) newMaturity;

All the work to create the yield term structures and pricing engine is hidden. In the interface above I have hand coded the maturity mutators. This is to demonstrate the type of work that you would need to do if you wanted to convert from Objective-C to QuantLib types when passing around values.

// example mutator methods to show how what is involved in
// interfacing between objective-c and C++ - the price method
// pulls in the maturity, but these show the sort of conversions
// that would need to be done if you wanted to fully expand the
// mutators in the Objective-C++ class.


- (NSDate *) maturity
{
    NSLog(@"Maturity get mutator called");
    
    // convert the QuantLib::Date to NSDate using a Date
    // Formatter it helps that the QuantLib day/month/year are
    // defined as ints so the compiler does the implicit
    // conversions for us
    
    QuantLib::Day day = _maturity.dayOfMonth();
    QuantLib::Month month = _maturity.month();
    QuantLib::Year year = _maturity.year();
    
    NSString * dateString = [[NSString alloc]
        initWithFormat:@"%d-%02d-%02d", year, month, day];
    NSDateFormatter * dateFormatter =
        [[NSDateFormatter alloc] init];
    [dateFormatter setDateFormat:@"yyyy-MM-dd"];
    
    NSLog(@"maturity day %@", dateString);
    
    NSDate * date = [dateFormatter dateFromString:dateString];
    
    return date;
}
- (void) setMaturity:(NSDate *) newMaturity
{
    NSLog(@"Maturity set mutator called");
    
    // convert the maturity date from an NSDate to a
    // QuantLib::Date
    
    NSDateFormatter *dateFormatter =
        [[NSDateFormatter alloc]init];
    dateFormatter.dateFormat = @"dd";
    NSString *dayString =
        [dateFormatter stringFromDate: newMaturity];
    dateFormatter.dateFormat = @"MM";
    NSString *monthString =
        [dateFormatter stringFromDate: newMaturity];
    dateFormatter.dateFormat = @"YYYY";
    NSString *yearString =
        [dateFormatter stringFromDate: newMaturity];
    
    NSLog(@"maturity day %@ month %@ year %@",
        dayString, monthString, yearString);
    
    QuantLib::Day day = [dayString intValue];
    QuantLib::Month month = intToQLMonth([monthString intValue]);
    QuantLib::Year year = [yearString intValue];
    
    _maturity = Date(day, month, year);
      
    // no need to set the maturity here
    // maturity = newMaturity;
}

These are then called using standard Objective-C callbacks from the GUI.

- (IBAction)maturityChanged:(UIDatePicker *)sender
{
    NSDate *date = [sender date];
    
    NSLog(@"maturityChanged %@", date);
    
    [fxvanillaswappricer setMaturity:date];
}

The pricing object is defined in the view as:

fxvanillaswappricer = [[FXVanillaSwapPricer alloc] init];

Again, this makes sense as the GUI that the user interacts with does not display yields, etc. I expect that if the user wanted to do this, then the interface would change to accomodate the requirement and the price method would grow or be split up to accomodate this.

The rest of the example application lets xcode do the work in creating the mutators. I define the QuantLib attributes in the interface:

@interface FXVanillaSwapPricer ()
{  
    QuantLib::Real _S;         // simple quote value
    QuantLib::Real _K;         // strike price
    QuantLib::Spread _f;       // Foreign rate
    QuantLib::Rate _r;         // Domestic rate
    QuantLib::Volatility _vol; // volatility
    QuantLib::Date _maturity;
    QuantLib::Date _todaysDate;
    QuantLib::Date _settlementDate;
    
    NSDate * maturity;
}
@end

And then copy the data at the start of the price method. A little lazy, but the point was to demonstrate techniques.

- (double) price
{
    using namespace QuantLib;
    
    QuantLib::DayCounter _dayCounter = Actual365Fixed();
    
    // get the parameters used to generate the price
    // if we hand crafted the mutators like the maturity example
    // we would not need to do this
    
    _S = quote;
    _K = strikePrice;
    _f = foreignRate;
    _r = domesticRate;
    _vol = volatility;


... etc

return npv;
}

If I was writing a more complicated application, I would need to make a decision on how to do this. Either to convert the Objective-C types into QuantLib types in the mutators and store them in the object (as above), or store them as Objective-C types and convert them before I wanted to use them. The application shows a hybrid approach for both techniques.

The swap price is displayed using a text field that is updated when the "calculate" button is pressed.

- (IBAction)calculate:(UIButton *)sender
{
    NSLog(@"calculate");
    double npv;
    npv = [fxvanillaswappricer price];
    [price setText:[NSString stringWithFormat:@"%2.6f", npv]];
}

It's a very basic application that hopefully provides pointers for how to call QuantLib on iOS.

No comments:

Post a Comment