Dukascopy
 
 
Wiki JStore Search Login

Attention! Read the forum rules carefully before posting a topic.

    Try to find an answer in Wiki before asking a question.
    Submit programming questions in this forum only.
    Off topics are strictly forbidden.

Any topics which do not satisfy these rules will be deleted.

Calling SMA, EMA and MA indicators with custom inputs return the same values - why?
 Post subject: Calling SMA, EMA and MA indicators with custom inputs return the same values - why? Post rating: 1   New post Posted: Tue 15 May, 2012, 06:57 

User rating: 2
Joined: Sun 26 Jun, 2011, 07:05
Posts: 15
Location: Australia, Melbourne
Hello again,

In my strategy I need to call SMA & EMA with custom input arrays, so I can not use simple IIndicators.calculateIndicator() method.

This means I need to call the IIndicator.calculate() method of an indicator after manually populating it's inputs & outputs. Unfortunately this always seems to return the same values for SMA, EMA, MA(SMA) & MA(EMA) calls.

I must be doing something fundamentally wrong. Please refer to the sample strategy below. When backtesting this over the last week it passes the same input arrays to the indicators, but they all return the same values - not different ones for different EMA & SMA calculations.

package jforexStrategies;

import com.dukascopy.api.*;
import com.dukascopy.api.indicators.*;
import com.dukascopy.api.IIndicators.AppliedPrice;

public class MaTestStrategy implements IStrategy
{
    double[][] price;
    int priceIndex = 0;
   
    @Configurable("Instrument") public com.dukascopy.api.Instrument instrument = Instrument.fromString("EUR/USD");
    @Configurable("Period") public int maPeriod = 89;
    @Configurable("Price") public AppliedPrice appPrice = AppliedPrice.CLOSE;
   
    private IContext context;
    private IIndicators indicators;
   
    IIndicator ema = null;
    IIndicator sma = null;
    IIndicator ma = null;
    IIndicator ma2 = null;
   
    public void onStart(IContext context) throws JFException
    {
        this.context = context;
        this.indicators = context.getIndicators();

        price = new double[AppliedPrice.values().length][maPeriod];

        // get indicators
        ema = indicators.getIndicator("EMA");
        sma = indicators.getIndicator("SMA");
        ma = indicators.getIndicator("MA");
        ma2 = indicators.getIndicator("MA");
       
        // set optional input parameters of indicators
        ema.setOptInputParameter(0, maPeriod);
        sma.setOptInputParameter(0, maPeriod);
        ma.setOptInputParameter(0, maPeriod);
        ma.setOptInputParameter(1, IIndicators.MaType.SMA.ordinal());
        ma2.setOptInputParameter(0, maPeriod);
        ma2.setOptInputParameter(1, IIndicators.MaType.EMA.ordinal());

    }

    public void onAccount(IAccount account) throws JFException {
    }

    public void onMessage(IMessage message) throws JFException {
    }

