未来是一枚失落的指针,往昔是一片无法删除的内存

Wednesday, 16 January 2008

Vanilla Interest Rate Derivatives (2)

Range Accrual Note (RAN)

A range accrual note (RAN) is similar to a fixed rate bond, except that interest only accrues on days when a reference rate falls within a specified range. So its payoff depends on the volatility of the reference rate: the lower the reference rate's volatility is, the higher the RAN's payoff is.

Suppose that in a RAN, the fixed rate is fix, and the reference rate is R_{ref}. The reference rate R_{ref} is observed every day during a cash flow period, and is tested against the specified range [L, U]. Define n as the number of days in the period when (L < R_{ref} < U), and N as the total number of days in the period. The payoff rate of the RAN is given by the following formula:

R_{payoff} = fix * (n / N)


If we replace the fixed rate fix by a leveraged floating rate (L * R + fix), where R is a floating rate, and the leverage L and the fixed rate fix are both constant, we can obtain a floating rate range accrual note. Its payoff rate is given by the following formula:

R_{payoff} = (L * R + fix) * (n / N)


Range Accrual Spread Note (SRAN)

In a range accrual note, if we replace the reference rate R_{ref} by a spread of two reference rates (R1 - R2), we can obtain a range accrual spread note (SRAN). In a SRAN, the condition to check is (L < R1 - R2 < U).

Dual Range Accrual Spread Note

A dual range accrual spread note is a range accrual note where the condition to check is based on two reference spreads (R11 - R12) and (R21 - R22), and two ranges [L1, U1] and [L2, U2]: ((L1 < R11 - R12 < U1) and (L2 < R21 - R22 < U2)).

Vanilla Interest Rate Derivatives (1)

Function Definitions

TODO: define some functions such as min, max, bound, etc.

Interest Rate Cap, Floor and Straddle

An interest rate cap is a derivative in which the buyer receives money at the end of each cash flow period in which the specified floating rate R exceeds the agreed strike price K. An example of a cap would be an agreement to receive money for each month the LIBOR rate exceeds 2.5%.

The interest rate cap can be analyzed as a series of European call options or caplets which exists for each cash flow period the cap agreement is in existence. In formulas, the caplet rate that will be applied on the notional for a cash flow period is:

R_{payoff} = max(R - K, 0)


Where R is the underlying floating rate, and K is the cap strike.

An interest rate floor is a series of European put options or floorlets on a specified floating rate R. The buyer of the floor receives money if on the maturity of any of the floorlets, the fixed floating rate R is below the agreed strike K of the floor. In formulas, the floorlet rate that will be applied on the notional for a cash flow period is:

R_{payoff} = max(K - R, 0)


An interest rate straddle is a portfolio of an interest rate cap and an interest rate floor on the same floating rate R with the same strike K. The payoff rate of a straddle cash flow (a straddle-let) is:

R_{payoff} = max(R - K, 0) + max(K - R, 0) = abs(R - K)


An interest rate straddle can be replicated by a portfolio of an interest rate cap and an interest rate floor.

Leveraged Cap/Floor

A capped/floored floating rate is a floating rate R with an upper bound U and a lower bound L. The payoff rate of the capped/floored floating rate is:


R_{payoff} = bound(R, L, U)
= U (if R > U), or
R (if L <= R <= U), or
L (if R < L)


We can re-write the formula above as the following:

R_{payoff} = R + max(L - R, 0) - max(R - U, 0)


So, the capped/floored payoff rate may be replicated using a portfolio of:

- +1 floating rate R,
- +1 floor on the floating rate R with a strike of L,
- -1 cap on the floating rate R with a strike of U.

In a capped/floored floating rate, if we replace the underlying floating rate R by a structured rate (L * R + fix), where the leverage L and the fixed rate fix are constants, we can obtain a leveraged cap/floor. The payoff rate is:

R_{payoff} = bound(L * R + fix, L, U)


The payoff rate may be replicated using a portfolio of:

