Created
April 11, 2016 19:23
-
-
Save tomas-rampas/dedefc877974c0081025a7ebb29b725c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Created by Tomas Rampas on 4/10/2016. | |
*/ | |
import com.dukascopy.api.*; | |
import com.dukascopy.api.drawings.*; | |
import com.dukascopy.api.feed.IFeedDescriptor; | |
import com.dukascopy.api.indicators.*; | |
import java.awt.*; | |
import java.util.*; | |
import java.util.List; | |
import java.util.concurrent.TimeUnit; | |
public class VolumeProfile implements IIndicator { | |
private IndicatorInfo indicatorInfo; | |
private InputParameterInfo[] inputParameterInfos; | |
private OptInputParameterInfo[] optInputParameterInfos; | |
private OutputParameterInfo[] outputParameterInfos; | |
private IBar[][] inputs = new IBar[1][]; | |
private int timePeriod = 5; | |
private int hour = 0; | |
private int minute = 0; | |
private int width = 21; | |
private double[][] outputs = new double[1][]; | |
private IFeedDescriptor feedDescriptor; | |
private IIndicatorChartPanel chart; | |
private IChartObjectFactory factory; | |
private IIndicatorContext context; | |
private static final String GUID = UUID.randomUUID().toString(); | |
//private IFeedDescriptor askTicksFeed, bidTicksFeed; | |
private IHistory history; | |
private Instrument instrument; | |
@Override | |
public void onStart(IIndicatorContext context) { | |
indicatorInfo = new IndicatorInfo("Volume Profile", "VolProfile", "Custom Indicators", true, false, false, 1, 1, 1); | |
inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Bars", InputParameterInfo.Type.BAR)}; | |
optInputParameterInfos = new OptInputParameterInfo[] { | |
new OptInputParameterInfo("No of days", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(timePeriod, 1, 200, 1)), | |
new OptInputParameterInfo("Hour", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(hour, 0, 23, 1)), | |
new OptInputParameterInfo("Minute", OptInputParameterInfo.Type.OTHER, new IntegerRangeDescription(minute, 0, 59, 1)) | |
}; | |
outputParameterInfos = new OutputParameterInfo[] { | |
new OutputParameterInfo("Out", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE) | |
}; | |
feedDescriptor = context.getFeedDescriptor(); | |
this.context = context; | |
this.history = this.context.getHistory(); | |
} | |
@Override | |
public IndicatorInfo getIndicatorInfo() { | |
return indicatorInfo; | |
} | |
@Override | |
public InputParameterInfo getInputParameterInfo(int index) { | |
if (index <= inputParameterInfos.length) { | |
return inputParameterInfos[index]; | |
} | |
return null; | |
} | |
@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] = (IBar[]) array; | |
} | |
@Override | |
public void setOptInputParameter(int index, Object value) {} | |
@Override | |
public void setOutputParameter(int index, Object array) { | |
outputs[index] = (double[]) array; | |
} | |
@Override | |
public int getLookback() { | |
return 0; | |
} | |
@Override | |
public int getLookforward() { return 0; } | |
@Override | |
public IndicatorResult calculate(int startIndex, int endIndex) { | |
if (startIndex - getLookback() < 0) { | |
startIndex -= startIndex - getLookback(); | |
} | |
if (startIndex > endIndex) { | |
return new IndicatorResult(0, 0); | |
} | |
if(factory == null){ | |
chart = context.getIndicatorChartPanel(); | |
//no chart opened - either indicator called from strategy or indicator | |
if(chart == null){ | |
return new IndicatorResult(startIndex, endIndex-startIndex + 1); | |
} | |
factory = chart.getChartObjectFactory(); | |
} | |
IBar lastDailyBar; long today = 0; | |
try { | |
today = history.getStartTimeOfCurrentBar(getInstrument(), Period.DAILY); | |
//context.getConsole().getOut().println(String.format("Today: %tc", today)); | |
} catch (JFException e1) { | |
// TODO Auto-generated catch block | |
e1.printStackTrace(); | |
} | |
for (int i = startIndex, j = 0; i <= endIndex; i++, j++) { | |
processBar(today, inputs[0][i].getTime()); | |
} | |
return new IndicatorResult(startIndex, endIndex-startIndex + 1); | |
} | |
private Instrument getInstrument() { | |
return context.getFeedDescriptor().getInstrument(); | |
} | |
private void processBar(long today, long timestamp) { | |
if(TimeUnit.MILLISECONDS.toDays(today-timestamp) > timePeriod) { | |
return; | |
} | |
Calendar calendar = Calendar.getInstance(); | |
calendar.setTimeInMillis(timestamp); | |
calendar.add(Calendar.HOUR, 24); | |
long timeoffset = calendar.getTimeInMillis(); | |
long milliseconds = timestamp; | |
int seconds = (int) (milliseconds / 1000) % 60 ; | |
int minutes = (int) ((milliseconds / (1000*60)) % 60); | |
int hours = (int) ((milliseconds / (1000*60*60)) % 24); | |
context.getConsole().getOut().print(String.format("Last day: %tc %tc", timeoffset,(new Date()).getTime())); | |
if((seconds == 0 && minutes == minute && hours == hour)){ | |
processDailyVolume(timestamp, timeoffset); | |
} | |
} | |
private void processDailyVolume(long timestamp, long timeoffset) { | |
try { | |
long currentTime = (new Date()).getTime(); | |
context.getConsole().getOut().print(String.format("Last day: %tc tc", timeoffset, currentTime)); | |
if( currentTime < timeoffset) | |
{ | |
timeoffset = currentTime; | |
} | |
//context.getConsole().getOut().println(String.format("%tc %tc", timestamp, timeoffset)); | |
double pip = getInstrument().getPipValue(); | |
long lastTick = history.getLastTick(getInstrument()).getTime(); | |
if(timeoffset > lastTick){ | |
timeoffset = lastTick; | |
} | |
List<ITick> ticks = history.getTicks(getInstrument(), timestamp, timeoffset); | |
ITick maxTick = Collections.max(ticks, new Comparator<ITick>() { | |
@Override | |
public int compare(ITick o1, ITick o2) { | |
return Double.compare(o1.getAsk(), o2.getAsk()); | |
} | |
}); | |
ITick minTick = Collections.min(ticks, new Comparator<ITick>() { | |
@Override | |
public int compare(ITick o1, ITick o2) { | |
return Double.compare(o1.getBid(), o2.getBid()); | |
} | |
}); | |
context.getConsole().getOut().println(String.format("%tc %tc %d %.1f %.1f", timestamp, timeoffset, ticks.size(), | |
maxTick.getAsk(), maxTick.getBid())); | |
int points = (int) (((maxTick.getAsk() - minTick.getBid())/pip)); | |
Integer[] sum = new Integer[points]; | |
int maxTicks = 0; | |
for (ITick tick : ticks) { | |
int idx = (int)((tick.getBid() - minTick.getBid())/pip); | |
if(sum[idx] == null) sum[idx] = 0; | |
sum[idx]++; | |
maxTicks = Math.max(sum[idx], maxTicks); | |
} | |
context.getConsole().getOut().println(String.format("%tc %tc %d %.1f %.1f", timestamp, timeoffset, ticks.size(), | |
maxTick.getAsk(), maxTick.getBid())); | |
if(sum.length < 1) return; | |
drawVerticalBackLine(timestamp, maxTick, minTick); | |
long oneTickMiliseconds =(long)((width * 60 * 60 * 1000)/maxTicks); | |
this.context.getConsole().getOut().println(String.format("%tc %.5f / %.5f %d tick levels %d, %d, %d", | |
timestamp, minTick.getBid(), maxTick.getAsk(), Arrays.asList(sum).size(), maxTicks, points, | |
oneTickMiliseconds)); | |
IPolyLineChartObject volBarLasso = factory.createPolyLine(GUID + "poly" + String.valueOf(timestamp)); | |
volBarLasso.addNewPoint(timestamp, minTick.getBid()); | |
for (int k = 0; k < sum.length; k++) { | |
int sumTicks = 1; | |
if(sum[k] != null) sumTicks = sum[k]; | |
long toTime = sumTicks * oneTickMiliseconds; | |
volBarLasso.addNewPoint(timestamp+toTime, minTick.getBid()+(k*pip)); | |
volBarLasso.addNewPoint(timestamp+toTime, minTick.getBid()+((k+1)*pip)); | |
//this.context.getConsole().getOut().println(String.format("%tc %tc %d", milliseconds, milliseconds+toTime, (k))); | |
String key = GUID + String.valueOf(timestamp) + k; | |
if(this.chart.get(key) != null) continue; | |
drawHorizonatalVolumeBar(timestamp, pip, minTick, k, sumTicks, toTime, key); | |
} | |
volBarLasso.addNewPoint(timestamp, maxTick.getAsk()); | |
volBarLasso.setLineWidth(2); | |
volBarLasso.setColor(Color.BLUE); | |
volBarLasso.setOpacity((float)0.4); | |
this.chart.add(volBarLasso); | |
} catch (JFException e) { | |
// TODO Auto-generated catch block | |
e.printStackTrace(context.getConsole().getErr()); | |
} | |
} | |
private void drawHorizonatalVolumeBar(long timestamp, double pip, ITick minTick, int k, int sumTicks, long toTime, String key) { | |
// IRectangleChartObject volBar1 = factory.createRectangle(key, | |
// timestamp, minTick.getBid()+(k*pip), timestamp+toTime, minTick.getBid()+((k+1)*pip)); | |
IShortLineChartObject volBar1 = factory.createShortLine(key, | |
timestamp, minTick.getBid()+(k*pip), timestamp+toTime, minTick.getBid()+(k*pip)); | |
volBar1.setTooltip(String.format("%.5f Ticks %d", minTick.getBid()+(k*pip), sumTicks)); | |
volBar1.setLineWidth(1); | |
volBar1.setColor(Color.BLUE); | |
volBar1.setOpacity((float)0.5); | |
//volBar1.setFillColor(Color.LIGHT_GRAY); | |
//volBar1.setFillOpacity((float)0.07); | |
this.chart.add(volBar1); | |
} | |
/** | |
* Draws verical back line. | |
* @param timestamp | |
* @param maxTick | |
* @param minTick | |
*/ | |
private void drawVerticalBackLine(long timestamp, ITick maxTick, ITick minTick) { | |
String key = GUID + String.valueOf(timestamp); | |
if(this.chart.get(key) != null) return; | |
IShortLineChartObject line = factory.createShortLine(key, | |
timestamp, minTick.getBid(), timestamp, maxTick.getAsk()); | |
line.setLineWidth(2); | |
line.setColor(Color.BLUE); | |
line.setOpacity((float) 0.4); | |
this.chart.add(line); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hello, I'm really a newbie to java. I've downloaded the volume profile indicator and when adding to a chart in jforex I get these error messages:
java.lang.ArrayIndexOutOfBoundsException
and then this message:
07:48:25 Last day: Tue Dec 20 04:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 04:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 05:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 05:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 06:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 06:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 07:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 07:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 08:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 08:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 09:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 09:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 10:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 10:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 11:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 11:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 12:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 12:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 13:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 13:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 14:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 14:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 15:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 15:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 16:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 16:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 17:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 17:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 18:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 18:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 19:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 19:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 20:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 20:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 21:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 21:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 22:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 22:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 23:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Tue Dec 20 23:30:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Wed Dec 21 00:00:00 UTC 2016 Fri Dec 23 07:48:26 UTC 2016Last day: Wed Dec 21 00:00:00 UTC 2016 tcTue Dec 20 00:00:00 UTC 2016 Wed Dec 21 00:00:00 UTC 2016 103835 118.2 118.2
Please can you help?
Cheers
Francisco