From 38e0753473ae4779865f439b16dc3d19ddf1ce67 Mon Sep 17 00:00:00 2001 From: Michael Foiani Date: Fri, 9 Apr 2021 16:10:30 -0400 Subject: Added functionality that adds to the DB directly. Also, can handle multiple trades within a transaction now. --- .../brown/cs/student/term/parsing/Transaction.java | 159 +++++++++++++++++++++ .../cs/student/term/repl/commands/LoadCommand.java | 76 ++++++++++ .../edu/brown/cs/student/term/trade/Trade.java | 4 + src/test/java/edu/brown/cs/student/TradeTest.java | 93 ------------ .../java/edu/brown/cs/student/TransactionTest.java | 108 ++++++++++++++ .../java/edu/brown/cs/student/XmlParserTest.java | 4 +- 6 files changed, 349 insertions(+), 95 deletions(-) create mode 100644 src/main/java/edu/brown/cs/student/term/parsing/Transaction.java create mode 100644 src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java delete mode 100644 src/test/java/edu/brown/cs/student/TradeTest.java create mode 100644 src/test/java/edu/brown/cs/student/TransactionTest.java (limited to 'src') diff --git a/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java new file mode 100644 index 0000000..ae33b14 --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/parsing/Transaction.java @@ -0,0 +1,159 @@ +package edu.brown.cs.student.term.parsing; + +import edu.brown.cs.student.term.hub.Holder; +import edu.brown.cs.student.term.trade.Trade; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.ArrayList; +import java.util.List; + + +/** + * This class represents the transaction data from the xml file. + */ +public class Transaction { + private Document doc; + private final List trades; + private final String personName; + private final int id; + private final String ticker; + + /** + * Constructor that extracts the important info from the document. + * @param document The document parsed from the xml file. + */ + public Transaction(Document document) { + // TODO: add log comments + doc = document; + trades = new ArrayList<>(); + + personName = personName(); + id = id(); + ticker = ticker(); + + NodeList tradesAsNodes = document.getElementsByTagName("nonDerivativeTransaction"); + int numTrades = tradesAsNodes.getLength(); + for(int i = 0; i < numTrades; i++) { + NodeList tradeValues = getValueList(tradesAsNodes.item(0)); + + // This stages the params for the trade. + // TODO: update with real timestamp + double ts = getDate(tradeValues).hashCode(); + int isBuy = getIsBuy(tradeValues) ? 1 : 0; + int numShares = getNumShares(tradeValues); + // TODO: update id? unique for each holder? + Holder holder = new Holder(id, personName); + + Trade trade = new Trade(id, ticker, ts, isBuy, numShares, holder); + trades.add(trade); + } + + doc = null; + } + + /** + * Extracts the id of the transaction from the document. + * @return The id. + */ + private int id() { + // Id of transaction + NodeList idNode = doc.getElementsByTagName("rptOwnerCik"); + // TODO: add error parsing + return Integer.parseInt(idNode.item(0).getTextContent()); + } + + /** + * Extracts the person's name of the transaction from the document. + * @return The person's name. + */ + private String personName() { + // Name of person + NodeList nameNode = doc.getElementsByTagName("rptOwnerName"); + return nameNode.item(0).getTextContent(); + } + + /** + * Extracts the security ticker of the transaction from the document + * @return The ticker. + */ + private String ticker() { + // Ticker of security + NodeList idNode = doc.getElementsByTagName("issuerTradingSymbol"); + return idNode.item(0).getTextContent(); + } + + /** + * Extracts the trade data of one trade within a transaction. + * @param trade One trade from the transaction as a node. + * @return A nodelist with each element holding specific info of the trade. + */ + public NodeList getValueList(Node trade) { + // Data of trade in an array of values + assert trade.getNodeType() == Node.ELEMENT_NODE; + Element tradeElement = (Element) trade; + return tradeElement.getElementsByTagName("value"); + } + + /** + * Extracts the trade date from a trade node. + * @param values The value array representing the trade. + * @return The date in mm-dd-yyyy format as a string. + */ + public String getDate(NodeList values) { + return values.item(1).getTextContent(); + } + + /** + * Extracts the number of shares moved from the trade. + * @param values The value array representing the trade. + * @return The number of shares. + */ + public int getNumShares(NodeList values) { + return Integer.parseInt(values.item(2).getTextContent()); + } + + /** + * Extracts the price each share cost from the trade. + * @param values The value array representing the trade. + * @return The price of each share. + */ + public int getPriceShares(NodeList values) { + return Integer.parseInt(values.item(3).getTextContent()); + } + + /** + * Determines whether the shares in the trade were bought or sold. + * @param values The value array representing the trade. + * @return True if they were bought (acquired). False, if sold. + */ + public boolean getIsBuy(NodeList values) { + return values.item(4).getTextContent().equals("A"); + } + + /** + * Returns the list of trades that occurred within the transaction. + * @return A list of trade objects. + */ + public List getTrades() { + return trades; + } + + /** + * Accessor method that returns the id of the transaction. + * @return The id. + */ + public int getId() { + return id; + } + + /** + * Accessor method that returns the person's name who did the transaction. + * @return The name of whom did the transaction. + */ + public String getPersonName() { + return personName; + } +} diff --git a/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java b/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java new file mode 100644 index 0000000..a20c23b --- /dev/null +++ b/src/main/java/edu/brown/cs/student/term/repl/commands/LoadCommand.java @@ -0,0 +1,76 @@ +package edu.brown.cs.student.term.repl.commands; + +import edu.brown.cs.student.term.DatabaseQuerier; +import edu.brown.cs.student.term.parsing.Transaction; +import edu.brown.cs.student.term.parsing.UrlXmlParser; +import edu.brown.cs.student.term.repl.Command; +import edu.brown.cs.student.term.trade.Trade; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +public class LoadCommand implements Command { + private final static Connection CONN = DatabaseQuerier.getConn(); + private final static UrlXmlParser URL_XML_PARSER = new UrlXmlParser(); + + /** + * Main run method for every command. + * + * @param args arguments for the command + */ + @Override + public String run(String[] args) { + // TODO: add log comments + System.err.println("LOG: Entered .run() of " + getClass()); + // TODO: call to api for urls to call through the urlxmlparser from reagan + String[] urls = new String[1]; + for (String url : urls) { + try { + System.err.println("LOG: Calling loadTransactionIntoDB() in " + getClass()); + loadTransactionIntoDB(url); + } catch (SQLException throwables) { + System.err.println("INTERNAL: SQLException in .run() of " + getClass()); + //throwables.printStackTrace(); + } + } + return "Loaded?"; + } + + /** + * Loads a whole transaction, which can have multiple trades, into the DB. + * @param url The url to the public xml file. + * @throws SQLException If the prep statement fails or db doesn't exist, throws. + */ + private static void loadTransactionIntoDB(String url) throws SQLException { + System.err.println("LOG: Parsing XML into transaction in loadTransactionIntoDB(). URL: " + url); + Transaction helper = new Transaction(URL_XML_PARSER.parse(url)); + for(Trade trade : helper.getTrades()) { + System.err.println("LOG: Loading a trade into DB -> " + trade); + loadTradeIntoDB(trade); + System.err.println("LOG: Loaded that trade."); + } + } + + /** + * Loads one trade into the DB. + * @param trade The trade to be loaded. + * @throws SQLException If the prep statement fails or db doesn't exist, throws. + */ + private static void loadTradeIntoDB(Trade trade) throws SQLException { + PreparedStatement prep = CONN.prepareStatement( + "INSERT into trades (stock_name, holder_name, trade_timestamp, is_buy, " + + "number_of_shares, holder_id) " + + "VALUES (?, ?, ?, ?, ?, ?)"); + + prep.setString(1, trade.getStock()); + prep.setString(2, trade.getHolder().getName()); + // TODO: update with timestamp @julia + prep.setDouble(3, trade.getTimestamp()); + prep.setInt(4, trade.isBuy() ? 1 : 0); + prep.setInt(5, trade.getNumShares()); + prep.setInt(6, trade.getHolder().getId()); + + prep.execute(); + } +} \ No newline at end of file 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 index 13f7ae1..95770e4 100644 --- a/src/main/java/edu/brown/cs/student/term/trade/Trade.java +++ b/src/main/java/edu/brown/cs/student/term/trade/Trade.java @@ -44,6 +44,10 @@ public class Trade { return holder; } + public int getNumShares() { + return numShares; + } + @Override public String toString() { return "Trade{" + diff --git a/src/test/java/edu/brown/cs/student/TradeTest.java b/src/test/java/edu/brown/cs/student/TradeTest.java deleted file mode 100644 index 90d656d..0000000 --- a/src/test/java/edu/brown/cs/student/TradeTest.java +++ /dev/null @@ -1,93 +0,0 @@ -package edu.brown.cs.student; - -import edu.brown.cs.student.term.parsing.LocalXmlParser; -import edu.brown.cs.student.term.parsing.XmlParser; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -import static org.junit.Assert.*; - -public class TradeTest { - private XmlParser _xmlParser; - private Document _doc; - - @Before - public void setUp() { - _xmlParser = new LocalXmlParser(); - } - - @After - public void tearDown() { - _xmlParser = null; - } - - @Test - public void personDataParse(){ - setUp(); - Document doc = _xmlParser.parse("data/xml_trade_test.xml"); - assertNotNull(doc); - - // Id of person - NodeList idNode = doc.getElementsByTagName("rptOwnerCik"); - assertEquals(idNode.getLength(), 1); - String id = idNode.item(0).getTextContent(); - assertEquals(id, "0001561844"); - - // Name of person - NodeList nameNode = doc.getElementsByTagName("rptOwnerName"); - assertEquals(nameNode.getLength(), 1); - String name = nameNode.item(0).getTextContent(); - assertEquals(name, "Levental Igor"); - - tearDown(); - } - - @Test - public void tradeDataParse(){ - setUp(); - Document doc = _xmlParser.parse("data/xml_trade_test.xml"); - assertNotEquals(doc, null); - - // Data of trade in an array of values - NodeList trade = doc.getElementsByTagName("nonDerivativeTransaction"); - assertEquals(trade.item(0).getNodeType(), Node.ELEMENT_NODE); - Element tradeElement = (Element) trade.item(0); - NodeList values = tradeElement.getElementsByTagName("value"); - assertEquals(values.getLength(), 7); - - // type of stock - String stockType = values.item(0).getTextContent(); - assertEquals(stockType, "Common Stock"); - - // date - String date = values.item(1).getTextContent(); - assertEquals(date, "2021-03-31"); - - // # of shares - String numShares = values.item(2).getTextContent(); - assertEquals(numShares, "8236"); - - // price of shares - String priceShares = values.item(3).getTextContent(); - assertEquals(priceShares, "0"); - - // transaction type (A for acquire) - String transactionType = values.item(4).getTextContent(); - assertEquals(transactionType, "A"); - - // shared after transaction - String sharesAfter = values.item(5).getTextContent(); - assertEquals(sharesAfter, "10799"); - - // ownership type - String ownershipType = values.item(6).getTextContent(); - assertEquals(ownershipType, "D"); - - tearDown(); - } -} diff --git a/src/test/java/edu/brown/cs/student/TransactionTest.java b/src/test/java/edu/brown/cs/student/TransactionTest.java new file mode 100644 index 0000000..a5e2987 --- /dev/null +++ b/src/test/java/edu/brown/cs/student/TransactionTest.java @@ -0,0 +1,108 @@ +package edu.brown.cs.student; + +import edu.brown.cs.student.term.parsing.LocalXmlParser; +import edu.brown.cs.student.term.parsing.XmlParser; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import static org.junit.Assert.*; + +public class TransactionTest { + private XmlParser _xmlParser; + private Document _doc; + + @Before + public void setUp() { + _xmlParser = new LocalXmlParser(); + } + + @After + public void tearDown() { + _xmlParser = null; + } + + @Test + public void personDataParse(){ + setUp(); + Document doc = _xmlParser.parse("data/xml_single_trade_test.xml"); + assertNotNull(doc); + + // Id of person + NodeList idNode = doc.getElementsByTagName("rptOwnerCik"); + assertEquals(idNode.getLength(), 1); + String id = idNode.item(0).getTextContent(); + assertEquals(id, "0001561844"); + + // Name of person + NodeList nameNode = doc.getElementsByTagName("rptOwnerName"); + assertEquals(nameNode.getLength(), 1); + String name = nameNode.item(0).getTextContent(); + assertEquals(name, "Levental Igor"); + + tearDown(); + } + + @Test + public void securityDataParse(){ + setUp(); + Document doc = _xmlParser.parse("data/xml_single_trade_test.xml"); + assertNotNull(doc); + + // Ticker of security + NodeList idNode = doc.getElementsByTagName("issuerTradingSymbol"); + assertEquals(idNode.getLength(), 1); + String id = idNode.item(0).getTextContent(); + assertEquals(id, "GATO"); + + tearDown(); + } + + @Test + public void tradeDataParse(){ + setUp(); + Document doc = _xmlParser.parse("data/xml_single_trade_test.xml"); + assertNotEquals(doc, null); + + // Data of trade in an array of values + NodeList trade = doc.getElementsByTagName("nonDerivativeTransaction"); + assertEquals(trade.item(0).getNodeType(), Node.ELEMENT_NODE); + Element tradeElement = (Element) trade.item(0); + NodeList values = tradeElement.getElementsByTagName("value"); + assertEquals(values.getLength(), 7); + + // type of stock + String stockType = values.item(0).getTextContent(); + assertEquals(stockType, "Common Stock"); + + // date + String date = values.item(1).getTextContent(); + assertEquals(date, "2021-03-31"); + + // # of shares + String numShares = values.item(2).getTextContent(); + assertEquals(numShares, "8236"); + + // price of shares + String priceShares = values.item(3).getTextContent(); + assertEquals(priceShares, "0"); + + // transaction type (A for acquire) + String transactionType = values.item(4).getTextContent(); + assertEquals(transactionType, "A"); + + // shared after transaction + String sharesAfter = values.item(5).getTextContent(); + assertEquals(sharesAfter, "10799"); + + // ownership type + String ownershipType = values.item(6).getTextContent(); + assertEquals(ownershipType, "D"); + + tearDown(); + } +} diff --git a/src/test/java/edu/brown/cs/student/XmlParserTest.java b/src/test/java/edu/brown/cs/student/XmlParserTest.java index d3bc4ff..5f5b7a8 100644 --- a/src/test/java/edu/brown/cs/student/XmlParserTest.java +++ b/src/test/java/edu/brown/cs/student/XmlParserTest.java @@ -34,7 +34,7 @@ public class XmlParserTest { @Test public void parsesLocal(){ setUp(); - Document doc = _localXmlParser.parse("data/xml_trade_test.xml"); + Document doc = _localXmlParser.parse("data/xml_single_trade_test.xml"); assertNotNull(doc); // Id of person @@ -64,7 +64,7 @@ public class XmlParserTest { @Test public void urlSameAsLocal(){ setUp(); - Document local = _localXmlParser.parse("data/xml_trade_test.xml"); + Document local = _localXmlParser.parse("data/xml_single_trade_test.xml"); Document url = _urlXmlParser.parse("https://www.sec.gov/Archives/edgar/data/1517006/000110465921046242/tm2112036-4_4seq1.xml"); -- cgit v1.2.3-70-g09d2