MATLAB: how to loop through my vector and round up or down - matlab

I have to write up a code whereby I use Mean-variance optimization to rebalance my portfolio for 12 months (one year). The only thing is that I have to determine how I will round my number of assets after each rebalancing. When I round, I need to see if the difference between my new portfolio value (after subtracting transaction costs) and my old portfolio value is positive, up to a set limit of about $3000.00.
For example, my initial number of assets was:
x_int = [4500, 6000, 0, 0, 0, 500, 1550, 0, 1000, 0];
My new rebalanced number of assets for the first period was:
x_new = [2490.67, 4401.78, 1502.30, 0, 1010.45, 2803.85, 3489.77, 0, 650.98, 1001.87];
My initial portfolio value was $1,897,560.30
My rebalanced portfolio value for the first period came out as $1,658,923.76 (after I rounded all my asset numbers down) and as $2,001,876.95 (after I rounded all my asset numbers up).
Is there a way to loop through my x_new values, round up and/or down each individual number of assets and check to see if my rounded assets will give me a new portfolio value that, when I subtract from the initial portfolio value will satisfy my criteria
Thanks!

Since there would generally be more than one ways of adjusting the portfolio to
meet the criterion, the answer would depend on what kind of adjustments you prefer. The following approach starts with rounding to nearest integer and then, if required to meet the budget, rounds some of the stocks to the opposite direction.
Let,
price be a vector the same size as x_new and represent the unit share price.
budget be the upper limit of the new portfolio value (i.e old portfolio value + 3000 + transaction costs).
Firstly, let's round the new portfolio stocks to nearest integer and compute the cost.
x_rnd = round(x_new);
cost_rnd = x_rnd * price';
Depending on whether cost_rnd is above or below budget we would tweak the number of individual shares. If cost_rnd is under-budget, we would try to round-up some of the stocks that were rounded-down. Similarly, if cost_rnd is over-budget we would change some of the roundings from up to down.
cost_rnd = x_rnd * price';
if (cost_rnd > budget) % exceeds budget, so we need to round a few of them down
x_adjust_dir = floor(x_new)-x_rnd;
cum_adjust_cost = cost_rnd + cumsum(x_adjust_dir .* price);
n_adjust = find(cum_adjust_cost < budget, 1, 'first');
elseif (cost_rnd < budget) % under-budget, so we should round a few of them up
x_adjust_dir = ceil(x_new)-x_rnd;
cum_adjust_cost = cost_rnd + cumsum(x_adjust_dir .* price);
n_adjust = find(cum_adjust_cost < budget, 1, 'last');
else % by some miracle the budget is exactly met
n_adjust = [];
end
Note that some elements of x_adjust_dir would be zeros. They represent the shares that are already rounded in the right direction. The remaining elements would be -1 for over-budget case and 1 for under-budget case. cum_adjust_cost is the cumulative change due to the rounding adjustments. n_adjust is the index of the cumulative adjustment that puts the adjusted cost just below the budget.
Now all that remains is to apply the adjustments:
x_final = x_rnd;
if ~isempty(n_adjust)
x_final(1:n_adjust) = x_final(1:n_adjust) + x_adjust_dir(1:n_adjust);
end
x_final is the adjusted portfolio that meets the criterion.

Related

TV has not function to detect dominant CycleLength. Script has some problems and I cannot find them