- +1 leveraged floating rate R', where R' = L * R + fix,
- +1 floor on the leveraged floating rate R' with a strike of L,
- -1 cap on the leveraged floating rate R' with a strike of U.

Leveraged Spread Cap/Floor

In a capped/floored floating rate, if we replace the underlying floating rate R by a leveraged spread (L * (L1 * R1 - L2 * R2) + fix), where R1 and R2 are two floating rates (such as 3-month LIBOR and 6-month LIBOR), and the leverages L, L1, L2, and the fixed rate fix are constants, we can obtain a leveraged spread cap/floor. The payoff rate is:

R_{payoff} = bound(L * (L1 * R1 - L2 * R2) + fix, L, U)


Digit Cap/Floor

The payoff rates of a digit cap and a digit floor are defined by the following formulas:


For digit cap:
R_{payoff} = fix (if R > K), or
0 (otherwise)
For digit floor:
R_{payoff} = fix (if R < K), or
0 (otherwise)


By using a proper epsilon e which is small enough, we can approximately replicate a digit cap using:

- +(fix/2e) cap on the floating rate R with a strike of (K - e),
- -(fix/2e) cap on the floating rate R with a strike of (K + e).

We can approximately replicate a digit floor the same way, using:

- +(fix/2e) floor on the floating rate R with a strike of (K + e),
- -(fix/2e) floor on the floating rate R with a strike of (K - e).

Barrier Cap/Floor

There are four types of barrier cap/floor: cap-up-and-in, cap-up-and-out, floor-down-and-in, and floor-down-and-out. Their payoff rates are
defined by the following furmulas:


For cap-up-and-in:
R_{payoff} = max(R - K, 0) (if R < B), or
0 (otherwise)
For cap-up-and-out:
R_{payoff} = max(R - K, 0) (if R > B), or
0 (otherwise)
For floor-down-and-in:
R_{payoff} = max(K - R, 0) (if R < B), or
0 (otherwise)
For floor-down-and-out:
R_{payoff} = max(K - R, 0) (if R > B), or
0 (otherwise)


Where R is the floating rate, K is the strike, and B is the barrier. In a barrier cap, the barrier should be greater than the strike (B > K). In a barrier floor, the barrier should be less than the strike (B < K).

We can use the following portfolio to replicate a cap-up-and-in:

- +1 cap on the floating rate R with a strike of K,
- -1 digit cap on the floating rate R with a strike of B and a fixed rate of (B - K),
- -1 cap on the floating rate R with a strike of B.

Since a portfolio of a cap-up-and-in and a cap-up-and-out on the same floating rate R with the same strike K and the same barrier B gives the payoff of a cap on the floating rate R with the strike K, we can replicate a cap-up-and-out using the following portfolio:

- +1 cap on the floating rate R with a strike of K,
- -1 cap-up-and-in on the floating rate R with a strike of K and a barrier of B.

We can use the following portfolio to replicate a floor-down-and-out:

- +1 floor on the floating rate R with a strike of K,
- -1 digit floor on the floating rate R with a strike of B and a fixed rate of (K - B),
- -1 floor on the floating rate R with a strike of B.

And the following portfolio to replicate a floor-down-and-in:

- +1 floor on the floating rate R with a strike of K,
- -1 floor-down-and-out on the floating rate R with a strike of K and a barrier of B.

Tuesday, 8 January 2008

Boost Tokenizer笔记

Boost Tokenizer模板类

先看boost::tokenizer模板类的声明:

// boost::tokenizer template class.
template<
class TokenizerFunc = char_delimiters_separator<char>,
class Iterator = std::string::const_iterator,
class Type = std::string
> class tokenizer;


boost::tokenizer模板类的第一个模板参数TokenizerFunc是一个方法对象,用于对序列进行语法分析,以寻找token。第二个模板参数Iterator定义了被分析的序列的iterator类型。第三个模板参数Type定义了序列容器的类型。默认情况下,boost::tokenizer用于分析字符串序列,所以Iterator的默认类型是std::string::const_iterator,而Type的默认类型是std::string。

TokenizerFunc