    public void onStop() throws JFException {
    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {
    }
   
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException
    {
        if (this.instrument == instrument && priceIndex < maPeriod && period == Period.ONE_HOUR)
        {
            context.getConsole().getOut().println("Storing values to use - priceIndex: " + priceIndex);

            // store current bar's info for later indicator calls
            price[AppliedPrice.OPEN.ordinal()][priceIndex] = bidBar.getOpen();
            price[AppliedPrice.CLOSE.ordinal()][priceIndex] = bidBar.getClose();
            price[AppliedPrice.HIGH.ordinal()][priceIndex] = bidBar.getHigh();
            price[AppliedPrice.LOW.ordinal()][priceIndex] = bidBar.getLow();
            price[AppliedPrice.VOLUME.ordinal()][priceIndex] = bidBar.getVolume();
            price[AppliedPrice.MEDIAN_PRICE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow())/2;
            price[AppliedPrice.TYPICAL_PRICE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow()+bidBar.getClose())/3;
            price[AppliedPrice.WEIGHTED_CLOSE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow()+2*bidBar.getClose())/4;
            price[AppliedPrice.TIMESTAMP.ordinal()][priceIndex] = bidBar.getTime();
                       
            priceIndex++;
           
            // do we have enough history to make the indicator calls?
            if (priceIndex == maPeriod)
            {
                // get indicator info's
                IndicatorInfo emaInfo = ema.getIndicatorInfo();
                IndicatorInfo smaInfo = ema.getIndicatorInfo();
                IndicatorInfo maInfo = ema.getIndicatorInfo();
                IndicatorInfo ma2Info = ema.getIndicatorInfo();
               
                // set output arrays
                double[][] emaOutputs = new double[emaInfo.getNumberOfOutputs()][];
                for (int i = 0; i < emaOutputs.length; i++)
                {
                    emaOutputs[i] = new double[1];
                    ema.setOutputParameter(i, emaOutputs[i]);
                }
                double[][] smaOutputs = new double[smaInfo.getNumberOfOutputs()][];
                for (int i = 0; i < smaOutputs.length; i++)
                {
                    smaOutputs[i] = new double[1];
                    sma.setOutputParameter(i, smaOutputs[i]);
                }
                double[][] maOutputs = new double[maInfo.getNumberOfOutputs()][];
                for (int i = 0; i < maOutputs.length; i++)
                {
                    maOutputs[i] = new double[1];
                    ma.setOutputParameter(i, maOutputs[i]);
                }
                double[][] ma2Outputs = new double[ma2Info.getNumberOfOutputs()][];
                for (int i = 0; i < ma2Outputs.length; i++)
                {
                    ma2Outputs[i] = new double[1];
                    ma2.setOutputParameter(i, ma2Outputs[i]);
                }
               
                // set input arrays
                ema.setInputParameter(0, price[appPrice.ordinal()]);
                sma.setInputParameter(0, price[appPrice.ordinal()]);
                ma.setInputParameter(0, price[appPrice.ordinal()]);
                ma2.setInputParameter(0, price[appPrice.ordinal()]);
   
                // calculate outputs
                int inputLength = price[0].length;
                int emaLB = ema.getLookback();
                IndicatorResult emaResult = ema.calculate(emaLB, inputLength-1); // only calculate 1 value, so start & end indexes should be the same
                double emaRetval = emaOutputs[0][0];
               
                int smaLB = sma.getLookback();
                IndicatorResult smaResult = sma.calculate(smaLB, inputLength-1); // only calculate 1 value, so start & end indexes should be the same
                double smaRetval = smaOutputs[0][0];
               
                int maLB = ma.getLookback();
                IndicatorResult maResult = ma.calculate(maLB, inputLength-1); // only calculate 1 value, so start & end indexes should be the same
                double maRetval = maOutputs[0][0];
               
                int ma2LB = ma2.getLookback();
                IndicatorResult ma2Result = ma2.calculate(ma2LB, inputLength-1); // only calculate 1 value, so start & end indexes should be the same
                double ma2Retval = ma2Outputs[0][0];
               
                // print values to console
                context.getConsole().getOut().println("The following values are passed as " + appPrice.toString() + " inputs to the indicators:");               
                for (int i = 0; i < maPeriod; i++)
                {
                    context.getConsole().getOut().println("["+i+"]: " + price[appPrice.ordinal()][i]);
                }
                context.getConsole().getOut().println("emaRetval(" + maPeriod + "): " + emaRetval);
                context.getConsole().getOut().println("smaRetval(" + maPeriod + "): " + smaRetval);
                context.getConsole().getOut().println("maRetval(" + maPeriod + ", " + IIndicators.MaType.SMA.ordinal() + "): " + maRetval);
                context.getConsole().getOut().println("ma2Retval(" + maPeriod + ", " + IIndicators.MaType.EMA.ordinal() + "): " + ma2Retval);
                context.getConsole().getOut().println("Why are they all the same?");
            }
        }
    }
}


Can you please advise me what I must do to correctly calculate EMA and SMA values?



thanks in advance,
Christian


 
 Post subject: Re: Calling SMA, EMA and MA indicators with custom inputs return the same values - why? Post rating: 0   New post Posted: Tue 15 May, 2012, 07:56 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
This is because EMA requires more inputs (this is indicated by unstable period property), hence, you need to pass more values to the indicator.


 
 Post subject: Re: Calling SMA, EMA and MA indicators with custom inputs return the same values - why? Post rating: 1   New post Posted: Tue 15 May, 2012, 11:50 

User rating: 2
Joined: Sun 26 Jun, 2011, 07:05
Posts: 15
Location: Australia, Melbourne
Hi support,

I have changed to code as per your advice and it now works.

2 quick follow up questions:
1. Do you have any advice as to how to estimate the extra input required for the EMA's unstable period?
2. Why isn't this taken into account in the IIndicator.getLookBack() call for each indicator?

Fixed sample code:

package jforexStrategies;
 
import com.dukascopy.api.*;
import com.dukascopy.api.indicators.*;
import com.dukascopy.api.IIndicators.AppliedPrice;
 
public class MaTestStrategy implements IStrategy
{
    double[][] price;
    int priceIndex = 0;
     
