/* Copyright (c) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package sample.finance; import com.google.gdata.client.finance.FinanceService; import com.google.gdata.client.finance.FinanceUtilities; import com.google.gdata.data.BaseEntry; import com.google.gdata.data.BaseFeed; import com.google.gdata.data.Link; import com.google.gdata.data.extensions.Money; import com.google.gdata.data.finance.PortfolioData; import com.google.gdata.data.finance.PortfolioEntry; import com.google.gdata.data.finance.PortfolioFeed; import com.google.gdata.data.finance.PositionData; import com.google.gdata.data.finance.PositionEntry; import com.google.gdata.data.finance.PositionFeed; import com.google.gdata.data.finance.TransactionData; import com.google.gdata.data.finance.TransactionEntry; import com.google.gdata.data.finance.TransactionFeed; import com.google.gdata.util.AuthenticationException; import com.google.gdata.util.ServiceException; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import java.util.Scanner; /** * Demonstrates interactions with Google Finance Data API's portfolio feeds * using the Java client library: * * <ul> * <li>Retrieve all of the user's portfolios</li> * <li>Retrieve a single user portfolio</li> * <li>Create a new portfolio</li> * <li>Rename an existing portfolio</li> * <li>Delete an existing portfolio</li> * <li>Retrieve all of the positions belonging to a user portfolio</li> * <li>Retrieve a single position belonging to a user portfolio</li> * <li>Create a new position</li> * <li>Delete an existing position</li> * <li>Retrieve all of the transactions belonging to a user position</li> * <li>Retrieve a single transaction belonging to a user position</li> * <li>Create a new transaction</li> * <li>Update an existing transaction</li> * <li>Delete an existing transaction</li> * </ul> */ public class FinancePortfoliosClient { private enum MainCommands { PORTFOLIOS, POSITIONS, TRANSACTIONS, HELP, QUIT } private enum PortfolioCommands { QUERY_FEED, QUERY_ENTRY, CREATE, UPDATE, DELETE, HELP, BACK, POSITIONS, QUIT } private enum PositionCommands { QUERY_FEED, QUERY_ENTRY, CREATE, DELETE, HELP, BACK, TRANSACTIONS, QUIT } private enum TransactionCommands { QUERY_FEED, QUERY_ENTRY, CREATE, UPDATE, DELETE, HELP, BACK, QUIT } // User's email and password: private static String userEmail = ""; private static String userPassword = ""; // Base URL for GData requests // GData Server is supplied as command-line argument and // appended with /finance/feeds/default private static String server = "http://finance.google.com"; private static String basePath = "/finance/feeds/"; private static String baseUrl = server + basePath + "default"; // Feed and Entry URI suffixes: private static final String PORTFOLIO_FEED_URL_SUFFIX = "/portfolios"; private static final String POSITION_FEED_URL_SUFFIX = "/positions"; private static final String TRANSACTION_FEED_URL_SUFFIX = "/transactions"; /** * Portfolio ID, Ticker, and Transaction ID are components of the * heirarchical feed URL: * e.g. The Portfolio Feed * http://finance.google.com/finance/feeds/default/portfolios * e.g. A Portfolio Entry * http://finance.google.com/finance/feeds/default/portfolios/<pid> * e.g. A Position Feed * http://finance.google.com/finance/feeds/default/portfolios/<pid> * /positions * e.g. A Position Entry * http://finance.google.com/finance/feeds/default/portfolios/<pid> * /positions/<ticker> * e.g. A Transaction Feed * http://finance.google.com/finance/feeds/default/portfolios/<pid> * /positions/<ticker>/transactions * e.g. A Transaction Entry * http://finance.google.com/finance/feeds/default/portfolios/<pid> * /positions/<ticker>/transactions/<tid> * (where pid (portfolioIdProperty) and tid (transactionIdProperty) are * 1, 2, 3, ... and a ticker is of the form NASDAQ:GOOG) */ private static String portfolioIdProperty; private static String tickerProperty; private static String transactionIdProperty; /** * Processes commands entered at the main menu. * * @param cmd user entered command * @return type of command */ private static MainCommands processMainMenuCommand(String cmd) { if (cmd.equals("portfolios") || cmd.equals("pr")) { return FinancePortfoliosClient.MainCommands.PORTFOLIOS; } else if (cmd.equals("positions") || cmd.equals("ps")) { return FinancePortfoliosClient.MainCommands.POSITIONS; } else if (cmd.equals("transactions") || cmd.equals("t")) { return FinancePortfoliosClient.MainCommands.TRANSACTIONS; } else if (cmd.equals("quit") || cmd.equals("q")) { return FinancePortfoliosClient.MainCommands.QUIT; } else { return FinancePortfoliosClient.MainCommands.HELP; } } /** * Processes commands entered at the portfolio menu. * * @param cmd user entered command * @return type of command */ private static PortfolioCommands processPortfolioMenuCommand(String cmd) { if (cmd.equals("list") || cmd.equals("l")) { return FinancePortfoliosClient.PortfolioCommands.QUERY_FEED; } else if (cmd.equals("show") || cmd.equals("s")) { return FinancePortfoliosClient.PortfolioCommands.QUERY_ENTRY; } else if (cmd.equals("create") || cmd.equals("c")) { return FinancePortfoliosClient.PortfolioCommands.CREATE; } else if (cmd.equals("update") || cmd.equals("u")) { return FinancePortfoliosClient.PortfolioCommands.UPDATE; } else if (cmd.equals("delete") || cmd.equals("d")) { return FinancePortfoliosClient.PortfolioCommands.DELETE; } else if (cmd.equals("back") || cmd.equals("b")) { return FinancePortfoliosClient.PortfolioCommands.BACK; } else if (cmd.equals("positions") || cmd.equals("p")) { return FinancePortfoliosClient.PortfolioCommands.POSITIONS; } else if (cmd.equals("quit") || cmd.equals("q")) { return FinancePortfoliosClient.PortfolioCommands.QUIT; } else { return FinancePortfoliosClient.PortfolioCommands.HELP; } } /** * Processes commands entered at the position menu. * * @param cmd user entered command * @return type of command */ private static PositionCommands processPositionMenuCommand(String cmd) { if (cmd.equals("list") || cmd.equals("l")) { return FinancePortfoliosClient.PositionCommands.QUERY_FEED; } else if (cmd.equals("show") || cmd.equals("s")) { return FinancePortfoliosClient.PositionCommands.QUERY_ENTRY; } else if (cmd.equals("back") || cmd.equals("b")) { return FinancePortfoliosClient.PositionCommands.BACK; } else if (cmd.equals("quit") || cmd.equals("q")) { return FinancePortfoliosClient.PositionCommands.QUIT; } else if (cmd.equals("transactions") || cmd.equals("t")) { return FinancePortfoliosClient.PositionCommands.TRANSACTIONS; } else { return FinancePortfoliosClient.PositionCommands.HELP; } } /** * Processes commands entered at the transaction menu. * * @param cmd user entered command * @return type of command */ private static TransactionCommands processTransactionMenuCommand(String cmd) { if (cmd.equals("list") || cmd.equals("l")) { return FinancePortfoliosClient.TransactionCommands.QUERY_FEED; } else if (cmd.equals("show") || cmd.equals("s")) { return FinancePortfoliosClient.TransactionCommands.QUERY_ENTRY; } else if (cmd.equals("create") || cmd.equals("c")) { return FinancePortfoliosClient.TransactionCommands.CREATE; } else if (cmd.equals("update") || cmd.equals("u")) { return FinancePortfoliosClient.TransactionCommands.UPDATE; } else if (cmd.equals("delete") || cmd.equals("d")) { return FinancePortfoliosClient.TransactionCommands.DELETE; } else if (cmd.equals("back") || cmd.equals("b")) { return FinancePortfoliosClient.TransactionCommands.BACK; } else if (cmd.equals("quit") || cmd.equals("q")) { return FinancePortfoliosClient.TransactionCommands.QUIT; } else { return FinancePortfoliosClient.TransactionCommands.HELP; } } /** * Portfolio menu. * * @param sc Scanner to read user input from the command line. * @throws IOException If there is a problem communicating with the server. * @throws ServiceException If the service is unable to handle the request. */ private static void portfolioMenu(FinanceService service, Scanner sc) throws IOException, ServiceException { printPortfolioMenuHelp(); while (true) { String requestUrl = baseUrl + PORTFOLIO_FEED_URL_SUFFIX; switch(processPortfolioMenuCommand(sc.nextLine().toLowerCase())) { case QUERY_FEED: System.out.print("Include returns in query response? (y/n) "); String includeReturns = sc.nextLine(); if (includeReturns.toLowerCase().equals("y") || includeReturns.toLowerCase().equals("yes")) { requestUrl += "?returns=true"; } else if (includeReturns.toLowerCase().equals("n") || includeReturns.toLowerCase().equals("no")) { requestUrl += "?returns=false"; } System.out.print("Inline positions in feed? (y/n) "); String inlinePositions = sc.nextLine(); if (inlinePositions.toLowerCase().equals("y") || inlinePositions.toLowerCase().equals("yes")) { requestUrl += "&positions=true"; } else if (inlinePositions.toLowerCase().equals("n") || inlinePositions.toLowerCase().equals("no")) { requestUrl += "&positions=false"; } queryPortfolioFeed(service, requestUrl); break; case QUERY_ENTRY: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); requestUrl += "/" + portfolioIdProperty; queryPortfolioEntry(service, requestUrl); break; case CREATE: System.out.println("Enter portfolio name"); String portfolioName = sc.nextLine(); System.out.println("Enter currency code"); String currencyCode = sc.nextLine(); PortfolioEntry entry = FinanceUtilities.makePortfolioEntry(portfolioName, currencyCode); insertPortfolioEntry(service, requestUrl, entry); break; case UPDATE: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); requestUrl += "/" + portfolioIdProperty; System.out.println("Enter new portfolio name"); portfolioName = sc.nextLine(); System.out.println("Enter new currency code"); currencyCode = sc.nextLine(); entry = FinanceUtilities.makePortfolioEntry(portfolioName, currencyCode); updatePortfolioEntry(service, requestUrl, entry); break; case DELETE: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); requestUrl += "/" + portfolioIdProperty; deletePortfolioEntry(service, requestUrl); break; case BACK: return; case POSITIONS: positionMenu(service, sc); break; case QUIT: System.exit(0); case HELP: printPortfolioMenuHelp(); break; default: printPortfolioMenuHelp(); } } } /** * Position menu. * * @param service authenticated client connection to a Finance GData service * @param sc Scanner to read user input from the command line. * @throws IOException If there is a problem communicating with the server. * @throws ServiceException If the service is unable to handle the request. */ private static void positionMenu(FinanceService service, Scanner sc) throws IOException, ServiceException { printPositionMenuHelp(); while (true) { String requestUrl = baseUrl + PORTFOLIO_FEED_URL_SUFFIX + "/"; switch(processPositionMenuCommand(sc.nextLine().toLowerCase())) { case QUERY_FEED: System.out.print("Enter portfolio ID: "); portfolioIdProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX; System.out.print("Include returns in query response? (y/n) "); String includeReturns = sc.nextLine(); if (includeReturns.toLowerCase().equals("y") || includeReturns.toLowerCase().equals("yes")) { requestUrl += "?returns=true"; } else if (includeReturns.toLowerCase().equals("n") || includeReturns.toLowerCase().equals("no")) { requestUrl += "?returns=false"; } System.out.print("Inline transactions in feed? (y/n) "); String inlinePositions = sc.nextLine(); if (inlinePositions.toLowerCase().equals("y") || inlinePositions.toLowerCase().equals("yes")) { requestUrl += "&transactions=true"; } else if (inlinePositions.toLowerCase().equals("n") || inlinePositions.toLowerCase().equals("no")) { requestUrl += "&transactions=false"; } queryPositionFeed(service, requestUrl); break; case QUERY_ENTRY: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<ticker>)"); tickerProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty; queryPositionEntry(service, requestUrl); break; case BACK: return; case TRANSACTIONS: transactionMenu(service, sc); break; case QUIT: System.exit(0); case HELP: printPositionMenuHelp(); break; default: printPositionMenuHelp(); } } } /** * Transaction menu. * * @param service authenticated client connection to a Finance GData service * @param sc Scanner to read user input from the command line. * @throws IOException If there is a problem communicating with the server. * @throws ServiceException If the service is unable to handle the request. */ private static void transactionMenu(FinanceService service, Scanner sc) throws IOException, ServiceException { printTransactionMenuHelp(); while (true) { String requestUrl = baseUrl + PORTFOLIO_FEED_URL_SUFFIX + "/"; switch(processTransactionMenuCommand(sc.nextLine().toLowerCase())) { case QUERY_FEED: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<symbol>)"); tickerProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty + TRANSACTION_FEED_URL_SUFFIX; queryTransactionFeed(service, requestUrl); break; case QUERY_ENTRY: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<ticker>)"); tickerProperty = sc.nextLine(); System.out.println("Enter transaction ID"); transactionIdProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty + TRANSACTION_FEED_URL_SUFFIX + "/" + transactionIdProperty; queryTransactionEntry(service, requestUrl); break; case CREATE: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<ticker>) "); tickerProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty + TRANSACTION_FEED_URL_SUFFIX; System.out.print("Enter transaction type (Buy, Sell, Sell Short, Buy to Cover): "); String type = sc.nextLine(); System.out.print("Enter transaction date (yyyy-mm-dd or blank): "); String date = sc.nextLine(); System.out.print("Enter number of shares (optional, e.g. 100.0): "); String shares = sc.nextLine(); System.out.print("Enter price (optional, e.g. 141.14): "); String price = sc.nextLine(); System.out.print("Enter commission (optional, e.g. 20.0): "); String commission = sc.nextLine(); System.out.print("Enter currency (optional, e.g. USD, EUR, JPY): "); String currency = sc.nextLine(); System.out.print("Enter any notes: "); String notes = sc.nextLine(); TransactionEntry entry = FinanceUtilities.makeTransactionEntry( type, date, shares, price, commission, currency, notes); insertTransactionEntry(service, requestUrl, entry); break; case UPDATE: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<ticker>) "); tickerProperty = sc.nextLine(); System.out.println("Enter transaction ID"); transactionIdProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty + TRANSACTION_FEED_URL_SUFFIX + "/" + transactionIdProperty; System.out.print("Enter transaction type (Buy, Sell, Sell Short, Buy to Cover): "); type = sc.nextLine(); System.out.print("Enter transaction date (yyyy-mm-dd or blank): "); date = sc.nextLine(); System.out.print("Enter number of shares (optional, e.g. 100.0): "); shares = sc.nextLine(); System.out.print("Enter price (optional, e.g. 141.14): "); price = sc.nextLine(); System.out.print("Enter commission (optional, e.g. 20.0): "); commission = sc.nextLine(); System.out.print("Enter currency (optional, e.g. USD, EUR, JPY): "); currency = sc.nextLine(); System.out.print("Enter any notes: "); notes = sc.nextLine(); entry = FinanceUtilities.makeTransactionEntry( type, date, shares, price, commission, currency, notes); updateTransactionEntry(service, requestUrl, entry); break; case DELETE: System.out.println("Enter portfolio ID"); portfolioIdProperty = sc.nextLine(); System.out.println("Enter ticker (<exchange>:<ticker>)"); tickerProperty = sc.nextLine(); System.out.println("Enter transaction ID"); transactionIdProperty = sc.nextLine(); requestUrl += portfolioIdProperty + POSITION_FEED_URL_SUFFIX + "/" + tickerProperty + TRANSACTION_FEED_URL_SUFFIX + "/" + transactionIdProperty; deleteTransactionEntry(service, requestUrl); break; case BACK: return; case QUIT: System.exit(0); case HELP: printTransactionMenuHelp(); break; default: printTransactionMenuHelp(); } } } /** * Prints the available commands at the main menu. */ private static void printMainMenuHelp() { System.out.println("<command> (<abbreviated command>) : <description>"); System.out.println("-------------------------------------------------"); System.out.println("portfolios (pr) : portfolio commands"); System.out.println("positions (ps) : position commands"); System.out.println("transactions (t) : transaction commands"); System.out.println("help (h) : help"); System.out.println("quit (q) : quit"); System.out.println(""); } /** * Prints the available commands at the portfolio menu. */ private static void printPortfolioMenuHelp() { System.out.println("<command> (<abbreviated command>) : <description>"); System.out.println("-------------------------------------------------"); System.out.println("list (l) : list portfolios"); System.out.println("show (s) : show portfolio"); System.out.println("create (c) : create new portfolio"); System.out.println("update (u) : update portfolio name or currency"); System.out.println("delete (d) : delete portfolio"); System.out.println("back (b) : go back to previous menu"); System.out.println("positions (p) : go to the positions menu"); System.out.println("help (h) : help"); System.out.println("quit (q) : quit"); System.out.println(""); } /** * Prints the available commands at the position menu. */ private static void printPositionMenuHelp() { System.out.println("<command> (<abbreviated command>) : <description>"); System.out.println("-------------------------------------------------"); System.out.println("list (l) : list positions"); System.out.println("show (s) : show position"); System.out.println("back (b) : go back to previous menu"); System.out.println("transactions (t) : go to the transactions menu"); System.out.println("help (h) : help"); System.out.println("quit (q) : quit"); System.out.println(""); } /** * Prints the available commands at the transaction menu. */ private static void printTransactionMenuHelp() { System.out.println("<command> (<abbreviated command>) : <description>"); System.out.println("-------------------------------------------------"); System.out.println("list (l) : list transactions"); System.out.println("show (s) : show transaction"); System.out.println("create (c) : create new transaction"); System.out.println("update (u) : update transaction details"); System.out.println("delete (d) : delete transaction"); System.out.println("back (b) : go back to previous menu"); System.out.println("help (h) : help"); System.out.println("quit (q) : quit"); System.out.println(""); } /** * Prints detailed information regarding a Generic Feed * * @param feed The feed of interest */ private static void printBasicFeedDetails(BaseFeed feed){ System.out.println("\tFeed is " + (feed.getCanPost() ? "writable!" : "read-only!")); System.out.println("\tNumber of entries: " + feed.getTotalResults()); System.out.println("\tStart Index: " + feed.getStartIndex()); System.out.println("\tEnd Index: " + feed.getItemsPerPage()); System.out.println("\tFeed URI: " + (feed.getSelfLink() == null ? "<none>" : feed.getSelfLink().getHref()) + "\n"); System.out.println("\tFeed Title: " + feed.getTitle().getPlainText()); System.out.println("\tAtom ID: " + feed.getId()); System.out.println("\tLast updated: " + feed.getUpdated()); System.out.println("\tFeed Categories:"); Iterator it = feed.getCategories().iterator(); while (it.hasNext()) { System.out.println("\t\t" + it.next().toString()); } System.out.println("\tLinks:"); if (feed.getLinks().size() == 0) { System.out.println("\t\t<No links, sorry!>"); } for (int i = 0; i < feed.getLinks().size(); i++) { System.out.println("\t\t" + feed.getLinks().get(i).getHref()); } System.out.println("\t" + "HTML Link: " + feed.getHtmlLink().getHref()); } /** * Prints detailed information regarding a Generic Entry * * @param entry The entry of interest **/ private static void printBasicEntryDetails(BaseEntry entry){ System.out.println("\tTitle: " + entry.getTitle().getPlainText()); System.out.println("\tAtom ID: " + entry.getId()); System.out.println("\tLast updated: " + entry.getUpdated()); System.out.println("\tEntry Categories:"); Iterator it = entry.getCategories().iterator(); while (it.hasNext()) { System.out.println("\t\t" + it.next().toString()); } System.out.println("\tLinks:"); if (entry.getLinks().size() == 0) { System.out.println("\t\t<No links, sorry!>"); } for (int i = 0; i < entry.getLinks().size(); i++) { System.out.println("\t\t" + ((Link) (entry.getLinks().get(i))).getHref()); } } /** * Prints detailed contents for a portfolio (i.e. a Portfolio Feed entry) * * @param portfolioEntry The portfolio entry of interest */ private static void printPortfolioEntry(PortfolioEntry portfolioEntry) { System.out.println("\nPortfolio Entry\n---------------"); printBasicEntryDetails(portfolioEntry); System.out.println("\tFeed Link: " + portfolioEntry.getFeedLink().getHref()); if (portfolioEntry.getFeedLink().getFeed() == null) { System.out.println("\tNo inlined feed."); } else { System.out.println("********** Beginning of inline feed ***************"); printBasicFeedDetails(portfolioEntry.getFeedLink().getFeed()); PositionFeed inlinedFeed = portfolioEntry.getFeedLink().getFeed(); printBasicFeedDetails(inlinedFeed); for (int i = 0; i < inlinedFeed.getEntries().size(); i++) { PositionEntry positionEntry = inlinedFeed.getEntries().get(i); printPositionEntry(positionEntry); } System.out.println("************* End of inlined feed *****************"); } PortfolioData portfolioData = portfolioEntry.getPortfolioData(); System.out.println("\tPortfolio Data:"); System.out.println("\t\tCurrency is " + portfolioData.getCurrencyCode()); System.out.printf("\t\tPercent Gain is %.2f%%\n", portfolioData.getGainPercentage() * 100.0); System.out.println("\t\tReturns:"); System.out.printf("\t\t\tOne week: %.2f%%\n", portfolioData.getReturn1w() * 100.0); System.out.printf("\t\t\tFour weeks: %.2f%%\n", portfolioData.getReturn4w() * 100.0); System.out.printf("\t\t\tThree months: %.2f%%\n", portfolioData.getReturn3m() * 100.0); System.out.printf("\t\t\tYear-to-date: %.2f%%\n", portfolioData.getReturnYTD() * 100.0); System.out.printf("\t\t\tOne year: %.2f%%\n", portfolioData.getReturn1y() * 100.0); System.out.printf("\t\t\tThree years: %.2f%%\n", portfolioData.getReturn3y() * 100.0); System.out.printf("\t\t\tFive years: %.2f%%\n", portfolioData.getReturn5y() * 100.0); System.out.printf("\t\t\tOverall: %.2f%%\n", portfolioData.getReturnOverall() * 100.0); if (portfolioData.getCostBasis() == null) { System.out.println("\t\tCost Basis not specified"); } else { for (int i = 0; i < portfolioData.getCostBasis().getMoney().size(); i++) { Money m = portfolioData.getCostBasis().getMoney().get(i); System.out.printf("\t\tThis portfolio cost %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } if (portfolioData.getDaysGain() == null) { System.out.println("\t\tDay's Gain not specified"); } else { for (int i = 0; i < portfolioData.getDaysGain().getMoney().size(); i++) { Money m = portfolioData.getDaysGain().getMoney().get(i); System.out.printf("\t\tThis portfolio made %.2f %s today.\n", m.getAmount(), m.getCurrencyCode()); } } if (portfolioData.getGain() == null) { System.out.println("\t\tTotal Gain not specified"); } else { for (int i = 0; i < portfolioData.getGain().getMoney().size(); i++) { Money m = portfolioData.getGain().getMoney().get(i); System.out.printf("\t\tThis portfolio has a total gain of %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } if (portfolioData.getMarketValue() == null) { System.out.println("\t\tMarket Value not specified"); } else { for (int i = 0; i < portfolioData.getMarketValue().getMoney().size(); i++) { Money m = portfolioData.getMarketValue().getMoney().get(i); System.out.printf("\t\tThis portfolio is worth %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } } /** * Prints detailed contents for a position (i.e. a Position Feed entry) * * @param positionEntry The position entry of interest */ private static void printPositionEntry(PositionEntry positionEntry) { System.out.println("\nPosition Entry\n--------------"); printBasicEntryDetails(positionEntry); System.out.println("\tFeed Link: " + positionEntry.getFeedLink().getHref()); if (positionEntry.getFeedLink().getFeed() == null) { System.out.println("\tNo inlined feed."); } else { System.out.println("********** Beginning of inline feed ***************"); printBasicFeedDetails(positionEntry.getFeedLink().getFeed()); TransactionFeed inlinedFeed = positionEntry.getFeedLink().getFeed(); printBasicFeedDetails(inlinedFeed); for (int i = 0; i < inlinedFeed.getEntries().size(); i++) { TransactionEntry transactionEntry = inlinedFeed.getEntries().get(i); printTransactionEntry(transactionEntry); } System.out.println("************* End of inlined feed *****************"); } System.out.println("\tTicker:"); System.out.println("\t\tExchange: " + positionEntry.getSymbol().getExchange()); System.out.println("\t\tSymbol: " + positionEntry.getSymbol().getSymbol()); System.out.println("\t\tFull Name: " + positionEntry.getSymbol().getFullName()); PositionData positionData = positionEntry.getPositionData(); System.out.println("\tPosition Data:"); System.out.printf("\t\tShare count: %.2f\n", positionData.getShares()); System.out.printf("\t\tPercent Gain is %.2f%%\n", positionData.getGainPercentage() * 100.0); System.out.println("\t\tReturns:"); System.out.printf("\t\t\tOne week: %.2f%%\n", positionData.getReturn1w() * 100.0); System.out.printf("\t\t\tFour weeks: %.2f%%\n", positionData.getReturn4w() * 100.0); System.out.printf("\t\t\tThree months: %.2f%%\n", positionData.getReturn3m() * 100.0); System.out.printf("\t\t\tYear-to-date: %.2f%%\n", positionData.getReturnYTD() * 100.0); System.out.printf("\t\t\tOne year: %.2f%%\n", positionData.getReturn1y() * 100.0); System.out.printf("\t\t\tThree years: %.2f%%\n", positionData.getReturn3y() * 100.0); System.out.printf("\t\t\tFive years: %.2f%%\n", positionData.getReturn5y() * 100.0); System.out.printf("\t\t\tOverall: %.2f%%\n", positionData.getReturnOverall() * 100.0); if (positionData.getCostBasis() == null) { System.out.println("\t\tCost Basis not specified"); } else { for (int i = 0; i < positionData.getCostBasis().getMoney().size(); i++) { Money m = positionData.getCostBasis().getMoney().get(i); System.out.printf("\t\tThis position cost %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } if (positionData.getDaysGain() == null) { System.out.println("\t\tDay's Gain not specified"); } else { for (int i = 0; i < positionData.getDaysGain().getMoney().size(); i++) { Money m = positionData.getDaysGain().getMoney().get(i); System.out.printf("\t\tThis position made %.2f %s today.\n", m.getAmount(), m.getCurrencyCode()); } } if (positionData.getGain() == null) { System.out.println("\t\tTotal Gain not specified"); } else { for (int i = 0; i < positionData.getGain().getMoney().size(); i++) { Money m = positionData.getGain().getMoney().get(i); System.out.printf("\t\tThis position has a total gain of %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } if (positionData.getMarketValue() == null) { System.out.println("\t\tMarket Value not specified"); } else { for (int i = 0; i < positionData.getMarketValue().getMoney().size(); i++) { Money m = positionData.getMarketValue().getMoney().get(i); System.out.printf("\t\tThis position is worth %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } } /** * Prints detailed contents for a transaction (i.e. a Transaction Feed entry) * * @param transactionEntry The transaction entry of interest */ private static void printTransactionEntry(TransactionEntry transactionEntry) { System.out.println("\nTransaction Entry\n-----------------"); printBasicEntryDetails(transactionEntry); TransactionData transactionData = transactionEntry.getTransactionData(); System.out.println("\tTransaction Data:"); System.out.println("\t\tType: " + (transactionData.getType() == null ? "no type" : transactionData.getType())); System.out.println("\t\tDate: " + (transactionData.getDate() == null ? "no date" : transactionData.getDate())); System.out.printf("\t\tShares: %.2f\n", transactionData.getShares()); if (transactionData.getPrice() == null) { System.out.println("\t\tPrice not specified"); } else { for (int i = 0; i < transactionData.getPrice().getMoney().size(); i++) { Money m = transactionData.getPrice().getMoney().get(i); System.out.printf("\t\tThis transaction had a unit price of %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } if (transactionData.getCommission() == null) { System.out.println("\t\tCommission not specified"); } else { for (int i = 0; i < transactionData.getCommission().getMoney().size(); i++) { Money m = transactionData.getCommission().getMoney().get(i); System.out.printf("\t\tThis transaction had a commission of %.2f %s.\n", m.getAmount(), m.getCurrencyCode()); } } System.out.println("\t\tNotes: " + (null == transactionData.getNotes() ? "none" : transactionData.getNotes())); } /** * Queries a portfolio feed and prints feed and entry details. * * @param service authenticated client connection to a Finance GData service * @param feedUrl resource URL for the feed, including GData query parameters * e.g. http://finance.google.com/finance/feeds/default/portfolios * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryPortfolioFeed(FinanceService service, String feedUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Feed at location: " + feedUrl); PortfolioFeed portfolioFeed = service.getFeed(new URL(feedUrl), PortfolioFeed.class); System.out.println("\nPortfolio Feed\n=============="); printBasicFeedDetails(portfolioFeed); for (int i = 0; i < portfolioFeed.getEntries().size(); i++) { PortfolioEntry portfolioEntry = portfolioFeed.getEntries().get(i); printPortfolioEntry(portfolioEntry); } } /** * Queries a portfolio entry and prints entry details. * * @param service authenticated client connection to a Finance GData service * @param entryUrl resource URL for the entry * e.g. http://finance.google.com/finance/feeds/default/portfolios/1 * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryPortfolioEntry(FinanceService service, String entryUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Entry at location: " + entryUrl); PortfolioEntry portfolioEntry = service.getEntry(new URL(entryUrl), PortfolioEntry.class); printPortfolioEntry(portfolioEntry); } /** * Inserts a portfolio entry into a feed and prints the new entry. * * @param service authenticated client connection to a Finance GData service * @param feedUrl the POST URI associated with the target feed * e.g. http://finance.google.com/finance/feeds/default/portfolios * @param entry the new entry to insert into the feed * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void insertPortfolioEntry(FinanceService service, String feedUrl, PortfolioEntry entry) throws IOException, MalformedURLException, ServiceException { System.out.println("Inserting Entry at location: " + feedUrl); PortfolioEntry insertedEntry = service.insert(new URL(feedUrl), entry); printPortfolioEntry(insertedEntry); } /** * Updates a portfolio entry in a feed and prints the updated entry. * * @param service authenticated client connection to a Finance GData service * @param entryUrl the edit URL associated with the entry * e.g. http://finance.google.com/finance/feeds/default/portfolios/1 * @param entry the modified Entry to be written to the server * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void updatePortfolioEntry(FinanceService service, String entryUrl, PortfolioEntry entry) throws IOException, MalformedURLException, ServiceException { System.out.println("Updating Entry at location: " + entryUrl); PortfolioEntry updatedEntry = service.update(new URL(entryUrl), entry); printPortfolioEntry(updatedEntry); } /** * Deletes a portfolio entry in a feed. * * @param service authenticated client connection to a Finance GData service * @param entryUrl the edit URL associated with the entry * e.g. http://finance.google.com/finance/feeds/default/portfolios/1 * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void deletePortfolioEntry(FinanceService service, String entryUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Deleting Entry at location: " + entryUrl); service.delete(new URL(entryUrl)); System.out.println("Delete Successful"); } /** * Queries a position feed and prints feed and entry details. * * @param service authenticated client connection to a Finance GData service * @param feedUrl resource URL for the feed, including GData query parameters * e.g. http://finance.google.com/finance/feeds/default/ portfolios/1/positions?returns=true * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryPositionFeed(FinanceService service, String feedUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Feed at location " + feedUrl); PositionFeed positionFeed = service.getFeed(new URL(feedUrl), PositionFeed.class); System.out.println("\nPosition Feed\n============="); printBasicFeedDetails(positionFeed); for (int i = 0; i < positionFeed.getEntries().size(); i++) { PositionEntry positionEntry = positionFeed.getEntries().get(i); printPositionEntry(positionEntry); } } /** * Queries a positon entry and prints entry details. * * @param service authenticated client connection to a Finance GData service * @param entryUrl resource URL for the entry * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryPositionEntry(FinanceService service, String entryUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Entry at location " + entryUrl); PositionEntry positionEntry = service.getEntry(new URL(entryUrl), PositionEntry.class); printPositionEntry(positionEntry); } /** * Queries a transaction feed and prints feed and entry details. * * @param service authenticated client connection to a Finance GData service * @param feedUrl resource URL for the feed, including GData query parameters * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM/transactions * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryTransactionFeed(FinanceService service, String feedUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Feed at location " + feedUrl); TransactionFeed transactionFeed = service.getFeed(new URL(feedUrl), TransactionFeed.class); System.out.println("\nTransaction Feed\n================"); printBasicFeedDetails(transactionFeed); for (int i = 0; i < transactionFeed.getEntries().size(); i++) { TransactionEntry transactionEntry = transactionFeed.getEntries().get(i); printTransactionEntry(transactionEntry); } } /** * Queries a transaction entry and prints entry details. * * @param service authenticated client connection to a Finance GData service * @param entryUrl resource URL for the entry * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM/transactions/1 * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void queryTransactionEntry(FinanceService service, String entryUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Requesting Entry at location: " + entryUrl); TransactionEntry transactionEntry = service.getEntry(new URL(entryUrl), TransactionEntry.class); printTransactionEntry(transactionEntry); } /** * Inserts a transaction entry into a feed and prints the new entry. * * @param service authenticated client connection to a Finance GData service * @param feedUrl the POST URI associated with the target feed * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM/transactions * @param entry the new entry to insert into the feed * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void insertTransactionEntry(FinanceService service, String feedUrl, TransactionEntry entry) throws IOException, MalformedURLException, ServiceException { System.out.println("Inserting Entry at location: " + feedUrl); TransactionEntry insertedEntry = service.insert(new URL(feedUrl), entry); printTransactionEntry(insertedEntry); } /** * Updates a transaction entry in a feed and prints the updated entry. * * @param service authenticated client connection to a Finance GData service * @param entryUrl the edit URL associated with the entry * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM/transactions/1 * @param entry the modified Entry to be written to the server * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void updateTransactionEntry(FinanceService service, String entryUrl, TransactionEntry entry) throws IOException, MalformedURLException, ServiceException { System.out.println("Updating Entry at location: " + entryUrl); TransactionEntry updatedEntry = service.update(new URL(entryUrl), entry); printTransactionEntry(updatedEntry); } /** * Deletes a transaction entry in a feed. * * @param service authenticated client connection to a Finance GData service * @param entryUrl the edit URL associated with the entry * e.g. http://finance.google.com/finance/feeds/default/ * portfolios/1/positions/NYSE:IBM/transactions/1 * @throws IOException If there is a problem communicating with the server. * @throws MalformedURLException If the URL is invalid. * @throws ServiceException If the service is unable to handle the request. */ private static void deleteTransactionEntry(FinanceService service, String entryUrl) throws IOException, MalformedURLException, ServiceException { System.out.println("Deleting Entry at location: " + entryUrl); service.delete(new URL(entryUrl)); System.out.println("Delete Successful"); } /** * Authenticates the user with the Google server after reading in the user * email and password. * * @param service authenticated client connection to a Finance GData service * @param userID Finance portfolio user ID (e.g. "bob@gmail.com") * @param userPassword Finance portfolio user password (e.g. "Bobs$tocks") * @return login success or failure */ private static Boolean loginUser(FinanceService service, String userID, String userPassword) { try { service.setUserCredentials(userID, userPassword); } catch (AuthenticationException e) { System.err.println("Invalid Credentials!"); e.printStackTrace(); return false; } return true; } private static void printUsage() { System.out.println(" Usage:"); System.out.println(" FinancePortfoliosClient <server> <account> <password>"); System.out.println(" Example:"); System.out.println(" FinancePortfoliosClient " + "http://finance.google.com user@gmail.com password"); } /** * Main menu for the Sample Google Finance Portfolios Client. * * @param args server, user email, and user password in that order. */ public static void main(String[] args) { // Google Finance GData service. FinanceService service = new FinanceService("Google-PortfoliosDemo-1.0"); Scanner sc = new Scanner(System.in); System.out.println("Sample Google Finance Portfolios Client"); if (args.length != 1 && args.length != 3) { printUsage(); System.exit(0); } // Set username and password from command-line arguments if they were passed // in. Otherwise prompt the user to login. if (args.length == 3) { userEmail = args[1]; userPassword = args[2]; } else { System.out.print("Enter user ID: "); userEmail = sc.nextLine(); System.out.print("Enter user password: "); userPassword = sc.nextLine(); } if (!loginUser(service, userEmail, userPassword)) { printUsage(); System.exit(0); } server = args[0]; baseUrl = server + basePath + "default"; printMainMenuHelp(); try { while (true) { switch(processMainMenuCommand(sc.nextLine().toLowerCase())) { case PORTFOLIOS: portfolioMenu(service, sc); break; case POSITIONS: positionMenu(service, sc); break; case TRANSACTIONS: transactionMenu(service, sc); break; case QUIT: System.exit(0); case HELP: printMainMenuHelp(); break; default: printMainMenuHelp(); } } } catch (IOException e) { // Communication error. System.err.println("There was a problem communicating with the service."); e.printStackTrace(); } catch (ServiceException e) { // Server side error. System.err.println("The server had a problem handling your request."); e.printStackTrace(); } } /** This class is only used for its static methods */ private FinancePortfoliosClient() { } }