/*
* Licensed Materials - Property of Perforce Software, Inc.
* © Copyright Perforce Software, Inc. 2014, 2021
* © Copyright IBM Corp. 2009, 2014
* © Copyright ILOG 1996, 2009
* All Rights Reserved.
*
* Note to U.S. Government Users Restricted Rights:
* The Software and Documentation were developed at private expense and
* are "Commercial Items" as that term is defined at 48 CFR 2.101,
* consisting of "Commercial Computer Software" and
* "Commercial Computer Software Documentation", as such terms are
* used in 48 CFR 12.212 or 48 CFR 227.7202-1 through 227.7202-4,
* as applicable.
*/
package thinstock;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletConfig;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import com.ibm.icu.text.DecimalFormat;
import com.ibm.icu.text.NumberFormat;
import ilog.views.chart.IlvAxis;
import ilog.views.chart.IlvChart;
import ilog.views.chart.IlvChartLayout;
import ilog.views.chart.IlvChartRenderer;
import ilog.views.chart.IlvColor;
import ilog.views.chart.IlvDataInterval;
import ilog.views.chart.IlvDefaultStepsDefinition;
import ilog.views.chart.IlvLegend;
import ilog.views.chart.IlvStyle;
import ilog.views.chart.IlvTimeUnit;
import ilog.views.chart.data.IlvDataSet;
import ilog.views.chart.data.IlvDefaultDataSet;
import ilog.views.chart.data.IlvDefaultDataSource;
import ilog.views.chart.event.AxisChangeEvent;
import ilog.views.chart.event.AxisListener;
import ilog.views.chart.event.AxisRangeEvent;
import ilog.views.chart.renderer.IlvHiLoChartRenderer;
import ilog.views.chart.renderer.IlvPolylineChartRenderer;
import ilog.views.chart.renderer.IlvSingleAreaRenderer;
import ilog.views.chart.renderer.IlvSingleBarRenderer;
import ilog.views.chart.renderer.IlvSinglePolylineRenderer;
import ilog.views.chart.renderer.IlvSingleStairRenderer;
import ilog.views.chart.util.IlvDoubleArray;
import ilog.views.util.IlvLocaleUtil;
import ilog.views.util.IlvResourceUtil;
import ilog.views.util.time.IlvCalendarFactory;
import stock.CategoryTimeSteps;
import stock.SharedGrid;
import stock.StockColors;
import stock.StockDataSource;
import stock.StockUtil;
import stock.Stripes;
import stock.ThresholdLines;
import stock.indicator.BollingerBandsIndicator;
import stock.indicator.MACDIndicator;
import stock.indicator.MovingAverageIndicator;
import stock.indicator.PriceChannelIndicator;
import stock.indicator.RSIIndicator;
import stock.indicator.StochasticIndicator;
import stock.indicator.TechnicalIndicator;
import stock.indicator.VolumeIndicator;
import stock.indicator.WilliamsRIndicator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class StockDemoApp implements StockColors
{
private static final Logger LOGGER = LoggerFactory.getLogger(StockDemoApp.class);
/** The number of lower charts. */
private static final int LOWER_CHART_COUNT = 2;
private static final int RIGHT_MARGIN = 6;
private static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 10);
public static final int LINE = 0;
public static final int AREA = 1;
public static final int BAR = 2;
public static final int STAIR = 3;
public static final int HLOC = 4;
public static final int CANDLE = 5;
/**
* The threshold beyond which quotes are displayed with an overview
* representation mode. This constant is equal to the approximate duration of
* 3 months for daily data and one year for weekly data.
*/
public static final double OVERVIEW_THRESHOLD = 65;
static {
List<Color> colorList = IlvColor.getDefaultColors();
colorList.clear();
colorList.addAll(Arrays.asList(DEFAULT_COLORS));
}
// == Chart related data members
StockDataSource stockDS;
IlvChart mainChart;
IlvChart[] lowerCharts;
List<TechnicalIndicator> upperIndicators = new ArrayList<TechnicalIndicator>();
TechnicalIndicator[] lowerIndicators;
/** The overview renderer for the primary symbol. */
IlvChartRenderer overviewRenderer;
/** The detailed renderer for the primary symbol. */
IlvChartRenderer detailedRenderer;
/** The renderer for the seconary symbols. */
IlvChartRenderer secondaryRenderer;
boolean antiAliasing = false;
// == UI related data members
private List<UpperIndicatorAction> upperIndicatorActions;
private List<LowerIndicatorAction>[] lowerIndicatorActions;
private NumberFormat numFmt = new DecimalFormat(".###");
private ThresholdLines threshold;
/** Creates a new instance of StockDemoApp */
public StockDemoApp(ServletConfig config) {
initDemo(config);
}
private void initDemo(ServletConfig config) {
numFmt = NumberFormat.getNumberInstance();
numFmt.setMaximumFractionDigits(3);
// Create the stock data source to read the result of the query.
URL defaultDataURL = null;
try {
defaultDataURL = config.getServletContext().getResource("/data/default.csv");
} catch (Exception x) {
x.printStackTrace();
}
stockDS = new StockDataSource(defaultDataURL);
// == Create the main chart.
mainChart = createMainChart();
setOverviewRepresentation(LINE);
setDetailedRepresentation(CANDLE);
secondaryRenderer = new IlvPolylineChartRenderer();
mainChart.addRenderer(secondaryRenderer);
// == Create indicator charts.
lowerCharts = createLowerCharts();
lowerIndicators = new TechnicalIndicator[lowerCharts.length];
initIndicatorActions();
setLowerIndicator(0, ((IndicatorAction) lowerIndicatorActions[0].get(0)).getIndicator());
setLowerIndicator(1, ((IndicatorAction) lowerIndicatorActions[1].get(1)).getIndicator());
setAntiAliasing(true);
// Load the default data.
loadDefaultData(config);
}
/**
* Returns the data source that holds the stock data.
*/
public StockDataSource getStockDataSource() {
return stockDS;
}
/**
* Returns the main chart.
*/
public IlvChart getMainChart() {
return mainChart;
}
/**
* Returns the lower chart of the specified index.
*/
public IlvChart getLowerChart(int idx) {
return lowerCharts[idx];
}
public boolean isOverviewVisible() {
return overviewRenderer.isVisible();
}
public IlvChartRenderer getOverviewRenderer() {
return overviewRenderer;
}
public IlvDataSet getDetailedDataSet() {
return detailedRenderer.getDataSource().getDataSet(2);
}
public IlvDataSet getLowerIndicatorDataSet(int chartIdx) {
return lowerIndicators[chartIdx].getMainDataSet();
}
// --------------------------------------------------------------------------
// - Indicators
public String getLowerIndicatorName(int chartIdx) {
return lowerIndicators[chartIdx].getName();
}
public void setLowerIndicator(int chartIdx, int indicatorIdx) {
((IndicatorAction) lowerIndicatorActions[chartIdx].get(indicatorIdx)).actionPerformed(null);
}
/** Sets a lower indicator. */
protected void setLowerIndicator(int idx, TechnicalIndicator indicator) {
if (lowerIndicators[idx] == indicator)
return;
if (lowerIndicators[idx] != null)
lowerIndicators[idx].detach();
if (indicator != null)
indicator.attach(lowerCharts[idx]);
lowerIndicators[idx] = indicator;
}
public void setUpperIndicators(int[] indicators) {
for (int i = 0; i < upperIndicatorActions.size(); ++i) {
UpperIndicatorAction action = (UpperIndicatorAction) upperIndicatorActions.get(i);
removeUpperIndicator(action.getIndicator());
action.reset();
}
for (int i = 0; i < indicators.length; ++i)
((IndicatorAction) upperIndicatorActions.get(indicators[i])).actionPerformed(null);
}
/** Adds an upper indicator. */
protected void addUpperIndicator(TechnicalIndicator indicator) {
if (indicator != null)
indicator.attach(mainChart);
upperIndicators.add(indicator);
}
/** Removes an upper indicator. */
protected void removeUpperIndicator(TechnicalIndicator indicator) {
if (!upperIndicators.contains(indicator))
return;
if (indicator != null)
indicator.detach();
upperIndicators.remove(indicator);
}
/**
* Creates the main chart. This chart displays the stock data and the upper
* indicators.
*/
protected IlvChart createMainChart() {
IlvChart chart = createChart();
chart.setBorder(BorderFactory.createEmptyBorder(0, 0, 4, 0));
setMargins(chart);
chart.getXAxis().setVisibleRange(0, 10);
chart.getYScale(0).setTitle("Share price ($)", 270);
chart.getYScale(0).getTitleRenderer().setFont(new Font("Dialog", Font.PLAIN, 12));
Stripes stripes = new Stripes(chart.getYScale(0), STRIPES_COLOR);
stripes.setDrawOrder(-3);
chart.addDecoration(stripes);
chart.getYAxis(0).setVisibleRange(0, 100);
chart.getXScale().setMajorTickVisible(false);
chart.getXScale().setVisible(false);
chart.getChartArea().setRightMargin(RIGHT_MARGIN);
// Add an axis listener to toggle the visibility of the
// quote renderers/quote overview.
chart.getXAxis().addAxisListener(new AxisListener() {
double oldLen = 0;
boolean oldAntiAliasing;
Override
public void axisRangeChanged(AxisRangeEvent evt) {
if (evt.isChangedEvent() && !evt.isAdjusting() && evt.isVisibleRangeEvent()) {
updateDisplay(evt.getAxis());
} else if (!evt.isChangedEvent()) {
double min = evt.getNewMin();
double max = evt.getNewMax();
if (max - min < StockUtil.MIN_XLEN) {
double mid = (max + min) / 2;
evt.setNewMax(mid + StockUtil.MIN_XLEN / 2);
evt.setNewMin(mid - StockUtil.MIN_XLEN / 2);
}
}
}
Override
public void axisChanged(AxisChangeEvent evt) {
if (evt.getType() == AxisChangeEvent.ADJUSTMENT_CHANGE) {
if (evt.isAdjusting()) {
if (StockDemoApp.this.antiAliasing) {
StockDemoApp.this.setAntiAliasing(false);
oldAntiAliasing = true;
}
} else {
if (oldAntiAliasing) {
StockDemoApp.this.setAntiAliasing(true);
oldAntiAliasing = false;
}
updateDisplay(evt.getAxis());
}
} else if (evt.getType() == AxisChangeEvent.TRANSFORMER_CHANGE) {
// LocalZoomHandler lzh = LocalZoomHandler.get(mainChart, -1);
// if (lzh == null) return;
// if (oldZoomfactor != lzh.getTransformer().getZoomFactor()) {
// zoomInAction.computeEnabled();
// zoomOutAction.computeEnabled();
// oldZoomfactor = lzh.getTransformer().getZoomFactor();
// }
}
}
private void updateDisplay(IlvAxis axis) {
// Check if the zoom level has changed and call the
// xRangeChanged() method.
IlvDataInterval xRange = mainChart.getXAxis().getVisibleRange();
double newLen = xRange.getLength();
boolean zoom = (oldLen == 0) || (Math.abs(newLen - oldLen) / oldLen > .01);
StockDemoApp.this.xRangeChanged(zoom);
oldLen = newLen;
}
});
chart.getYAxis(0).addAxisListener(new AxisListener() {
Override
public void axisRangeChanged(AxisRangeEvent evt) {
if (evt.isAboutToChangeEvent()) {
IlvDataInterval range = StockUtil.getYDataRange(mainChart, 0, mainChart.getXAxis().getVisibleRange());
if (!range.isEmpty()) {
evt.setNewMin(range.min);
evt.setNewMax(range.max);
}
}
}
Override
public void axisChanged(AxisChangeEvent evt) {
}
});
// == Add the quote display panel and the legend as a header.
// JPanel header = new JPanel(new GridLayout(0,1,0,4));
// header.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 8));
// header.setBackground(HEADER_COLOR);
IlvLegend legend = createLegend();
// chart.setLegend(legend);
// header.add(legend);
// chart.setHeader(header);
chart.addLegend(legend, IlvChartLayout.NORTH_BOTTOM);
return chart;
}
/** Creates the charts displaying lower indicators. */
protected IlvChart[] createLowerCharts() {
IlvChart[] charts = new IlvChart[LOWER_CHART_COUNT];
for (int i = 0; i < LOWER_CHART_COUNT; ++i) {
charts[i] = createLowerChart();
}
return charts;
}
/** Creates a lower chart. */
private IlvChart createLowerChart() {
IlvChart chart = createChart();
chart.synchronizeAxis(mainChart, IlvAxis.X_AXIS, false);
chart.setXScale(null);
chart.setXGrid(new SharedGrid(mainChart.getXScale(), GRID_COLOR));
setMargins(chart);
// JPanel header = new JPanel(new GridLayout(0,1,0,4));
// header.setBorder(BorderFactory.createEmptyBorder(4, 0, 0, 8));
// header.setBackground(HEADER_COLOR);
IlvLegend legend = createLegend();
// chart.setLegend(legend);
// header.add(legend);
// chart.setHeader(header);
chart.addLegend(legend, IlvChartLayout.NORTH_BOTTOM);
return chart;
}
private void setMargins(IlvChart chart) {
chart.getChartArea().setHorizontalMargins(50, 3);
}
/** Creates the list of upper indicators. */
protected List<TechnicalIndicator> createUpperIndicators() {
List<TechnicalIndicator> list = new ArrayList<TechnicalIndicator>();
list.add(new BollingerBandsIndicator(stockDS));
list.add(new PriceChannelIndicator(stockDS));
list.add(MovingAverageIndicator.createSMA(stockDS, 20));
list.add(MovingAverageIndicator.createSMA(stockDS, 40));
list.add(MovingAverageIndicator.createEMA(stockDS, 20));
list.add(MovingAverageIndicator.createEMA(stockDS, 40));
return list;
}
/** Creates the list of lower indicators. */
protected List<TechnicalIndicator> createLowerIndicators() {
List<TechnicalIndicator> list = new ArrayList<TechnicalIndicator>();
list.add(new VolumeIndicator(stockDS));
list.add(new RSIIndicator(stockDS, 14));
list.add(MACDIndicator.createMACD(stockDS));
list.add(new WilliamsRIndicator(stockDS, 14));
list.add(StochasticIndicator.createFastStochastic(stockDS));
list.add(StochasticIndicator.createSlowStochastic(stockDS));
return list;
}
/** Initializes the actions associated with indicators. */
SuppressWarnings("unchecked")
private void initIndicatorActions() {
List<TechnicalIndicator> list = createUpperIndicators();
Iterator<TechnicalIndicator> ite = list.iterator();
upperIndicatorActions = new ArrayList<StockDemoApp.UpperIndicatorAction>(list.size());
while (ite.hasNext()) {
TechnicalIndicator indicator = (TechnicalIndicator) ite.next();
UpperIndicatorAction action = new UpperIndicatorAction(indicator);
action.updateEnabled();
upperIndicatorActions.add(action);
}
lowerIndicatorActions = new ArrayList[lowerCharts.length];
for (int i = 0; i < lowerIndicatorActions.length; ++i) {
lowerIndicatorActions[i] = new ArrayList<LowerIndicatorAction>();
ite = createLowerIndicators().iterator();
while (ite.hasNext()) {
TechnicalIndicator indicator = (TechnicalIndicator) ite.next();
LowerIndicatorAction action = new LowerIndicatorAction(indicator, i);
action.updateEnabled();
lowerIndicatorActions[i].add(action);
}
}
}
/** Toggles the price threshold. */
public void setThreshold(boolean set) {
if (set) {
if (threshold == null) {
Color upperColor = new Color(120, 220, 120);
Color midColor = new Color(233, 150, 122);
Color lowerColor = IlvColor.indianRed;
threshold = new ThresholdLines(FOREGROUND, BACKGROUND, lowerColor, midColor, upperColor);
ThresholdLines.set(threshold, mainChart, 0);
threshold.setThresholds(mainChart.getYAxis(0).getDataRange());
} else {
ThresholdLines.set(threshold, mainChart, 0);
}
overviewRenderer.setRenderingHint(threshold);
detailedRenderer.setRenderingHint(threshold);
} else {
ThresholdLines.remove(mainChart, 0);
overviewRenderer.setRenderingHint(null);
detailedRenderer.setRenderingHint(null);
}
}
/** Toggles anti-aliasing for the charts. */
public void setAntiAliasing(boolean b) {
if (antiAliasing == b)
return;
mainChart.setAntiAliasing(b);
mainChart.getChartArea().repaint();
for (int i = 0; i < lowerCharts.length; ++i) {
lowerCharts[i].setAntiAliasing(b);
lowerCharts[i].getChartArea().repaint();
}
antiAliasing = b;
}
/**
* Sets the input API key on the StockDataSource instance.
*/
public void setAPIKey(String apiKey) {
stockDS.setAPIKey(apiKey);
}
/**
* Loads the quotes.
*/
public boolean loadQuotes(final String symbol, Date startDate, Date endDate, int frequency, String[] secsymbols) {
boolean retVal = false;
if (symbol == null || symbol.length() == 0)
LOGGER.warn("Missing ticker symbol!");
else if (stockDS == null || stockDS.getAPIKey().isEmpty())
LOGGER.warn("Missing API key!");
else {
// == Reset all data
overviewRenderer.getDataSource().setDataSets(null);
detailedRenderer.getDataSource().setDataSets(null);
secondaryRenderer.getDataSource().setDataSets(null);
// == Workaround BUG IlvHiLoChartRenderer (setDataSets(null))
int mode = ((IlvHiLoChartRenderer) detailedRenderer).getMode();
if (mode == IlvHiLoChartRenderer.CANDLE)
setDetailedRepresentation(CANDLE);
else
setDetailedRepresentation(HLOC);
// == End Workaround
stockDS.reset();
updateIndicators();
stockDS.loadData(symbol, startDate, endDate, frequency, null);
// primaryDataLoaded(symbol, secsymbols);
retVal = true;
}
return retVal;
}
private void loadDefaultData(ServletConfig config) {
URL dataFile = null;
try {
dataFile = config.getServletContext().getResource("/data/default.csv");
} catch (MalformedURLException e) {
e.printStackTrace();
}
stockDS.loadDefaultData(dataFile);
primaryDataLoaded(StockDataSource.DEFAULT_SYMBOL, null);
setThreshold(true);
threshold.setThresholds(new IlvDataInterval(25, 45));
}
public void primaryDataLoaded(String expectedSymbol, String[] secsymbols) {
if (stockDS.getDataSetCount() > 0) {
if (threshold != null && ThresholdLines.get(mainChart, 0) == null) // i.e.
// Threshold
// has
// been
// hidden
threshold = null;
String symbol = stockDS.getSymbol().toUpperCase();
if (!symbol.equalsIgnoreCase(expectedSymbol)) {
String msg = IlvResourceUtil.getServerLocaleString(StockDemoApp.class, "PrimarySymbolNotFound");
System.err.println(MessageFormat.format(msg, expectedSymbol));
}
// == Update overview Renderer
overviewRenderer.getDataSource().addDataSet(stockDS.getCloseDataSet());
overviewRenderer.setName(symbol);
// == Update detailed renderer
IlvDataSet[] quotes = { stockDS.getLowDataSet(), // low
stockDS.getHighDataSet(), // high
stockDS.getOpenDataSet(), // open
stockDS.getCloseDataSet() // close
};
detailedRenderer.getDataSource().setDataSets(quotes);
detailedRenderer.setName(symbol);
Color c = PRIMARY_COLOR;
IlvStyle style1 = IlvStyle.createStroked(c);
IlvStyle style2 = new IlvStyle(c, IlvColor.brighter(c));
IlvStyle style3 = new IlvStyle(c, IlvColor.darker(c));
detailedRenderer.setStyles(new IlvStyle[] { style1, style1, style2, style3 });
// == Load data for secondary symbols
// final String[] secondarySymbols = queryPanel.getSecondarySymbols();
if (secsymbols != null && secsymbols.length > 0) {
IlvDoubleArray[] data = stockDS.loadData(secsymbols, null);
secondaryDataLoaded(secsymbols, data);
}
}
// == Update indicators
updateIndicators();
// == Reset visible range and history.
resetVisibleRange();
// == Update the x-scale
updateXScale();
// Adjust existing threshold
if (threshold != null) {
threshold.setThresholds(mainChart.getYAxis(0).getVisibleRange());
}
}
private void secondaryDataLoaded(String[] symbols, IlvDoubleArray[] data) {
IlvDefaultDataSource dataSource = new IlvDefaultDataSource();
if (data != null) { // else loading was interrupted by another request
// Update the renderer for the secondary symbols.
String error = null;
for (int i = 0; i < data.length; ++i) {
if (data[i] == null) {
if (error == null)
error = symbols[i];
else
error += ", " + symbols[i];
continue;
}
String name = symbols[i].toUpperCase();
data[i].trim();
dataSource.addDataSet(new IlvDefaultDataSet(name, data[i].data()));
}
if (error != null) {
String msg = IlvResourceUtil.getServerLocaleString(StockDemoApp.class, "secondSymbolNotFound");
System.out.println(msg + error);
}
}
secondaryRenderer.setDataSource(dataSource);
}
/**
* Invoked when quotes are loaded for the primary symbol. This method updates
* the steps definition of the x-scale.
*/
private void updateXScale() {
Date[] dates = stockDS.getDates();
if (dates == null) {
mainChart.getXScale().setVisible(false);
mainChart.getXScale().setStepsDefinition(new IlvDefaultStepsDefinition());
} else {
IlvTimeUnit unit = null;
switch (stockDS.getFrequency()) {
case StockDataSource.MONTHLY:
unit = IlvTimeUnit.MONTH;
break;
case StockDataSource.WEEKLY:
unit = IlvTimeUnit.WEEK;
break;
case StockDataSource.DAILY:
default:
unit = IlvTimeUnit.DAY;
break;
}
CategoryTimeSteps def;
def = new CategoryTimeSteps(dates, unit);
mainChart.getXScale().setStepsDefinition(def);
mainChart.getXScale().setVisible(true);
}
}
/**
* Invoked when quotes are loaded for the primary symbol. This method updates
* the indicators and the enabled state of their associated actions
*/
private void updateIndicators() {
// Refresh indicators.
for (int i = 0; i < lowerIndicators.length; ++i) {
if (lowerIndicators[i] != null)
lowerIndicators[i].refresh();
}
Iterator<TechnicalIndicator> ite = upperIndicators.iterator();
while (ite.hasNext())
((TechnicalIndicator) ite.next()).refresh();
// Update the enabled state of actions.
Iterator<UpperIndicatorAction> ite2 = upperIndicatorActions.iterator();
while (ite2.hasNext()) {
((UpperIndicatorAction) ite2.next()).updateEnabled();
}
Iterator<LowerIndicatorAction> ite3;
for (int i = 0; i < lowerIndicatorActions.length; ++i) {
ite3 = lowerIndicatorActions[i].iterator();
while (ite3.hasNext()) {
((LowerIndicatorAction) ite3.next()).updateEnabled();
}
}
}
private void resetVisibleRange() {
mainChart.getXAxis().setAutoVisibleRange(true);
mainChart.getYAxis(0).setAutoVisibleRange(true);
}
/**
* Creates a legend for the charts.
*/
protected IlvLegend createLegend() {
IlvLegend legend = new IlvLegend();
legend.setLayout(new FlowLayout(FlowLayout.LEFT, 12, 2));
legend.setPaintingBackground(false);
legend.setBorder(null);
legend.setForeground(FOREGROUND);
legend.setMovable(false);
legend.setFont(DEFAULT_FONT);
legend.setSymbolSize(new Dimension(16, 12));
return legend;
}
/**
* Creates a new <code>IlvChart</code> and sets common properties.
*/
protected IlvChart createChart() {
IlvChart chart = new IlvChart();
chart.getXGrid().setMajorPaint(GRID_COLOR);
chart.getYGrid(0).setMajorPaint(GRID_COLOR);
chart.getXGrid().setDrawOrder(-2);
chart.getYGrid(0).setDrawOrder(-2);
chart.setForeground(FOREGROUND);
chart.setBackground(BACKGROUND);
chart.setOpaque(true);
chart.setFont(DEFAULT_FONT);
IlvStyle style = chart.getChartArea().getPlotStyle();
if (style != null)
chart.getChartArea().setPlotStyle(style.setFillOn(false));
return chart;
}
/**
* Invoked when the visible time range changes.
* <p>
* This method toggles the visibility of the quote overview/quote renderers
* according to the visible time range.
*/
private void xRangeChanged(boolean zoom) {
IlvDataInterval xRange = mainChart.getXAxis().getVisibleRange();
if (xRange.isEmpty())
return;
IlvDataInterval yRange = StockUtil.getYDataRange(mainChart, 0, xRange);
if (!yRange.isEmpty())
mainChart.getYAxis(0).setVisibleRange(yRange);
if (zoom) {
boolean hideOverview = (xRange.getLength() < OVERVIEW_THRESHOLD);
mainChart.getYAxis(0).setAutoDataRange(false);
overviewRenderer.setVisible(!hideOverview);
detailedRenderer.setVisible(hideOverview);
mainChart.getYAxis(0).setAutoDataRange(true);
}
}
/**
* Specifies the stock overview representation.
*
* @param representation
* The desired representation.
* @see #BAR
* @see #LINE
* @see #AREA
* @see #STAIR
*/
public void setOverviewRepresentation(int representation) {
int idx = mainChart.getRenderers().indexOf(overviewRenderer);
IlvChartRenderer r = null;
Color c = DEFAULT_COLORS[0];
IlvStyle filledStyle = new IlvStyle(c, IlvColor.setAlpha(c, .45f));
IlvStyle strokedStyle = new IlvStyle(2.f, c);
switch (representation) {
case BAR:
r = new IlvSingleBarRenderer(filledStyle, 100.);
break;
case STAIR:
r = new IlvSingleStairRenderer(filledStyle);
break;
case AREA:
r = new IlvSingleAreaRenderer(filledStyle);
break;
case LINE:
default:
r = new IlvSinglePolylineRenderer(strokedStyle);
break;
}
if (idx == -1) {
mainChart.addRenderer(r);
} else {
r.setVisible(overviewRenderer.isVisible());
r.setName(overviewRenderer.getName());
mainChart.setRenderer(idx, r);
// Update y-range explicitly since the setRenderer can modify
// the x-range before the new renderer is added.
xRangeChanged(false);
}
overviewRenderer = r;
}
/**
* Specifies the stock overview representation.
*
* @param representation
* The desired representation.
* @see #HLOC
* @see #CANDLE
*/
public void setDetailedRepresentation(int representation) {
int idx = mainChart.getRenderers().indexOf(detailedRenderer);
IlvChartRenderer r = null;
switch (representation) {
case HLOC:
r = new IlvHiLoChartRenderer(IlvHiLoChartRenderer.OPENCLOSE, 0, 80);
break;
case CANDLE:
default:
r = new IlvHiLoChartRenderer(IlvHiLoChartRenderer.CANDLE, 0, 80);
break;
}
if (idx == -1)
mainChart.addRenderer(r);
else {
r.setVisible(detailedRenderer.isVisible());
r.setName(detailedRenderer.getName());
IlvStyle[] styles = detailedRenderer.getStyles();
mainChart.setRenderer(idx, r);
r.setStyles(styles);
xRangeChanged(false);
}
detailedRenderer = r;
}
/**
* Returns the default start date for quote queries.
*
* @return One year before the current date.
*/
static final Date getDefaultStartDate() {
Calendar cal = IlvCalendarFactory.createInstance(IlvLocaleUtil.getCurrentULocale());
cal.setTime(new Date());
cal.add(Calendar.YEAR, -1);
return cal.getTime();
}
// --------------------------------------------------------------------------
/**
* The base action class for setting indicators.
*/
abstract class IndicatorAction extends AbstractAction {
private TechnicalIndicator indicator;
/**
* Creates a new <code>UpperIndicatorAction</code> that references the
* specified indicator.
*/
public IndicatorAction(TechnicalIndicator indicator) {
super(indicator.getName());
this.indicator = indicator;
}
/**
* Computes the enable state of the action.
*/
public void updateEnabled() {
boolean enabled = (stockDS.getDataSetCount() > 0);
setEnabled(enabled);
}
/**
* Returns the indicator associated with this action.
*/
public final TechnicalIndicator getIndicator() {
return indicator;
}
}
/**
* An action class used to add upper indicators.
*/
class UpperIndicatorAction extends IndicatorAction {
private boolean added;
/**
* Creates a new <code>UpperIndicatorAction</code> that references the
* specified indicator.
*/
public UpperIndicatorAction(TechnicalIndicator indicator) {
super(indicator);
}
/** Invoked when an action occurs. */
Override
public void actionPerformed(ActionEvent evt) {
if (!isEnabled())
return;
if (added) {
removeUpperIndicator(getIndicator());
added = false;
} else {
addUpperIndicator(getIndicator());
added = true;
}
}
public void reset() {
added = false;
}
}
/**
* An action class used to set lower indicators.
*/
class LowerIndicatorAction extends IndicatorAction {
private int chartIdx;
/**
* Creates a new <code>LowerIndicatorAction</code> that references the
* specified indicator.
*/
public LowerIndicatorAction(TechnicalIndicator indicator, int chartIdx) {
super(indicator);
this.chartIdx = chartIdx;
}
/** Invoked when an action occurs. */
Override
public void actionPerformed(ActionEvent evt) {
if (!isEnabled())
return;
setLowerIndicator(chartIdx, getIndicator());
}
}
}