Underhood is a clone of a website version of a popular stock exchange app called Robinhood. Underhood allows users to simulate the buy and sell stocks with real-time data, historical data and additional feature such as creating watchlist and fund management. The app also pulls the latest headline of all major new sources as well as news article related to each individual stock at the stock's show page.
- Frontend:
- React
- HTML/CSS
- Backend:
- Ruby
- Javascript
- AJAX
- JBuilder
- Rails
- Redux
- PostgreSQL
- HTML/CSS
- APIs:
- Chart.js
- Finnhub(News)
- AlphaVantage(Search & Live Price)
- Other:
- Amazon AWS S3
- Heroku
- Material UI
- User signup and login as well as a demo user function

- Portoflio page with sidebar of all owned stocks and watchlists
- Note: The portfolio chart currently utilizes hardcoded sandbox datas. This is a design choice as the official Robinhood portfolio chart is based on the histoical market prices of the owned shares. In order to recreate a similar chart, we would have to fire API calls each time we navigate to the portfolio page to acquire those datas, and this would deplete the API call limit within a new clicks and returns.

- Note: The portfolio chart currently utilizes hardcoded sandbox datas. This is a design choice as the official Robinhood portfolio chart is based on the histoical market prices of the owned shares. In order to recreate a similar chart, we would have to fire API calls each time we navigate to the portfolio page to acquire those datas, and this would deplete the API call limit within a new clicks and returns.
- Buying power that limits user from stock purchase and the ability to add to that balance.

- News section displaying latest current event from a New API

- Stock page displaying real time price chart and latest current event of the specific asset

- Purchase and sell stock in shares or dollars based on live price

- Create multiple watchlist and add stocks to those watchlists

- Search bar with stock symbols and names from API

- A Portfolio Chart of all owned assets based on their historical shares and price flunctuations, can also be option for different time periods.
- Having multiple API keys that rotates the key being used based on a API call counter, and bypassing the 5 call per min limitation.
- Stock/company details on the stock pages(Market Value, Cost, Stats on the stock(market cap, 52 day high/low etc)
- A leaderboard of all the users's net worth and rules for a stock simulatior game
- By default each change to the search bar would fire off an API call, and with the AlphaVantage limit of 5 API calls per minute, this limit was quickly exceed. A debounce function was added to reduce API pulls. With the debounce function, the call to the API only occurs if the user stops typing for 1 second.
debounceSearch() {
let timer;
return (keyword) => {
clearTimeout(timer);
timer = setTimeout(() => {
Promise.all([this.props.fetchSearch(keyword)])
.then(() => {
this.setState({ results: this.props.results[keyword] || [] })
})
}, 1000);
}
}
handleSearch(e) {
const keyword = e.currentTarget.value;
if (!keyword) {
this.setState({ keyword: '', results: '' });
} else {
this.setState({ keyword: keyword },
this.debounceSearch(keyword)
)
}
}- With limits on the free version of the stocks API. A second Stock API FinnHub is utilized for fetching company news. For the same stock symbol used for stock price fetch, it is used in second API call to fetch that company's news, and the object return is then parsed and styled in workable company news sections and company news items, effectively working around the API limits of using a single stock API.

const CompanyNews = ({ companyNews }) => {
const news = Object.values(companyNews).map((article, i) => {
return (
<CompanyNewsItem
key={i}
url={article.url}
source={article.source}
headline={article.headline}
summary={article.summary}
image={article.image}
/>
);
});
return (
<div className="news">
{news.slice(0, 5)}
</div>
);
};
const CompanyNewsItem = ({ url, source, headline, summary, image }) => {
return (
<div className="company-news-item-container">
<a href={url} className="company-news-item-link" target="_blank">
<div className="news_box">
<h3 className="news_source">{source}</h3>
<h2 className="news_headline">{headline}</h2>
<p className="news_summary">
{summary.split("").slice(0, 75).join("") + "..."}
</p>
</div>
<img
src={image}
width="200px"
height="135px"
className="news_img"
/>
</a>
</div>
);
};