The code has an array or loop error or cannot use the information. I want to calculate for 1 to 100 all cycles. And from these Cycles it should find out the most dominant cycle length and plot this dominant one to the chart. Better would be to get the 3 most dominant cycles and put them together into one plotted line. Please help! unfortunately
TV has no functions for detecting dominant cycles and this should solve the problem but it hast some script Problems.
//#version=5
// Import the ta-lib library
indicator("ta-lib")
// Define the period range for the analysis
periodStart = 1
periodEnd = 100
// Define the data series
dataSeries = close
// Create an array to store the magnitude of the DFT for each period
magnitudeArray = array.new<float>(periodEnd)
// Loop over the periods
for period = periodStart to periodEnd
// Initialize the real and imaginary parts of the DFT for each period
re = 0.0
im = 0.0
// Loop over the data for each period
for i = 0 to period-1
re := re + dataSeries[i]*math.cos(-2*math.pi*i/period)
im := im + dataSeries[i]*math.sin(-2*math.pi*i/period)
// Calculate the magnitude of the complex numbers for each period
magnitudeArray[period] := math.sqrt(re*re + im*im)
// Initialize a variable to store the maximum magnitude and its corresponding period
maxMagnitude = 0.0
dominantCyclePeriod = 0
// Loop over the magnitude array to find the period with the highest magnitude
for period = periodStart to periodEnd
if array.max(magnitudeArray[period]) > maxMagnitude
maxMagnitude = array.max(magnitudeArray[period])
dominantCyclePeriod = period
// Plot the dominant cycle period on the chart
plot(dominantCyclePeriod)

trial structure psychtoolbox experiment

I want to program an experiment that should consist of 10 trials (10 pictures) that a shown either on the left or right side. At the same time there is a odd or even number shown on the opposite side. I want to measure reaction time and response (odd or even). I guess I am stuck with the trial structure.
Is it enough to just define the ntrials = length(pictures) or do I need a for loop for the variables (pic_position, number_position)?
This is my approach so far:
pic_pos = {'left' 'right'};
num_pos = {'left' 'right'};
evenodd = {'odd' 'even'};
ntrials = length(pictures);
for n = 1:length(pictures)
trials(ntrials).picture = pictures(n)
end
pictures = Shuffle(pictures);
for trial = 1:ntrials
currentnumber = num2str(numbers{trial})
switch trials(trial).num_pos
case 'right'
x = screencentrex + img_dist
case 'left'
x = screencentrex - img_dist
end;
Screen('TextSize', win, [25]);
DrawFormattedText(win, currentnumber, [x], 'center', [255 255 255]);
Screen('Flip', win);
WaitSecs(3);
Unfortunately it doesn't show me the number.
You don't neccessarily need to loop over the position or number variables. Instead, you can generate the stimulus parameters for each trial in advance, for example using the Psychtoolbox function BalanceFactors
[trialNumberPositions, trialNumberEvenOrOdd] = BalanceTrials(ntrials, 1, num_pos, evenodd);
This returns combinations of the levels of the factors 'num_pos' and 'evenodd', the orders of which are then randomized. So for example the number position for the trial number saved within the variable 'trial', in your example would be accessed as trialNumberPositions{trial}. Keep in mind that you have 4 unique combinations of evenodd and num_pos, so for your trial numbers to be balanced across conditions you would have a total number of trials that is a multiple of 4 (for example 12 trials total, rather than 10). I didn't include pic_pos because the pic_pos would always be whatever num_pos is not, as in your description the two stimuli would never be presented on the same side.
As to why your number isn't being displayed, it is hard to tell without more of the experiment script. But you are currently writing white text to the screen, is the background non-white?

Use MATLAB to double a parameter until a certain value

