Skip to content

Latest commit

 

History

History
290 lines (236 loc) · 9.04 KB

README.md

File metadata and controls

290 lines (236 loc) · 9.04 KB

Team Cannon Project

GreenChip

Overview:

GreenChip is a real-time stock market game, where players can play the real stock market using virtual currency. Players are given $10,000 to invest, and they are able to buy, sell, hold, and invest their funds in any way they choose. Graphs help to show a portfolio's diversification and the trajectory of growth (or losses!) over time.


The Team:

Cainan Barboza

Primary team role: Back-end organization, API calls, functionality, and data structuring.

Micah Peterson

Primary team role: HTML and CSS styling, UI development, and functionality.

Dan Gelok

Primary team role: Project Management, API calls, and Authentication.

RJ Eppenger

Primary team role: Data Visualization and HTML/CSS styling.


Tools used in the project:

Languages:

  • HTML
  • CSS
  • JavaScript

Other:

  • JQuery
  • JSON
  • Bootstrap
  • FontAwesome
  • ChartJS

APIs

Base Objectives:

  • Users have the ability to buy, sell, or keep individual stocks and liquid cash
  • Deliver stock prices in real time
  • Provide an easy-search function for finding stocks
  • Display up-to-date stock information alongside current financial holdings
  • Track investment data over time using data persistence

Flex Goals Completed:

  • Provide universal login from anywhere
  • Smoothen out navigation for natural UI experience

Stretch Goals Future

  • Provide percentage growth/loss for individual stock holding
  • Provide individual growth/loss tracking graphs for unique holdings
  • Allow for competitive play against friends
  • Provide purchasable icons and UI upgrades available for purchase (with in-game virtual earnings)

Challenges & Solutions:

Some of the biggest challenges we faced with this project build included:

Challenge: Version and Merge Control
Solution: After much trial and error, our Git/GitHub procedures and skills were greatly refined and allowed for much smoother interaction between developers.

Challenge: Multiple API calls
Solution: Independent API calls and refactoring to allow for asynchronous events smoothened out user experience and consistency.

Challenge: Functional Complexity
Solution: Refactoring to allow portfolios using OOP techniques made the program significantly more efficient and streamlined remaining development for ease of use.

Challenge: CSS Manipulation of Components
Solution: Significant under-the-hood work on pre-existing components provided a much more visually pleasing end product on charts and graphs.


Code Snippets:

This snippet showcases the declaration of our user Class (including methods and attributes), and demonstrates OOP concepts.

class User{
    constructor(userName, cash,currentNetWorth, holdings = []){
        this.userName = userName;
        this.cash = cash;
        this.currentNetWorth = [currentNetWorth];
        this.holdings = holdings;
        this.currentStockAwaitingPurchase = {};
        this.currentStockAwaitingSell = {};
    }

    addStockToPurchaseList(name, symbol){
        this.currentStockAwaitingPurchase = {
            name : name,
            symbol : symbol,
        }
    }

    saveUser(){
        localStorage.setItem(`${this.userName}`, JSON.stringify(this))
        db.collection("users").doc(`${this.userName}`).set({
            info: JSON.stringify(this)
        }).then(console.log("saved to database"))
    }

    createNewHolding(name, symbol, numShares){
        let found = false;
        for(let comp of this.holdings){
            if(symbol == comp.symbol){
                comp.totalShares += numShares
                console.log(comp.totalShares);
                found = true;
            }
        }
        if(found == false){
            let newHolding = new Holding(name,symbol,numShares)
            console.log(newHolding.totalShares);
            this.holdings.push(newHolding)
        }
    }

    async buyStock(name, symbol, numShares, latestPrice){
        let stockPrice = await latestPrice(symbol)
        console.log(typeof this.cash,typeof numShares, typeof stockPrice)
        if(this.cash >= numShares * stockPrice){
            console.log("Cash is enough to buy");
            console.log(this.cash);
            this.createNewHolding(name, symbol, numShares)
            
            this.cash = this.cash - (numShares * stockPrice)
            console.log(this.cash);
        }
        this.saveUser();
    }

    async sellStock(symbol, numSharesToSell, latestPrice){
        console.log(this.cash);
        let totalSellPrice = parseFloat(numSharesToSell).toFixed(2) * parseFloat(latestPrice).toFixed(2)
        console.log(totalSellPrice);
        for(let comp of this.holdings){
            if(comp.symbol == symbol){
                comp.totalShares -= numSharesToSell
                console.log(comp.totalShares);
            }
        }
        this.holdings = this.holdings.filter(comp => comp.totalShares > 0)
        console.log(this.holdings);
        this.cash += totalSellPrice;
        console.log(this.cash);
        this.saveUser();
        await this.getData();
        createLineGraph();
    }

    async getStockData(stockSymbol){
        let response = await fetch(`https://cloud.iexapis.com/stable/stock/${stockSymbol}/quote/?token=${APIurls[2]}`)
        let json = await response.json();
        return json;
    }

    async getStockLatestPrice(stockSymbol){
        let response = await fetch(`https://cloud.iexapis.com/stable/stock/${stockSymbol}/quote/?token=${APIurls[2]}`)
            let json = await response.json();
            console.log(json)
            let currentPrice = json.latestPrice;
            console.log(currentPrice);
            return currentPrice;
    }

    async getPortfolioData(){
        return Promise.all(this.holdings.map( comp => {
            return fetch(`https://cloud.iexapis.com/stable/stock/${comp.symbol}/quote/?token=${APIurls[2]}`).then(resp => resp.json())
        })).then(results => {
            let total = 0;
            let companyArray = []
            results.forEach((comp, index)=>{
            
            let currentCompInHoldings = this.holdings[index];
            let latestPrice = parseFloat(comp.latestPrice); 
            let totalSharesOfComp =  parseInt(currentCompInHoldings.totalShares);  
            total += (latestPrice * totalSharesOfComp);
            companyArray.push({
                name : currentCompInHoldings.name,
                totalSharesValue : (latestPrice * totalSharesOfComp)
            })
        })
        return {
            totalPortfolioValue : total + this.cash,
            companys : companyArray
        }
    })
}


The following code is part of the Firebase Authentication Protocol, and redirects users from 'inner' pages to the login page if they are not properly logged in.

const auth = firebase.auth();
auth.onAuthStateChanged(user => {
    if (user) {
        console.log(`user logged in: ${user.email}`)
        // console.log(user)
    }
    else {
        console.log('user logged out')
        window.location.href = "./index.html"
    }
})


This excerpt, taken from the dashboard page, is a table populated from the user's portfolio object. It demonstrates bootstrap manipuation, HTML component development, and pure CSS styling, and is the main focal point displaying data in the user's dashboard.

<div class="row ml-1">

    <div class="col-lg-2 col-sm-auto">
    </div>

    <div class="col" style="padding-right:15px;">
    <table class="table table-success">
        <thead class="table-dark">
            <tr>
            <th scope="col">Company (Ticker)</th>
            <th scope="col">Shares</th>
            <th scope="col">Price</th>
            <th scope="col">Total</th>
            <th scope="col"></th>
            </tr>
        </thead>
        <tbody id="tbody">
            
        </tbody>
        </table>
    </div>
    <div class="col-lg-2 col-sm-auto mr-sm-1">
    </div>

</div>


Screenshots:

Login and user registration.


Live-updated graphs of a player's current portfolio.


Drop-down menu providing an easy search for stocks to buy or sell.