BookmarkSubscribeRSS Feed
🔒 This topic is solved and locked. Need further help from the community? Please sign in and ask a new question.
1 ACCEPTED SOLUTION

Accepted Solutions
RobPratt
SAS Super FREQ

The following code should at least get you started:

proc optmodel printlevel=0;
   set INSTANCES;
   num ticker {INSTANCES};
   num date {INSTANCES};
   num alpha_init {INSTANCES};
   num delta_init {INSTANCES};
   num mu_init {INSTANCES};
   num eta_B_init {INSTANCES};
   num eta_S_init {INSTANCES};
   read data initials into INSTANCES=[_N_]
      ticker date alpha_init=alpha delta_init=delta mu_init=mu eta_B_init=eta_B eta_S_init=eta_S;

   set <num,num,num> TICKER_DATE_OBS;
   num B {TICKER_DATE_OBS};
   num S {TICKER_DATE_OBS};
   read data trades into TICKER_DATE_OBS=[ticker date _N_] B S;
   num t_this, d_this;
   set OBS_THIS;

   var alpha >= 0 <= 1, delta >= 0 <= 1;
   var mu >= 0, eta_B >= 0, eta_S >= 0;
   impvar one_minus_d = 1.0 - delta;
   impvar one_minus_alpha = 1.0 - alpha;
   impvar e1 {obs in OBS_THIS} = -1.0*mu - B[t_this,d_this,obs]*log(1+mu/eta_B);
   impvar e2 {obs in OBS_THIS} = -1.0*mu - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar e3 {obs in OBS_THIS} = -B[t_this,d_this,obs]*log(1+mu/eta_B) - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar emax {obs in OBS_THIS} = max(e1[obs], e2[obs], e3[obs]);
   max loglik = sum {obs in OBS_THIS} (
     -1.0*eta_B + B[t_this,d_this,obs]*log(mu+eta_B)
     -1.0*eta_S + S[t_this,d_this,obs]*log(mu+eta_S)
     + emax[obs]
     + log( 
        alpha * one_minus_d * exp(e2[obs] - emax[obs])
          + alpha * delta * exp(e1[obs] - emax[obs])
            + one_minus_alpha * exp(e3[obs] - emax[obs])
       ));

   str solstatus {INSTANCES};
   num alpha_sol {INSTANCES};
   num delta_sol {INSTANCES};
   num mu_sol {INSTANCES};
   num eta_B_sol {INSTANCES};
   num eta_S_sol {INSTANCES};
   num loglik_sol {INSTANCES};
   for {i in INSTANCES} do;
      t_this = ticker[i];
      d_this = date[i];
      OBS_THIS = {<(t_this),(d_this),obs> in TICKER_DATE_OBS};
      put i= t_this= d_this= monyy7. ' ';
      alpha = alpha_init[i];
      delta = delta_init[i];
      mu    = mu_init[i];
      eta_B = eta_B_init[i];
      eta_S = eta_S_init[i];
      solve;
      solstatus[i] = _solution_status_;
      alpha_sol[i]  = alpha;
      delta_sol[i]  = delta;
      mu_sol[i]     = mu;
      eta_B_sol[i]  = eta_B;
      eta_S_sol[i]  = eta_S;
      loglik_sol[i] = loglik;
   end;
   create data solutions from [instance]=INSTANCES
      ticker date/format=monyy7. solstatus loglik=loglik_sol alpha=alpha_sol delta=delta_sol mu=mu_sol eta_B=eta_B_sol eta_S=eta_S_sol;
quit;

View solution in original post

10 REPLIES 10
trungcva112
Obsidian | Level 7

Anyone has some ideas?

RobPratt
SAS Super FREQ

PROC NLP is a legacy procedure that is no longer even documented, and PROC OPTMODEL is recommended instead.  With PROC OPTMODEL, you can call the solver in a loop, setting the initial values for the variables before each solver call.  In fact, you can use a COFOR loop to solve these independent problems concurrently.

trungcva112
Obsidian | Level 7

Thanks @RobPratt

but is there any other way to use PROC NLP?. PROC OPTMODEL is very complicated, I have to change the whole code, and this procedure is very difficult to understand to me. It is much appreciated if you could give me instructions on how to do it

RobPratt
SAS Super FREQ

The following code should at least get you started:

