Get BarsSince() for nth occurrence instead of 1st occurrence - amibroker

The function BarsSince() will return number of bars (time periods) that have passed since ARRAY was true (or 1) for the 1st occurrence of the condition true.
https://www.amibroker.com/guide/afl/barssince.html
For example, I have an array like this;
arr_test = [1 0 0 0 1 0 0 1 0 0 1 0 0];
BarsSince(arr_test) will return 3 as that is the first occurrence of 1.
What if I want to find out the number of bars that have passed for the nth occurrence of the true condition? As illustration, I would like to have a function such that
BarsSince_N(arr_test, n=2) will return 6.
Thank you.
I am using Amibroker ver6.30.5

You might want to look at Valuewhen.
So, then you can do something like:
bi = ValueWhen(arr_test > 0, BarIndex(), "nth occurence - 0 is the latest");
bars_since = LastValue(Close) - bi;
Here, I'm just using LastValue to get the last barnumber of the entire price series. This is untested, but you should get the idea.

Related

Countif the Result of Subtracting Two Arrays Exceeds a Certain Value in Excel

I am new to array formulae and am having trouble with the following scenario:
I have the following matrix:
F G H I J ... R S T U V
1 0 0 1 1
0 1 1 1 2 3 1 2
2 0 2 3 1 2 0 1 0 0
2 1 0 0 1 0 0 3 0 0
My goal is to count the number of rows within which the difference between the sum of columns F:J and the sum of columns R:V is greater than a threshold. Critically, only rows with full data should be included: row 1 (where there are only values for columns F1:J1) and row 2 (where there are only some values for columns F2:J2) should be ignored.
If the threshold = 2.5, then the solution is 1. That is, row 3 is the only row with complete data where the difference between the sum of F3:J3 (8) and the sum of R3:V3 (3) is greater than 2.5 (e.g., 5 > 2.5).
I have tried to put together the following formula, rather pathetically, based on the teachings of #Tom Sharpe and #QHarr:
=COUNT(IF(SUBTOTAL(9,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))-SUBTOTAL(9,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))>2.5,IF(AND(SUBTOTAL(2,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))=COLUMNS(F1:J1),SUBTOTAL(2,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))=COLUMNS(R1:V1)),SUBTOTAL(9,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))),IF(AND(SUBTOTAL(2,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))=COLUMNS(F1:J1),SUBTOTAL(2,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))=COLUMNS(R1:V1)),SUBTOTAL(9,OFFSET(R1,ROW(R1:V1)-ROW(R1),0,1,COLUMNS(R1:V1))))))
But it seems to always produce a value of 1, even if I edit the matrix such that the difference between the sum of F4:J4 and R4:v4 also exceeds 2.5. Sadly I am struggling to understand why and would appreciate any guidance on the matter.
As an array formula in one cell without volatile functions:
=SUM((MMULT(--(LEN(F2:J5)*LEN(R2:V5)>0),--TRANSPOSE(COLUMN(F2:J2)>0))=5)*(MMULT(F2:J5-R2:V5,TRANSPOSE(--(COLUMN(F2:J2)>0)))>2.5))
should do the trick :D
Maybe, in say X1 (assuming you have labelled your columns):
=COUNTIF(Y:Y,TRUE)
In Y1 whatever your chosen cutoff (eg 2.5) and in Y2:
=((COUNTBLANK(F2:J2)+COUNTBLANK(R2:V2)=0)*SUM(F2:J2)-SUM(R2:V2))>Y$1
copied down to suit.
Try this:
=SUMPRODUCT((MMULT(F1:J4-R1:V4,--(ROW(INDIRECT("1:"&COLUMNS(F1:J4)))>0))>2.5)*(MMULT((LEN(F1:J4)>0)+(LEN(R1:V4)>0),--(ROW(INDIRECT("1:"&COLUMNS(F1:J4)))>0))=(COLUMNS(F1:J4)+COLUMNS(R1:V4))))
I think this will do it, replacing your AND's by multiplies (*):
=SUMPRODUCT(--((SUBTOTAL(9,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))-SUBTOTAL(9,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))>2.5)*(SUBTOTAL(2,OFFSET(F1,ROW(F1:F4)-ROW(F1),0,1,COLUMNS(F1:J1)))=COLUMNS(F1:J1))*(SUBTOTAL(2,OFFSET(R1,ROW(R1:R4)-ROW(R1),0,1,COLUMNS(R1:V1)))=COLUMNS(R1:V1))>0))
It could be simplified a bit more but a bit short of time.
Just another option...
=IF(NOT(OR(IFERROR(MATCH(TRUE,ISBLANK(F1:J1),0),FALSE),IFERROR(MATCH(TRUE,ISBLANK(R1:V1),0),FALSE))), SUBTOTAL(9,F1:J1)-SUBTOTAL(9,R1:V1), "Missing Value(s)")
My approach was a little different from what you tried to adapt from #TomSharp in that I'm validating the cells have data (not blank) and then perform the calculation, othewise return an error message. This is still an array function call, so when you enter the formulas, press ctrl+shft+enter.
The condition part of the opening if() checks to see that each range's cells are not blank: if a match( true= isblank(cell))
means a cell is blank (bad), if no match ... ie no blank cells, Match will return an #NA "error" (good). False is good = Errors found ? No. ((ie no blank cells))
Then the threshold condition becomes:
=COUNTIF(X1:X4,">"&Threshold)' Note: no Array formula here
I gave the threshold (Cell W6) a named range for read ablity.

