package org.chartsy.stochastics; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.Stroke; import java.text.DecimalFormat; import java.util.LinkedHashMap; import org.chartsy.main.ChartFrame; import org.chartsy.main.chart.Indicator; import org.chartsy.main.data.DataItem; import org.chartsy.main.data.Dataset; import org.chartsy.main.utils.DefaultPainter; import org.chartsy.main.utils.Range; import org.chartsy.main.utils.SerialVersion; import org.chartsy.main.utils.StrokeGenerator; import org.openide.nodes.AbstractNode; /** * * @author viorel.gheba */ public class Stochastics extends Indicator { private static final long serialVersionUID = SerialVersion.APPVERSION; public static final String SLOWD = "slow%D"; public static final String SLOWK = "slow%K"; public static final String FASTD = "fast%D"; public static final String FASTK = "fast%K"; private IndicatorProperties properties; public Stochastics() { super(); properties = new IndicatorProperties(); } public String getName() { return "Stochastic"; } public String getLabel() { return properties.getLabel() + (properties.getSF() ? " Fast" : "") + " (" + properties.getPeriodK() + ", " + properties.getSmooth() + ", " + properties.getPeriodD() + ")"; } public String getPaintedLabel(ChartFrame cf) { return getLabel(); } public Indicator newInstance() { return new Stochastics(); } public LinkedHashMap getHTML(ChartFrame cf, int i) { LinkedHashMap ht = new LinkedHashMap(); DecimalFormat df = new DecimalFormat("#,##0.00"); double[] values = getValues(cf, i); String[] labels = {"%D:", "%K:"}; ht.put(getLabel(), " "); if (values.length > 0) { Color[] colors = getColors(); for (int j = 0; j < values.length; j++) { ht.put(getFontHTML(colors[j], labels[j]), getFontHTML(colors[j], df.format(values[j]))); } } return ht; } @Override public Range getRange(ChartFrame cf) { return new Range(0, 100); } public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds) { Dataset stoD = visibleDataset(cf, properties.getSF() ? FASTD : SLOWD); Dataset stoK = visibleDataset(cf, properties.getSF() ? FASTK : SLOWK); if (stoD != null && stoK != null) { if (maximized) { Range range = getRange(cf); DefaultPainter.line(g, cf, range, bounds, stoD, properties.getColorD(), properties.getStrokeD()); DefaultPainter.line(g, cf, range, bounds, stoK, properties.getColorK(), properties.getStrokeK()); } } } public void calculate() { Dataset initial = getDataset(); if (initial != null && !initial.isEmpty()) { Dataset[] ds = getDataset(initial); addDataset(SLOWD, ds[0]); addDataset(SLOWK, ds[1]); addDataset(FASTD, ds[2]); addDataset(FASTK, ds[3]); } } public boolean hasZeroLine() { return false; } public boolean getZeroLineVisibility() { return false; } public Color getZeroLineColor() { return null; } public Stroke getZeroLineStroke() { return null; } public boolean hasDelimiters() { return true; } public boolean getDelimitersVisibility() { return true; } public double[] getDelimitersValues() { return new double[] {20d, 50d, 80d}; } public Color getDelimitersColor() { return new Color(0xbbbbbb); } public Stroke getDelimitersStroke() { return StrokeGenerator.getStroke(1); } public Color[] getColors() { return new Color[] {properties.getColorD(), properties.getColorK()}; } public double[] getValues(ChartFrame cf) { Dataset stoD = visibleDataset(cf, properties.getSF() ? FASTD : SLOWD); Dataset stoK = visibleDataset(cf, properties.getSF() ? FASTK : SLOWK); if (stoD != null && stoK != null) return new double[] {stoD.getLastClose(), stoK.getLastClose()}; return new double[] {}; } public double[] getValues(ChartFrame cf, int i) { Dataset stoD = visibleDataset(cf, properties.getSF() ? FASTD : SLOWD); Dataset stoK = visibleDataset(cf, properties.getSF() ? FASTK : SLOWK); if (stoD != null && stoK != null) return new double[] {stoD.getCloseAt(i), stoK.getCloseAt(i)}; return new double[] {}; } public boolean getMarkerVisibility() { return properties.getMarker(); } public AbstractNode getNode() { return new IndicatorNode(properties); } @Override public Double[] getPriceValues(ChartFrame cf) { return new Double[] {new Double(20), new Double(50), new Double(80)}; } private Dataset[] getDataset(final Dataset initial) { int periodK = properties.getPeriodK(); int smooth = properties.getSmooth(); int periodD = properties.getPeriodD(); int count = initial.getItemsCount(); Dataset F_K = Dataset.EMPTY(count); // fast %K for (int i = periodK - 1; i < count; i++) { double lk = initial.getLowAt(i); double hk = initial.getHighAt(i); for (int j = 0; j < periodK; j++) { lk = Math.min(lk, initial.getLowAt(i-j)); hk = Math.max(hk, initial.getHighAt(i-j)); } double currentFK = hk != lk ? 100 * (initial.getCloseAt(i) - lk) / (hk - lk) : 0; currentFK = currentFK < 0 ? 0 : currentFK; F_K.setDataItem(i, new DataItem(initial.getTimeAt(i), currentFK)); } Dataset F_D = Dataset.SMA(F_K, periodD); // fast %D Dataset S_K = Dataset.SMA(F_K, smooth); // slow %K Dataset S_D = Dataset.SMA(S_K, periodD); // slow %D Dataset[] result = new Dataset[4]; result[0] = S_D; result[1] = S_K; result[2] = F_D; result[3] = F_K; return result; } }