代码改变世界

QuantLib 101之Swap

2010-10-01 15:03  xxmplus  阅读(961)  评论(0编辑  收藏  举报

所谓的swap(掉期交易)是指两家公司相互交换未来现金流的协议,这份协议定义了现金流支付的日期以及计算的方法,通常现金流的计算会涉及利率、汇率,或者其他市场变量的预期值。

(例1)远期合约是一种简单形式的swap。比如,在2009年3月1日,公司A以900美元/盎司的价格买入100盎司的一年远期黄金。它可以在收到这一年期黄金的时候立即抛出。这样的远期合约就相当于是一个swap,即这家公司同意它会在2010年3月1日支付90000美元并收到100S美元,这里的S是2010年3月1日这一天一盎司黄金的市场单价。

远期合约相当于在未来的某一天交换现金流,而swap通常会在多个未来日子进行交换。

最常见的swap类型是所谓的“plain vanilla” interest rate swap,利率掉期交易。公司A同意以固定利率在几年之内为一定的本金支付现金流(也就是利息),作为回报,它会在同样时期内得到同样本金上浮动利率的现金流。绝大多数利率掉期采用的浮动利率都是伦敦同业拆放利率(LIBOR)。LIBOR是国际金融市场上借贷的参考利率,通常LIBOR会以各大主要货币的形式提供1、3、6、12个月的利率。比如(例2),一个5年期的债券可以规定其票息率为6个月的LIBOR加0.5%年息。这样,这个债券就被分成十个阶段,利率是每个阶段一开始时6个月LIBOR利率加0.5%年息,并在这个阶段结束时支付。

(例3)假设微软和英特尔在2007年3月5日设立了一个3年的swap。微软答应以一亿美元(100million)为本金principal,向英特尔支付5%的年息,作为回报,英特尔答应向微软支付以同数额为本金的LIBOR利率,每半年支付一次。在这里微软是固定利率支付方fixed-rate payer,而英特尔是浮动利率支付方floating-rate payer。这样,第一次支付日期将是2007年9月5日,微软要支付的金额是2.5million,英特尔要支付的是这个日期的六个月之前的LIBOR利率,假设为4.2%,因此就是0.5*0.042*100million = 2.1million。注意这次付款金额是确定的,因为在签订合约的时候,LIBOR就已经确定下来了。第二次支付日期是2008年3月5日,微软要支付2.5million,英特尔要支付2007年9月5日的LIBOR利率,假设为4.8%,因此是0.5*0.048*100million = 2.4million。如此一共要支付6次。注意,本金在这里只是名义上的(notional),双方并不会真的支付它们。这个swap也可以看作是固定利率债券和浮动利率债券的交换。

因此,swap可以将浮动利率的现金流和固定利率的现金流对调,让双方规避风险或者最大化利益。通常会有一个中间商(比如银行)从中协调并抽取佣金,同时承担其中一方无法履行合约的风险。由于不同信用评级的公司/国家在国际市场上借贷时的利率是不一样的,因此swap可以帮助交换双方找到最适合自己的方式。

 

#include <ql/instrument.hpp>
#include <ql/cashflow.hpp>

class Event : public Observable {
public:
    virtual ~Event() {}
    virtual Date date() const = 0;
    // 若event在date之前发生则返回true。如果includeRefDate为真,那么在date等于refDate的情况下,认为event未发生,即返回false
    virtual bool hasOccurred(const Date &refDate = Date(), boost::optional<bool> includeRefDate = boost::none) const;
    virtual void accept(AcyclicVisitor&);
};

class CashFlow : public Event {
public:
    virtual ~CashFlow() {}
    virtual Date date() const = 0;
    virtual bool hasOccurred(const Date &refDate = Date(), boost::optional<bool> includeRefDate = boost::none) const;
    // this is the amount paid on the cash flow date, it is not discounted.
    virtual Real amount() const = 0;
    virtual void accept(AcyclicVisitor&);
};

typedef std::vector<boost::shared_ptr<CashFlow> > Leg;

class Swap : public Instrument {
public:
    class arguments;
    class results;
    class engine;

    // first leg's cash flows are paid, while the second leg's cash flows are received.
    Swap(const Leg &firstLeg, const Leg &secondLeg);
    Swap(const std::vector<Leg> &legs, const std::vector<bool> &payer);

    bool isExpired() const;
    void setupArguments(PricingEngine::arguments*) const;
    void fetchResults(const PricingEngine::results*) const;

    Date startDate() const;
    Date maturityDate() const;
    Real legBPS(Size j) const {
        QL_REQUIRE(j<legs_.size(), "leg# "<<j<<" doesn't exist!");
        calculate();
        return legBPS_[j];
    }
    Real legNPV(Size j) const {
        QL_REQUIRE(j<legs_.size(), "leg# "<<j<<" doesn't exist!");
        calculate();
        return legNPV_[j];        
    }
    const Leg& leg(Size j) const {
        QL_REQUIRE(j<legs_.size(), "leg# "<<j<<" doesn't exist!");
        return legs_[j];
    }
protected:
    Swap(Size legs);
    void setupExpired() const;

    std::vector<Leg> legs_;
    std::vector<Real> payer_;
    mutable std::vector<Real> legNPV_;
    mutable std::vector<Real> legBPS_;
};

class Swap::arguments : public virtual PricingEngine::arguments {
public:
    std::vector<Leg> legs;
    std::vector<Real> payer;
    void validate() const;
};

class Swap::results : public Instrument::results {
public:
    std::vector<Real> legNPV;
    std::vector<Real> legBPS;
    void reset();
};

class Swap::engine : public GenericEngine<Swap::arguments, Swap::results> {};

 

  • 这里的CashFlow是Visitor模式的client,具体关于Acyclic Visitor的信息可以在这里找到。

// 首先将Swap注册成为两条Leg的observer,这样在它们发生变化的时候就可以触发重新计算
Swap::Swap(const Leg& firstLeg, const Leg& secondLeg) : legs_(2), payer_(2), legNPV_(2, 0.0), legBPS_(2, 0.0) {
    legs_[0] = firstLeg;
    legs_[1] = secondLeg;
    payer_[0] = -1.0;
    payer_[1] =  1.0;
    for (Leg::iterator i = legs_[0].begin(); i!= legs_[0].end(); ++i)
        registerWith(*i);
    for (Leg::iterator i = legs_[1].begin(); i!= legs_[1].end(); ++i)
        registerWith(*i);
}

// 只要Leg里有CashFlow还未发生,那么就返回false表示没有过期。
bool Swap::isExpired() const {
    for (Size j=0; j<legs_.size(); ++j) {
        Leg::const_iterator i;
        for (i = legs_[j].begin(); i!= legs_[j].end(); ++i)
            if (!(*i)->hasOccurred())
                return false;
    }
    return true;
}

void Swap::setupExpired() const {
    Instrument::setupExpired();
    std::fill(legBPS_.begin(), legBPS_.end(), 0.0);
    std::fill(legNPV_.begin(), legNPV_.end(), 0.0);
}


cont.