根据Boost Tokenizer的文档:TokenizerFunc是一个方法对象(functor),它的作用是对一个给定的序列进行语法分析,直到找到了一个token为止,或者直到序列结束为止。

A TokenizerFunction is a functor whose purpose is to parse a given sequence until exactly 1 token has been found or the end is reached. It then updates the token, and informs the caller of the location in the sequence of the next element immediately after the last element of the sequence that was parsed for the current token.

TODO: How to implement a customized tokenizer func?

Boost Tokenizer库中提供了三个实现好的TokenizerFunc:

- escaped_list_separator
- offset_separator
- char_delimiters_separator

Char Delimiters Separator

boost::char_delimiters_separator使用单个字符作为token的分隔符。分隔符分为两类:返回型分隔符和非返回型分隔符。以下解释这两类分隔符的区别。

假设我们需要tokenize一个用于表示方程组的字符串,如下:

x + y = 100; x-y=10;


我们希望获得的token是:

token[0] = "x"
token[1] = "+"
token[2] = "y"
token[3] = "="
token[4] = "100"
token[5] = "x"
token[6] = "-"
token[7] = "y"
token[8] = "="
token[9] = "10"


在这种情况下,字符';'和空格字符的作用仅仅是分隔token,它们本身并不是token,因此它们是非返回型分隔符,不会被tokenizer作为一个token返回;而字符'+','-'和'='的作用不仅是分隔token,它们本身也是token,因此它们属于返回型分隔符,会被tokenizer作为一个token返回。

boost::char_delimiters_separator的构造函数声明如下:

// boost::char_delimiters_separator template class.
template<class Char, class Traits = std::char_traits<Char> >
class char_delimiters_separator {
public:
// ...
explicit char_delimiters_separator(
bool return_delims = false,
const Char* returnable = "",
const Char* nonreturnable = "");
//...
};


第一个参数return_delims决定了是否某些分隔符可以作为token被返回,注意它的默认值是false。第二个参数returnable定义了一组返回型的分隔符,注意仅当第一个参数的值为true时,这些返回型的分隔符才会被作为token返回。第三个参数nonreturnable定义了一组非返回型的分隔符。

以下代码使用了boost::tokenizer来分析上述表示方程组的字符串,并获得我们期望的结果:


#include <boost/tokenizer.hpp>
#include <string>
#include <iostream>

int main(int, char**) {
typedef boost::char_delimiters_separator<char> separator;
typedef boost::tokenizer<Separator> tokenizer;
std::string str = "x + y = 100; x-y=10;";
separator sep(true, "+-=", " ;");
tokenizer tok(str, sep);
unsigned int count = 0;
for (tokenizer::iterator i = tok.begin();
i != tok.end();
++i, ++count) {
std::cout << "token[" << count << "] = "
<< (*i) << std::endl;
}
return 0;
}


TODO: How to use escaped_list_separator and offset_separator?

Saturday, 5 January 2008

Pimpl的const成员函数

先给一个pimpl的例子:

////////////////////////////////////////////////////////////
// person.hpp: pimpl class header file.
//

#include <string>

class person {

public:
explicit person();
~person();
const std::string& first_name() const;
const std::string& last_name() const;
void set_name(const std::string& first_name,
const std::string& last_name);

private:
struct impl; // forward declaration.
impl* pimpl_; // pointer to impl.
}; // class person

////////////////////////////////////////////////////////////
// person.cpp: pimpl class source file.
//

#include "person.hpp"
#include <string>

struct person::impl {
std::string first_name_;
std::string last_name_;
explicit impl(): first_name_(), last_name() {
// Do nothing.
}
};

person::person(): pimpl_(new impl()) {
// Do nothing.
}

person::~person() {
delete pimpl_;
}

const std::string& person::first_name() const {
return pimpl_->first_name_;
}

const std::string& person::last_name() const {
return pimpl_->last_name_;
}

void person::set_name(const std::string& first_name,
const std::string& last_name) {
pimpl_->first_name_ = first_name;
pimpl_->last_name_ = last_name;
}