    @Configurable("Instrument") public com.dukascopy.api.Instrument instrument = Instrument.fromString("EUR/USD");
    @Configurable("Bar Period") public Period barPeriod = Period.FIVE_MINS;
    @Configurable("Moving Average Period") public int maPeriod = 89;
    @Configurable("Unstable Period Expansion") public int unstable = 1000;
    @Configurable("Price") public AppliedPrice appPrice = AppliedPrice.CLOSE;
     
    private IContext context;
    private IIndicators indicators;
     
    private IIndicator ema = null;
    private IIndicator sma = null;
    private IIndicator ma = null;
    private IIndicator ma2 = null;
     
    private IndicatorInfo emaInfo;
    private IndicatorInfo smaInfo;
    private IndicatorInfo maInfo;
    private IndicatorInfo ma2Info;
     
    private boolean unstableFlag = false;
     
    public void onStart(IContext context) throws JFException
    {
        this.context = context;
        this.indicators = context.getIndicators();
 
        // get indicators
        ema = indicators.getIndicator("EMA");
        sma = indicators.getIndicator("SMA");
        ma = indicators.getIndicator("MA");
        ma2 = indicators.getIndicator("MA");
         
        // set optional input parameters of indicators
        ema.setOptInputParameter(0, maPeriod);
        sma.setOptInputParameter(0, maPeriod);
        ma.setOptInputParameter(0, maPeriod);
        ma.setOptInputParameter(1, IIndicators.MaType.SMA.ordinal());
        ma2.setOptInputParameter(0, maPeriod);
        ma2.setOptInputParameter(1, IIndicators.MaType.EMA.ordinal());
 
         // get indicator info's
        emaInfo = ema.getIndicatorInfo();
        smaInfo = ema.getIndicatorInfo();
        maInfo = ema.getIndicatorInfo();
        ma2Info = ema.getIndicatorInfo();

        // if any of the indicators have an unstable period, then add the user defined unstable period to the indicators' period
        if (emaInfo.isUnstablePeriod() ||
            smaInfo.isUnstablePeriod() ||
            maInfo.isUnstablePeriod() ||
            ma2Info.isUnstablePeriod())
        {
            unstableFlag = true;
            price = new double[AppliedPrice.values().length][maPeriod+unstable];
        }
        else
        {
            price = new double[AppliedPrice.values().length][maPeriod];
        }
 
     }
 
    public void onAccount(IAccount account) throws JFException {
    }
 
    public void onMessage(IMessage message) throws JFException {
    }
 
    public void onStop() throws JFException {
    }
 
