Dukascopy
 
 
Wiki JStore Search Login

JFOREX-3299 context.getInstrument() - null in IIndicator
 Post subject: JFOREX-3299 context.getInstrument() - null in IIndicator Post rating: 0   New post Posted: Tue 25 Oct, 2011, 23:20 

User rating: -
It appears that context.getInstrument() and InputParameterInfo.getInstrument() always return null within IIndicator, which renders all calls to IHistory.getBars(instrument....) useless / unworkable!

(Unless you provide a pre-specified instrument - which is pointless for an indicator - it should be attached to a chart which in turn supplies the instrument).

Is there are workaround for this issue? I can rewrite the logic of the indicators to get multiple timeframes and parse them in a different fashion, but ideally I really only want to work with the last X daily/weekly/monthly bars, so history.getBar(...) is the logical and efficient approach... but it cannot be called from within an IIndicator!

Is this likely to be fixed anytime soon?

Consider the follow code snippet, specifically the parts highlighted in RED and the associated console output for detail example of the issue:

public class CPRIndicator implements IIndicator, IDrawingIndicator
{
private IndicatorInfo indicatorInfo;
private InputParameterInfo[] inputParameterInfos;
private OutputParameterInfo[] outputParameterInfos;
private OptInputParameterInfo[] optInputParameterInfos;

private IBar[][] inputs = new IBar[2][];

private double[][] outputs = new double[4][];
private InputParameterInfo calculationTimeframe, displayTimeframe;
private DecimalFormat decimalFormat;

private final GeneralPath generalPath = new GeneralPath();
private List<Point> tmpHandlesPoints = new ArrayList<Point>();

private boolean displayPeriod = false;
private int offset = 2;
private int noDays = 5;

private IIndicatorContext context = null;
private Instrument instrument = null;
// private IFeedDescriptor feedDescriptor;
private IHistory history = null;
private IConsole console;

private int period = 2; // default = DAILY
int[] periodValues = new int[5];
String[] periodNames = new String[5];

private Color DemiBlack = new Color(64, 64, 64);
private Color Orchid = new Color(218, 112, 214);
private Color Gray = new Color(128, 128, 128);

public static DecimalFormat df = new DecimalFormat("0.0000");


public void onStart(IIndicatorContext context)
{
this.context = context;
console = context.getConsole();
instrument = context.getInstrument();
// feedDescriptor = context.getFeedDescriptor();
history = context.getHistory();

indicatorInfo = new IndicatorInfo("CENTRAL PIVOT RANGE ", "Pivot Range", "Overlap Studies", true, false, true, 2, 3, 4);
indicatorInfo.setSparceIndicator(true);
indicatorInfo.setRecalculateAll(true);

calculationTimeframe = new InputParameterInfo("Calculation Input data", InputParameterInfo.Type.BAR);
calculationTimeframe.setPeriod(Period.DAILY_SUNDAY_IN_MONDAY);
calculationTimeframe.setFilter(Filter.WEEKENDS);

displayTimeframe = new InputParameterInfo("Display Input data", InputParameterInfo.Type.BAR);
displayTimeframe.setFilter(Filter.WEEKENDS);

inputParameterInfos = new InputParameterInfo[]
{
displayTimeframe,
calculationTimeframe
};


instrument = displayTimeframe.getInstrument();
if (instrument != null)
{
console.getOut().println("instrument="+instrument.toString()); // this never outputs anything
}



periodValues[0] = 0;
periodNames[0] = "Hourly";
periodValues[1] = 1;
periodNames[1] = "4 Hour";
periodValues[2] = 2;
periodNames[2] = "Daily";
periodValues[3] = 3;
periodNames[3] = "Weekly";
periodValues[4] = 4;
periodNames[4] = "Monthly";

optInputParameterInfos = new OptInputParameterInfo[]
{
new OptInputParameterInfo("Period", OptInputParameterInfo.Type.OTHER, new IntegerListDescription( period, periodValues, periodNames)),
new OptInputParameterInfo("Number Days Lookback", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(noDays, 2, 20, 1)),
new OptInputParameterInfo("Display Period", OptInputParameterInfo.Type.OTHER, new BooleanOptInputDescription(displayPeriod))

};

outputParameterInfos = new OutputParameterInfo[]
{
createOutputParameterInfo("PV", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
createOutputParameterInfo("TC", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
createOutputParameterInfo("BC", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE),
createOutputParameterInfo("Separators", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.DASH_LINE )
};

outputParameterInfos[0].setColor(DemiBlack);
outputParameterInfos[1].setColor(Orchid);
outputParameterInfos[2].setColor(Orchid);
outputParameterInfos[3].setColor(Gray);

decimalFormat = new DecimalFormat("0.0000");

}

private OutputParameterInfo createOutputParameterInfo(String name, Type type, DrawingStyle drawingStyle)
{
return new OutputParameterInfo(name, type, drawingStyle, false)
{{
setDrawnByIndicator(true);
}};
}

public IndicatorResult calculate(int startIndex, int endIndex)
{
console.getOut().println("calculate: startIndex="+startIndex+" endIndex="+endIndex);
// is the pivot period smaller than the chart period?
if ( calculationTimeframe.getPeriod().isSmallerThan(displayTimeframe.getPeriod()) ||
calculationTimeframe.getPeriod().equals(displayTimeframe.getPeriod()) )
/* || calculationTimeframe.getPeriod().isSmallerThan(Period.DAILY_SUNDAY_IN_MONDAY) */
{
new IndicatorResult(0, 0);
}
console.getOut().println("calculate: 2");
if (instrument != null)
{
console.getOut().println("instrument="+instrument.toString()); // this never outputs anything i.e. instrument is null
}


IBar bar = null;
try { bar = history.getBar(context.getInstrument(), calculationTimeframe.getPeriod(), OfferSide.BID, 0); } // this fails because instrument is null
catch (JFException e) { e.printStackTrace(); }

if (bar != null)
{
double open = bar.getOpen();
console.getOut().println("today's open="+df.format(open)); // this never outputs anything either
}


//default values for indicator outputs
Arrays.fill(outputs[0], Double.NaN);
Arrays.fill(outputs[1], Double.NaN);
Arrays.fill(outputs[2], Double.NaN);
Arrays.fill(outputs[3], 0);

// find the first noDays calculation timeframe bars, then convert to display timeframe start and endIndex
IBar currentBar = null;
IBar previousBar = null;
int timeIndex = -1;

for (int i = 0; i < noDays; i++)
{
// console.getOut().println("i="+i);
// using this approach I can probably limit my inputs to just the chart timeframe in bars i.e. IBar inputs[][1]
try { currentBar = history.getBar(instrument, calculationTimeframe.getPeriod(), OfferSide.BID, i);
} catch (JFException e) { e.printStackTrace(); }

try { previousBar = history.getBar(instrument, calculationTimeframe.getPeriod(), OfferSide.BID, i+1);
} catch (JFException e) { e.printStackTrace(); }

if (previousBar != null)
{
// console.getOut().println("previousBar !=null, i="+i);
double high = previousBar.getHigh();
double low = previousBar.getLow();
double close = previousBar.getClose();
double p = (close + high + low)/3;
double bc = (high + low)/2;
double tc = (2*p - bc);

if (bc > tc)
{
double temp = bc;
bc = tc;
tc = temp;
}
console.getOut().println("pivot("+i+") ="+ df.format(p)+ " high="+ df.format(high)+" low="+df.format(low)+" close="+df.format(close));

// get the open time of the current calculationTimeframe.bar,
// and find this time value on the display (chart) timeframe
timeIndex = getTimeIndex(currentBar.getTime(), inputs[0]);

// found the right bar in the display timeframe, populate values
// question - do we need to populate all indexes between each new
// timeIndex with pivot values to display them or not?
if (timeIndex > -1)
{
console.getOut().println(" time=" + df.format(timeIndex) + " pivot =" + df.format(p));
outputs[0][timeIndex] = p; // PV
outputs[1][timeIndex] = tc; // TC
outputs[2][timeIndex] = bc; // BC
outputs[3][timeIndex] = 0d; // Separator bar
}
}
}
// IndicatorResult(int firstValueIndex, int numberOfElements, int lastValueIndex)
int noElements = endIndex - startIndex - timeIndex;
return new IndicatorResult(startIndex, noElements);
// return new IndicatorResult(startIndex, endIndex);
}


private int getTimeIndex(long time, IBar[] target)
{
if (target == null) { return -1; }

int first = 0;
int upto = target.length;

while (first < upto)
{
int mid = (first + upto) / 2;
IBar data = target[mid];

if (data.getTime() == time) { return mid; }
else if (time < data.getTime()) { upto = mid; }
else if (time > data.getTime()) { first = mid + 1; }
}
return -1;
}


public IndicatorInfo getIndicatorInfo()
{
return indicatorInfo;
}

public InputParameterInfo getInputParameterInfo(int index)
{
if (index <= inputParameterInfos.length)
{
return inputParameterInfos[index];
}
return null;
}

public int getLookback()
{
return 0;
}

public int getLookforward()
{
return 0;
}

public OptInputParameterInfo getOptInputParameterInfo(int index)
{
if (index <= optInputParameterInfos.length)
{
return optInputParameterInfos[index];
}
return null;
}

public OutputParameterInfo getOutputParameterInfo(int index)
{
if (index <= outputParameterInfos.length)
{
return outputParameterInfos[index];
}
return null;
}

public void setInputParameter(int index, Object array)
{
inputs[index] = (IBar[]) array;
}

public void setOptInputParameter(int index, Object value)
{
if (index == 0)
{
int period = ((Integer) value).intValue();
switch (period)
{
case 0 : calculationTimeframe.setPeriod(Period.ONE_HOUR); break;
case 1 : calculationTimeframe.setPeriod(Period.FOUR_HOURS); break;
case 2 : calculationTimeframe.setPeriod(Period.DAILY_SUNDAY_IN_MONDAY); break;
case 3 : calculationTimeframe.setPeriod(Period.WEEKLY); break;
case 4 : calculationTimeframe.setPeriod(Period.MONTHLY); break;
default: calculationTimeframe.setPeriod(Period.DAILY_SUNDAY_IN_MONDAY);
}
}
else if (index == 1)
{
noDays = (Integer) value;
}
else if (index == 2)
{
displayPeriod= (Boolean) value;
}
}

public void setOutputParameter(int index, Object array)
{
outputs[index] = (double[]) array;
}


 
 Post subject: Re: JFOREX-3299 context.getInstrument() - null in IIndicator Post rating: 0   New post Posted: Wed 26 Oct, 2011, 16:42 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Have another look at the Jforex API documentation which states that "IIndicatorContext.getInstrument() "returns instrument of the primary input when called from the IIndicator.calculate(int, int) or IIndicator.setInputParameter(int, java.lang.Object) methods". It means that context itself should be initialized inside the onStart method of the indicator, the instrument may be safely requested from context inside the above mentioned methods.


 
 Post subject: Re: JFOREX-3299 context.getInstrument() - null in IIndicator Post rating: 0   New post Posted: Wed 26 Oct, 2011, 16:43 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Fixed in 2.6.47


 

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