proc optmodel printlevel=0;
   set INSTANCES;
   num ticker {INSTANCES};
   num date {INSTANCES};
   num alpha_init {INSTANCES};
   num delta_init {INSTANCES};
   num mu_init {INSTANCES};
   num eta_B_init {INSTANCES};
   num eta_S_init {INSTANCES};
   read data initials into INSTANCES=[_N_]
      ticker date alpha_init=alpha delta_init=delta mu_init=mu eta_B_init=eta_B eta_S_init=eta_S;

   set <num,num,num> TICKER_DATE_OBS;
   num B {TICKER_DATE_OBS};
   num S {TICKER_DATE_OBS};
   read data trades into TICKER_DATE_OBS=[ticker date _N_] B S;
   num t_this, d_this;
   set OBS_THIS;

   var alpha >= 0 <= 1, delta >= 0 <= 1;
   var mu >= 0, eta_B >= 0, eta_S >= 0;
   impvar one_minus_d = 1.0 - delta;
   impvar one_minus_alpha = 1.0 - alpha;
   impvar e1 {obs in OBS_THIS} = -1.0*mu - B[t_this,d_this,obs]*log(1+mu/eta_B);
   impvar e2 {obs in OBS_THIS} = -1.0*mu - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar e3 {obs in OBS_THIS} = -B[t_this,d_this,obs]*log(1+mu/eta_B) - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar emax {obs in OBS_THIS} = max(e1[obs], e2[obs], e3[obs]);
   max loglik = sum {obs in OBS_THIS} (
     -1.0*eta_B + B[t_this,d_this,obs]*log(mu+eta_B)
     -1.0*eta_S + S[t_this,d_this,obs]*log(mu+eta_S)
     + emax[obs]
     + log( 
        alpha * one_minus_d * exp(e2[obs] - emax[obs])
          + alpha * delta * exp(e1[obs] - emax[obs])
            + one_minus_alpha * exp(e3[obs] - emax[obs])
       ));

   str solstatus {INSTANCES};
   num alpha_sol {INSTANCES};
   num delta_sol {INSTANCES};
   num mu_sol {INSTANCES};
   num eta_B_sol {INSTANCES};
   num eta_S_sol {INSTANCES};
   num loglik_sol {INSTANCES};
   for {i in INSTANCES} do;
      t_this = ticker[i];
      d_this = date[i];
      OBS_THIS = {<(t_this),(d_this),obs> in TICKER_DATE_OBS};
      put i= t_this= d_this= monyy7. ' ';
      alpha = alpha_init[i];
      delta = delta_init[i];
      mu    = mu_init[i];
      eta_B = eta_B_init[i];
      eta_S = eta_S_init[i];
      solve;
      solstatus[i] = _solution_status_;
      alpha_sol[i]  = alpha;
      delta_sol[i]  = delta;
      mu_sol[i]     = mu;
      eta_B_sol[i]  = eta_B;
      eta_S_sol[i]  = eta_S;
      loglik_sol[i] = loglik;
   end;
   create data solutions from [instance]=INSTANCES
      ticker date/format=monyy7. solstatus loglik=loglik_sol alpha=alpha_sol delta=delta_sol mu=mu_sol eta_B=eta_B_sol eta_S=eta_S_sol;
quit;
trungcva112
Obsidian | Level 7

Thanks @RobPratt Now it goes through all the initials

 

However, I am not able to get the right solution among these. For example, ticker 99999 must have solution: alpha=0.4, delta=0.5, mu=50, eta_B=eta_S=40. I can not find this in the output dataset

 

When I run my old PROC NLP code, using only 1 set of initials for ticker 99999 (alpha=0.9, delta=0.7, mu=18.5, eta_B=45, eta_S=38.3), it gives me the right solution. So it confirms that the "true" solution lies in one of my initials

 

After examining your PROC OPTMODEL, I think the issue might be:

 

- The PROC NLP uses Newton-Ralphson technique; PROC OPTMODEL uses interior point technique. I searched but I can not find Newton-Ralphson technique or any equivalent in PROC OPTMODEL

 

- eta_B, eta_S, mu are strictly > 0 (rather than >=0). However, when I change this constraint by using

   var alpha >= 0 <= 1, delta >= 0 <= 1;
   var mu, eta_B, eta_S;
   con mu>0, eta_B>0, eta_S>0;

It gives me error:

ERROR: The problem contains strict inequality or predicate constraints that reference non-integer
       variables.

 

Could you please advise me on this? Thank you very much

RobPratt
SAS Super FREQ

You cannot have strict inequalities.

 

The issue is that I had initially misinterpreted the trades data set.  Please see the corrected code above.

 

