Time Series¶
This is a module for working with discrete floating point time series. It is designed so that every operation is very fast, typically much faster than with other generic code, e.g., Python lists of doubles or even NumPy arrays. The semantics of time series is more similar to Python lists of doubles than Sage real double vectors or NumPy 1-D arrays. In particular, time series are not endowed with much algebraic structure and are always mutable.
Note
NumPy arrays are faster at slicing, since slices return references, and NumPy arrays have strides. However, this speed at slicing makes NumPy slower at certain other operations.
EXAMPLES:
sage: set_random_seed(1)
sage: t = finance.TimeSeries([random()-0.5 for _ in range(10)]); t
[0.3294, 0.0959, -0.0706, -0.4646, 0.4311, 0.2275, -0.3840, -0.3528, -0.4119, -0.2933]
sage: t.sums()
[0.3294, 0.4253, 0.3547, -0.1099, 0.3212, 0.5487, 0.1647, -0.1882, -0.6001, -0.8933]
sage: t.exponential_moving_average(0.7)
[0.0000, 0.3294, 0.1660, 0.0003, -0.3251, 0.2042, 0.2205, -0.2027, -0.3078, -0.3807]
sage: t.standard_deviation()
0.33729638212891383
sage: t.mean()
-0.08933425506929439
sage: t.variance()
0.1137688493972542...
AUTHOR:
William Stein
-
class
sage.finance.time_series.
TimeSeries
¶ Bases:
object
Initialize new time series.
INPUT:
values
– integer (number of values) or an iterable of floats.initialize
– bool (default:True
); ifFalse
, do not bother to zero out the entries of the new time series. For large series that you are going to just fill in, this can be way faster.
EXAMPLES:
This implicitly calls init:
sage: finance.TimeSeries([pi, 3, 18.2]) [3.1416, 3.0000, 18.2000]
Conversion from a NumPy 1-D array, which is very fast:
sage: v = finance.TimeSeries([1..5]) sage: w = v.numpy() sage: finance.TimeSeries(w) [1.0000, 2.0000, 3.0000, 4.0000, 5.0000]
Conversion from an n-dimensional NumPy array also works:
sage: import numpy sage: v = numpy.array([[1,2], [3,4]], dtype=float); v array([[1., 2.], [3., 4.]]) sage: finance.TimeSeries(v) [1.0000, 2.0000, 3.0000, 4.0000] sage: finance.TimeSeries(v[:,0]) [1.0000, 3.0000] sage: u = numpy.array([[1,2],[3,4]]) sage: finance.TimeSeries(u) [1.0000, 2.0000, 3.0000, 4.0000]
For speed purposes we don’t initialize (so value is garbage):
sage: t = finance.TimeSeries(10, initialize=False)
-
abs
()¶ Return new time series got by replacing all entries of
self
by their absolute value.OUTPUT:
A new time series.
EXAMPLES:
sage: v = finance.TimeSeries([1,3.1908439,-4,5.93932]) sage: v [1.0000, 3.1908, -4.0000, 5.9393] sage: v.abs() [1.0000, 3.1908, 4.0000, 5.9393]
-
add_entries
(t)¶ Add corresponding entries of
self
andt
together, extending eitherself
ort
by 0’s if they do not have the same length.Note
To add a single number to the entries of a time series, use the
add_scalar
method.INPUT:
t
– a time series.
OUTPUT:
A time series with length the maxima of the lengths of
self
andt
.EXAMPLES:
sage: v = finance.TimeSeries([1,2,-5]); v [1.0000, 2.0000, -5.0000] sage: v.add_entries([3,4]) [4.0000, 6.0000, -5.0000] sage: v.add_entries(v) [2.0000, 4.0000, -10.0000] sage: v.add_entries([3,4,7,18.5]) [4.0000, 6.0000, 2.0000, 18.5000]
-
add_scalar
(s)¶ Return new time series obtained by adding a scalar to every value in the series.
Note
To add componentwise, use the
add_entries
method.INPUT:
s
– a float.
OUTPUT:
A new time series with
s
added to all values.EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.add_scalar(0.5) [5.5000, 4.5000, 1.8000, 2.5000, 8.5000, 10.5000, 3.5000, -4.5000]
-
autocorrelation
(k=1)¶ Return the k-th sample autocorrelation of this time series \(x_i\).
Let \(\mu\) be the sample mean. Then the sample autocorrelation function is
\[\frac{\sum_{t=0}^{n-k-1} (x_t - \mu)(x_{t+k} - \mu) } {\sum_{t=0}^{n-1} (x_t - \mu)^2}.\]Note that the variance must be nonzero or you will get a
ZeroDivisionError
.INPUT:
k
– a nonnegative integer (default: 1)
OUTPUT:
A time series.
EXAMPLES:
sage: v = finance.TimeSeries([13,8,15,4,4,12,11,7,14,12]) sage: v.autocorrelation() -0.1875 sage: v.autocorrelation(1) -0.1875 sage: v.autocorrelation(0) 1.0 sage: v.autocorrelation(2) -0.20138888888888887 sage: v.autocorrelation(3) 0.18055555555555555 sage: finance.TimeSeries([1..1000]).autocorrelation() 0.997
-
autocovariance
(k=0)¶ Return the k-th autocovariance function \(\gamma(k)\) of
self
. This is the covariance ofself
withself
shifted by \(k\), i.e.,\[\left. \left( \sum_{t=0}^{n-k-1} (x_t - \mu)(x_{t + k} - \mu) \right) \right/ n,\]where \(n\) is the length of
self
.Note the denominator of \(n\), which gives a “better” sample estimator.
INPUT:
k
– a nonnegative integer (default: 0)
OUTPUT:
A float.
EXAMPLES:
sage: v = finance.TimeSeries([13,8,15,4,4,12,11,7,14,12]) sage: v.autocovariance(0) 14.4 sage: mu = v.mean(); sum([(a-mu)^2 for a in v])/len(v) 14.4 sage: v.autocovariance(1) -2.7 sage: mu = v.mean(); sum([(v[i]-mu)*(v[i+1]-mu) for i in range(len(v)-1)])/len(v) -2.7 sage: v.autocovariance(1) -2.7
We illustrate with a random sample that an independently and identically distributed distribution with zero mean and variance \(\sigma^2\) has autocovariance function \(\gamma(h)\) with \(\gamma(0) = \sigma^2\) and \(\gamma(h) = 0\) for \(h\neq 0\).
sage: set_random_seed(0) sage: v = finance.TimeSeries(10^6) sage: v.randomize('normal', 0, 5) [3.3835, -2.0055, 1.7882, -2.9319, -4.6827 ... -5.1868, 9.2613, 0.9274, -6.2282, -8.7652] sage: v.autocovariance(0) 24.95410689... sage: v.autocovariance(1) -0.00508390... sage: v.autocovariance(2) 0.022056325... sage: v.autocovariance(3) -0.01902000...
-
autoregressive_fit
(M)¶ This method fits the time series to an autoregressive process of order
M
. That is, we assume the process is given by \(X_t-\mu=a_1(X_{t-1}-\mu)+a_2(X_{t-1}-\mu)+\cdots+a_M(X_{t-M}-\mu)+Z_t\) where \(\mu\) is the mean of the process and \(Z_t\) is noise. This method returns estimates for \(a_1,\dots,a_M\).The method works by solving the Yule-Walker equations \(\Gamma a =\gamma\), where \(\gamma=(\gamma(1),\dots,\gamma(M))\), \(a=(a_1,\dots,a_M)\) with \(\gamma(i)\) the autocovariance of lag \(i\) and \(\Gamma_{ij}=\gamma(i-j)\).
Warning
The input sequence is assumed to be stationary, which means that the autocovariance \(\langle y_j y_k \rangle\) depends only on the difference \(|j-k|\).
INPUT:
M
– an integer.
OUTPUT:
A time series – the coefficients of the autoregressive process.
EXAMPLES:
sage: set_random_seed(0) sage: v = finance.TimeSeries(10^4).randomize('normal').sums() sage: F = v.autoregressive_fit(100) sage: v [0.6767, 0.2756, 0.6332, 0.0469, -0.8897 ... 87.6759, 87.6825, 87.4120, 87.6639, 86.3194] sage: v.autoregressive_forecast(F) 86.0177285042... sage: F [1.0148, -0.0029, -0.0105, 0.0067, -0.0232 ... -0.0106, -0.0068, 0.0085, -0.0131, 0.0092] sage: set_random_seed(0) sage: t=finance.TimeSeries(2000) sage: z=finance.TimeSeries(2000) sage: z.randomize('normal',1) [1.6767, 0.5989, 1.3576, 0.4136, 0.0635 ... 1.0057, -1.1467, 1.2809, 1.5705, 1.1095] sage: t[0]=1 sage: t[1]=2 sage: for i in range(2,2000): ....: t[i]=t[i-1]-0.5*t[i-2]+z[i] sage: c=t[0:-1].autoregressive_fit(2) #recovers recurrence relation sage: c #should be close to [1,-0.5] [1.0371, -0.5199]
-
autoregressive_forecast
(filter)¶ Given the autoregression coefficients as outputted by the
autoregressive_fit
command, compute the forecast for the next term in the series.INPUT:
filter
– a time series outputted by theautoregressive_fit
command.
EXAMPLES:
sage: set_random_seed(0) sage: v = finance.TimeSeries(100).randomize('normal').sums() sage: F = v[:-1].autoregressive_fit(5); F [1.0019, -0.0524, -0.0643, 0.1323, -0.0539] sage: v.autoregressive_forecast(F) 11.7820298611... sage: v [0.6767, 0.2756, 0.6332, 0.0469, -0.8897 ... 9.2447, 9.6709, 10.4037, 10.4836, 12.1960]
-
central_moment
(k)¶ Return the k-th central moment of
self
, which is just the mean of the k-th powers of the differencesself[i] - mu
, wheremu
is the mean ofself
.INPUT:
k
– a positive integer.
OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,2,3]) sage: v.central_moment(2) 0.6666666666666666
Note that the central moment is different from the moment here, since the mean is not \(0\):
sage: v.moment(2) # doesn't subtract off mean 4.666666666666667
We compute the central moment directly:
sage: mu = v.mean(); mu 2.0 sage: ((1-mu)^2 + (2-mu)^2 + (3-mu)^2) / 3 0.6666666666666666
-
clip_remove
(min=None, max=None)¶ Return new time series obtained from
self
by removing all values that are less than or equal to a certain minimum value or greater than or equal to a certain maximum.INPUT:
min
– (default:None
)None
or double.max
– (default:None
)None
or double.
OUTPUT:
A time series.
EXAMPLES:
sage: v = finance.TimeSeries([1..10]) sage: v.clip_remove(3,7) [3.0000, 4.0000, 5.0000, 6.0000, 7.0000] sage: v.clip_remove(3) [3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000] sage: v.clip_remove(max=7) [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000]
-
correlation
(other)¶ Return the correlation of
self
andother
, which is the covariance ofself
andother
divided by the product of their standard deviation.INPUT:
self
,other
– time series.
Whichever time series has more terms is truncated.
EXAMPLES:
sage: v = finance.TimeSeries([1,-2,3]); w = finance.TimeSeries([4,5,-10]) sage: v.correlation(w) -0.558041609... sage: v.covariance(w)/(v.standard_deviation() * w.standard_deviation()) -0.558041609...
-
covariance
(other)¶ Return the covariance of the time series
self
andother
.INPUT:
self
,other
– time series.
Whichever time series has more terms is truncated.
EXAMPLES:
sage: v = finance.TimeSeries([1,-2,3]); w = finance.TimeSeries([4,5,-10]) sage: v.covariance(w) -11.777777777777779
-
diffs
(k=1)¶ Return the new time series got by taking the differences of successive terms in the time series. So if
self
is the time series \(X_0, X_1, X_2, \dots\), then this function outputs the series \(X_1 - X_0, X_2 - X_1, \dots\). The output series has one less term than the input series. If the optional parameter \(k\) is given, return \(X_k - X_0, X_{2k} - X_k, \dots\).INPUT:
k
– positive integer (default: 1)
OUTPUT:
A new time series.
EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000] sage: v.diffs() [-1.0000, -2.7000, 0.7000, 6.0000]
-
exp
()¶ Return new time series got by applying the exponential map to all the terms in the time series.
OUTPUT:
A new time series.
EXAMPLES:
sage: v = finance.TimeSeries([1..5]); v [1.0000, 2.0000, 3.0000, 4.0000, 5.0000] sage: v.exp() [2.7183, 7.3891, 20.0855, 54.5982, 148.4132] sage: v.exp().log() [1.0000, 2.0000, 3.0000, 4.0000, 5.0000]
-
exponential_moving_average
(alpha)¶ Return the exponential moving average time series. Assumes the input time series was constant with its starting value for negative time. The t-th step of the output is the sum of the previous k-1 steps of
self
and the k-th step divided by k.The 0-th term is formally undefined, so we define it to be 0, and we define the first term to be
self[0]
.INPUT:
alpha
– float; a smoothing factor with0 <= alpha <= 1
.
OUTPUT:
A time series with the same number of steps as
self
.EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.exponential_moving_average(0) [0.0000, 1.0000, 1.0000, 1.0000, 1.0000] sage: v.exponential_moving_average(1) [0.0000, 1.0000, 1.0000, 1.0000, 2.0000] sage: v.exponential_moving_average(0.5) [0.0000, 1.0000, 1.0000, 1.0000, 1.5000]
Some more examples:
sage: v = finance.TimeSeries([1,2,3,4,5]) sage: v.exponential_moving_average(1) [0.0000, 1.0000, 2.0000, 3.0000, 4.0000] sage: v.exponential_moving_average(0) [0.0000, 1.0000, 1.0000, 1.0000, 1.0000]
-
extend
(right)¶ Extend this time series by appending elements from the iterable
right
.INPUT:
right
– iterable that can be converted to a time series.
EXAMPLES:
sage: v = finance.TimeSeries([1,2,-5]); v [1.0000, 2.0000, -5.0000] sage: v.extend([-3.5, 2]) sage: v [1.0000, 2.0000, -5.0000, -3.5000, 2.0000]
-
fft
(overwrite=False)¶ Return the real discrete fast Fourier transform of
self
, as a real time series:\[ \begin{align}\begin{aligned}[y(0),\Re(y(1)),\Im(y(1)),\dots,\Re(y(n/2))] \text{ if $n$ is even}\\[y(0),\Re(y(1)),\Im(y(1)),\dots,\Re(y(n/2)),\Im(y(n/2))] \text{ if $n$ is odd}\end{aligned}\end{align} \]where
\[y(j) = \sum_{k=0}^{n-1} x[k] \cdot \exp(-\sqrt{-1} \cdot jk \cdot 2\pi/n)\]for \(j = 0,\dots,n-1\). Note that \(y(-j) = y(n-j)\).
EXAMPLES:
sage: v = finance.TimeSeries([1..9]); v [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000] sage: w = v.fft(); w [45.0000, -4.5000, 12.3636, -4.5000, 5.3629, -4.5000, 2.5981, -4.5000, 0.7935]
We get just the series of real parts of
sage: finance.TimeSeries([w[0]]) + w[1:].scale_time(2) [45.0000, -4.5000, -4.5000, -4.5000, -4.5000]
An example with an even number of terms:
sage: v = finance.TimeSeries([1..10]); v [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000] sage: w = v.fft(); w [55.0000, -5.0000, 15.3884, -5.0000, 6.8819, -5.0000, 3.6327, -5.0000, 1.6246, -5.0000] sage: v.fft().ifft() [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000]
-
histogram
(bins=50, normalize=False)¶ Return the frequency histogram of the values in this time series divided up into the given number of bins.
INPUT:
bins
– a positive integer (default: 50)normalize
– (default:False
) whether to normalize so the total area in the bars of the histogram is 1.
OUTPUT:
counts – list of counts of numbers of elements in each bin.
endpoints – list of 2-tuples (a,b) that give the endpoints of the bins.
EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.histogram(3) ([1, 4, 3], [(-5.0, 0.0), (0.0, 5.0), (5.0, 10.0)])
-
hurst_exponent
()¶ Return an estimate of the Hurst exponent of this time series.
We use the algorithm from pages 61 – 63 of [Peteres, Fractal Market Analysis (1994); see Google Books].
We define the Hurst exponent of a constant time series to be 1.
EXAMPLES:
The Hurst exponent of Brownian motion is 1/2. We approximate it with some specific samples. Note that the estimator is biased and slightly overestimates.
sage: set_random_seed(0) sage: bm = finance.TimeSeries(10^5).randomize('normal').sums(); bm [0.6767, 0.2756, 0.6332, 0.0469, -0.8897 ... 152.2437, 151.5327, 152.7629, 152.9169, 152.9084] sage: bm.hurst_exponent() 0.527450972...
We compute the Hurst exponent of a simulated fractional Brownian motion with Hurst parameter 0.7. This function estimates the Hurst exponent as 0.706511951…
sage: set_random_seed(0) sage: fbm = finance.fractional_brownian_motion_simulation(0.7,0.1,10^5,1)[0] sage: fbm.hurst_exponent() 0.706511951...
Another example with small Hurst exponent (notice the overestimation).
sage: fbm = finance.fractional_brownian_motion_simulation(0.2,0.1,10^5,1)[0] sage: fbm.hurst_exponent() 0.278997441...
We compute the mean Hurst exponent of 100 simulated multifractal cascade random walks:
sage: set_random_seed(0) sage: y = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100) sage: finance.TimeSeries([z.hurst_exponent() for z in y]).mean() 0.57984822577934...
We compute the mean Hurst exponent of 100 simulated Markov switching multifractal time series. The Hurst exponent is quite small.
sage: set_random_seed(0) sage: msm = finance.MarkovSwitchingMultifractal(8,1.4,0.5,0.95,3) sage: y = msm.simulations(1000,100) sage: finance.TimeSeries([z.hurst_exponent() for z in y]).mean() 0.286102325623705...
-
ifft
(overwrite=False)¶ Return the real discrete inverse fast Fourier transform of
self
, which is also a real time series.This is the inverse of
fft()
.The returned real array contains
\[[y(0),y(1),\dots,y(n-1)]\]where for \(n\) is even
\[y(j) = 1/n \left( \sum_{k=1}^{n/2-1} (x[2k-1]+\sqrt{-1} \cdot x[2k]) \cdot \exp(\sqrt{-1} \cdot jk \cdot 2pi/n) + c.c. + x[0] + (-1)^j x[n-1] \right)\]and for \(n\) is odd
\[y(j) = 1/n \left( \sum_{k=1}^{(n-1)/2} (x[2k-1]+\sqrt{-1} \cdot x[2k]) \cdot \exp(\sqrt{-1} \cdot jk \cdot 2pi/n) + c.c. + x[0] \right)\]where \(c.c.\) denotes complex conjugate of preceding expression.
EXAMPLES:
sage: v = finance.TimeSeries([1..10]); v [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000] sage: v.ifft() [5.1000, -5.6876, 1.4764, -1.0774, 0.4249, -0.1000, -0.2249, 0.6663, -1.2764, 1.6988] sage: v.ifft().fft() [1.0000, 2.0000, 3.0000, 4.0000, 5.0000, 6.0000, 7.0000, 8.0000, 9.0000, 10.0000]
-
list
()¶ Return list of elements of
self
.EXAMPLES:
sage: v = finance.TimeSeries([1,-4,3,-2.5,-4,3]) sage: v.list() [1.0, -4.0, 3.0, -2.5, -4.0, 3.0]
-
log
()¶ Return new time series got by taking the logarithms of all the terms in the time series.
OUTPUT:
A new time series.
EXAMPLES:
We exponentiate then log a time series and get back the original series:
sage: v = finance.TimeSeries([1,-4,3,-2.5,-4,3]); v [1.0000, -4.0000, 3.0000, -2.5000, -4.0000, 3.0000] sage: v.exp() [2.7183, 0.0183, 20.0855, 0.0821, 0.0183, 20.0855] sage: v.exp().log() [1.0000, -4.0000, 3.0000, -2.5000, -4.0000, 3.0000]
Log of 0 gives
-inf
:sage: finance.TimeSeries([1,0,3]).log()[1] -inf
-
max
(index=False)¶ Return the largest value in this time series. If this series has length 0 we raise a
ValueError
.INPUT:
index
– bool (default:False
); ifTrue
, also return index of maximum entry.
OUTPUT:
float – largest value.
integer – index of largest value; only returned if
index=True
.
EXAMPLES:
sage: v = finance.TimeSeries([1,-4,3,-2.5,-4,3]) sage: v.max() 3.0 sage: v.max(index=True) (3.0, 2)
-
mean
()¶ Return the mean (average) of the elements of
self
.OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.mean() 1.6
-
min
(index=False)¶ Return the smallest value in this time series. If this series has length 0 we raise a
ValueError
.INPUT:
index
– bool (default:False
); ifTrue
, also return index of minimal entry.
OUTPUT:
float – smallest value.
integer – index of smallest value; only returned if
index=True
.
EXAMPLES:
sage: v = finance.TimeSeries([1,-4,3,-2.5,-4]) sage: v.min() -4.0 sage: v.min(index=True) (-4.0, 1)
-
moment
(k)¶ Return the k-th moment of
self
, which is just the mean of the k-th powers of the elements ofself
.INPUT:
k
– a positive integer.
OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.moment(1) 1.6 sage: v.moment(2) 3.2
-
numpy
(copy=True)¶ Return a NumPy version of this time series.
Note
If copy is
False
, return a NumPy 1-D array reference to exactly the same block of memory as this time series. This is very, very fast and makes it easy to quickly use all NumPy/SciPy functionality onself
. However, it is dangerous because when this time series goes out of scope and is garbage collected, the corresponding NumPy reference object will point to garbage.INPUT:
copy
– bool (default:True
)
OUTPUT:
A numpy 1-D array.
EXAMPLES:
sage: v = finance.TimeSeries([1,-3,4.5,-2]) sage: w = v.numpy(copy=False); w array([ 1. , -3. , 4.5, -2. ]) sage: type(w) <... 'numpy.ndarray'> sage: w.shape (4,)
Notice that changing
w
also changesv
too!sage: w[0] = 20 sage: w array([20. , -3. , 4.5, -2. ]) sage: v [20.0000, -3.0000, 4.5000, -2.0000]
If you want a separate copy do not give the
copy=False
option.sage: z = v.numpy(); z array([20. , -3. , 4.5, -2. ]) sage: z[0] = -10 sage: v [20.0000, -3.0000, 4.5000, -2.0000]
-
plot
(plot_points=1000, points=False, **kwds)¶ Return a plot of this time series as a line or points through \((i,T(i))\), where \(i\) ranges over nonnegative integers up to the length of
self
.INPUT:
plot_points
– (default: 1000) 0 or positive integer. Only plot the given number of equally spaced points in the time series. If 0, plot all points.points
– bool (default:False
). IfTrue
, return just the points of the time series.**kwds
– passed to the line or point command.
EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.plot() Graphics object consisting of 1 graphics primitive sage: v.plot(points=True) Graphics object consisting of 1 graphics primitive sage: v.plot() + v.plot(points=True, rgbcolor='red') Graphics object consisting of 2 graphics primitives sage: v.plot() + v.plot(points=True, rgbcolor='red', pointsize=50) Graphics object consisting of 2 graphics primitives
-
plot_candlestick
(bins=30)¶ Return a candlestick plot of this time series with the given number of bins.
A candlestick plot is a style of bar-chart used to view open, high, low, and close stock data. At each bin, the line represents the high / low range. The bar represents the open / close range. The interval is colored blue if the open for that bin is less than the close. If the close is less than the open, then that bin is colored red instead.
INPUT:
bins
– positive integer (default: 30), the number of bins or candles.
OUTPUT:
A candlestick plot.
EXAMPLES:
Here we look at the candlestick plot for Brownian motion:
sage: v = finance.TimeSeries(1000).randomize() sage: v.plot_candlestick(bins=20) Graphics object consisting of 40 graphics primitives
-
plot_histogram
(bins=50, normalize=True, **kwds)¶ Return histogram plot of this time series with given number of bins.
INPUT:
bins
– positive integer (default: 50)normalize
– (default:True
) whether to normalize so the total area in the bars of the histogram is 1.
OUTPUT:
A histogram plot.
EXAMPLES:
sage: v = finance.TimeSeries([1..50]) sage: v.plot_histogram(bins=10) Graphics object consisting of 10 graphics primitives
sage: v.plot_histogram(bins=3,normalize=False,aspect_ratio=1) Graphics object consisting of 3 graphics primitives
-
pow
(k)¶ Return a new time series with every elements of
self
raised to the k-th power.INPUT:
k
– a float.
OUTPUT:
A time series.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.pow(2) [1.0000, 1.0000, 1.0000, 4.0000, 9.0000]
-
prod
()¶ Return the product of all the entries of
self
. Ifself
has length 0, returns 1.OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.prod() 6.0
-
randomize
(distribution='uniform', loc=0, scale=1, **kwds)¶ Randomize the entries in this time series, and return a reference to
self
. Thus this function both changesself
in place, and returns a copy ofself
, for convenience.INPUT:
distribution
– (default:"uniform"
); supported values are:'uniform'
– fromloc
toloc + scale
'normal'
– meanloc
and standard deviationscale
'semicircle'
– with center atloc
(scale
is ignored)'lognormal'
– meanloc
and standard deviationscale
loc
– float (default: 0)scale
– float (default: 1)
Note
All random numbers are generated using algorithms that build on the high quality GMP random number function gmp_urandomb_ui. Thus this function fully respects the Sage
set_random_state
command. It’s not quite as fast as the C library random number generator, but is of course much better quality, and is platform independent.EXAMPLES:
We generate 5 uniform random numbers in the interval [0,1]:
sage: set_random_seed(0) sage: finance.TimeSeries(5).randomize() [0.8685, 0.2816, 0.0229, 0.1456, 0.7314]
We generate 5 uniform random numbers from 5 to \(5+2=7\):
sage: set_random_seed(0) sage: finance.TimeSeries(10).randomize('uniform', 5, 2) [6.7369, 5.5632, 5.0459, 5.2911, 6.4628, 5.2412, 5.2010, 5.2761, 5.5813, 5.5439]
We generate 5 normal random values with mean 0 and variance 1.
sage: set_random_seed(0) sage: finance.TimeSeries(5).randomize('normal') [0.6767, -0.4011, 0.3576, -0.5864, -0.9365]
We generate 10 normal random values with mean 5 and variance 2.
sage: set_random_seed(0) sage: finance.TimeSeries(10).randomize('normal', 5, 2) [6.3534, 4.1978, 5.7153, 3.8273, 3.1269, 2.9598, 3.7484, 6.7472, 3.8986, 4.6271]
We generate 5 values using the semicircle distribution.
sage: set_random_seed(0) sage: finance.TimeSeries(5).randomize('semicircle') [0.7369, -0.9541, 0.4628, -0.7990, -0.4187]
We generate 1 million normal random values and create a frequency histogram.
sage: set_random_seed(0) sage: a = finance.TimeSeries(10^6).randomize('normal') sage: a.histogram(10)[0] [36, 1148, 19604, 130699, 340054, 347870, 137953, 21290, 1311, 35]
We take the above values, and compute the proportion that lie within 1, 2, 3, 5, and 6 standard deviations of the mean (0):
sage: s = a.standard_deviation() sage: len(a.clip_remove(-s,s))/float(len(a)) 0.683094 sage: len(a.clip_remove(-2*s,2*s))/float(len(a)) 0.954559 sage: len(a.clip_remove(-3*s,3*s))/float(len(a)) 0.997228 sage: len(a.clip_remove(-5*s,5*s))/float(len(a)) 0.999998
There were no “six sigma events”:
sage: len(a.clip_remove(-6*s,6*s))/float(len(a)) 1.0
-
range_statistic
(b=None)¶ Return the rescaled range statistic \(R/S\) of
self
, which is defined as follows (see Hurst 1951). If the optional parameterb
is given, return the average of \(R/S\) range statistics of disjoint blocks of sizeb
.Let \(\sigma\) be the standard deviation of the sequence of differences of
self
, and let \(Y_k\) be the k-th term ofself
. Let \(n\) be the number of terms ofself
, and set \(Z_k = Y_k - ((k+1)/n) \cdot Y_n\). Then\[R/S = \big( \max(Z_k) - \min(Z_k) \big) / \sigma\]where the max and min are over all \(Z_k\). Basically replacing \(Y_k\) by \(Z_k\) allows us to measure the difference from the line from the origin to \((n,Y_n)\).
INPUT:
self
– a time series (not the series of differences).b
– integer (default:None
); if given instead divide the input time series up intoj = floor(n/b)
disjoint blocks, compute the \(R/S\) statistic for each block, and return the average of those \(R/S\) statistics.
OUTPUT:
A float.
EXAMPLES:
Notice that if we make a Brownian motion random walk, there is no difference if we change the standard deviation.
sage: set_random_seed(0); finance.TimeSeries(10^6).randomize('normal').sums().range_statistic() 1897.8392602... sage: set_random_seed(0); finance.TimeSeries(10^6).randomize('normal',0,100).sums().range_statistic() 1897.8392602...
-
rescale
(s)¶ Change
self
by multiplying every value in the series bys
.INPUT:
s
– a float.
EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.rescale(0.5) sage: v [2.5000, 2.0000, 0.6500, 1.0000, 4.0000, 5.0000, 1.5000, -2.5000]
-
reversed
()¶ Return new time series obtain from this time series by reversing the order of the entries in this time series.
OUTPUT:
A time series.
EXAMPLES:
sage: v = finance.TimeSeries([1..5]) sage: v.reversed() [5.0000, 4.0000, 3.0000, 2.0000, 1.0000]
-
scale
(s)¶ Return new time series obtained by multiplying every value in the series by
s
.INPUT:
s
– a float.
OUTPUT:
A new time series with all values multiplied by
s
.EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.scale(0.5) [2.5000, 2.0000, 0.6500, 1.0000, 4.0000, 5.0000, 1.5000, -2.5000]
-
scale_time
(k)¶ Return the new time series at scale
k
. If the input time series is \(X_0, X_1, X_2, \dots\), then this function returns the shorter time series \(X_0, X_k, X_{2k}, \dots\).INPUT:
k
– a positive integer.
OUTPUT:
A new time series.
EXAMPLES:
sage: v = finance.TimeSeries([5,4,1.3,2,8,10,3,-5]); v [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.scale_time(1) [5.0000, 4.0000, 1.3000, 2.0000, 8.0000, 10.0000, 3.0000, -5.0000] sage: v.scale_time(2) [5.0000, 1.3000, 8.0000, 3.0000] sage: v.scale_time(3) [5.0000, 2.0000] sage: v.scale_time(10) []
A series of odd length:
sage: v = finance.TimeSeries([1..5]); v [1.0000, 2.0000, 3.0000, 4.0000, 5.0000] sage: v.scale_time(2) [1.0000, 3.0000, 5.0000]
-
show
(*args, **kwds)¶ Calls plot and passes all arguments onto the plot function. This is thus just an alias for plot.
EXAMPLES:
Draw a plot of a time series:
sage: finance.TimeSeries([1..10]).show() Graphics object consisting of 1 graphics primitive
-
simple_moving_average
(k)¶ Return the moving average time series over the last
k
time units. Assumes the input time series was constant with its starting value for negative time. The t-th step of the output is the sum of the previousk - 1
steps ofself
and thek
-th step divided byk
. Thusk
values are averaged at each point.INPUT:
k
– positive integer.
OUTPUT:
A time series with the same number of steps as
self
.EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.simple_moving_average(0) [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.simple_moving_average(1) [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.simple_moving_average(2) [1.0000, 1.0000, 1.0000, 1.5000, 2.5000] sage: v.simple_moving_average(3) [1.0000, 1.0000, 1.0000, 1.3333, 2.0000]
-
standard_deviation
(bias=False)¶ Return the standard deviation of the entries of
self
.INPUT:
bias
– bool (default:False
); ifFalse
, divide byself.length() - 1
instead ofself.length()
to give a less biased estimator for the variance.
OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.standard_deviation() 0.8944271909... sage: v.standard_deviation(bias=True) 0.8
-
sum
()¶ Return the sum of all the entries of
self
. Ifself
has length 0, returns 0.OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.sum() 8.0
-
sums
(s=0)¶ Return the new time series got by taking the running partial sums of the terms of this time series.
INPUT:
s
– starting value for partial sums.
OUTPUT:
A time series.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.sums() [1.0000, 2.0000, 3.0000, 5.0000, 8.0000]
-
variance
(bias=False)¶ Return the variance of the elements of
self
, which is the mean of the squares of the differences from the mean.INPUT:
bias
– bool (default:False
); ifFalse
, divide byself.length() - 1
instead ofself.length()
to give a less biased estimator for the variance.
OUTPUT:
A double.
EXAMPLES:
sage: v = finance.TimeSeries([1,1,1,2,3]); v [1.0000, 1.0000, 1.0000, 2.0000, 3.0000] sage: v.variance() 0.8 sage: v.variance(bias=True) 0.64
-
vector
()¶ Return real double vector whose entries are the values of this time series. This is useful since vectors have standard algebraic structure and play well with matrices.
OUTPUT:
A real double vector.
EXAMPLES:
sage: v = finance.TimeSeries([1..10]) sage: v.vector() (1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0)
-
sage.finance.time_series.
autoregressive_fit
(acvs)¶ Given a sequence of lagged autocovariances of length \(M\) produce \(a_1,\dots,a_p\) so that the first \(M\) autocovariance coefficients of the autoregressive processes \(X_t=a_1X_{t_1}+\cdots+a_pX_{t-p}+Z_t\) are the same as the input sequence.
The function works by solving the Yule-Walker equations \(\Gamma a =\gamma\), where \(\gamma=(\gamma(1),\dots,\gamma(M))\), \(a=(a_1,\dots,a_M)\), with \(\gamma(i)\) the autocovariance of lag \(i\) and \(\Gamma_{ij}=\gamma(i-j)\).
EXAMPLES:
In this example we consider the multifractal cascade random walk of length 1000, and use simulations to estimate the expected first few autocovariance parameters for this model, then use them to construct a linear filter that works vastly better than a linear filter constructed from the same data but not using this model. The Monte-Carlo method illustrated below should work for predicting one “time step” into the future for any model that can be simulated. To predict k time steps into the future would require using a similar technique but would require scaling time by k.
We create 100 simulations of a multifractal random walk. This models the logarithms of a stock price sequence.
sage: set_random_seed(0) sage: y = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100)
For each walk below we replace the walk by the walk but where each step size is replaced by its absolute value – this is what we expect to be able to predict given the model, which is only a model for predicting volatility. We compute the first 200 autocovariance values for every random walk:
sage: c = [[a.diffs().abs().sums().autocovariance(i) for a in y] for i in range(200)]
We make a time series out of the expected values of the autocovariances:
sage: ac = finance.TimeSeries([finance.TimeSeries(z).mean() for z in c]) sage: ac [3.9962, 3.9842, 3.9722, 3.9601, 3.9481 ... 1.7144, 1.7033, 1.6922, 1.6812, 1.6701]
Note
ac
looks like a line – one could best fit it to yield a lot more approximate autocovariances.We compute the autoregression coefficients matching the above autocovariances:
sage: F = finance.autoregressive_fit(ac); F [0.9982, -0.0002, -0.0002, 0.0003, 0.0001 ... 0.0002, -0.0002, -0.0000, -0.0002, -0.0014]
Note that the sum is close to 1:
sage: sum(F) 0.99593284089454...
Now we make up an ‘out of sample’ sequence:
sage: y2 = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,1)[0].diffs().abs().sums() sage: y2 [0.0013, 0.0059, 0.0066, 0.0068, 0.0184 ... 6.8004, 6.8009, 6.8063, 6.8090, 6.8339]
And we forecast the very last value using our linear filter; the forecast is close:
sage: y2[:-1].autoregressive_forecast(F) 6.7836741372407...
In fact it is closer than we would get by forecasting using a linear filter made from all the autocovariances of our sequence:
sage: y2[:-1].autoregressive_forecast(y2[:-1].autoregressive_fit(len(y2))) 6.770168705668...
We record the last 20 forecasts, always using all correct values up to the one we are forecasting:
sage: s1 = sum([(y2[:-i].autoregressive_forecast(F)-y2[-i])^2 for i in range(1,20)])
We do the same, but using the autocovariances of the sample sequence:
sage: F2 = y2[:-100].autoregressive_fit(len(F)) sage: s2 = sum([(y2[:-i].autoregressive_forecast(F2)-y2[-i])^2 for i in range(1,20)])
Our model gives us something that is 15 percent better in this case:
sage: s2/s1 1.15464636102...
How does it compare overall? To find out we do 100 simulations and for each we compute the percent that our model beats naively using the autocovariances of the sample:
sage: y_out = finance.multifractal_cascade_random_walk_simulation(3700,0.02,0.01,0.01,1000,100) sage: s1 = []; s2 = [] sage: for v in y_out: ....: s1.append(sum([(v[:-i].autoregressive_forecast(F)-v[-i])^2 for i in range(1,20)])) ....: F2 = v[:-len(F)].autoregressive_fit(len(F)) ....: s2.append(sum([(v[:-i].autoregressive_forecast(F2)-v[-i])^2 for i in range(1,20)]))
We find that overall the model beats naive linear forecasting by 35 percent!
sage: s = finance.TimeSeries([s2[i]/s1[i] for i in range(len(s1))]) sage: s.mean() 1.354073591877...
-
sage.finance.time_series.
unpickle_time_series_v1
(v, n)¶ Version 1 unpickle method.
INPUT:
v
– a raw char buffer
EXAMPLES:
sage: v = finance.TimeSeries([1,2,3]) sage: s = v.__reduce__()[1][0] sage: type(s) # py2 <type 'str'> sage: type(s) # py3 <type 'bytes'> sage: sage.finance.time_series.unpickle_time_series_v1(s,3) [1.0000, 2.0000, 3.0000] sage: sage.finance.time_series.unpickle_time_series_v1(s+s,6) [1.0000, 2.0000, 3.0000, 1.0000, 2.0000, 3.0000] sage: sage.finance.time_series.unpickle_time_series_v1(b'',0) []