package uk.ac.cam.cstibhotel.otcanalyser.dataanalysis;
import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import uk.ac.cam.cstibhotel.otcanalyser.communicationlayer.Search;
//gets analysis data by querying the database
public class DBAnalysis {
public static final String END_DATE = "endDate";
public static final String EFFECTIVE_DATE = "effectiveDate";
public static final String EXECUTION_TIME = "executionTime";
//if the database scheme changes, this should ideally be the only method to change
private static PreparedStatement statementPreparer(Search s, String select, String where,
String grouporder, Connection conn) throws SQLException {
String query = "SELECT "+select+" FROM data WHERE "
+"tradeType = ? AND "
+"assetClass = ? AND ";
if (!(s.getAsset()==null||s.getAsset().equals(""))) {
query += " (underlyingAsset1 LIKE ? OR underlyingAsset2 LIKE ?) AND ";
}
if (!(s.getMinPrice()==s.getMaxPrice())) {
query += " roundedNotionalAmount1 >= ? AND "
+" roundedNotionalAmount1 <= ? AND ";
}
if (!(s.getCurrency()==null||s.getCurrency().equals(""))) {
query += " (notionalCurrency1 LIKE ?) AND ";
}
if (!(s.getUPI()==null||s.getUPI().equals(""))) {
query += " taxonomy LIKE ? AND ";
}
query += " executionTime >= ? AND "
+" executionTime <= ?";
if (!where.isEmpty()) {
query += " AND "+where;
}
query += " "+grouporder;
PreparedStatement ps = conn.prepareStatement(query);
int i = 1;
ps.setShort(i, s.getTradeType().getValue());
i++;
ps.setShort(i, s.getAssetClass().getValue());
i++;
if (!(s.getAsset()==null||s.getAsset().equals(""))) {
ps.setString(i, "%"+s.getAsset()+"%");
i++;
ps.setString(i, "%"+s.getAsset()+"%");
i++;
}
if (!(s.getMinPrice()==s.getMaxPrice())) {
ps.setFloat(i, s.getMinPrice());
i++;
ps.setFloat(i, s.getMaxPrice());
i++;
}
if (!(s.getCurrency()==null||s.getCurrency().equals(""))) {
ps.setString(i, s.getCurrency());
i++;
}
if (!(s.getUPI()==null||s.getUPI().equals(""))) {
ps.setString(i, "%"+s.getUPI()+"%");
i++;
}
ps.setTimestamp(i, new Timestamp(s.getStartTime().getTime()));
i++;
ps.setTimestamp(i, new Timestamp(s.getEndTime().getTime()));
i++;
return ps;
}
//gets currencies
public static List<String> getCurrencies(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "DISTINCT notionalCurrency1", "", "", conn);
ResultSet rs = ps.executeQuery();
List<String> list = new ArrayList<>();
while (rs.next()) {
list.add(rs.getString("notionalCurrency1"));
}
return list;
}
//gets most and least traded underlying assets
public static String[] getMostAndLeastTradedUnderlyingAsset(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "underlyingAsset1, count(underlyingAsset1) AS cntTrade", "", "GROUP BY underlyingAsset1", conn);
ResultSet rs = ps.executeQuery();
long maxCount = 0;
String mostTraded = "";
long minCount = Integer.MAX_VALUE;
String leastTraded = "";
while (rs.next()) {
//System.out.println(rs.getString("underlyingAsset1"));
if (rs.getLong("cntTrade")>maxCount) {
maxCount = rs.getLong("cntTrade");
mostTraded = rs.getString("underlyingAsset1");
}
if (rs.getLong("cntTrade")<minCount) {
minCount = rs.getLong("cntTrade");
leastTraded = rs.getString("underlyingAsset1");
}
}
return new String[]{mostTraded, leastTraded};
}
@Deprecated
public static String[] getMostAndLeastTradedUnderlyingAssetButAlsoHangForAtLeastOneMinute(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "DISTINCT underlyingAsset1", "", "", conn);
ResultSet rs = ps.executeQuery();
long maxCount = 0;
String mostTraded = "";
long minCount = Integer.MAX_VALUE;
String leastTraded = "";
while (rs.next()) { //cycle through each underlying asset to find the maximum
ps = statementPreparer(s, "count(underlyingAsset1) AS num", "underlyingAsset1 = ?", "", conn);
//set the last parameter, which is the underlyingAsset1 to match
ps.setString(ps.getParameterMetaData().getParameterCount(), rs.getString("underlyingAsset1"));
ResultSet gs = ps.executeQuery();
if (gs.next()) {
if (gs.getLong("num")>maxCount) { //number of trades with this underlying asset > maximum so far
maxCount = gs.getLong("num");
mostTraded = rs.getString("underlyingAsset1");
}
if (gs.getLong("num")<minCount) {
minCount = gs.getLong("num");
leastTraded = rs.getString("underlyingAsset1");
}
}
}
return new String[]{mostTraded, leastTraded};
}
//returns true if difference between months is large enough and false otherwise
public static boolean graphByMonth(Search s, Connection conn, String date) throws SQLException {
PreparedStatement ps = statementPreparer(s, "max("+date+") as lastDate, min("+date+") as firstDate", "", "", conn);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
Calendar first = Calendar.getInstance();
first.setTime(rs.getDate("firstDate"));
Calendar last = Calendar.getInstance();
last.setTime(rs.getDate("lastDate"));
if (last.get(Calendar.YEAR)-first.get(Calendar.YEAR)>0&&first.get(Calendar.MONTH)-last.get(Calendar.MONTH)<9) {
return true;
} else {
return last.get(Calendar.MONTH)-first.get(Calendar.MONTH)>3;
}
} else {
throw new SQLException();
}
}
//gets max Rounded Notional Amount 1
public static AnalysisItem getMaxPrice(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "notionalCurrency1 AS curr,"
+"underlyingAsset1 as asset, roundedNotionalAmount1 AS maxRNA, "+EXECUTION_TIME, "",
"ORDER by maxRNA DESC, "+EXECUTION_TIME+" DESC LIMIT 1", conn);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return new AnalysisItem(new Date(rs.getTimestamp(EXECUTION_TIME).getTime()), rs.getString("curr"), rs.getLong("maxRNA"), rs.getString("asset"));
} else {
return null;
}
}
//gets min Rounded Notional Amount 1
public static AnalysisItem getMinPrice(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "notionalCurrency1 AS curr,"
+"underlyingAsset1 as asset, roundedNotionalAmount1 AS maxRNA, "+EXECUTION_TIME, "",
"ORDER by maxRNA ASC, "+EXECUTION_TIME+" DESC LIMIT 1", conn);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return new AnalysisItem(new Date(rs.getTimestamp(EXECUTION_TIME).getTime()), rs.getString("curr"), rs.getLong("maxRNA"), rs.getString("asset"));
} else {
return null;
}
}
//gets avg Rounded Notional Amount 1
public static double getAvgPrice(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "avg(CAST(roundedNotionalAmount1 AS DOUBLE)) AS avgRNA", "", "", conn);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getDouble("avgRNA");
} else {
return 0;
}
}
//gets population std dev of Rounded Notional Amount 1
public static double getStdDevPrice(Search s, Connection conn) throws SQLException {
PreparedStatement ps = statementPreparer(s, "STDDEV_POP(roundedNotionalAmount1) AS stddev", "", "", conn);
ResultSet rs = ps.executeQuery();
if (rs.next()) {
return rs.getDouble("stddev");
} else {
return 0;
}
}
public static StatisticalDataSet<PriceTimePair> getPerMonthStats(Search s, Connection conn, String date) throws SQLException {
StatisticalDataSet<PriceTimePair> result = new StatisticalDataSet<>();
PreparedStatement ps = statementPreparer(s,
"max(roundedNotionalAmount1) AS maxRNA, min(roundedNotionalAmount1) AS minRNA, "
+"avg(CAST(roundedNotionalAmount1 AS DOUBLE)) AS avgRNA, STDDEV_POP(CAST(roundedNotionalAmount1 AS DOUBLE)) AS stddev, "
+"MONTH(" + date + ") AS month, YEAR(" + date + ") AS year, notionalCurrency1 AS curr",
"", "GROUP BY month, year, curr", conn);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Calendar c = Calendar.getInstance();
c.setTime(new Date(0));
c.set(Calendar.MONTH, rs.getInt("month")-1);
c.set(Calendar.YEAR, rs.getInt("year"));
result.getMax().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getLong("maxRNA"), null));
result.getMin().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getLong("minRNA"), null));
result.getAvg().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getDouble("avgRNA"), null));
//result.getStddev().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getDouble("stddev"), null));
}
return result;
}
public static StatisticalDataSet<PriceTimePair> getPerDayStats(Search s, Connection conn, String date) throws SQLException {
StatisticalDataSet<PriceTimePair> result = new StatisticalDataSet<>();
PreparedStatement ps = statementPreparer(s,
"max(roundedNotionalAmount1) AS maxRNA, min(roundedNotionalAmount1) AS minRNA, "
+"avg(CAST(roundedNotionalAmount1 AS DOUBLE)) AS avgRNA, "
+"DAY("+date+") as day, MONTH("+date+") AS month, YEAR("+date+") AS year, "
+"notionalCurrency1 AS curr", "", "GROUP BY day, month, year, curr", conn);
ResultSet rs = ps.executeQuery();
while (rs.next()) {
Calendar c = Calendar.getInstance();
c.setTime(new Date(0));
c.set(Calendar.DAY_OF_MONTH, rs.getInt("day"));
c.set(Calendar.MONTH, rs.getInt("month")-1);
c.set(Calendar.YEAR, rs.getInt("year"));
result.getMin().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getLong("minRNA"), null));
result.getMax().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getLong("maxRNA"), null));
result.getAvg().add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getDouble("avgRNA"), null));
}
return result;
}
public static List<PriceTimePair> getDataPoints(Search s, Connection conn, String date) throws SQLException {
PreparedStatement ps = statementPreparer(s, "roundedNotionalAmount1 as RNA, DAY(" + date + ") as day, MONTH(" + date + ") AS month, YEAR("
+ date + ") AS year, notionalCurrency1 AS curr", "","",conn);
ResultSet rs = ps.executeQuery();
ArrayList<PriceTimePair> list = new ArrayList<>();
while(rs.next()){
Calendar c = Calendar.getInstance();
c.set(Calendar.DAY_OF_MONTH, rs.getInt("day"));
c.set(Calendar.MONTH, rs.getInt("month"));
c.set(Calendar.YEAR, rs.getInt("year"));
list.add(new AnalysisItem(c.getTime(), rs.getString("curr"), rs.getLong("RNA"), null));
}
return list;
}
}