Create intervals with 'datenum' - matlab

I am creating the limits for an equally spaced time series and I need to be able to change the time interval (1min, 5min, 10min, 15min, 30min, 60min etc.). My bounds are opening and closing time of the market. The stocks I am working on trades from 17.00 to 16.15 of the day after.
Here is what I am using:
timevec=datenum(2013,1,1,17,0:1*interval:1395,0)';
% It creates a time vector from 1-1-2013 17.00.00 to 1-2-2013 16.15.00
% spaced by "1min*interval"
The formula to be used is pretty simple but a problem arise if I need to use 10min or 30min as the result would be:
(10min)
02-Jan-2013 15:50:00
02-Jan-2013 16:00:00
02-Jan-2013 16:10:00
(30min)
02-Jan-2013 15:30:00
02-Jan-2013 16:00:00
What I would like to have is an extra interval 16:20:00 for the ten min case and 16:30:00 for the 30min case. The only solution I can come up with is moving the bound to 16:30 and adding an if statement to remove the extra observations in case they are not needed or keep the bound at 16:15:00 and adding an if statement to add the extra observation in case they are needed.
Is there anyway to do a one-line able to treat these two cases?

Matlab creates ranges such that all values are inside the limits. If you want to add one additional value right outside the limits, you can modify the upper limit by adding almost one interval length to the end:
step = 15;
1:step:100+0.99*step
ans =
1 16 31 46 61 76 91 106

Related

Are there any instances where a negative time type could give unexpected results?

Are there any instances where a negative time type could give unexpected results if used for specific purposes? When time deltas are calculated between negative time values and non-negative time values for example, there do not appear to be any issues.
time
val
00:00:31.384
-0.3170017
00:06:00.139
0.9033492
00:07:01.099
-0.7661049
Then, for the purpose of a window join later over a 10-min window
win:00:10:00;
winForJoin: (neg win;00:00:00) +\:(exec time from data);
first[winForJoin] gives -00:09:28.616 -00:03:59.861 -00:02:58.901
winForJoin[1]-winForJoin[0] gives 10 minutes as expected
If I understand correctly, you're asking how would a window join behave if the opening interval was a negative time? (due to the interval subtraction taking the values into negative territory, relative to 00:00).
The simple answer is that it won't behave any differently than if the times were numbers, but in practice you may see results you don't expect depending on how your table is set up and what you're trying to achieve.
Taking the example in the official wiki as a starting point: https://code.kx.com/q/ref/wj/
q)t:([]sym:3#`ibm;time:10:01:01 10:01:04 10:01:08;price:100 101 105)
q)a:101 103 103 104 104 107 108 107 108
q)b:98 99 102 103 103 104 106 106 107
q)q:([]sym:`ibm; time:10:01:01+til 9; ask:a; bid:b)
q)f:`sym`time
q)w:-2 1+\:t.time
/add volume too so it's easier to follow:
q)s:908 360 522 257 858 585 90 683 90;
q)update size:s from `q
/add an alternative range which has negative starting time
q)w2:(-11:00;1)+\:t.time
The window join takes all rows in q whose times are between the pairs of time ranges:
q)q[`time]within/:flip w
110000000b
011110000b
000001111b
Under the covers it's asking: are these positive numbers (the quote times) in between those two positive numbers (the window range). There's no reason it can't also ask: are these positive numbers in between this negative number and this positive number
q)q[`time]within/:flip w2
110000000b
111110000b
111111111b
You'll notice that all of them are greater than the negative time - meaning that it will include all rows from the beginning of the q table, up until the end time of that pair. This can be considered expected behaviour - if your start time is negative you must mean "from the beginning of time" - aka, all rows from the beginning of the table.
Comparing sum of size shows how the results differ:
q)wj[w;f;t;(q;(sum;`size))]
sym time price size
-----------------------
ibm 10:01:01 100 1268
ibm 10:01:04 101 1997
ibm 10:01:08 105 1448
q)wj[w2;f;t;(q;(sum;`size))]
sym time price size
-----------------------
ibm 10:01:01 100 1268
ibm 10:01:04 101 2905
ibm 10:01:08 105 4353
Finally - where it might get complicated.....it depends on what "negative" time means in your table. If you're at 00:00 (midnight) and you subtract 10 minutes, are you trying to access data from 23:50 the day before? Or does 00:00 represent the starting time (row zero) of your table? If you're trying to access 23:50 from the day before then you will have problems because 23:50 is NOT in between your negative start time and your positive end time, e.g:
q)23:50 within(-00:58:59;10:01:02)
0b
Again this all depends on how your data looks and what you're trying to do

