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