    public void onTick(Instrument instrument, ITick tick) throws JFException {
    }
     
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException
    {
        if (this.instrument == instrument && period == barPeriod &&
            ((unstableFlag == false && priceIndex < maPeriod) || (unstableFlag == true && priceIndex < maPeriod + unstable)) )
        {
            context.getConsole().getOut().println("Storing values to use - priceIndex: " + priceIndex);
 
            // store current bar's info for later indicator calls
            price[AppliedPrice.OPEN.ordinal()][priceIndex] = bidBar.getOpen();
            price[AppliedPrice.CLOSE.ordinal()][priceIndex] = bidBar.getClose();
            price[AppliedPrice.HIGH.ordinal()][priceIndex] = bidBar.getHigh();
            price[AppliedPrice.LOW.ordinal()][priceIndex] = bidBar.getLow();
            price[AppliedPrice.VOLUME.ordinal()][priceIndex] = bidBar.getVolume();
            price[AppliedPrice.MEDIAN_PRICE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow())/2;
            price[AppliedPrice.TYPICAL_PRICE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow()+bidBar.getClose())/3;
            price[AppliedPrice.WEIGHTED_CLOSE.ordinal()][priceIndex] = (bidBar.getHigh()+bidBar.getLow()+2*bidBar.getClose())/4;
            price[AppliedPrice.TIMESTAMP.ordinal()][priceIndex] = bidBar.getTime();
                         
            priceIndex++;
             
            // do we have enough history to make the indicator calls?
            if ((unstableFlag == false && priceIndex == maPeriod) ||
                (unstableFlag == true && priceIndex == maPeriod + unstable))
            {

                // set output arrays
                double[][] emaOutputs = new double[emaInfo.getNumberOfOutputs()][];
                for (int i = 0; i < emaOutputs.length; i++)
                {
                    emaOutputs[i] = new double[unstableFlag ? unstable+1 : 1];
                    ema.setOutputParameter(i, emaOutputs[i]);
                }
                double[][] smaOutputs = new double[smaInfo.getNumberOfOutputs()][];
                for (int i = 0; i < smaOutputs.length; i++)
                {
                    smaOutputs[i] = new double[unstableFlag ? unstable+1 : 1];
                    sma.setOutputParameter(i, smaOutputs[i]);
                }
                double[][] maOutputs = new double[maInfo.getNumberOfOutputs()][];
                for (int i = 0; i < maOutputs.length; i++)
                {
                    maOutputs[i] = new double[unstableFlag ? unstable+1 : 1];
                    ma.setOutputParameter(i, maOutputs[i]);
                }
                double[][] ma2Outputs = new double[ma2Info.getNumberOfOutputs()][];
                for (int i = 0; i < ma2Outputs.length; i++)
                {
                    ma2Outputs[i] = new double[unstableFlag ? unstable+1 : 1];
                    ma2.setOutputParameter(i, ma2Outputs[i]);
                }
                 
                // set input arrays
                ema.setInputParameter(0, price[appPrice.ordinal()]);
                sma.setInputParameter(0, price[appPrice.ordinal()]);
                ma.setInputParameter(0, price[appPrice.ordinal()]);
                ma2.setInputParameter(0, price[appPrice.ordinal()]);
     
                // calculate outputs
                int inputLength = price[0].length;
                IndicatorResult emaResult = ema.calculate(ema.getLookback(), inputLength-1);
                double emaRetval = emaOutputs[0][unstableFlag ? emaOutputs[0].length-1 : 0];
                 
                IndicatorResult smaResult = sma.calculate(sma.getLookback(), inputLength-1);
                double smaRetval = smaOutputs[0][unstableFlag ? smaOutputs[0].length-1 : 0];
                 
                IndicatorResult maResult = ma.calculate(ma.getLookback(), inputLength-1);
                double maRetval = maOutputs[0][unstableFlag ? maOutputs[0].length-1 : 0];
                 
                IndicatorResult ma2Result = ma2.calculate(ma2.getLookback(), inputLength-1);
                double ma2Retval = ma2Outputs[0][unstableFlag ? ma2Outputs[0].length-1 : 0];
                 
                // print values to console
                context.getConsole().getOut().println("The following values are passed as " + appPrice.toString() + " inputs to the indicators:");               
                for (int i = 0; i < price[0].length; i++)
                {
                    context.getConsole().getOut().println("price["+appPrice.toString()+"]["+i+"]: " + price[appPrice.ordinal()][i]);
                }
                context.getConsole().getOut().println("emaRetval(" + maPeriod + "): " + emaRetval + ", emaOutput[0].length = " + emaOutputs[0].length);
                context.getConsole().getOut().println("smaRetval(" + maPeriod + "): " + smaRetval + ", smaOutput[0].length = " + smaOutputs[0].length);
                context.getConsole().getOut().println("maRetval(" + maPeriod + ", " + IIndicators.MaType.SMA.ordinal() + "): " + maRetval + ", maOutput[0].length = " + maOutputs[0].length);
                context.getConsole().getOut().println("ma2Retval(" + maPeriod + ", " + IIndicators.MaType.EMA.ordinal() + "): " + ma2Retval + ", ma2Output[0].length = " + ma2Outputs[0].length);
                context.getConsole().getOut().println("Why are they all the same?");
               
            }
           
        }
    }
}



thanks,
Christian


 
 Post subject: Re: Calling SMA, EMA and MA indicators with custom inputs return the same values - why? Post rating: 0   New post Posted: Tue 15 May, 2012, 12:29 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
ChristianMEL wrote:
1. Do you have any advice as to how to estimate the extra input required for the EMA's unstable period?
The platform uses 100 extra inputs, however if you would compare the values yielded by using 10 and 100 extra outputs, the difference would be <0.1 pip, hence for the case of EMA, 10 extra inputs appear to be sufficient.
ChristianMEL wrote:
2. Why isn't this taken into account in the IIndicator.getLookBack() call for each indicator?
Because by API design lookback and unstablePeriod properties are treated separately. If you wish, you can create a custom indicator which in IIndicator.getLookBack() also considers unstablePeriod property.


 

Jump to:  

  © 1998-2025 Dukascopy® Bank SA
On-line Currency forex trading with Swiss Forex Broker - ECN Forex Brokerage,
Managed Forex Accounts, introducing forex brokers, Currency Forex Data Feed and News
Currency Forex Trading Platform provided on-line by Dukascopy.com