I've always preferred to use the middle of the spread rather than the bid or the ask as the best indication of the instantaneous true market price. This is of course easy to calculate, and I decided to make an indicator to do so.
What I wrote works fine, but after it has been running a while, ever 200 seconds or so (quite regularly) it gives an error message:
18:48:45 Error in indicator: calculate() method of indicator [MID-PRICE] returned less values than expected. Requested from-to [0]-[9,999], input array size [10,000], returned first calculated index [0], number of calculated values [9,800], lookback [0], lookforward [0], expected number of elements is [10,000]
The questions are (1) Why? and (2) How can it be fixed?
Here is the indicator code:
package com.rochefx.svm;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.indicators.*;
import com.dukascopy.api.*;
/**
* This indicator calculates the mid-price of the close of an instrument at the resolution of the chosen chart
* The motivation is that the mid-price is that by averaging the bid and the ask, some spread-related noise is removed
* with no additional lag. In consequence the mid-price is a slightly superior price to use for most purposes where
* bid or ask is usually used.
* Can be adapted to perform the same job for bar high, low, open, and also mid-price of bar (there are two types of
* averaging involved in that case).
*
* @author Liam Roche
*/
public class MidsIndicator implements IIndicator {
private IndicatorInfo indicatorInfo;
private InputParameterInfo[] inputParameterInfos;
private OptInputParameterInfo[] optInputParameterInfos;
private OutputParameterInfo[] outputParameterInfos;
private final double[][] inputs = new double[2][];
private final double[][] outputs = new double[1][];
@Override
public void onStart(IIndicatorContext context) {
//indicator with 2 inputs, no optional parameters and 1 output
indicatorInfo = new IndicatorInfo("MID-PRICE", "Midprice of close", "My indicators",
true, false, false, 2, 0, 1);
// 2 input arrays of doubles: bids and asks
inputParameterInfos = new InputParameterInfo[] {
new InputParameterInfo("BID", InputParameterInfo.Type.DOUBLE),
new InputParameterInfo("ASK", InputParameterInfo.Type.DOUBLE)
};
for (int i = 0; i < 2; i++) {
inputParameterInfos[i].setAppliedPrice(IIndicators.AppliedPrice.CLOSE);
inputParameterInfos[i].setFilter(Filter.WEEKENDS);
}
inputParameterInfos[0].setOfferSide(OfferSide.BID);
inputParameterInfos[1].setOfferSide(OfferSide.ASK);
// Note we might do this dynamically and only use a single input. But the difference seems small.
// no optional input params
outputParameterInfos = new OutputParameterInfo[1];
outputParameterInfos[0] = new OutputParameterInfo("MID", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE);
}
@Override
public IndicatorResult calculate(int startIndex, int endIndex) {
if (startIndex - getLookback() < 0) {
startIndex -= startIndex - getLookback();
}
if (startIndex > endIndex) { // inadequate data to calculate anything
return new IndicatorResult(0, 0);
}
endIndex = Math.min(endIndex, inputs[0].length-1);
endIndex = Math.min(endIndex, inputs[1].length-1);
int i, j;
for (i = startIndex, j = 0; i <= endIndex; i++, j++) {
outputs[0][j] = (inputs[0][i] + inputs[1][i]) / 2;
}
IndicatorResult result = new IndicatorResult(startIndex, endIndex - startIndex + 1);
return result;
}
@Override
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
@Override
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
@Override
public int getLookback() {
return 0;
}
@Override
public int getLookforward() {
return 0;
}
@Override
public OptInputParameterInfo getOptInputParameterInfo(int index) {
if (index <= optInputParameterInfos.length) {
return optInputParameterInfos[index];
}
return null;
}
@Override
public OutputParameterInfo getOutputParameterInfo(int index) {
if (index <= outputParameterInfos.length) {
return outputParameterInfos[index];
}
return null;
}
@Override
public void setInputParameter(int index, Object array) {
inputs[index] = (double[]) array;
}
@Override
public void setOptInputParameter(int index, Object value) {
}
@Override
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
}