aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/profit_testing.sqlite3bin8192 -> 8192 bytes
-rw-r--r--src/main/java/edu/brown/cs/student/term/Main.java6
-rw-r--r--src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java13
-rw-r--r--src/main/java/edu/brown/cs/student/term/profit/ProfitCalculation.java185
-rw-r--r--src/test/java/edu/brown/cs/student/ProfitCalculationTest.java29
5 files changed, 187 insertions, 46 deletions
diff --git a/data/profit_testing.sqlite3 b/data/profit_testing.sqlite3
index c3b32ee..33dd2b8 100644
--- a/data/profit_testing.sqlite3
+++ b/data/profit_testing.sqlite3
Binary files differ
diff --git a/src/main/java/edu/brown/cs/student/term/Main.java b/src/main/java/edu/brown/cs/student/term/Main.java
index 6a20de3..dd304c5 100644
--- a/src/main/java/edu/brown/cs/student/term/Main.java
+++ b/src/main/java/edu/brown/cs/student/term/Main.java
@@ -151,7 +151,6 @@ public final class Main {
public Object handle(Request request, Response response) throws Exception {
//String str = request.body();
//xmlLinks = new JSONObject(str); //this is all the filedAt times and xml files
- long startTime = System.currentTimeMillis();
try {
System.err.println("LOG: Call to /data from frontend");
DatabaseQuerier db = SetupCommand.getDq();
@@ -167,9 +166,6 @@ public final class Main {
List<Holder> suspiciousHolders = ranker.getSuspicionScoreList(start, end);
System.err.println("LOG: Making map " + getClass());
Map<String, Object> variables = ImmutableMap.of("holders", suspiciousHolders);
-
- System.out.println("DATA ENDPOINT " + ((System.currentTimeMillis() - startTime) / 1000) + "seconds");
-
return GSON.toJson(variables);
} catch (Exception e) {
System.out.println("Error retrieving the suspicion ranks for GUI");
@@ -189,7 +185,7 @@ public final class Main {
ProfitCalculation profit =
new ProfitCalculation(DatabaseQuerier.getConn(), person, startPeriod, endPeriod);
List<StockHolding> holdings = profit.getHoldingsList();
- double gains = profit.calculateGains();
+ double gains = profit.calculateGainsSingle();
double sp500PercentGain = profit.compareToSP500();
Map<String, Object> res = new HashMap<>();
diff --git a/src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java b/src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java
index c77eb9f..9f17569 100644
--- a/src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java
+++ b/src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java
@@ -16,8 +16,9 @@ public class SuspicionRanker {
}
private <K, V extends Comparable<V>> V getMaxOfMap(Map<K, V> map) {
- Map.Entry<K, V> maxEntry = Collections.max(map.entrySet(), Map.Entry.comparingByValue());
- return maxEntry.getValue();
+ //Map.Entry<K, V> maxEntry = Collections.max(map.entrySet(), Map.Entry.comparingByValue());
+ Collection<V> values = map.values();
+ return Collections.max(map.values());
}
private <K, V extends Comparable<V>> V getMinOfMap(Map<K, V> map) {
@@ -82,10 +83,14 @@ public class SuspicionRanker {
double hubMax = getMaxOfMap(holderToHubScore);
for (Holder guy : holderToHubScore.keySet()) {
- //double normalizedProfitScore = profitMap.get(guy.getId()) / profitMax;
+ double normalizedProfitScore = 0;
+ if (profitMap.containsKey(guy.getId())) {
+ normalizedProfitScore = profitMap.get(guy.getId()) / profitMax;
+ }
+
double normalizedHubScore = holderToHubScore.get(guy) / hubMax;
- double suspicionScore = normalizedHubScore; //* 0.6 + normalizedProfitScore * 0.4;
+ double suspicionScore = normalizedHubScore * 0.6 + normalizedProfitScore * 0.4;
guy.setSuspicionScore(suspicionScore);
orderedSuspicion.add(guy);
}
diff --git a/src/main/java/edu/brown/cs/student/term/profit/ProfitCalculation.java b/src/main/java/edu/brown/cs/student/term/profit/ProfitCalculation.java
index ab76003..d0df8a8 100644
--- a/src/main/java/edu/brown/cs/student/term/profit/ProfitCalculation.java
+++ b/src/main/java/edu/brown/cs/student/term/profit/ProfitCalculation.java
@@ -99,7 +99,7 @@ public class ProfitCalculation {
PreparedStatement prep;
prep =
conn.prepareStatement("SELECT * FROM \'trades\' WHERE holder_name= ? "
- + " AND trade_timestamp BETWEEN ? AND ?"
+ + " AND trade_timestamp BETWEEN ? AND ? "
+ "order by trade_timestamp asc;");
prep.setString(1, this.person);
prep.setDate(2, startTime);
@@ -283,7 +283,7 @@ public class ProfitCalculation {
}
- public double calculateGains() {
+ public double calculateGainsSingle() {
if (!tablesFilled) {
organizeOrders();
@@ -389,33 +389,188 @@ public class ProfitCalculation {
long START = System.currentTimeMillis();
prep =
conn.prepareStatement(
- "SELECT * From trades GROUP BY holder_name having max(is_buy) = 1;");
+ "SELECT * From trades GROUP BY holder_id having max(is_buy) = 1;");
ResultSet rs = prep.executeQuery();
long QUERY = System.currentTimeMillis();
- System.out.println((QUERY - START) + " query time");
+ //System.out.println((QUERY - START) + " query time");
+ //set of all people who have made both buy and sell orders
+ Set<Integer> people = new HashSet<>();
+
+ while (rs.next()) {
+// int id = rs.getInt("holder_id");
+// this.person = rs.getString("holder_name");
+// resetClass();
+//
+//
+//
+// double gain = this.calculateGains();
+// if (moneyInput == 0) {
+// profitMap.put(id, 0.0);
+// } else {
+// profitMap.put(id, gain / moneyInput);
+// }
+ people.add(rs.getInt("holder_id"));
+
+ }
+
+ profitMap = calculateGains(people);
+
+ long LOOP = System.currentTimeMillis();
+ //System.out.println((LOOP - QUERY) + " loop");
+
+ } catch (SQLException throwables) {
+ System.out.println("ERROR: SQl error in profit calculation");
+ }
+ return profitMap;
+ }
+
+ private Map<Integer, Double> calculateGains(Set<Integer> people) {
+ Map<Integer, Double> gainsMap = new HashMap<>();
+
+ //map of stock to list of buy orders, first element in list is oldest
+ Map<Integer, Map<String, LinkedList<OrderTuple>>> sellMap = new HashMap<>();
+ //map of stock to list of buy orders, first element in list is oldest
+ Map<Integer, Map<String, LinkedList<OrderTuple>>> buyMap = new HashMap<>();
+ //money input
+ Map<Integer, Double> moneyInMap = new HashMap<>();
+
+
+ try {
+ PreparedStatement prep;
+ prep =
+ conn.prepareStatement("SELECT * FROM \'trades\'"
+ + " WHERE NOT number_of_shares = 0 AND trade_timestamp BETWEEN ? AND ? "
+ + "order by trade_timestamp asc;");
+ prep.setDate(1, startTime);
+ prep.setDate(2, endTime);
+ ResultSet rs = prep.executeQuery();
while (rs.next()) {
- int id = rs.getInt("holder_id");
- this.person = rs.getString("holder_name");
- resetClass();
+ if (people.contains(rs.getInt("holder_id"))) {
+ String ticker = rs.getString("stock_name");
+ ticker = validateTicker(ticker);
+ if (ticker.equals("")) {
+ continue;
+ }
+ int shares = rs.getInt("number_of_shares");
+ double price = rs.getDouble("share_price");
+ int holder_id = rs.getInt("holder_id");
+ if (!buyMap.containsKey(holder_id)) {
+ buyMap.put(holder_id, new HashMap<>());
+ }
+ if (!sellMap.containsKey(holder_id)) {
+ sellMap.put(holder_id, new HashMap<>());
+ }
+
+
+ OrderTuple order = new OrderTuple(shares, price, rs.getDate("trade_timestamp"));
+
+ //one element list for first time ticker is seen.
+ LinkedList<OrderTuple> oneElement = new LinkedList<OrderTuple>();
+ oneElement.addLast(order);
+
+ //for buy orders, build up buy history
+ if (rs.getInt("is_buy") != 0) {
+
+ if (moneyInMap.containsKey(holder_id)) {
+ moneyInMap.put(holder_id, moneyInMap.get(holder_id) + shares * price);
+ } else {
+ moneyInMap.put(holder_id, shares * price);
+ }
+
+
+ if (buyMap.get(holder_id).containsKey(ticker)) {
+ buyMap.get(holder_id).get(ticker).addLast(order);
+ } else {
+ buyMap.get(holder_id).put(ticker, oneElement);
+ }
+ } else {
+ //ignore sell orders for which we do not have buys for
+ if (sellMap.get(holder_id).containsKey(ticker)) {
+ sellMap.get(holder_id).get(ticker).addLast(order);
+ } else {
+ sellMap.get(holder_id).put(ticker, oneElement);
+ }
+
+ }
+ }
+ }
+ } catch (SQLException e) {
+ System.out.println("ERROR: sql error getting trades");
+ }
+
+
+ //part 2 doing math...
+ for (Integer person : people) {
+ this.buyHistoryMap = buyMap.get(person);
+ this.sellHistoryMap = sellMap.get(person);
+ if (sellHistoryMap == null) {
+ continue;
+ }
+
+ for (String ticker : sellHistoryMap.keySet()) {
+ //use FIFO selling
+ LinkedList<OrderTuple> sells = sellHistoryMap.get(ticker);
+ LinkedList<OrderTuple> buys = buyHistoryMap.get(ticker);
+ double realizedGain = 0;
+ if (sells != null && buys != null) {
+ //process each sell order (unless all buy orders are "drained"
+ for (OrderTuple sell : sells) {
+ //stop if buys are empty, stop if buy happened after sell
+ if (buys.isEmpty()) {
+ break;
+ }
+
+ int sharesToSell = sell.getShares();
+
+ //sell off through list of buys
+ while (sharesToSell > 0 && !buys.isEmpty()) {
+ //dont sell from buys which didn't exist at the time.
+ if (sell.getDate().after(buys.getFirst().getDate())
+ || sell.getDate().equals(buys.getFirst().getDate())) {
+ OrderTuple buyBundle = buys.removeFirst();
+ int sharesAtBundlePrice;
+ //the buy has more shares than we want to sell
+ if (buyBundle.getShares() > sharesToSell) {
+ sharesAtBundlePrice = sharesToSell;
+ sharesToSell = 0;
+ //add back the holdings that were not sold
+ buyBundle.setShares(buyBundle.getShares() - sharesAtBundlePrice);
+ buys.addFirst(buyBundle);
+ } else {
+ sharesToSell -= buyBundle.getShares();
+ sharesAtBundlePrice = buyBundle.getShares();
+ }
+ realizedGain += sharesAtBundlePrice * (sell.getCost() - buyBundle.getCost());
+ } else {
+ break;
+ }
+ }
+ }
+ }
- double gain = this.calculateGains();
- if (moneyInput == 0) {
- profitMap.put(id, 0.0);
+ if (gainsMap.containsKey(person)) {
+ gainsMap.put(person, gainsMap.get(person) + realizedGain);
} else {
- profitMap.put(id, gain / moneyInput);
+ gainsMap.put(person, realizedGain);
}
}
-
- } catch (SQLException throwables) {
- System.out.println("ERROR: SQl error in profit calculation");
+ //percent gain
+ if (gainsMap.containsKey(person) && moneyInMap.containsKey(person)) {
+ gainsMap.put(person, gainsMap.get(person) / moneyInMap.get(person));
+ } else {
+ gainsMap.put(person, 0.0);
+ }
+
+
}
- return profitMap;
+
+ return gainsMap;
}
public double getMoneyInput() {
diff --git a/src/test/java/edu/brown/cs/student/ProfitCalculationTest.java b/src/test/java/edu/brown/cs/student/ProfitCalculationTest.java
index 4ca1780..68f53fc 100644
--- a/src/test/java/edu/brown/cs/student/ProfitCalculationTest.java
+++ b/src/test/java/edu/brown/cs/student/ProfitCalculationTest.java
@@ -67,7 +67,7 @@ public class ProfitCalculationTest {
new Date(1618698807000l));
trade = profitCalculation.getHoldingsList();
assertTrue(trade.isEmpty());
- assertEquals(profitCalculation.calculateGains(), 0, 0.001);
+ assertEquals(profitCalculation.calculateGainsSingle(), 0, 0.001);
tearDown();
}
@@ -80,16 +80,18 @@ public class ProfitCalculationTest {
new ProfitCalculation(DatabaseQuerier.getConn(), "concurrentBS", new Date(1518010558000l),
new Date(1715629591000l));
- assertEquals(profitCalculation.getProfitMap().get(100), 1, .01);
+ Map<Integer, Double> map = profitCalculation.getProfitMap();
+
+ assertEquals(map.get(100), 1, .01);
//buys at multiple prices
profitCalculation =
new ProfitCalculation(DatabaseQuerier.getConn(), "mulitpleBuyPrices",
new Date(1518010558000l),
new Date(1715629591000l));
- assertEquals(profitCalculation.getProfitMap().get(101), 1, .01);
- assertEquals(profitCalculation.getMoneyInput(), 3750, .01);
+
assertEquals(profitCalculation.getHoldingsList().get(0).getRealizedGain(), 3750, 0.01);
+ assertEquals(profitCalculation.getMoneyInput(), 3750, .01);
//left over holdings
profitCalculation =
@@ -136,25 +138,8 @@ public class ProfitCalculationTest {
profitCalculation =
new ProfitCalculation(DatabaseQuerier.getConn(), "invalidTicker", new Date(1518010558000l),
new Date(1618698807000l));
- assertEquals(profitCalculation.getHoldingsList().get(0).getRealizedGain(), 0, .01);
- assertEquals(profitCalculation.getHoldingsList().get(0).getUnrealizedGain(), 0, .01);
- }
+ assertTrue(profitCalculation.getHoldingsList().isEmpty());
- @Test
- public void optimizationTest() {
- try {
- db = new DatabaseQuerier("data/trades.sqlite3");
- } catch (Exception e) {
- System.out.println("DBQuerier Test, couldn't connect to db???");
- }
-
- ProfitCalculation profitCalculation = new ProfitCalculation(DatabaseQuerier.getConn(), "invalidTicker", new Date(1618223864000l),
- new Date(1618483064000l));
-
- long startTime = System.currentTimeMillis();
- profitCalculation.getProfitMap();
- System.out.println("DATA ENDPOINT " + ((System.currentTimeMillis() - startTime) / 1000) + "seconds");
}
-
} \ No newline at end of file