UTC to GPS time for finding TOW in Simulink

for my project, I need to calculate TOW (Time of week) in Simulink. I know this can be achieved through conversion of UTC time to GPS time.
I have written a simple m-file in Matlab which does the action for me in Matlab as follow:
date_gps_int = 10000*y + 100*m + d
date_gps_str = int2str(date_gps_int)
date_gps_str_to_serial = datenum(date_gps_str,'yyyymmdd')
date_str_format = datestr(date_gps_str_to_serial,'dd-mmmm-yyyy')
Num_Days = daysact('06-jan-1980',date_str_format)
Num_Weeks = Num_Days/7
TOW = Num_Weeks - 1024
My first intention was to use this as a function in simulink. But apparently because of 'datenum' and 'datestr' it is not possible, since simulink does not handle strings.
Now I am wondering if anyone can help me with this issue. Is there any way to calculate TOW from the UTC date in Matlab without using those predefined functions?
I also tried to write an algorithm for calculating number of days since '6 January 1980' and then calculating number of weeks by dividing that by 7. But since I am not very familiar with leap year calculation and I don't really know the formula for these kinds of calculations, my result differs from real TOW.
I would appreciate if anybody can help me on this.
There are three formats handled by Matlab for time: formatted date strings - what datestr outputs -, serial date - scalar double, what datenum outputs - and date vectors (see datevec). Conversion functions work with these three, and the most convenient way to convert individual variables (year, month, etc) to a date is to build a date vector [yyyy mm dd HH MM SS].
date_gps_str_to_serial = datenum([y m d 0 0 0]); % midnight on day y-m-d
date_Jan_6_1980 = datenum([1980 01 06 0 0 0]); % midnight on Jan 6th, 1980
Num_Days = date_gps_str_to_serial - date_Jan_6_1980;
Now, beware of leap seconds...
GPS time is computed form the time elapsed since Jan 6th 1980. Take the number of seconds elapsed since that day, as measured by the satellites' atomic clocks, divide by (24*3600) to get a number of days, the remainder is the time of the day (in seconds since midnight).
But, once in a while, the International Earth Rotation and Reference Systems Service will decide that a day will last one second longer to accommodate for the slowing of Earth rotation. It may happen twice a year, on June 30th or December 31st. The calculation of GPS time is wrong, because it does not take into account that some days last 86401 seconds (so dividing by 24*3600 does not work) and will advance by 1 second with respect to UTC each time this happens. There has been 18 such days since Jan 6th 1980, so one should subtract 18 seconds from GPS time to find UTC time. The next time a leap second may be added is June 2019.

MATLAB- Adding Terms In An Array

I am fairly new to programming, and I am have a difficult time with finishing a function to use in my homework assignment. Below I have the code for a function that is intended to take the month entered subtract 1 from it, and add the number of days that are entered. Returning the total number of day. For example, if m=4, days= 3, then it would go through the for loop and add 31+28+31+4. I would greatly appreciate your help. Thank you for your time!
function bday=daysinmonth(m, d)
array=[31 28 31 30 31 30 31 31 30 31 30 31];
for i=1:m-1
md=sum(array(i))
end
%sum=md+d
end
The array holding the number of days for each months is a good starting point. Then I don't understand why you iterate up to the month. What you are looking for is the sum up to the current month, so something like:
md=sum(array(1:m-1));
And yes, then you can add the current day to the accumulated days from previous months with
sum=md+d;
You also want to make sure, that you return the this number with
function sum=daysinmonth(m, d)