注意person类的两个const成员函数first_name()和last_name(),因为被标记为const,所以这两个成员函数应该不能修改person对象的内部状态。

在C++中,每一个成员函数都拥有一个隐含的参数,即指向对象的this指针。对于一个const成员函数,this是一个被const了的指针。在没有使用pimpl的时候,如果我们试图(通过const的this指针)修改对象的状态,将产生一个编译错误。在这种情况下,编译器很体贴地帮我们保证了const成员函数语义的正确性。

可是注意,当我们使用了pimpl的时候,我们就失去了编译器这样的关怀。假设我们这样实现first_name()成员函数:

// Const member function is no longer that "const"...
const std::string& person::first_name() const {
pimpl_->first_name_ = "Whatever"; // Note this assignment!
return pimpl_->first_name_;
}


这段代码可以很顺利地通过编译,连一个警告都不会有。为什么?因为对于一个指向const person类型的this指针,它const的其实是pimpl_指针的地址,而不是pimpl_所指向的那个对象。也就是说,编译器只能帮我们保证在实现person的const成员函数的时候无法修改pimpl_的地址值,却无法为我们保证我们不去修改pimpl_所指向的person::impl对象的内容。

失去了编译器的检查,就增加了我们写出语义错误的代码的可能性。对此,我们可以通过如下的规范来重新获得编译器的这种关怀。

第一,在person.hpp头文件中为person类增加两个private成员函数,如下:

////////////////////////////////////////////////////////////
// person.hpp: pimpl class header file.
//

class person {

// ...

private:
struct impl; // forward declaration.
const impl* pimpl() const {
return pimpl_;
}
impl* pimpl() {
return pimpl_;
}
impl* pimpl_;
};


第二,在实现person的成员函数时,每当我们需要使用pimpl_指针,总是通过调用pimpl()成员函数来获得:

////////////////////////////////////////////////////////////
// person.cpp: pimpl class source file.
//

// ...

const std::string& person::first_name() const {
// Won't compile any more if we keep using pimpl().
// pimpl()->first_name_ = "Whatever";
return pimpl()->first_name_;
}

const std::string& person::last_name() const {
return pimpl()->last_name_;
}

void person::set_name(const std::string& first_name,
const std::string& last_name) {
pimpl()->first_name_ = first_name;
pimpl()->last_name_ = last_name;
}

Wednesday, 2 January 2008

Boost Multi-index笔记

Boost Multi-index介绍

注意: 为了在MSVC7.1下顺利编译boost multi-index,需要关掉/Gm选项(C/C++ | Code Generation | Enable Minimal Rebuild)。否则可能会产生Buffer Overrun错误。详情请参考Boost Multi-index文档

不同的STL容器用不同的方法来管理自己的元素,提供不同的访问元素的方法。比如,std::set通过一个比较函数来为元素排序,std::list则允许用户自由地制定插入元素的位置。某些情况下,对于同一个元素集合,用户会希望拥有不同的访问接口,这有点类似于MVC模式中的Model和View:同一个Model拥有不同的View。Boost multi-index就是用来满足这样的需求的。

举例说明。比如我创建了一个Employee类来为公司员工建模:

#include <string>
#include <iostream>

//! The employee class...
class employee {

public:

//! Default constructor.
explicit employee(): id_(), email_(), name_() {
// Do nothing.
}

explicit employee(const std::string& id,
const std::string& email,
const std::string& name)
: id_(id), email_(email), name_(name) {
// Do nothing.
}

// Use auto-generated copy constructor.
// Use auto-generated copy assignment.
// Use auto-generated destructor.

bool operator<(const employee& rhs) const {
return (id_ < rhs.id_);
}

public:

std::string id_; // Unique ID.
std::string email_; // Unique email address.
std::string name_; // Name.

}; // class employee

//! Writes an employee information to the output stream.
std::ostream& operator<<(std::ostream& os,
const employee& e) {
os << "Employee #" << e.id_
<< " : " << e.name_
<< " ( " << e.email_ << " ) ";
return os;
}