Also note that the MULTISTART option for the NLP solver in PROC OPTMODEL can automate the selection of starting points for you, and that would also simplify the code.

trungcva112
Obsidian | Level 7

Thanks @RobPratt. You are my hero. It works now

RobPratt
SAS Super FREQ

Glad to help.  For completeness, here is the multistart approach I mentioned:

proc optmodel printlevel=0;
   set <num,num,num> TICKER_DATE_OBS;
   num B {TICKER_DATE_OBS};
   num S {TICKER_DATE_OBS};
   read data trades into TICKER_DATE_OBS=[ticker date _N_] B S;
   num t_this, d_this;
   set OBS_THIS;

   var alpha >= 0 <= 1, delta >= 0 <= 1;
   var mu >= 0, eta_B >= 0, eta_S >= 0;
   impvar one_minus_d = 1.0 - delta;
   impvar one_minus_alpha = 1.0 - alpha;
   impvar e1 {obs in OBS_THIS} = -1.0*mu - B[t_this,d_this,obs]*log(1+mu/eta_B);
   impvar e2 {obs in OBS_THIS} = -1.0*mu - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar e3 {obs in OBS_THIS} = -B[t_this,d_this,obs]*log(1+mu/eta_B) - S[t_this,d_this,obs]*log(1+mu/eta_S);
   impvar emax {obs in OBS_THIS} = max(e1[obs], e2[obs], e3[obs]);
   max loglik = sum {obs in OBS_THIS} (
     -1.0*eta_B + B[t_this,d_this,obs]*log(mu+eta_B)
     -1.0*eta_S + S[t_this,d_this,obs]*log(mu+eta_S)
     + emax[obs]
     + log( 
        alpha * one_minus_d * exp(e2[obs] - emax[obs])
          + alpha * delta * exp(e1[obs] - emax[obs])
            + one_minus_alpha * exp(e3[obs] - emax[obs])
       ));

   set TICKER_DATE = setof {<t,d,o> in TICKER_DATE_OBS} <t,d>;
   str solstatus {TICKER_DATE};
   num alpha_sol {TICKER_DATE};
   num delta_sol {TICKER_DATE};
   num mu_sol {TICKER_DATE};
   num eta_B_sol {TICKER_DATE};
   num eta_S_sol {TICKER_DATE};
   num loglik_sol {TICKER_DATE};
   for {<t,d> in TICKER_DATE} do;
      put t= d= monyy7.;
      t_this = t;
      d_this = d;
      OBS_THIS = {<(t_this),(d_this),obs> in TICKER_DATE_OBS};
      solve with nlp / ms;
      solstatus[t,d]  = _solution_status_;
      alpha_sol[t,d]  = alpha;
      delta_sol[t,d]  = delta;
      mu_sol[t,d]     = mu;
      eta_B_sol[t,d]  = eta_B;
      eta_S_sol[t,d]  = eta_S;
      loglik_sol[t,d] = loglik;
   end;
   create data solutions_ms from [ticker date/format=monyy7.]=TICKER_DATE
      solstatus loglik=loglik_sol alpha=alpha_sol delta=delta_sol mu=mu_sol eta_B=eta_B_sol eta_S=eta_S_sol;
quit;
trungcva112
Obsidian | Level 7
Brilliant!. Thanks a lot @RobPratt
Just curious, is there any difference between "solve" and "solve with nlp". I searched but it seems not clear to me
RobPratt
SAS Super FREQ

SOLVE chooses a default solver based on the problem structure.  In this case, it chooses the NLP solver.  SOLVE WITH NLP explicitly specifies the NLP solver.  To include solver options (like MS, in this case), you need the WITH clause.

 

https://go.documentation.sas.com/?docsetId=ormpug&docsetTarget=ormpug_optmodel_syntax11.htm&docsetVe...

sas-innovate-2024.png

Don't miss out on SAS Innovate - Register now for the FREE Livestream!

Can't make it to Vegas? No problem! Watch our general sessions LIVE or on-demand starting April 17th. Hear from SAS execs, best-selling author Adam Grant, Hot Ones host Sean Evans, top tech journalist Kara Swisher, AI expert Cassie Kozyrkov, and the mind-blowing dance crew iLuminate! Plus, get access to over 20 breakout sessions.

 

Register now!

Multiple Linear Regression in SAS

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.

Discussion stats
  • 10 replies
  • 2275 views
  • 2 likes
  • 2 in conversation