Average and synchronize a timeseries with varying timestamps to a user-defined interval in MATLAB

Assume the following timeseries (ts) with assigned values:
time val
15:00 4
15:45 7
17:12 2.3
17:50 2.9
Every value from a timestamp is valid until the next appears. Thus, from 15:00 to 15:45 the value is 4 or from 15:45 to 17:12 it is 2.3. Every new data point between these timestamps should have the same value. What i want is a new ts, with a constant time-interval and a pre-defined start point. Let's say the starting point is 15:00 and the interval should be 30 min. Normally, I could use the synchronize function - however, the function uses the interpolation method and this is not what i need here, since the values between the data points should not be interpolated, but be averaged if timestamps are overlapping.
The new ts should be like:
time val
15:00 4
15:30 5.5
16:00 7
16:30 7
17:00 4.18
The value for timestamp 15:30 is computed as = (4*15+7*15)/30, and so on. I have implemented a code, that is capable of fixing this by applying the trapz function with a lot of if statements. However, I was wondering if there are better/simpler solutions around, as a modified synchronize function, since I have more than 500.000 data points.
Thanks in advance
I managed to fix my problem by dividing all time steps into minute-values and afterwards applying the trapezoidal rule to get the sum of the area under the curve (AUC) and then the average by dividing with the applied minute interval.
AllValues = interp1(Time,Data,NewTime,'previous')';
[Xdata,Ydata] = stairs(NewTime,AllValues);
NewTS = timeseries(Xdata,Ydata);
TrapzSum = cumtrapz(NewTS.time,NewTS.data);
TrapzSum = TrapzSum(1:2:end);
NewResults = diff(TrapzSum(IndicesOfNewInterval))/MinInt;

Counting the frequency of varying day-events

Let's say I have a few matrices where the first column is a serial date, and the second column is the information for that specific date. These matrices are organized in a way that all of the dates are at a minimum number of consecutive days. In the example below (A), this number is 3. This being said, A has runs of 3 consecutive days, 4 consecutive days, 5 consecutive days, and so forth, making the consecutive day count 3+. My total set of matrices range from 2+ to 5+.
A=
694094 91
694095 92
694096 94
694097 86
694157 95
694158 99
694159 99
694160 97
694183 100
694184 99
694185 96
694505 94
694506 92
694507 89
...
I want to find a way to count the varying amount of consecutive days per year. That is, count the amount of 3-day events, 4-day events, and onward. So, using the above example, the output would look like:
B=
1900 3
1901 1
....
Which states that there are three 3+ consecutive day events in 1900, and according to the example, only one 3+ consecutive day event in 1901. The years come from the serial date numbers, and the documentation on that can be found here. My data ranges from 1900 to 2013.
So far I've tried to use the diff function to try and split the day events by the amount of 1s in a string, find those indices, and then use histc to count the events per year but I'm realizing that this is a failed approach. I'm sure accumarray could help in this situation -- but I'm still foggy on the function after going through examples on mathworks and SO.
Code
N = 3; %// 3 for 3+ events. Change it to 2 or 5 for 2+ and 5+ events respectively
%// Year IDs
year_ID = str2num(datestr(A(:,1),'yyyy'))
%// Binary array, where ones represent consecutive dates starting with zero
%// as the start of a pack of consecutive dates
diffA1 = [0 ; diff(A(:,1))==1]' %//'
%// Row numbers of A that signal the start of N+ events.
%// STRFIND here works like a "sliding-matcher" if I may call it that way.
%// It works with a matching window that slides across diffA1 to find N+ events
%// using a proper filter. Here a filter [0 1 1] is used for 3+ events
row_ID = strfind(diffA1,[0 ones(1,N-1)])
%// N+ events for each year
Nplus_event = year_ID(row_ID)
%// Desired output as a count of such N+ events against each year
B = [unique(Nplus_event) histc(Nplus_event,unique(Nplus_event))]