//! Compares two employees by their names.
struct comp_name {
// TODO:
};


我希望拥有一个员工对象的集合,该集合提供了以下几种不同的访问员工对象的方式:

- 按照元素插入的顺序提供顺序访问(类似std::list)。
- 按照employee自己的比较函数(比较id_)排序,提供顺序访问(类似std::set)。
- 按照name_排序(使用CompName比较函数),提供顺序访问(类似std::set)。
- 以id_为key访问对象(类似std::map)。
- 以email_为key访问对象(类似std::map)。

容器的模型和视图

Boost multi-index中的容器模型使用boost::multi_index::multi_index_container模板类来描述,而与容器模型相联系的每个视图都由一个index类型来描述。Index类型可以被划分为以下两大类:

- Unique:不允许出现拥有相同键值的两个或多个元素。
- Non-unique:允许两个或多个元素拥有相同的键值。

对应于以上的需求,可以这样定义容器的模型:

namespace bmi = boost::multi_index; // namespace alias

//! Typedef of the multi-index container model.
typedef bmi::multi_index_container<
employee, // the element type...
bmi::indexed_by< // views for this container...
// index #0: sequenced
bmi::sequenced<>,
// index #1: sort by employee::operator<
bmi::ordered_unique<bmi::identity<employee> >,
// index #2: sort by std::less<std::string> on name_
bmi::ordered_non_unique<
bmi::member<employee,
std::string,
&employee::name_> >
> // end of bmi::indexed_by
> employee_set;


对于一个employee_set容器,可以通过指定下标的方法获得不同的index视图:

//! Typedef of the sequenced index.
typedef employee_set::nth_index<0>::type sequenced_index;

//! Typedef of the built-in less-than index.
typedef employee_set::nth_index<1>::type less_than_index;

//! Typedef of the name index.
typedef employee_set::nth_index<2>::type name_index;

//! Returns the sequenced index of the underlying set.
sequenced_index& get_sequenced_index(employee_set& es) {
return es.get<0>(); // index #0
}

//! Returns the less-than index of the underlying set.
less_than_index& get_less_than_index(employee_set& es) {
return es.get<1>(); // index #1
}

//! Returns the name index of the underlying set.
name_index& get_name_index(employee_set& es) {
return es.get<2>(); // index #2
}


注意:容器模型的视图需要通过引用传递,而不可以通过值拷贝。

使用Tag来标记Index

容器模型自身的成员函数

通过Index插入元素的方法

通过Index遍历元素的方法

每个一个index视图(sequenced_index,less_than_index和name_index)都提供自己的iterator和const_iterator类型,它们按照各个视图所定义的顺序来遍历容器中的元素。以下代码演示了如何通过index的const_iterator来遍历容器中的元素:

//! Iterates through all employees.
template<class Index>
void write_by(const Index& index) {
for (Index::const_iterator i = index.begin();
i != index.end(); ++i) {
std::cout << (*i) << std::endl;
}
}

//! Iterates through all employees using different index.
void test_index_iterators() {
// Populate employees to the container.
employee_set es = ...;
// Iterate through employees using different index.
write_by(get_sequenced_index(es));
write_by(get_less_than_index(es));
write_by(get_name_index(es));
}


为什么没有index提供std::vector那样的[]操作符和at()函数?在没有读过boost multi-index源代码的情况下,我的理解是:在STL中,std::vector是一种很特殊的容器,它是唯一一个使用连续内存存储元素的容器(所以它可以和C语言中的数组兼容)。由于它的这种实现方法,使得[]操作符和at()函数的实现可以非常高效。而对于任何一种其它的STL容器而言,这种随机存取的方法实现起来都太昂贵了。Boost multi-index中的容器应该没有使用连续内存来存储元素,所以它也不会提供这种随机存取元素的方法。

通过Index查找元素的方法

TODO:

- How to insert elements.
- How to look up elements (find).
- How to tag an index.
- Common functions in multi_index_container.
- How to use customized comparator.
- identity: should operator equals (==) be implemented?