matlab: how to speed up the count of consecutive values in a cell array

I have the 137x19 cell array Location(1,4).loc and I want to find the number of times that horizontal consecutive values are present in Location(1,4).loc. I have used this code:
x=Location(1,4).loc;
y={x(:,1),x(:,2)};
for ii=1:137
cnt(ii,1)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3)};
for ii=1:137
cnt(ii,2)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3),x(:,4)};
for ii=1:137
cnt(ii,3)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1})&strcmp(x(:,4),y{1,4}{ii,1}));
end
y={x(:,1),x(:,2),x(:,3),x(:,4),x(:,5)};
for ii=1:137
cnt(ii,4)=sum(strcmp(x(:,1),y{1,1}{ii,1})&strcmp(x(:,2),y{1,2}{ii,1})&strcmp(x(:,3),y{1,3}{ii,1})&strcmp(x(:,4),y{1,4}{ii,1})&strcmp(x(:,5),y{1,5}{ii,1}));
end
... continue for all the columns. This code run and gives me the correct result but it's not automated and it's slow. Can you give me ideas to automate and speed up the code?
I think I will write an answer to this since I've not done so for a while.
First convert your cell Array to a matrix,this will ease the following steps by a lot. Then diff is the way to go
A = randi(5,[137,19]);
DiffA = diff(A')'; %// Diff creates a matrix that is 136 by 19, where each consecutive value is subtracted by its previous value.
So a 0 in DiffA would represent 2 consecutive numbers in A are equal, 2 consecutive 0s would mean 3 consecutive numbers in A are equal.
idx = DiffA==0;
cnt(:,1) = sum(idx,2);
To do 3 consecutive number counts, you could do something like:
idx2 = abs(DiffA(:,1:end-1))+abs(DiffA(:,2:end)) == 0;
cnt(:,2) = sum(idx2,2);
Or use another Diff, the abs is used to avoid negative number + positive number that also happens to give 0; otherwise only 0 + 0 will give you a 0; you can now continue this pattern by doing:
idx3 = abs(DiffA(:,1:end-2))+abs(DiffA(:,2:end-1))+abs(DiffA(:,3:end)) == 0
cnt(:,3) = sum(idx3,2);
In loop format:
absDiffA = abs(DiffA)
for ii = 1:W
absDiffA = abs(absDiffA(:,1:end-1) + absDiffA(:,1+1:end));
idx = (absDiffA == 0);
cnt(:,ii) = sum(idx,2);
end
NOTE: this method counts [0,0,0] twice when evaluating 2 consecutives, and once when evaluating 3 consecutives.

How to compare each matrix to mean and return value in Matlab

for example lets consider
a = fix(8 * randn(10,5));
and mean(a) would give me mean of each column.
So, what I was planning to do was comparing the mean of first column to each of its content till the column and and proceed to the next column with its mean and comparing with each of its content.
I was able to get this code here (I know there are multiple for loops but thats the best I could come up with, any alternate answer would be greatly accepted)
if(ndims(a)==2)
b = mean(a);
for c = 1:size(a,2)
for d = 1:size(a)
for e = 1:size(b,2)
if(a(d,c)>b(1,c))
disp(1);
else
disp(false);
end
end
end
end
else
disp('Input should be a 2D matrix');
end
I don't know if this is the right answer? Could any one tell me?
Thanks in advance.
It seems you want to know whether each entry is greater than its column-mean.
This is done efficiently with bsxfun:
result = bsxfun(#gt, a, mean(a,1));
Example:
a =
3 1 3 2
5 2 3 1
1 3 5 2
The column-means, given by mean(a,1), are
ans =
3.000000000000000 2.000000000000000 3.666666666666667 1.666666666666667
Then
>> result = bsxfun(#gt, a, mean(a,1))
result =
0 0 0 1
1 0 0 0
0 1 1 1
If you are trying to do what I think you are (print one if the average value of a column is greater than the value in that column, zero otherwise) you can eliminate a lot of loops doing the following (using your same a and b):
for ii=1:length(b)
c(:,ii) = b(ii) > a(:,ii);
end
c will be your array of ones and zeros.

FOR loop with multiple values from two arrays in different configurations

I am working on a project involving calculating the work volume for a device.
Given that I have two angles, beta1 and beta2 between let's say 0-10 degrees ([deg] used for simplification here, in reality in [rad]),
I want to calculate the work volume for different combinations of e.g.
beta1 = 1 [deg]
and at the same time
beta2 = 8 [deg]
I can't get my head around how to do it. I tried to cheat by running the FOR loop for 1000 values of beta1 and then a random entry from the beta2 array, but obviously it is not very reliable.
Here is the code: (it is a mess, but it is just trigonometry)
for ii=1:1000
for jj=randi(1000)
T_0{ii} = [0 0 0 (l_joint/beta1(ii))*tan(beta1(ii)/2); 0 1 0 0; 0 0 1 0; 0 0 0 1];
T_1{ii} = [cos(beta1(ii)) -sin(beta1(ii))*cos(alpha1) sin(beta1(ii))*sin(alpha1) ...
((l_joint/beta1(ii))*tan(beta1(ii)/2)+l_disk+(l_joint/beta2(ii))*tan(beta2(jj)/2))*cos(beta1(ii)); ...
sin(beta1(ii)) cos(beta1(ii))*cos(alpha1) -cos(beta1(ii))*sin(alpha1) ...
((l_joint/beta1(ii))*tan(beta1(ii)/2)+l_disk+(l_joint/beta2(jj))*tan(beta2(jj)/2))*sin(beta1(ii)); ...
0 sin(alpha1) cos(alpha1) 0; ...
0 0 0 1];
T_2{ii} = [cos(beta2(jj)) -sin(beta2(jj))*cos(alpha2) sin(beta2(jj))*sin(alpha2) ...
((l_disk+(l_joint/beta2(jj))*tan(beta2(jj)/2)))*cos(beta2(jj)); ...
sin(beta2(jj)) cos(beta2(jj))*cos(alpha2) -cos(beta2(jj))*sin(alpha2) ...
((l_disk+(l_joint/beta2(jj))*tan(beta2(jj)/2)))*sin(beta2(jj)); ...
0 sin(alpha2) cos(alpha2) 0; ...
0 0 0 1];
T_section{ii} = (T_0{ii}*T_1{ii}*T_2{ii})^n;
end end
As far as i can work out, you have a function T_section with 2 parameters beta1 and beta2 and are asking how to calculate the value of the function T_section(beta1, beta2) for all combinations of beta1 and beta2. You can calculate and visualize the results of a 2-D function in MATLAB like this:
beta1 = 0:0.1:10;
beta2 = 0:0.1:10;
[B1, B2] = meshgrid(beta1, beta2);
T_section = sind(10*B2)*cosd(20*B1); % replace with actual function
surf(beta1, beta2, T_section,'EdgeColor','none')
xlabel('\beta_1'); ylabel('\beta_2');
which yields this plot:
No need for loops here, vectorizing your calculations in MATLAB is very likely much faster (see the excellent MATLAB documentation, e.g. http://de.mathworks.com/help/matlab/matlab_prog/vectorization.html). You should probably also read the documentation about meshgrid (doc meshgrid on the console).

2D Array containing only 0 or 1

I have a 2 dimensional array which randomly contains values of 0 or 1.
How can I ( most efficiently ) determine the lower most element of value 1 ( the biggest row iteration i ) and the right most element ( the highest column iteration j ) ?
For example:
0 0 1 0
1 0 1 0
0 1 0 0
1 0 0 0
My program should answer i = 3 ( assuming first row is i = 0) and j = 2 ( assuming first column is 0 ).
Here's an idea:
Starting with the bottom-most row, use memrchr to find the last 1 in each row (I'm sort of assuming you store the numbers as char aka 8-bit integers).
Eventually you will find a row which has a 1. This is your answer for i. We got this far using cache-friendly, row-at-a-time operations because C uses row-major order.
Above, you also now know the lower bound for j (because you found the last 1 in the last row that had any 1s).
For the remaining rows, use memrchr from one past the lower bound for j to the end of each row. If you find any 1s there, update the lower bound. Repeat until you have inspected all the rows.
Of course, if you ever find a 1 in the last column, you can stop right away.
Use a plain loop and simply search from the beginning (or the end, depending on what you want to achieve) and check each element. There is no more efficient way.
As far as C and C++ are concerned, what is efficient and what is not lies in the nature of the implementation. If this is a bit field matrix for example, then you can optimize the code slightly by first comparing each byte against 0, before you start searching through the individual bits.
And as usual, it doesn't make sense to talk about efficiency without specifying what it means. Speed? Memory consumption? Program size? It also doesn't make sense to talk about efficient implementation in C or C++ without a given system in mind.
Here is the naive method - just iterating through all positions in the array. Worst case O(n*m):
#define WIDTH 4
#define HEIGHT 4
int main ()
{
int i,j,col,row;
int arr[HEIGHT][WIDTH] = set_Array();
for (j=0;j<HEIGHT;j++){
for (i = 0; i<WIDTH; i++){
if (arr[j][i]){
row = j>row?j:row;
col = i>col?i:col;
}}}
}
How can we improve this? Well we can start from the end and work backwards, but we will have to do the rows and columns alternately rather than just visiting each cell in turn. We could look for column, and then row, but that would be less efficient.
0. 1. 2. 3.
0. 0 0 1 0
1. 1 0 1 0
2. 0 1 0 0
3. 1 0 0 0
In this example, we search row 3 and column 3 first, and eliminate them from the search. Then row 2 and column 2 up to but not including the eliminated column 3 and row 3. Then row 1...
Of course, we stop searching rows when the bottom most one containing a 1 is found, and stop searching columns when the rightmost one containing a 1 is found.
Code:
#include <stdio.h>
#define WIDTH 4
#define HEIGHT 4
int main ()
{
int i,j,col = 0, row = 0;
int current_row = HEIGHT;
int current_col = WIDTH;
int arr[WIDTH][HEIGHT] = {{0,0,1,0},{1,0,1,0},{0,1,0,0},{1,0,0,0}};
while (!(row && col))
{
current_row--;
current_col--;
if (!row){
printf("searching row: %d\n",current_row);
for (i = 0; i < current_col; i++){
if (arr[current_row][i]){
row = current_row;
}}}
if (!col){
printf("searching col: %d\n",current_col);
for (j = 0; j < current_row; j++){
if (arr[j][current_col]){
col = current_col;
}}}
}
printf("col: %d, row: %d\n", col, row);
}
See it live
Output:
searching row: 3
searching col: 3
searching col: 2
col: 2, row: 3
The worst case is still O(m*n), and is actually slightly worse (you test cells on the diagonal starting from the bottom right twice), but the average case is better.
We scan through the lowest unsearched row for a 1, then search through the rightmost unsearched column for a 1.
When you find the lowest 1 you no longer search each row for more 1's. When you find the rightmost 1 you no longer search each column for more 1's either.
This way we stop the search once we find the answer, and unlike the naive method, this means that we don't usually have to go through each value in the array.
If the row size of the array is up to 32 numbers you can use a single int32_t to represent a whole row: The value of the number is the whole row.
Then your whole array will be a one dimensional array of int32_t's:
int32_t matrix[nRows];
Now you can find the lowermost row by finding the last number of matrix that is not equal to 0 in O(nRows) time with a very simple implementation.
Also, you can find the rightmost 1 by with the following trick:
For each matrix[i] you isolate the rightmost 1 by calculating matrix[i] & -matrix[i]. Then calculating the log2 of this result gives you the number of the column. The largest number of column for all matrix[i] numbers gives you the result you want. (Again O(nRows) time with a very simple implementation).
Of course, if the row size is larger that 32 values, you have to use more int32_t values per row, but the principle remains the same.

Resources