1 /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*
4  Copyright (C) 2006 Joseph Wang
5  Copyright (C) 2010 Liquidnet Holdings, Inc.
6 
7  This file is part of QuantLib, a free-software/open-source library
8  for financial quantitative analysts and developers - http://quantlib.org/
9 
10  QuantLib is free software: you can redistribute it and/or modify it
11  under the terms of the QuantLib license.  You should have received a
12  copy of the license along with this program; if not, please email
13  <quantlib-dev@lists.sf.net>. The license is also available online at
14  <http://quantlib.org/license.shtml>.
15 
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the license for more details.
19 */
20 
21 /*! \file timeseries.hpp
22     \brief Container for historical data
23 */
24 
25 #ifndef quantlib_timeseries_hpp
26 #define quantlib_timeseries_hpp
27 
28 #include <ql/time/date.hpp>
29 #include <ql/utilities/null.hpp>
30 #include <ql/errors.hpp>
31 #include <ql/functional.hpp>
32 #include <boost/iterator/transform_iterator.hpp>
33 #include <boost/iterator/reverse_iterator.hpp>
34 #include <boost/utility.hpp>
35 #include <map>
36 #include <vector>
37 
38 namespace QuantLib {
39 
40     //! Container for historical data
41     /*! This class acts as a generic repository for a set of
42         historical data.  Any single datum can be accessed through its
43         date, while sets of consecutive data can be accessed through
44         iterators.
45 
46         \pre The <c>Container</c> type must satisfy the requirements
47              set by the C++ standard for associative containers.
48     */
49     template <class T, class Container = std::map<Date, T> >
50     class TimeSeries {
51       public:
52         typedef Date key_type;
53         typedef T value_type;
54       private:
55         mutable Container values_;
56       public:
57         /*! Default constructor */
TimeSeries()58         TimeSeries() {}
59         /*! This constructor initializes the history with a set of
60             values passed as two sequences, the first containing dates
61             and the second containing corresponding values.
62         */
63         template <class DateIterator, class ValueIterator>
TimeSeries(DateIterator dBegin,DateIterator dEnd,ValueIterator vBegin)64         TimeSeries(DateIterator dBegin, DateIterator dEnd,
65                    ValueIterator vBegin) {
66             while (dBegin != dEnd)
67                 values_[*(dBegin++)] = *(vBegin++);
68         }
69         /*! This constructor initializes the history with a set of
70             values. Such values are assigned to a corresponding number
71             of consecutive dates starting from <b><i>firstDate</i></b>
72             included.
73         */
74         template <class ValueIterator>
TimeSeries(const Date & firstDate,ValueIterator begin,ValueIterator end)75         TimeSeries(const Date& firstDate,
76                    ValueIterator begin, ValueIterator end) {
77             Date d = firstDate;
78             while (begin != end)
79                 values_[d++] = *(begin++);
80         }
81         //! \name Inspectors
82         //@{
83         //! returns the first date for which a historical datum exists
84         Date firstDate() const;
85         //! returns the last date for which a historical datum exists
86         Date lastDate() const;
87         //! returns the number of historical data including null ones
88         Size size() const;
89         //! returns whether the series contains any data
90         bool empty() const;
91         //@}
92         //! \name Historical data access
93         //@{
94         //! returns the (possibly null) datum corresponding to the given date
operator [](const Date & d) const95         T operator[](const Date& d) const {
96             if (values_.find(d) != values_.end())
97                 return values_[d];
98             else
99                 return Null<T>();
100         }
operator [](const Date & d)101         T& operator[](const Date& d) {
102             if (values_.find(d) == values_.end())
103                 values_[d] = Null<T>();
104             return values_[d];
105         }
106         //@}
107 
108         //! \name Iterators
109         //@{
110         typedef typename Container::const_iterator const_iterator;
111         typedef typename const_iterator::iterator_category iterator_category;
112 
113         // Reverse iterators
114         // The following class makes compilation fail for the code
115         // that calls rbegin or rend with a container that does not
116         // support reverse iterators.  All the rest TimeSeries class
117         // features should compile and work for this type of
118         // containers.
119         template <class container, class iterator_category>
120         struct reverse {
121             typedef boost::reverse_iterator<typename container::const_iterator>
122                                                        const_reverse_iterator;
reverseQuantLib::TimeSeries::reverse123             reverse(const container& c) : c_(c) {}
rbeginQuantLib::TimeSeries::reverse124             const_reverse_iterator rbegin() const {
125                 return const_reverse_iterator(c_.end());
126             }
rendQuantLib::TimeSeries::reverse127             const_reverse_iterator rend() const {
128                 return const_reverse_iterator(c_.begin());
129             }
130             const container& c_;
131         };
132 
133         // This class defines reverse iterator features via
134         // container's native calls.
135         template <class container>
136         struct reverse<container, std::bidirectional_iterator_tag> {
137             typedef typename container::const_reverse_iterator
138                                                        const_reverse_iterator;
reverseQuantLib::TimeSeries::reverse139             reverse(const container& c) : c_(c) {}
rbeginQuantLib::TimeSeries::reverse140             const_reverse_iterator rbegin() const { return c_.rbegin(); }
rendQuantLib::TimeSeries::reverse141             const_reverse_iterator rend() const { return c_.rend(); }
142             const container& c_;
143         };
144 
145         // The following typedef enables reverse iterators for
146         // bidirectional_iterator_tag category.
147         typedef typename boost::mpl::if_ <
148             boost::mpl::or_ <
149                 boost::is_same<iterator_category,
150                                std::bidirectional_iterator_tag>,
151                 boost::is_base_of<std::bidirectional_iterator_tag,
152                                   iterator_category> >,
153             std::bidirectional_iterator_tag,
154             std::input_iterator_tag>::type enable_reverse;
155 
156         typedef typename
157         reverse<Container, enable_reverse>::const_reverse_iterator
158                                                        const_reverse_iterator;
159 
160         const_iterator cbegin() const;
161         const_iterator cend() const;
begin() const162         const_iterator begin() const { return cbegin(); }
end() const163         const_iterator end() const { return cend(); }
crbegin() const164         const_reverse_iterator crbegin() const {
165             return reverse<Container, enable_reverse>(values_).rbegin();
166         }
crend() const167         const_reverse_iterator crend() const {
168             return reverse<Container, enable_reverse>(values_).rend();
169         }
rbegin() const170         const_reverse_iterator rbegin() const { return crbegin(); }
rend() const171         const_reverse_iterator rend() const { return crend(); }
172         //@}
173 
174       private:
175         typedef typename Container::value_type container_value_type;
176         typedef ext::function<Date(const container_value_type&)>
177                                                               projection_time;
178         typedef ext::function<T(const container_value_type&)>
179                                                              projection_value;
180 
181       public:
182         //! \name Projection iterators
183         //@{
184 
185         typedef boost::transform_iterator<projection_time, const_iterator>
186                                                           const_time_iterator;
187         typedef boost::transform_iterator<projection_value, const_iterator>
188                                                          const_value_iterator;
189         typedef boost::transform_iterator<projection_time,
190                                           const_reverse_iterator>
191                                                   const_reverse_time_iterator;
192         typedef boost::transform_iterator<projection_value,
193                                           const_reverse_iterator>
194                                                  const_reverse_value_iterator;
195 
cbegin_values() const196         const_value_iterator cbegin_values() const {
197             return const_value_iterator(cbegin(), get_value);
198         }
cend_values() const199         const_value_iterator cend_values() const {
200             return const_value_iterator(cend(), get_value);
201         }
crbegin_values() const202         const_reverse_value_iterator crbegin_values() const {
203             return const_reverse_value_iterator(crbegin(), get_value);
204         }
crend_values() const205         const_reverse_value_iterator crend_values() const {
206             return const_reverse_value_iterator(crend(), get_value);
207         }
208 
cbegin_time() const209         const_time_iterator cbegin_time() const {
210             return const_time_iterator(cbegin(), get_time);
211         }
cend_time() const212         const_time_iterator cend_time() const {
213             return const_time_iterator(cend(), get_time);
214         }
crbegin_time() const215         const_reverse_time_iterator crbegin_time() const {
216             return const_reverse_time_iterator(crbegin(), get_time);
217         }
crend_time() const218         const_reverse_time_iterator crend_time() const {
219             return const_reverse_time_iterator(crend(), get_time);
220         }
221 
222         //! \name Utilities
223         //@{
224         const_iterator find(const Date&);
225         //! returns the dates for which historical data exist
226         std::vector<Date> dates() const;
227         //! returns the historical data
228         std::vector<T> values() const;
229         //@}
230 
231       private:
get_time(const container_value_type & v)232         static const Date& get_time (const container_value_type& v) {
233             return v.first;
234         }
get_value(const container_value_type & v)235         static const T& get_value (const container_value_type& v) {
236             return v.second;
237         }
238     };
239 
240 
241     // inline definitions
242 
243     template <class T, class C>
firstDate() const244     inline Date TimeSeries<T,C>::firstDate() const {
245         QL_REQUIRE(!values_.empty(), "empty timeseries");
246         return values_.begin()->first;
247     }
248 
249     template <class T, class C>
lastDate() const250     inline Date TimeSeries<T,C>::lastDate() const {
251         QL_REQUIRE(!values_.empty(), "empty timeseries");
252         return rbegin()->first;
253     }
254 
255     template <class T, class C>
size() const256     inline Size TimeSeries<T,C>::size() const {
257         return values_.size();
258     }
259 
260     template <class T, class C>
empty() const261     inline bool TimeSeries<T,C>::empty() const {
262         return values_.empty();
263     }
264 
265     template <class T, class C>
266     inline typename TimeSeries<T,C>::const_iterator
cbegin() const267     TimeSeries<T,C>::cbegin() const {
268         return values_.begin();
269     }
270 
271     template <class T, class C>
272     inline typename TimeSeries<T,C>::const_iterator
cend() const273     TimeSeries<T,C>::cend() const {
274         return values_.end();
275     }
276 
277     template <class T, class C>
278     inline typename TimeSeries<T,C>::const_iterator
find(const Date & d)279     TimeSeries<T,C>::find(const Date& d) {
280         const_iterator i = values_.find(d);
281         if (i == values_.end()) {
282             values_[d] = Null<T>();
283             i = values_.find(d);
284         }
285         return i;
286     }
287 
288     template <class T, class C>
dates() const289     std::vector<Date> TimeSeries<T,C>::dates() const {
290         std::vector<Date> v;
291         v.reserve(size());
292         std::transform(cbegin(), cend(), std::back_inserter(v),
293                        TimeSeries<T,C>::get_time);
294         return v;
295     }
296 
297     template <class T, class C>
values() const298     std::vector<T> TimeSeries<T,C>::values() const {
299         std::vector<T> v;
300         v.reserve(size());
301         std::transform(cbegin(), cend(), std::back_inserter(v),
302                        TimeSeries<T,C>::get_value);
303         return v;
304     }
305 
306 }
307 
308 #endif
309