I want to double a parameter (population size) until it reaches a certain value, regardless of the number of loops (generations). Say I have the following loop:
population_size = 10; %initial population size
for i = 0:10, %no. of generations
%(*call function for model*)
population_size = (population_size*2);
gene_frequency = (gene_frequency*population_size)/population_size;
end
How would I do this in MATLAB?
As Yvon has suggested, use a while loop that will keep looping until you meet a certain condition. I can see that your population size is doubling, and so you want to make the while loop until is it equal to, or exceeds this number.
I do have one question though: Your gene_frequency call seems useless. You are taking the variable, multiplying by population_size, then dividing by population_size.... and you'll just get the same number as you did last time. I'm going to leave this statement out as it doesn't contribute anything meaningful to your question.
As such:
population_size = 10; %initial population size
target_population = ... ;%// You place the population you want met here
while population_size < target_population %// NEW
%//(*call function for model*)
population_size = (population_size*2);
end
Edit - July 30th, 2014
You have mentioned in your comments that you want to run this for 15 generations, but when the population size reaches its limit, it will remain the same for the rest of the generations. You can combine this with a for loop and an if statement. We will go through each generation, then check to see what the population size is. As long as the population size is less than the target population, we will double the size. Once it finally exceeds the population size, this will no longer double but the loop will keep going until go through the rest of the generations.
You can do this like so:
population_size = 10; %initial population size
target_population = ... ;%// You place the population you want met here
for gen = 1 : 15
%//(*call function for model*)
if (population_size <= target_population)
population_size = (population_size*2);
end
end

How to identify timestamps (indices) of multiple threshold crossings in continuous data

From an audio stream vector in Matlab I am trying to identify the time of onset and finish of audible events that occur multiple times within the time series data.
I am very much a novice with Matlab, but I have written code which identifies the peak and location of the event, however, I need to get the start of the event relative to a user defined threshold which occurs several tens of milliseconds before the peak.
Here is the code I am using at the moment:
function [emg] = calcPeaks(EMG, thresh)
%Rectify and downsample data
emg = resample(abs(hilbert(EMG)),1000,10000);
%Low Pass Filter
[b,a]=butter(8,0.01,'low');
emg=filtfilt(b,a,emg);
%Plot the processed vector
plot (emg); hold on;
%Find maximum for each Peak and Location
[pks,locs] = findpeaks(emg(1:end-2000),'minpeakheight',thresh);
plot(locs, emg(locs), 'ko'); hold on;
%Find Crossings above threshold
[FindCross] = find(emg(1:end-2000) > thresh);
[Gaps] = find(diff(FindCross)> thresh);
plot(FindCross, emg(FindCross), 'ro');
plot(Gaps, emg(Gaps), 'bo');
I tried to post an image of the datat but I don't have enough reputation :(
This should be getting you close to what you want (although same thresh for both is probably not what you intend):
[FindCross] = find(emg(1:end-2000) > thresh); %thresh is your minimum volume
[Gaps] = find(diff(FindCross)> thresh2); % thresh2 is related to the timing of events
However, note that this only finds gaps between areas which are above your noise level threshold, so won't locate the first event (presuming at start of data you are below the threshold).
A simple way to do this sort of thing is to threshold and then use diff to look for rising and falling edges in the thresholded data.
emg2 = emg > thresh; %emg2 = 1 and 0 for event / non event
demg = diff(emg2); % contains 0, -1, 1
rise = find(demg>0)+1; %+1 because of how diff works
fall = find(demg<0);
rise should then contain the positions where emg goes from below threshold to above threshold. If the data is sufficiently noisy, this could contain false positives, so you may want to then filter those results with additional criteria - e.g. check that after the rise the data stays above threshold for some minimum period.
The problem with doing it by the method you're using to find gaps is the following. Presume your data looks like this, where 0 is below threshold and 1 above threshold: 000111000111000. That is, our first event starts at index 4 and finishes at index 6, and the second starts at index 10 and ends at index 12.
emgT = find(emg > thresh);
This finds all the places where our data = 1, so emgT = [4,5,6,10,11,12]
emgD = diff(emgT);
This takes the difference between emgT(n+1), and emgT(n) - since there's no n+1 for the final datapoint, the output is one smaller than emgT. Our output is [1 1 4 1 1] - that is, it will find the gap between the two events, but not the gap between the start of the file and the first event, or the gap between the last event and the end of the file.

Can this Matlab function be vectorized (or made to run faster by other another method)?

