diff options
Diffstat (limited to 'src')
12 files changed, 582 insertions, 24 deletions
diff --git a/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java b/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java new file mode 100644 index 0000000..1bb49c7 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/DatabaseQuerier.java @@ -0,0 +1,92 @@ +package edu.brown.cs.student.term; +import edu.brown.cs.student.term.hub.Holder; +import edu.brown.cs.student.term.trade.Trade; + +import java.sql.*; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +public class DatabaseQuerier{ + private static Connection conn = null; + + //TODO: Be prepared to overhaul this to account for IDs + /** + * Makes a database querier for a particular sqlite database + * @param filename - String representing filepath of database + * @throws SQLException + * @throws ClassNotFoundException + */ + public DatabaseQuerier(String filename) throws SQLException, + ClassNotFoundException { + Class.forName("org.sqlite.JDBC"); + String urlToDB = "jdbc:sqlite:" + filename; + // AutoClosable TRY-WITH-RESOURCES ensures database connection will be closed when it is done + conn = DriverManager.getConnection(urlToDB); + } + + public static Connection getConn() { + return conn; + } + + /** + * Gets the names of all stocks traded between start and end ddate + * @param startDate - the start date + * @param endDate - the end date + * @return a list of stock names + * @throws SQLException + */ + public List<String> getRecentStocks(Instant startDate, Instant endDate) throws SQLException { + List<String> stocks = new ArrayList<>(); + + PreparedStatement prep = conn.prepareStatement( + "SELECT DISTINCT stock_name FROM trades WHERE trade_timestamp <= ? AND trade_timestamp >= ?"); + + prep.setLong(1, endDate.toEpochMilli()); + prep.setLong(2, startDate.toEpochMilli()); + ResultSet rs = prep.executeQuery(); + + while(rs.next()){ + stocks.add(rs.getString(1)); + } + return stocks; + } + + //TODO: Fill these in + public List<List<Trade>> getAllTradesByStock(Instant startDate, Instant endDate) throws SQLException { + List<List<Trade>> allTrades = new ArrayList<>(); + List<String> stocks = getRecentStocks(startDate, endDate); + //get the buys and sells for each stock + for(String stock: stocks){ + allTrades.add(getTradeByStock(stock, 1, startDate, endDate)); + allTrades.add(getTradeByStock(stock, 0, startDate, endDate)); + } + return allTrades; + } + + public List<Trade> getTradeByStock(String stock, int isBuy, Instant startDate, Instant endDate) throws SQLException{ + List<Trade> trades = new ArrayList<>(); + + PreparedStatement prep = conn.prepareStatement( + "SELECT * FROM trades WHERE (stock_name = ? AND is_buy = ?) " + + "AND (trade_timestamp <= ? AND trade_timestamp >= ?) ORDER BY trade_timestamp"); + + prep.setString(1, stock); + prep.setInt(2, isBuy); + prep.setLong(3, endDate.toEpochMilli()); + prep.setLong(4, startDate.toEpochMilli()); + ResultSet rs = prep.executeQuery(); + + while(rs.next()){ + trades.add(new Trade(rs.getInt(1), rs.getString(2), + rs.getLong(4), rs.getInt(5), + rs.getInt(6), new Holder(rs.getInt(7), rs.getString(3)))); + } + + return trades; + } + + + + +} 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 3124ea4..bd9e096 100644 --- a/src/main/java/edu/brown/cs/student/term/Main.java +++ b/src/main/java/edu/brown/cs/student/term/Main.java @@ -2,6 +2,7 @@ package edu.brown.cs.student.term; import edu.brown.cs.student.term.repl.Command; import edu.brown.cs.student.term.repl.REPL; +import edu.brown.cs.student.term.repl.commands.SetupCommand; import joptsimple.OptionParser; import joptsimple.OptionSet; @@ -47,23 +48,11 @@ public final class Main { //runSparkServer((int) options.valueOf("port")); } - - ProfitCalculation person = new ProfitCalculation(null, "Sophie", new Date(1515629591000L), new Date(1715507898000L)); - try { - person.setConnection("./data/mock_tradeClarks.sqlite3"); - } catch(Exception e) { - e.printStackTrace(); - } - - person.calculateGains(); - person.compareToNASDAQ(); - -// HashMap<String, Command> commandHashMap = new HashMap<>(); -// /** add commands to map here! */ -// REPL repl = new REPL(commandHashMap); -// repl.runREPL(); - - // TODO: Process commands in a REPL + HashMap<String, Command> commandHashMap = new HashMap<>(); + commandHashMap.put("setup", new SetupCommand()); + /** add commands to map here! */ + REPL repl = new REPL(commandHashMap); + repl.runREPL(); } diff --git a/src/main/java/edu/brown/cs/student/term/hub/Holder.java b/src/main/java/edu/brown/cs/student/term/hub/Holder.java new file mode 100644 index 0000000..21c0aea --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/hub/Holder.java @@ -0,0 +1,42 @@ +package edu.brown.cs.student.term.hub; + +import java.util.Objects; + +public class Holder { + private int id; + private String name; + + public Holder(int id, String name){ + this.id = id; + this.name = name; + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + @Override + public String toString() { + return "Holder{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Holder holder = (Holder) o; + return id == holder.id && Objects.equals(name, holder.name); + } + + @Override + public int hashCode() { + return Objects.hash(id, name); + } +} diff --git a/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java b/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java new file mode 100644 index 0000000..4c382ec --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/hub/HubSearch.java @@ -0,0 +1,45 @@ +package edu.brown.cs.student.term.hub; + +public class HubSearch { + + /* + def pageRank(pList: List[Page]): mutable.HashMap[Int, Double] = { + val n = pList.length + val weights = new Array[Double](n) + val r = new Array[Double](n) + val rPrime = Array.fill[Double](n)(1.0 / n) + + while (!distance(r, rPrime)) { + Array.copy(rPrime, 0, r, 0, n) + for (j <- 0 to n - 1) { + rPrime(j) = 0 + for (k <- 0 to n - 1) { + val wjk = getWeight(pList(j), pList(k), n) + rPrime(j) = (rPrime(j) + (wjk * r(k))) + } + } + } + + val pageRank = new mutable.HashMap[Int, Double]() + + for (i <- 0 to rPrime.length - 1) { + pageRank.put(pList(i).getID, rPrime(i)) + } + pageRank + } + + def getWeight(j: Page, k: Page, n: Int): Double = { + + val links = k.getLinks + val nk = links.size + + if (links.contains(j.getTitle.toLowerCase)) { + ((0.15 / n) + ((1 - 0.15) * (1.0 / nk))) + } else if (nk == 0) { + ((0.15 / n) + ((1 - 0.15) * (1.0 / n))) + } else { + (0.15 / n) + } + } + */ +} diff --git a/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java b/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java new file mode 100644 index 0000000..f4ec0a7 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/hub/LinkMapper.java @@ -0,0 +1,94 @@ +package edu.brown.cs.student.term.hub; + +import edu.brown.cs.student.term.DatabaseQuerier; +import edu.brown.cs.student.term.repl.commands.SetupCommand; +import edu.brown.cs.student.term.trade.Trade; + +import java.sql.SQLException; +import java.time.Instant; +import java.util.*; + +public class LinkMapper { + + //not strictly necessary but may be nice to maintain + private List<List<Trade>> allTrades = new ArrayList<>(); + private Map<Holder, List<Trade>> personToTradesMap = new HashMap<>(); + private Map<Holder, List<Holder>> personToFollowers = new HashMap<>(); + private DatabaseQuerier databaseQuerier; + + public LinkMapper(DatabaseQuerier db){ + this.databaseQuerier = db; + } + + /** + * Returns the person => trades map as is, does not update it + * @return person to trades map + */ + public Map<Holder, List<Trade>> getPersonToTradesMap() { + return personToTradesMap; + } + + /** + * Returns the person => follower map as is, does not update it + * @return person to follower map + */ + public Map<Holder, List<Holder>> getPersonToFollowers() { + return personToFollowers; + } + + /** + * The links between people and their followers who made the same trade + * in the same time period + * @return the newly updated link map + */ + public Map<Holder, List<Holder>> makeFollowerLinks(Instant start, Instant end){ + if(databaseQuerier != null){ + try{ + List<List<Trade>> allTrades = databaseQuerier.getAllTradesByStock(start, end); + //reset the map to be blank + personToFollowers = new HashMap<>(); + + for(List<Trade> tradeList : allTrades){ + convertTradeListToFollowerMap(tradeList); + } + + //System.out.println(personToFollowers.toString()); + System.out.println("num people in map: " + personToFollowers.size()); + + } catch(SQLException e) { + System.out.println("ERROR: SQL Error while retrieving trade list"); + } + } else { + System.out.println("ERROR: No database loaded in yet"); + } + + return personToFollowers; + } + + private void convertTradeListToFollowerMap(List<Trade> tradeList){ + List<Holder> holderList = new ArrayList<>(); + + //gets in order list of people + for (Trade trade : tradeList) { + holderList.add(trade.getHolder()); + } + + Set<Holder> followers = new HashSet<>(holderList); + Set<Holder> encountered = new HashSet<>(); + + for(Holder current: holderList){ + //want to check if we've already gotten followers for this trade for this holder + if(!encountered.contains(current)){ + encountered.add(current); + followers.remove(current); + if(personToFollowers.containsKey(current)){ + //TODO: this probably makes it O(n^2), might want to optimize later + personToFollowers.get(current).addAll(followers); + } else { + List<Holder> currentFollowers = new ArrayList<>(followers); + personToFollowers.put(current, currentFollowers); + } + } + } + } +} 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 new file mode 100644 index 0000000..a1196d8 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/hub/SuspicionRanker.java @@ -0,0 +1,4 @@ +package edu.brown.cs.student.term.hub; + +public class SuspicionRanker { +} diff --git a/src/main/java/edu/brown/cs/student/term/repl/Command.java b/src/main/java/edu/brown/cs/student/term/repl/Command.java index f8b0b04..056c7df 100644 --- a/src/main/java/edu/brown/cs/student/term/repl/Command.java +++ b/src/main/java/edu/brown/cs/student/term/repl/Command.java @@ -10,10 +10,4 @@ public interface Command { * @param args arguments for the command */ String run(String[] args); - - /** - * Used to print command output to GUI. - * @return String representing neighbors found by NeighborsCommand and RadiusCommand commands - */ - String toString(); } diff --git a/src/main/java/edu/brown/cs/student/term/repl/REPL.java b/src/main/java/edu/brown/cs/student/term/repl/REPL.java index 0be7e3f..a1d5c23 100644 --- a/src/main/java/edu/brown/cs/student/term/repl/REPL.java +++ b/src/main/java/edu/brown/cs/student/term/repl/REPL.java @@ -1,5 +1,4 @@ package edu.brown.cs.student.term.repl; -import edu.brown.cs.student.term.repl.Command; import java.io.BufferedReader; import java.io.IOException; diff --git a/src/main/java/edu/brown/cs/student/term/repl/commands/SetupCommand.java b/src/main/java/edu/brown/cs/student/term/repl/commands/SetupCommand.java new file mode 100644 index 0000000..e19117c --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/repl/commands/SetupCommand.java @@ -0,0 +1,71 @@ +package edu.brown.cs.student.term.repl.commands; + +import edu.brown.cs.student.term.DatabaseQuerier; +import edu.brown.cs.student.term.repl.Command; +import edu.brown.cs.student.term.trade.Trade; + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.List; + +public class SetupCommand implements Command { + + private String error; + private static DatabaseQuerier dq; + + @Override + /** + * Sets up connection to the database + * Returns an empty string if no errors, non empty with error message otherwise + */ + public String run(String[] args) { + error = ""; + if(args.length == 1){ + try{ + dq = new DatabaseQuerier(args[0]); + } catch (Exception e) { + error = "ERROR: Could not connect to database. Ensure this is a valid database."; + System.out.println(error); + return error; + } + } else { + error = "ERROR: Incorrect number of arguments for setup command"; + System.out.println(error); + return error; + } + + try{ + /** Just for testing purposes **/ + //12 am on 3/12 in UTC + Instant start = Instant.parse("2021-03-12T05:00:00.00Z"); + //12 am on 3/27 in UTC + Instant end = Instant.parse("2021-03-27T05:00:00.00Z"); + + System.out.println(end.toEpochMilli()); + System.out.println(start.getEpochSecond()); + + ZonedDateTime zdt = ZonedDateTime.ofInstant(start, ZoneId.of("America/New_York")); + System.out.println(zdt.toString()); + List<List<Trade>> trades = dq.getAllTradesByStock(start, end); + + int sum = 0; + for(List<Trade> t: trades){ + System.out.println(t); + sum += t.size(); + } + + System.out.println("num of trades: " + sum); + + + } catch(Exception e){ + e.printStackTrace(); + } + + return error; + } + + public static DatabaseQuerier getDq() { + return dq; + } +} diff --git a/src/main/java/edu/brown/cs/student/term/trade/Trade.java b/src/main/java/edu/brown/cs/student/term/trade/Trade.java new file mode 100644 index 0000000..13f7ae1 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/trade/Trade.java @@ -0,0 +1,58 @@ +package edu.brown.cs.student.term.trade; + +import edu.brown.cs.student.term.hub.Holder; + +public class Trade { + + private int id; + private String stock; + private int isBuy; + private double timestamp; + private Holder holder; + private int numShares; + + public Trade(int id, String stockName, double ts, int buy, int shares, Holder holder){ + this.id = id; + this.stock = stockName; + this.isBuy = buy; + this.timestamp = ts; + this.holder = holder; + this.numShares = shares; + } + + public int getId() { + return id; + } + + public boolean isBuy() { + if(isBuy == 1){ + return true; + } else { + return false; + } + } + + public double getTimestamp() { + return timestamp; + } + + public String getStock() { + return stock; + } + + public Holder getHolder() { + return holder; + } + + @Override + public String toString() { + return "Trade{" + + "id=" + id + + ", stock='" + stock + '\'' + + ", isBuy=" + isBuy + + ", timestamp=" + timestamp + + ", holder='" + holder + '\'' + + ", numShares=" + numShares + + '}'; + } +} diff --git a/src/test/java/edu/brown/cs/student/DBQuerierTest.java b/src/test/java/edu/brown/cs/student/DBQuerierTest.java new file mode 100644 index 0000000..d813969 --- /dev/null +++ b/src/test/java/edu/brown/cs/student/DBQuerierTest.java @@ -0,0 +1,122 @@ +package edu.brown.cs.student; + +import java.io.PrintStream; +import java.sql.SQLException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.List; + +import edu.brown.cs.student.term.DatabaseQuerier; +import edu.brown.cs.student.term.repl.commands.SetupCommand; +import edu.brown.cs.student.term.trade.Trade; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +//TODO: Write more tests for methods besides stock by name +public class DBQuerierTest { + + /** these should span the entire mock dataset */ + //12 am on 3/11 in UTC + private Instant start = Instant.parse("2021-03-11T05:00:00.00Z"); + //12 am on 3/28 in UTC + private Instant end = Instant.parse("2021-03-28T05:00:00.00Z"); + + private DatabaseQuerier db; + + @Before + public void setUp() { + try{ + db = new DatabaseQuerier("data/mock_trades.sqlite3"); + } catch(Exception e){ + System.out.println("DBQuerier Test, couldn't connect to db???"); + } + } + + /* + * try{ + + } catch(Exception e) { + System.out.println("Error in test"); + }*/ + + @After + public void tearDown() { + db = null; + } + + @Test + public void testNonExistentStock(){ + setUp(); + try{ + List<Trade> fakeStockList = db.getTradeByStock("NONO", 1, start, end); + assertTrue(fakeStockList.isEmpty()); + + } catch(Exception e) { + System.out.println("Error in test"); + } + tearDown(); + } + + @Test + public void testFlippedDates(){ + setUp(); + try{ + List<Trade> gmeBadDatesList = db.getTradeByStock("GME", 1, end, start); + assertTrue(gmeBadDatesList.isEmpty()); + + } catch(Exception e) { + System.out.println("Error in test"); + } + tearDown(); + } + + @Test + public void testTradeByStockNameBuy(){ + setUp(); + try{ + List<Trade> gmeBuyList = db.getTradeByStock("GME", 1, start, end); + System.out.println(gmeBuyList); + assertEquals(gmeBuyList.size(), 6); + assertEquals(gmeBuyList.get(0).getId(), 482); + assertEquals(gmeBuyList.get(3).getId(), 149); + assertEquals(gmeBuyList.get(4).getId(), 275); + assertEquals(gmeBuyList.get(5).getId(), 30); + + + List<Trade> teslaBuyList = db.getTradeByStock("TSLA", 1, start, end); + assertEquals(teslaBuyList.size(), 16); + assertEquals(teslaBuyList.get(0).getId(), 328); + assertEquals(teslaBuyList.get(7).getId(), 241); + assertEquals(teslaBuyList.get(15).getId(), 774); + + } catch(Exception e) { + System.out.println("Error in testTradeByStockName"); + } + + tearDown(); + } + + @Test + public void testTradeByNameOrdering(){ + setUp(); + + try{ + List<Trade> gmeSellList = db.getTradeByStock("GME", 0, start, end); + for(int i = 1; i < gmeSellList.size(); i++){ + assertTrue(gmeSellList.get(i-1).getTimestamp() < gmeSellList.get(i).getTimestamp()); + } + + List<Trade> amznBuyList = db.getTradeByStock("AMZN", 1, start, end); + for(int i = 1; i < amznBuyList.size(); i++){ + assertTrue(amznBuyList.get(i-1).getTimestamp() < amznBuyList.get(i).getTimestamp()); + } + + } catch(Exception e) { + System.out.println("Error in test"); + } + tearDown(); + } +} diff --git a/src/test/java/edu/brown/cs/student/LinkMapperTest.java b/src/test/java/edu/brown/cs/student/LinkMapperTest.java new file mode 100644 index 0000000..9b46d5e --- /dev/null +++ b/src/test/java/edu/brown/cs/student/LinkMapperTest.java @@ -0,0 +1,48 @@ +package edu.brown.cs.student; + +import edu.brown.cs.student.term.DatabaseQuerier; +import edu.brown.cs.student.term.hub.LinkMapper; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.time.Instant; + +public class LinkMapperTest { + + /** these should span the entire mock dataset */ + //12 am on 3/11 in UTC + private Instant start = Instant.parse("2021-03-11T05:00:00.00Z"); + //12 am on 3/28 in UTC + private Instant end = Instant.parse("2021-03-28T05:00:00.00Z"); + + private DatabaseQuerier db; + + @Before + public void setUp() { + try{ + db = new DatabaseQuerier("data/mock_trades.sqlite3"); + } catch(Exception e){ + System.out.println("DBQuerier Test, couldn't connect to db???"); + } + } + + /* + * try{ + + } catch(Exception e) { + System.out.println("Error in test"); + }*/ + + @After + public void tearDown() { + db = null; + } + + @Test + public void testMapper(){ + setUp(); + LinkMapper lm = new LinkMapper(db); + lm.makeFollowerLinks(start, end); + } +} |