Self Referential Series


DSL allows users to manipulate series, but not individual values! There is, however, one exception. It is possible to add values to a special type of series one value at a time. This feature is necessary so that series can be self-referential. The type of series that allows this is class self_ref_series<T>. A simple rolling sum would be declared as

 

                    void on_prepare_dsl(void)   override

                    {

                              self_ref_series<double> rolling_sum(0.0); // creates self referential series, init to zero

                              rolling_sum = rolling_sum + 1.0;          // add 1.0 to existing value

                              DPRINT(rolling_sum);

                    }

 

The ability to be self-referential is important as some indicators are defined in terms of self. For example, an exponential moving average function would be defined as:

 

sref<double> EMA_DEMO(sref<double> ser, size_t period)

{

          verify_non_zero(period);

 

          self_ref_series<double> ema(0.0);              // creates self referential series, init to zero

          auto weight = CONST(20.0 / (period + 1.0));

          ema = (ser * weight) + (1.0 - weight) * ema;   // new value is function of previous value of self

          return ema;

}

 

The way this works is that self_ref_series<T> creates an internally managed function object initialized to a certain value. When the self_ref_series<T> object goes out of scope, the internally managed function object survives and will keep track of the object's value. class self_ref_series<T>'s assignment operator allows object binding in such a way that self a referential relationship exists.  DSL does otherwise not allow self referential relationships. Another thing to  know is :

 

Assignment operator=() can only be called *ONCE* on a given self_ref_series<T> object! 

 

for example:

 

self_ref_series<double> ema(0.0);

ema = ema + 1;  //assign once only!

ema = ema + 2;  //error!

ema = ema + 3;  //error!

 

 

Examples of Self Referential Functions


 

      series_tuple<double> BANDPASSFILTER(sref<double> data, size_t period, double bandwidth)

          {

                    verify_non_zero(period);

                    verify_non_zero(bandwidth);

                    self_ref_series<double> HP(0.0);

                    self_ref_series<double> BP(0.0);

                    self_ref_series<double> peak(0.0);

                    self_ref_series<double> trigger(0.0);

 

                    auto alpha2 = (COS(0.25*bandwidth * 2.0 * PI() / period)

                + SIN(0.25*bandwidth * 2.0 * PI() / period) - 1.0) / COS(0.25*bandwidth * 2.0 * PI() / period);

                    HP = (1.0 + alpha2 / 2.0)*(data - data(1)) + (1.0 - alpha2)*HP;

                    auto beta1 = COS(2.0 * PI() / period);

                    auto gamma1 = 1.0 / COS(2.0 * PI() * bandwidth / period);

                    auto alpha1 = gamma1 - SQRT(gamma1*gamma1 - 1.0);

                    BP = 0.5*(1.0 - alpha1)*(HP - HP(2)) + beta1*(1.0 + alpha1)*BP - alpha1*BP(1);

                    peak = IF(ABS(BP) > 0.991*peak, ABS(BP), 0.991*peak);

                    auto signal = SAFE_DIVIDE(BP, peak);

                    alpha2 = (COS(1.5*bandwidth * 2.0 * PI() / period)

              + SIN(1.5*bandwidth * 2.0 * PI() / period) - 1.0) / COS(1.5*bandwidth * 2.0 * PI() / period);

                    trigger = (1.0 + alpha2 / 2)*(signal - signal(1)) + (1.0 - alpha2)*trigger;

 

                    series_tuple<double> tuple = {

                              signal.name("Signal").plot_as("Signal", 0, plot_type::line, color::white),

                              trigger.name("Trigger").plot_as("Trigger", 0, plot_type::line, color::yellow)

                    };

 

                    return tuple;

          }

 

 

 

 

          sref<double> LAGUERREMA(sref<double> data, double gamma)

          {

                    verify_non_zero(gamma);

                    self_ref_series<double> L0(0.0);

                    self_ref_series<double> L1(0.0);

                    self_ref_series<double> L2(0.0);

                    self_ref_series<double> L3(0.0);

                    self_ref_series<double> filt(0.0);

 

                    L0 = (1.0 - gamma)*data + gamma*L0;

                    L1 = -gamma*L0 + L0(1) + gamma*L1;

                    L2 = -gamma*L1 + L1(1) + gamma*L2;

                    L3 = -gamma*L2 + L2(1) + gamma*L3;

                    filt = (L0 + 2.0 * L1 + 2.0 * L1 + L3) / 6.0;

 

                    filt.plot_as("Laguerre MA", 0, plot_type::line, color::cadet_blue, 2);

                    return filt;

          }