package hu.ppke.itk.itkStock.gui.chart.candlestick;
import hu.ppke.itk.itkStock.server.db.historicData.StockData;
import hu.ppke.itk.itkStock.server.db.historicData.StockDate;
import hu.ppke.itk.itkStock.server.db.historicData.StockTime;
import hu.ppke.itk.itkStock.server.db.historicData.Transaction;
import java.awt.Dimension;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import javax.swing.JPanel;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Shell;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.XYPlot;
import org.jfree.data.xy.DefaultHighLowDataset;
import org.jfree.data.xy.OHLCDataset;
import org.jfree.ui.ApplicationFrame;
import org.jfree.ui.RefineryUtilities;
public class CandleStickChart extends ApplicationFrame {
private static final long serialVersionUID = 1L;
private static final Calendar calendar = Calendar.getInstance(); //a calendar for the createDate method
private Map<String, SortedMap<StockDate, SortedMap<StockTime, Transaction> > > db; //the result of the query in the init method
private String title; // = paper_name
private StockDate fromdate; // the date we seek
private OHLCDataset dataset;
private int MODE;
public static final int MODE_DAYS = 10;
public static final int MODE_HOURS = 11;
/**
* Consturcts a chart and then displays the result
* @param title paper_name
* @param stockDate the date
*/
public CandleStickChart(String title, StockDate fromdate, StockDate enddate, int MODE)
{
super(title);
this.title = title;
this.fromdate = fromdate;
this.MODE = MODE;
init(title, fromdate, enddate);
}
private void init(String title, StockDate from, StockDate to)
{
try {
if (from.compareTo(to)==0)
db = StockData.fetchData(title, from);
else if (from.compareTo(to)<0)
db = StockData.fetchData(title, from, to);
else if (from.compareTo(to)>0) {
System.err.println("Date interval is invalid, end date is lesser than from date\nOnly from date will be considered!");
db = StockData.fetchData(title, from);
}
SortedMap<StockTime, Transaction> map = null;
ArrayList<StockDate> dates = new ArrayList<StockDate>();
if (db.get(title)!=null) {
map = db.get(title).get(from);
dates.add(from);
if (MODE == MODE_DAYS)
{
dataset = createDatasetByDays(sumDay(parseDay(map), from));
while(from.compareTo(to)<0)
{
StockDate t = next(from);
map = db.get(title).get(t);
dates.add(t);
if (map!=null)
{
dataset = mergeDatasets(dataset, dates, 9, createDatasetByDays(sumDay(parseDay(map), t)), t, 9);
}
from = t;
}
}
else if (MODE == MODE_HOURS)
{
dataset = createDataset(parseDay(map));
while(from.compareTo(to)<0)
{
StockDate t = next(from);
map = db.get(title).get(t);
dates.add(t);
if (map!=null)
{
dataset = mergeDatasets(dataset, dates, 9, createDataset(parseDay(map)), t, 9);
}
from = t;
}
}
else {
showMessage();
throw new IllegalStateException("Invalid mode has been set!");
}
/*
System.out.println(parseDay(map));
System.out.println(sumDay(parseDay(map), from));
dataset = createDataset(parseDay(map));
dataset = createDatasetByDays(sumDay(parseDay(map), from));
map = db.get(title).get(to);
OHLCDataset temp = createDatasetByDays(sumDay(parseDay(map), to));
dataset = mergeDatasets(dataset, from, 9, temp, to, 9);
*/
} else {
System.err.println("Empty Dataset!\nCannot make a chart of an empty dataset");
throw new IllegalArgumentException("No such ticker!");
}
JPanel jpanel = createDemoPanel();
jpanel.setPreferredSize(new Dimension(500, 270));
setContentPane(jpanel);
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
private void showMessage() {
MessageBox messageBox = new MessageBox(new Shell(), SWT.ICON_ERROR | SWT.OK);
messageBox.setText("IllegalStateException");
messageBox.setMessage("Invalid mode has been set! Please set Hourly or Daily mode\nCTRL+N to start again.");
messageBox.open();
}
private OHLCDataset mergeDatasets(OHLCDataset dataset1, ArrayList<StockDate> date1, int starthour1,
OHLCDataset dataset2, StockDate date2, int starthour2)
{
Date[] date = new Date [dataset1.getItemCount(0) + dataset2.getItemCount(0)];
double[] high = new double[dataset1.getItemCount(0) + dataset2.getItemCount(0)];
double[] low = new double[dataset1.getItemCount(0) + dataset2.getItemCount(0)];
double[] open = new double[dataset1.getItemCount(0) + dataset2.getItemCount(0)];
double[] close = new double[dataset1.getItemCount(0) + dataset2.getItemCount(0)];
double[] volume = new double[dataset1.getItemCount(0) + dataset2.getItemCount(0)];
int j = 0;
for (int i = 0; i<dataset1.getItemCount(0); i++)
{
if (j<date1.size()) {
date[i] = createDate(date1.get(j), starthour1);
if (MODE == MODE_HOURS && i%8 == 0 && i>0) {
j++;
starthour1 = 9;
}
else if (MODE == MODE_DAYS){
j++;
starthour1 = 9;
}
}
else {
date[i] = createDate(date1.get(0), starthour1);
}
// date[i] = createDate(date1.get(j), starthour1);
starthour1++;
open[i] = dataset1.getOpenValue(0, i);
volume[i] = dataset1.getVolumeValue(0, i);
high[i] = dataset1.getHighValue(0, i);
low[i] = dataset1.getLowValue(0, i);
close[i] = dataset1.getCloseValue(0, i);
}
for (int i = 0; i<dataset2.getItemCount(0); i++)
{
date[i+dataset1.getItemCount(0)] = createDate(date2, starthour2);
starthour2++;
open[i+dataset1.getItemCount(0)] = dataset2.getOpenValue(0, i);
volume[i+dataset1.getItemCount(0)] = dataset2.getVolumeValue(0, i);
high[i+dataset1.getItemCount(0)] = dataset2.getHighValue(0, i);
low[i+dataset1.getItemCount(0)] = dataset2.getLowValue(0, i);
close[i+dataset1.getItemCount(0)] = dataset2.getCloseValue(0, i);
}
return new DefaultHighLowDataset(title, date, high, low, open, close, volume);
}
//új függvény: adott nap parse-olása
private SortedMap<Integer, HashMap<String, Double>> parseDay(SortedMap<StockTime, Transaction> map) throws Exception
{
if (map==null)
throw new Exception("Empty Dataset!");
SortedMap<Integer, HashMap<String, Double>> ret = new TreeMap<Integer, HashMap<String, Double>>();
for (Entry<StockTime, Transaction> entry : map.entrySet())
{
int hour = entry.getKey().getHour();
double price = entry.getValue().getPrice();
if (ret.containsKey(hour)) {
double lowprice = ret.get(hour).get("low");
double highprice = ret.get(hour).get("high");
price = entry.getValue().getPrice();
double volume = ret.get(hour).get("volume") + entry.getValue().getVolume();
if (price < lowprice) {
ret.get(hour).put("low", price);
}
if (price > highprice) {
ret.get(hour).put("high", price);
}
ret.get(hour).put("close", price);
ret.get(hour).put("volume", volume);
} else {
HashMap<String, Double> tmp = new HashMap<String, Double>();
tmp.put("open", price);
tmp.put("high", price);
tmp.put("low", price);
tmp.put("volume", 0.0);
ret.put(hour, tmp);
}
}
return ret;
}
//új függvény: nap összesítése
private SortedMap<StockDate, HashMap<String, Double>> sumDay(SortedMap<Integer, HashMap<String, Double>> map, StockDate date)
{
SortedMap<StockDate, HashMap<String, Double>> ret = new TreeMap<StockDate, HashMap<String, Double>>();
double open = -1;
double close = -1;
double volume = 0.0;
double low;
double high;
Iterator<Entry<Integer, HashMap<String, Double>>> iterator = map.entrySet().iterator();
HashMap<String, Double> value = iterator.next().getValue();
open = value.get("open");
close = value.get("close");
low = value.get("low");
high = value.get("high");
volume += value.get("volume");
for(Iterator<Entry<Integer, HashMap<String, Double>>> it = iterator; it.hasNext();) {
value = it.next().getValue();
close = value.get("close");
volume += value.get("volume");
if (value.get("low")<low) low = value.get("low");
if (value.get("high")>high) high = value.get("high");
}
HashMap<String, Double> m = new HashMap<String, Double>();
m.put("open", open);
m.put("close", close);
m.put("low", low);
m.put("high", high);
m.put("volume", volume);
ret.put(fromdate, m);
return ret;
}
/**
* Creates the chart from the dataset
* @return the chart
*/
public JFreeChart createChart()
{
JFreeChart jfreechart = ChartFactory.createCandlestickChart("Graph", "Time", "Value", dataset, true);
XYPlot xyplot = (XYPlot)jfreechart.getPlot();
xyplot.setDomainPannable(true);
NumberAxis numberaxis = (NumberAxis)xyplot.getRangeAxis();
numberaxis.setAutoRangeIncludesZero(false);
numberaxis.setUpperMargin(0.0D);
numberaxis.setLowerMargin(0.0D);
return jfreechart;
}
private static StockDate next(StockDate today)
{
int year = today.getYear();
int month = today.getMonth();
int day = today.getDay();
if (day==31)
{
if (month==12)
year++;
else
month++;
}
else
day++;
return new StockDate(year, month, day);
}
/**
* A method which creates date for the dataset of the chart
* @param year
* @param month
* @param day
* @param hour
* @param min
* @return the date specified by year, month, day, hour, min
*/
public static Date createDate(int year, int month, int day, int hour, int min)
{
calendar.clear();
calendar.set(year, month-1, day, hour, min);
return calendar.getTime();
}
/**
* A method which creates date for tha dataset of the chart
* @param date
* @param hour
* @return the date specified by a StockDate and hour
*/
public static Date createDate(StockDate date, int hour)
{
calendar.clear();
calendar.set(date.getYear(), date.getMonth(), date.getDay(), hour, 0);
return calendar.getTime();
}
/**
* Generates the dataset for the CandlestickChart<br>
* The dataset containts arrays for the values needed to create a candlestick chart
* @param chartdata
* @return OHLCDataset containing the arrays
*/
private OHLCDataset createDataset(SortedMap<Integer, HashMap<String, Double>> chartdata)
{
Date[] date = new Date[chartdata.size()];
double[] high = new double[chartdata.size()];
double[] low = new double[chartdata.size()];
double[] open = new double[chartdata.size()];
double[] close = new double[chartdata.size()];
double[] volume = new double[chartdata.size()];
StockDate sdate = new StockDate(2011, 02, 18);
int i = 0;
for (Map.Entry<Integer, HashMap<String, Double>> mapentry : chartdata.entrySet())
{
date[i] = createDate(sdate, mapentry.getKey());
high[i] = mapentry.getValue().get("high");
low[i] = mapentry.getValue().get("low");
open[i] = mapentry.getValue().get("open");
close[i] = mapentry.getValue().get("close");
volume[i] = mapentry.getValue().get("volume");
i++;
}
return new DefaultHighLowDataset(title, date, high, low, open, close, volume);
}
private OHLCDataset createDatasetByDays(SortedMap<StockDate, HashMap<String, Double>> chartdata)
{
Date[] date = new Date[chartdata.size()];
double[] high = new double[chartdata.size()];
double[] low = new double[chartdata.size()];
double[] open = new double[chartdata.size()];
double[] close = new double[chartdata.size()];
double[] volume = new double[chartdata.size()];
int i = 0;
for (Entry<StockDate, HashMap<String, Double>> mapentry : chartdata.entrySet())
{
date[i] = createDate(mapentry.getKey(), 12);
high[i] = mapentry.getValue().get("high");
low[i] = mapentry.getValue().get("low");
open[i] = mapentry.getValue().get("open");
close[i] = mapentry.getValue().get("close");
volume[i] = mapentry.getValue().get("volume");
i++;
}
return new DefaultHighLowDataset(title, date, high, low, open, close, volume);
}
/**
* Creates panel for chart
* @return panel
*/
public JPanel createDemoPanel()
{
JFreeChart jfreechart = createChart();
ChartPanel chartpanel = new ChartPanel(jfreechart);
chartpanel.setMouseWheelEnabled(true);
return chartpanel;
}
/**
* Test main
* @param args
*/
public static void main(String args[]) //testmain
{
// CandleStickChart chart = new CandleStickChart("MOL", new StockDate(2006, 6, 6));
// CandleStickChart chart = new CandleStickChart("MOL", new StockDate(2006, 6, 6), new StockDate(2006, 6, 6), MODE_HOURS);
CandleStickChart chart = new CandleStickChart("MOL", new StockDate(2006, 6, 6), new StockDate(2006, 6, 9), MODE_HOURS);
// CandleStickChart chart = new CandleStickChart("MOL", new StockDate(2006, 6, 6), new StockDate(2006, 6, 9), MODE_DAYS);
chart.pack();
RefineryUtilities.centerFrameOnScreen(chart);
chart.setVisible(true);
}
}