The main problem is finding values at a fixed offset from the current value.
My current method is very slow when the Value vector is large (typically 100000's of elements).
function [ AverageValue ] = CalculateAverageValueOverAngle( Value, Angle )
% function [ AverageValue ] = CalculateAverageValueOverAngle( Value, Angle )
% Calculate average value from instantaneous value and angle
% Average value is calculated over +- 90 degrees from current angle
AverageValue = zeros( size( Value ) );
UnwrappedRadians = unwrap( Angle ./ 180 * pi );
for i=1:length(UnwrappedRadians)
mid = UnwrappedRadians(i);
start = find( UnwrappedRadians(1:i) < (mid - pi/2), 1, 'Last');
finish = find( UnwrappedRadians(i:end) > (mid + pi/2), 1, 'First');
if isempty(start) | isempty(finish)
AverageValue(i) = Value(i);
else
AverageValue(i) = mean(Value(start:finish+i-1)); % nanmean
end
end
end
A minor refactoring will save the second find in instances where you don't find results, and preallocating with AverageValue with Value saves the else part.
UnwrappedRadians = unwrap( Angle ./ 180 * pi);
AverageValue = Value;
for i=1:length(UnwrappedRadians)
mid = UnwrappedRadians(i);
start = find( UnwrappedRadians(1:i) < (mid - pi/2), 1, 'Last');
if ~isempty(start)
finish = find( UnwrappedRadians(i:end) > (mid + pi/2), 1, 'First');
if ~isempty(finish)
AverageValue(i) = mean(Value(start:finish+i-1)); % nanmean
end
end
end
If you find that the calculation of finish is empty more often than the calculation of start, you can switch their order so that the finish check is done first.
It's not clear if UnwrappedRadians will always be sorted. If so, you can reuse the results from earlier finds to reduce the size of the subvector you search over. For instance, if the you look for the last 1 between 11 and the end of the vector and it is element 23, when you search for 1.1, you can reduce the search to between 24 and the end of the vector. I've found that this technique can yield really big increases in speed.
Vectorization is difficult in cases like this, because you are using the indexing variable (i) as an index again (in the find statements). It is possible to rig something up using arrayfun, but it is highly unlikely to be faster (I would guess slower, actually) and will definitely be less readable than what you have.
MatlabSorter has provided a refactoring which makes sense to me, so if your code really does what you want, his refactoring is the way forward :-).
Note that in my tests with numel(Angle)=50000, his refactoring did not save much (probably because my sample data assumed that the find()s will almost never fail except at the very beginning and at the end of your data trace).
However, while looking at your code, I was wondering: Are you sure you absolutely want to average all values from the first time the angle gets into the mid-pi/2...mid+pi/2 range, until the last time it leaves that range? If your unwrapped Angles are non-monotonous (for example if backwards movements are allowed, if the sampling rate is too low to avoid aliasing, or simply due to measurement noise in the angle) then you will also be averaging over some values outside (and possibly well outside) the 180° range.
Note that in any case the first measurement (Value(start)) you average over is always more than pi/2 before your "mid" angle (you start with the last angle before the interval), while your last measurement (Value(finish+i-1)) is always more than pi/2 behind mid. So your effective range you average over is always larger than pi, even if data values at exactly mid-pi/2 and mid+pi/2 are available... is that really intended?
So in case you are really interested in averaging only Values where Angle is less than pi/2 from mid, here is my code suggestion, which sadly has only marginally quicker runtime than what you currently use. Note that this is NOT a refactoring, because it acts differently from your code in the two ways described above.
UnwrappedRadians = unwrap( Angle ./ 180 * pi);
AverageValue = Value;
avgstart=find( UnwrappedRadians > (UnwrappedRadians(1) + pi/2), 2, 'First');
avgend=find( UnwrappedRadians < (UnwrappedRadians(end) - pi/2), 1, 'Last');
for i=avgstart:avgend
AverageValue(i) = mean(Value(abs(UnwrappedRadians-UnwrappedRadians(i)) <= pi/2)); % nanmean
end