Dear IML Users,
I initially posted this query elsewhere, but realised it should be posted here instead.
I am populating a matrix using the row values of another matrix (this is a part of a bigger programming issue I have and I have tried to simplify the issue down to its basics - I understand that do loops should be avoided in Proc IML, but in this case it is unavoidable)
The issue is that the program works fine as individual statements, but when I insert a do loop, the 'vwap' matrix no longer updates properly - it inserts the number of rows and values from the last iteration and remain unchanged thereafter. I dont understand this as all the other elements update correctly and their properties are the same, so I cant see why it should fail.
To see what is happening run the code below, I have hard coded the first two iterations and they work fine, vwap updates with the correct number of rows and the right values inserted. When I used a do loop to control the third execution, the same number of rows and values are inserted from the last iteration.
Any help you could give would be most appreciated as this really has be perplexed.
proc iml;
reset print;
xxx = {10 2 2.91, 10 3 3.05, 10 1 3.07};
volume = xxx[1,2];
price = xxx[1,3];
call symput ('volume', char(volume));
call symput ('price', char(price));
vwap = {[&volume] &price}`;
volume = xxx[2,2];
price = xxx[2,3];
call symput ('volume', char(volume));
call symput ('price', char(price));
vwap = vwap//{[&volume] &price}`;
do i = 3 to 3;
volume = xxx[i,2];
price = xxx[i,3];
call symput ('volume', char(volume));
call symput ('price', char(price));
vwap = VWAP//{[&volume] &price}`;
end;
quit;
This is a good question, and definitely nonobvious until you start to think about it.
The key point to remember that &price is evaluated by the macro preprocessor AT PARSE TIME, not at run time. The SAS/IML code never sees &price at run time, only the constant that was substituted.
You probably already nknew that, but what you might not know is that the SAS/IML language parses the ENTIRE body of the DO loop prior to execution. (This is done for efficiency and to check for syntax errors.) The preprocessor substitutes the current values of the macro variables AT PARSE TIME. When the DO loop executes, the values are constant within the loop.
I would not recommend the approach that you are using. Creating all those macro variables is less efficient than just using the SAS/IML values. However, if you insist upon using macro variables, use the SYMGET function to grab the values of the macros at run time.
PS. That concatenation within the loop is going to kill the performance. See Tip #3 at Eight tips to make your simulation run faster - The DO Loop
This is a good question, and definitely nonobvious until you start to think about it.
The key point to remember that &price is evaluated by the macro preprocessor AT PARSE TIME, not at run time. The SAS/IML code never sees &price at run time, only the constant that was substituted.
You probably already nknew that, but what you might not know is that the SAS/IML language parses the ENTIRE body of the DO loop prior to execution. (This is done for efficiency and to check for syntax errors.) The preprocessor substitutes the current values of the macro variables AT PARSE TIME. When the DO loop executes, the values are constant within the loop.
I would not recommend the approach that you are using. Creating all those macro variables is less efficient than just using the SAS/IML values. However, if you insist upon using macro variables, use the SYMGET function to grab the values of the macros at run time.
PS. That concatenation within the loop is going to kill the performance. See Tip #3 at Eight tips to make your simulation run faster - The DO Loop
Rick,
Thanks so much for your reply. It is much appreciated (as are your other posts to this forum).
I understand the concerns around this code, but I just cant think of a better way to do it.
What I am trying to calculate is the volume weighted average price of a portfolio of assets. A person buys and sell shares - column 2 of the xxx matrix is the size of the trade and column 3 is the price (column 1 is a buy sell indicator and at the moment I only have buys (=10) until I get the code right).
The problem with calculating VWAP is when an investor sells that shares as, depending on what assumption you make about which shares are being sold, the vwap of the remaining shares held in the portfolio will be different. The two standard conventions are last in, first out (LIFO) and first in, first out (FIFO).
My approach to this was to create a vector consisting of a price entry for each share (hence why I am using the repetition factor set equal to volume to stack up a vector of prices). The average of this vector is the vwap of the holding. When a sale of shares happens, I can modify this vector by deleting a number of rows equal to the number of shares sold either at the beginning or the end of the vector depending on whether the LIFO or FIFO assumption is employed . By taking the average of the remaining values in the vector I will get the vwap of the shares held in the portfolio after the sale. Then we move on to the next trade.
I hope all this makes sense. Not the most elegant solution, but I am not sure how else to do it.
Thanks again.
Use the REPEAT function, which eliminates the need for the repitition factor.
Thanks Rick, all sorted now.
See also Repetition factors versus frequency variables - The DO Loop and the links within that article.
I wrote a more thourough explanation of this problem: Macros and loops in the SAS/IML language - The DO Loop
Are you ready for the spotlight? We're accepting content ideas for SAS Innovate 2025 to be held May 6-9 in Orlando, FL. The call is open until September 16. Read more here about why you should contribute and what is in it for you!
Learn how to run multiple linear regression models with and without interactions, presented by SAS user Alex Chaplin.
Find more tutorials on the SAS Users YouTube channel.