I wrote
do while (A<=B<=C);...;end
and I did not obtain what I expected (which is A<=B and B<=C). So how does SAS interpret the expression A<=B<=C ? Note: SAS did not give an error for A<=B<=C.
I believe it evaluates left to right:
(A <= B) <= C
A <= B evaluates to 0 or 1. This value is then compared to C.
This works as you expect in a Data Step. It does not work in PROC IML.
1189 data _null_;
1190 a = 10;
1191 b = 10;
1192 c = 15;
1193
1194 do while(a<=b<=c);
1195 put b=;
1196 b = b + 1;
1197 /*Abort if this runs away*/
1198 if b > 20 then
1199 stop;
1200 end;
1201 run;
b=10
b=11
b=12
b=13
b=14
b=15
NOTE: DATA statement used (Total process time):
real time 0.00 seconds
cpu time 0.00 seconds
1203 proc iml;
NOTE: IML Ready
1204 a = 10;
1205 b = 10;
1206 c = 15;
1207 file log;
1208
1209 do while (a<=b<=c);
1210 put "B=" b;
1211 b = b+1;
1212
1213 if b>20 then stop;
1214 end;
B= 10
B= 11
B= 12
B= 13
B= 14
B= 15
B= 16
B= 17
B= 18
B= 19
B= 20
1215 quit;
NOTE: Exiting IML.
NOTE: PROCEDURE IML used (Total process time):
real time 0.00 seconds
cpu time 0.01 seconds
IML has slightly different logical syntax than Base SAS. In IML, use
do while ( (a<=b) & (b<=c));
Related
I have a vector made of 10 random integers like this:
a <- c(400,1,1,1,1,1,1,1,1,13)
and I have a random integer:
n <- 100
My goal is to divide n so that the components of a have the smallest differences between them. The desired output in this case is c(400,14,14,14,14,13,13,13,13,13) (13+13+13+13+12+12+12+12 = 100)
My approach was to use a recursive function:
dis <- function(n,a){
a[which.min(a)] <- a[which.min(a)] + 1
n <- n -1
if(!n){
return(a)
}
dis(n,a)
}
dis(100, c(400,1,1,1,1,1,1,1,1,13))
But I found problems when n is larger, e.g. when n is 1000 I get this message
Error: C stack usage 7969684 is too close to the m
I'm not sure if there is something to avoid recursion, maybe an arithmetic solution, or another approach.
Why not do it as a while loop rather than using deeply nested recursion?
dis <- function(n,a) {
while(n > 0)
{
a[which.min(a)] <- a[which.min(a)] + 1
n <- n - 1
}
a
}
dis(100, c(400,1,1,1,1,1,1,1,1,13))
#> [1] 400 14 14 14 14 13 13 13 13 13
dis(10000, c(400,1,1,1,1,1,1,1,1,13))
#> [1] 1043 1042 1042 1042 1042 1042 1042 1042 1042 1042
You need some minor modification over your recursive function, e.g.,
dis <- function(n, a) {
if (!n) {
return(a)
} else {
a[which.min(a)] <- a[which.min(a)] + 1
dis(n-1, a)
}
}
Example
> dis(100,a)
[1] 400 14 14 14 14 13 13 13 13 13
> dis(1000,a)
[1] 400 114 114 114 114 113 113 113 113 113
just looking for an easy way to run trig functions in SAS without having to manually correct in each calculation. Below is what I am working with.
I am running this in SAS 9 probably, the SAS Studio Student Module but this is a general SAS question.
I have manually created a variable, 'rad' in the 'calc' data step to deal with this but it adds a step of complexity that I would like to avoid.
I am asking whether there is a system setting, alternate trig function or ... ? that would change the calculation from:
bh_x = cos(rad*bh_a)*bh_l ;
to:
bh_x = cos(bh_a)*bh_l ;
so I don't have to manually convert my angle in degrees to radians for the trig function to work.
Thanks to anyone reading this and putting any mental effort to the solution!
Tim
data spec ;
length
b2h_a 8
b2h_l 8
b2h_l_e 8
bike $ 8
name $ 16
;
input
bike $
name $
bh_a
bh_l
ht_a
spcr
st_h
st_a
st_l
hb_r
hb_a
;
datalines ;
srcn (0,0) 0 0 67 0 0 0 0 0 0
srcn c 41 658 71.5 27 40 25 120 100 13
srcn ne_27_n13 41 658 71.5 27 40 27 127 100 13
srcn ne_15_0 41 658 71.5 15 40 27 127 100 0
srcn ne_5_0 41 658 71.5 5 40 27 127 100 0
srcn ne_2_n9 41 658 71.5 2 40 27 127 100 9
srcn ne_5_10 41 658 71.5 5 40 27 127 100 -10
srcn ne_10_rf10 41 658 71.5 10 40 27 127 20 -10
srcn max 41 658 90 250 0 0 250 0 0
;
run ;
data calc ;
set spec ;
pi=constant('pi') ;
rad=pi/180 ;
bh_x = cos(rad*bh_a)*bh_l ;
bh_y = sin(rad*bh_a)*bh_l ;
sr_x = (cos(rad*ht_a)*(spcr+st_h/2))*-1 ;
sr_y = sin(rad*ht_a)*(spcr+st_h/2);
st_x = cos(rad*(90-ht_a+st_a))*st_l ;
st_y = sin(rad*(90-ht_a+st_a))*st_l ;
hb_x = cos(rad*(90-hb_a))*hb_r*-1 ;
hb_y = sin(rad*(90-hb_a))*hb_r ;
hd_x = bh_x + sr_x + st_x + hb_x ;
hd_y = bh_y + sr_y + st_y + hb_y ;
if hd_x=0 then do ;
b2h_a=0 ;
b2h_l=0 ;
end ;
else do ;
b2h_a = atan(hd_y/hd_x)/rad ;
b2h_l = hd_y/sin(b2h_a*rad) ;
end ;
b2h_l_e = b2h_l/25.4 ;
drop pi rad ;
format
b2h_a 5.
b2h_l 5.
b2h_l_e 5.
bh_a 5.
bh_l 5.
ht_a 5.
spcr 5.
st_h 5.
st_a 5.
st_l 5.
hb_r 5.
hb_a 5.
bh_x 5.
bh_y 5.
sr_x 5.
sr_y 5.
st_x 5.
st_y 5.
hb_x 5.
hb_y 5.
hd_x 5.
hd_y 5.
b2h_a 5.
b2h_l 5.
b2h_l_e 5.1
;
run ;
There are no trig functions in SAS that accept DEGREE or GRADIAN arguments. You always need to convert from your data's angular measurement system to RADIAN.
You can write a macro to perform the conversion. Example:
%macro cosD(theta);
%* theta is angle in degrees;
%* emit data step source code that performs conversion from degrees to radians;
cos(&theta*constant('PI')/180)
%mend;
In use:
data calc ;
set spec ;
bh_x = %cosD(bh_a) * bh_l ;
You could convert the angular data to radians during the step where input occurs and then not have to worry about it again.
I am using the code below to do meta-regression in R and repeat it several time for different variables.
My dataframe and codes are as follow
data<-read.table(text="Studlab PCI.total.FU CABG.total.FU PCI CABG Mean.Age Females..
A 4515 4485 45 51 65.1 22.35
B 4740 4785 74 49 65.95 23.15
C 3621.4 3598.6 41 31 63.15 28.65
D 2337 2314.2 20 29 60 30.5
E 1835.2 1835.2 20 16 66.2 22
F 2014.8 2033.2 11 6 64.45 28.55
G 1125 1125 4 5 61.95 20.65
H 1500 1500 6 3 62.25 23.5
I 976 1000 11 3 61.5 21
J 202 194 10 0 62.4 1", sep="", header=T)
library(meta);library(metafor)
mr <- metainc( PCI, PCI.total.FU,CABG, CABG.total.FU,
data = data, studlab = Studlab, method = "Inverse")
Then for meta-regression I used the following code
MEG<-metareg (mr, ~Mean.Age);MEG ;
#==================================
b = round(MEG[["b"]], digits = 2)
se = round(MEG[["se"]], digits = 2)
pval = round(MEG[["pval"]], digits = 2)
paste0(b,"±",se,", P=",pval)
# Then I repeat meta-regression with another variable
MEG<-metareg (mr, ~Females..);MEG
#==================================
b = round(MEG[["b"]], digits = 2)
se = round(MEG[["se"]], digits = 2)
pval = round(MEG[["pval"]], digits = 2)
paste0(b,"±",se,", P=",pval)
and so on. So; b,se, pval and paste0 steps will be repeated frequently to get the needed output
The content of MEG is shown in the screenshot below.
My question is there is anyway to repeat this function (those repeated steps) several times with different variables (here I used "Mean.Age" then I used "Females..". In another term , I reproduce several MEG with different variables. I am thinking if there is anyway like Macro or so to call those function repeatedly without continuous copy and paste the code several times
Any advice will be greatly appreciated.
I am doing that to finally create a table like this
I am trying to backtest a trading strategy.
I am coding in R 3.6
The data is in two dataframes. The first is five years of daily price activity (i.e. fiveyrdaily). The second dataframe is price activity for the same five years only at the one minute level (i.e. fiveyrminutes). This data includes sessions low, high, open, and close.
My strategy is to loop over the respective days of the minute dataframe, while referring to and populating data on the daily dataframe to determine the following:
Condition that warrants the opening of a position (i.e. long or short).
Whether the target or stop price has been achieved.
Log the "trade" on a third dataframe (ORBOorders).
The embedded loops are not working the way I thought they would and I can't figure out why.
I know I can make the code simplier but it keeps getting drawn out so I can figure out where it is I'm going wrong.
I understand that appending to a vector in a loop is not the preferred way to handle vectors but I don't know how large the vector will be after the program is complete. I'd love to hear any ideas.
This is a strategy that seeks to catch price as it moves out of the range established in the first five minutes of the day.
This is the code to identify the direction of price movement after the initial 5 minutes. The counter is not working. The goal is to know the index of a specific event within the subsetted fiveyrminute dataframe (i.e. todaysdate); I will use this in the next batch of code below. The counter starts at 6 for the sixth minute. The output is never higher than 7, so, it's not counting with each iteration of the loop. I can't figure out why.
for (i in 1:length(fiveyrdaily$Date)){
todaysdate <- subset(fiveyrminutes, fiveyrdaily$Date[i] == fiveyrminutes$Date) # subset so I'm only seeing the respective days in the minutes dataframe
counter3 <- 6 # start a counter so I can track which position I'm in within the minutes dataframe, start after ORBO
for (t in counter:length(todaysdate$Date)){ #loop over the minutes dataframe
if ((fiveyrdaily$FiveHighClose[i] == 0) & (todaysdate$Close[t] > fiveyrdaily$FiveMinuteHigh[i])) {
fiveyrdaily$FiveHighClose[i] <- todaysdate$Close[t]
fiveyrdaily$FiveHighAfterClose[i] <- todaysdate$High[t] #record the session's high
counter3 <- counter3 + 1
fiveyrdaily$counterhigh[i] <- counter3 # record the position of this event within the subset of the minute dataframe
}
else if ((fiveyrdaily$FiveLowClose[i] == 0) & (todaysdate$Close[t] < fiveyrdaily$FiveMinuteLow[i])) {
fiveyrdaily$FiveLowClose[i] <- todaysdate$Close[t]
fiveyrdaily$FiveLowAfterClose[i] <- todaysdate$Low[t] # record the session's low
counter3 <- counter3 + 1
fiveyrdaily$counterlow[i] <- counter3
}
counter3 <- counter + 1
}
}
This is the "for" loop to determine if to buy and record the outcome.
#Open a long position
for (i in 1:length(fiveyrdaily$Date)){
if ((fiveyrdaily$counterhigh[i] < fiveyrdaily$counterlow[i]) & openposition < 2) {
#entryprice is the price predetermined ticks above the high
entryprice <- fiveyrdaily$FiveHighAfterClose[i] + (openticksaway * tickvalue)
#create stoploss
stoplossprice <- entryprice - stoplossvalue
#uncover target closest to five minute high
if (possibletargets > fiveyrdaily$FiveHighAfterClose[i]){ fiveyrdaily$ORBOtarget[i] <- min(possibletargets)}
poscounter <- fiveyrdaily$counterhigh[i]
beginforloop <- todaysdate[poscounter]
for (c in beginforloop:length(todaysdate$Date)){ #see where to open position starting from the occurence of the high
if ((entryprice > todaysdate$Low[c]) & (entryprice < todaysdate$High[c]) & (openposition < 2)){ #determine if conditions warrant entry
openposition <- openposition + 1 # open a position
if (openposition > 0){ #trade management
openpos <- 1
if ((stoplossprice < todaysdate$high[c]) & (stoplossprice > todaysdate$Low[c])){ # determine if stoploss has been hit
orderdate <- c(orderdate, todaysdate[c]) #enter data into orders dataframe
orderstrategy <- c(orderstrategy, "ORBO")
ordertype <- c(ordertype, "Long")
ordersymbol <- c(ordersymbol, "ES")
orderentry <- c(orderentry, entryprice)
orderclose <- c(orderclose, stoplossprice)
orderprofit <- c(orderprofit, abs((entryprice - stoplossprice) * pointvalue))
openpos <- 0
}
else if ((fiveyrdaily$ORBOtarget[i] < todaysdate$high[c]) & (fiveyrdaily$ORBOtarget[i] > todaysdate$Low[c])){ # determine if target has been hit
orderdate <- c(orderdate, todaysdate[c]) #enter data into orders dataframe
orderstrategy <- c(orderstrategy, "ORBO")
ordertype <- c(ordertype, "Long")
ordersymbol <- c(ordersymbol, "ES")
orderentry <- c(orderentry, entryprice)
orderclose <- c(orderclose, stoplossprice)
orderprofit <- c(orderprofit, abs((fiveyrdaily$ORBOtarget[i] - entryprice) * pointvalue))
openpos <- 0
}
}
}
}
}
}
Here is the data that is in the daily dataframe - fiveyrdaily:
> tail(fiveyrdaily)
Date Time Open High Low Close Vol OI UpperBand
1254 06/12/2019 16:15 2883.50 2889.75 2875.25 2881.00 1205406 2495060 2919.12
1255 06/13/2019 16:15 2894.75 2900.50 2886.75 2898.50 523312 448119 2925.39
1256 06/14/2019 16:15 2893.00 2899.75 2884.25 2894.75 1318938 951568 2927.99
1257 06/17/2019 16:15 2895.50 2902.75 2892.00 2896.25 1649621 1595842 2932.71
1258 06/18/2019 16:15 2914.00 2936.50 2910.25 2926.25 2257843 2093571 2944.19
1259 06/19/2019 16:15 2925.50 2936.75 2915.25 2933.50 1639495 2093571 2954.61
LowerBand MidLine PP RSI OverBot OverSld SlowK SlowD OverBot.1
1254 2751.13 2835.13 2892.58 56.24 70 30 86.82 87.54 80
1255 2749.21 2837.30 2882.00 59.06 70 30 87.60 88.11 80
1256 2748.24 2838.11 2895.25 58.19 70 30 89.01 87.81 80
1257 2746.94 2839.82 2892.92 58.46 70 30 91.79 89.47 80
1258 2743.68 2843.94 2897.00 63.41 70 30 92.63 91.14 80
1259 2740.02 2847.31 2924.33 64.51 70 30 95.20 93.21 80
OverSld.1 Volume Momentum ZeroLine InOrOut GapUpOrDown TypeOfDay PPTrend
1254 20 1205406 49.25 0 Disregard Disregard Bear Uptrend
1255 20 523312 93.50 0 Disregard Gap Up Bull Uptrend
1256 20 1318938 114.75 0 Disregard Disregard Bull Uptrend
1257 20 1649621 105.75 0 Disregard Disregard Bull Uptrend
1258 20 2257843 173.75 0 Disregard Gap Up Bull Uptrend
1259 20 1639495 184.00 0 Disregard Disregard Bull Uptrend
FiveMinuteLow FiveMinuteHigh FiveMinHtoL DollarFiveHtoL FiveHighClose
1254 2881.25 2889.75 8.50 425.0 0.00
1255 2892.00 2895.75 3.75 187.5 2896.00
1256 2886.25 2893.75 7.50 375.0 2894.75
1257 2892.00 2897.00 5.00 250.0 2897.25
1258 2910.25 2915.50 5.25 262.5 2920.75
1259 2923.25 2927.25 4.00 200.0 2930.00
FiveHighAfterClose FiveLowClose FiveLowAfterClose ORBOtarget counterhigh
1254 0.00 2881.00 2880.75 0 0
1255 2896.00 2891.75 2891.00 0 6
1256 2894.75 2886.00 2885.00 0 7
1257 2897.50 0.00 0.00 0 7
1258 2921.75 0.00 0.00 0 7
1259 2931.50 2922.50 2922.25 0 7
counterlow DollarOpentoHigh DollarOpentoClose DollarOpentoLow
1254 7 312.5 125.0 412.5
1255 7 287.5 187.5 400.0
1256 7 337.5 87.5 437.5
1257 0 362.5 37.5 175.0
1258 0 1125.0 612.5 187.5
1259 7 562.5 400.0 512.5
This is the data that is in the minutes dataframe - fiveyrminutes:
Date Time Open High Low Close Up Down UpperBand
509796 06/19/2019 16:10 2932.25 2932.50 2932.25 2932.50 717 430 2935.66
509797 06/19/2019 16:11 2932.25 2932.50 2932.25 2932.25 125 276 2935.46
509798 06/19/2019 16:12 2932.25 2932.75 2932.25 2932.75 612 604 2934.95
509799 06/19/2019 16:13 2932.50 2933.25 2932.50 2933.00 830 153 2934.66
509800 06/19/2019 16:14 2933.25 2933.25 2932.75 2933.00 676 376 2934.26
509801 06/19/2019 16:15 2932.75 2934.00 2932.75 2933.25 2929 2026 2933.90
LowerBand MidLine PP RSI OverBot OverSld SlowK SlowD OverBot.1
509796 2930.27 2932.96 2932.42 47.94 70 30 45.45 40.66 80
509797 2930.24 2932.85 2932.42 46.22 70 30 53.70 46.21 80
509798 2930.45 2932.70 2932.33 50.07 70 30 63.83 54.33 80
509799 2930.56 2932.61 2932.58 51.92 70 30 72.73 63.42 80
509800 2930.76 2932.51 2932.92 51.92 70 30 83.33 73.30 80
509801 2930.97 2932.44 2933.00 53.90 70 30 85.00 80.35 80
OverSld.1 Volume Momentum ZeroLine
509796 20 1147 -0.50 0
509797 20 401 -1.00 0
509798 20 1216 1.75 0
509799 20 983 1.75 0
509800 20 1052 2.00 0
509801 20 4955 1.75 0
This is the output for the orders dataframe, notice how it's empty - ORBOorders:
ORBOorders
orderdate orderstrategy ordertype ordersymbol orderentry orderclose
1 0 0
orderprofit
1 0
These are the problems:
-counter3 isn't working (to find after which point I should buy)
-The second batch of code gives this error:
Error in beginforloop:length(todaysdate$Date) : argument of length 0
In addition: Warning message: In if (possibletargets >
fiveyrdaily$FiveHighAfterClose[i]) { : the condition has length > 1
and only the first element will be used
-The ORBOorder dataframe has absolutely no data in it.
Thanks for any help in advance!
Sorry for the confusing title, but i wasn't sure how to title what i am trying to do. My objective is to create a dataset of 1000 obs each would be the length of the run. I have created a phase1 dataset, from which a set of control limits are produced. What i am trying to do now is create a phase2 dataset most likely using rnorm. what im trying to do is create a repeat loop that will continuously create values in the phase2 dataset until one of those values is outside of the control limits produced from the phase1 dataset. for example if i had 3.0 and -3.0 as control limits the phase2 dataset would create a bunch of observations until obs 398 when the value here happens to be 3.45, thus stopping the creation of data. my objective is then to record the number 398. Furthermore, I am then trying to loop the code back to the phase1 dataset/ control limits portion and create a new set of control limits and then run another phase2, until i have 1000 run lengths recorded. the code i have for the phase1/ control limits works fine and looks like this:
nphase1=50
nphase2=1000
varcount=1
meanshift= 0
sigmashift= 1
##### phase1 dataset/ control limits #####
phase1 <- matrix(rnorm(nphase1*varcount, 0, 1), nrow = nphase1, ncol=varcount)
mean_var <- apply(phase1, 2, mean)
std_var <- apply(phase1, 2, sd)
df_var <- data.frame(mean_var, std_var)
Upper_SPC_Limit_Method1 <- with(df_var, mean_var + 3 * std_var)
Lower_SPC_Limit_Method1 <- with(df_var, mean_var - 3 * std_var)
df_control_limits<- data.frame(Upper_SPC_Limit_Method1, Lower_SPC_Limit_Method1)
I have previously created this code in SAS and it looks like this. might be a better reference for what i am trying to achieve then me trying to explain it.
%macro phase2_dataset (n=,varcount=, meanshift=, sigmashift=, nphase1=,simID=,);
%do z=1 %to &n;
%phase1_dataset (n=&nphase1, varcount=&varcount);
data phase2; set control_limits n=lastobs;
call streaminit(0);
do until (phase2_var1<Lower_SPC_limit_method1_var1 or
phase2_var1>Upper_SPC_limit_method1_var1);
phase2_var1 = rand("normal", &meanshift, &sigmashift);
output;
end;
run;
ods exclude all;
proc means data=phase2;
var phase2_var1;
ods output summary=x;
run;
ods select all;
data run_length; set x;
keep Phase2_var1_n;
run;
proc append base= QA.Phase2_dataset&simID data=Run_length force; run;
%end;
%mend;
Also been doing research about using a while loop in replace of the repeat loop.
Im new to R so Any ideas you are able to throw my way are greatly appreciated. Thanks!
Using a while loop indeed seems to be the way to go. Here's what I think you're looking for:
set.seed(10) #Making results reproducible
replicate(100, { #100 is easier to display here
phase1 <- matrix(rnorm(nphase1*varcount, 0, 1), nrow = nphase1, ncol=varcount)
mean_var <- colMeans(phase1) #Slightly better than apply
std_var <- apply(phase1, 2, sd)
df_var <- data.frame(mean_var, std_var)
Upper_SPC_Limit_Method1 <- with(df_var, mean_var + 3 * std_var)
Lower_SPC_Limit_Method1 <- with(df_var, mean_var - 3 * std_var)
df_control_limits<- data.frame(Upper_SPC_Limit_Method1, Lower_SPC_Limit_Method1)
#Phase 2
x <- 0
count <- 0
while(x > Lower_SPC_Limit_Method1 && x < Upper_SPC_Limit_Method1) {
x <- rnorm(1)
count <- count + 1
}
count
})
The result is:
[1] 225 91 97 118 304 275 550 58 115 6 218 63 176 100 308 844 90 2758
[19] 161 311 1462 717 2446 74 175 91 331 210 118 1517 420 32 39 201 350 89
[37] 64 385 212 4 72 730 151 7 1159 65 36 333 97 306 531 1502 26 18
[55] 67 329 75 532 64 427 39 352 283 483 19 9 2 1018 137 160 223 98
[73] 15 182 98 41 25 1136 405 474 1025 1331 159 70 84 129 233 2 41 66
[91] 1 23 8 325 10 455 363 351 108 3
If performance becomes a problem, perhaps it would be interesting to explore some improvements, like creating more numbers with rnorm() at a time and then counting how many are necessary to exceed the limits and repeat if necessary.