StockedUp! is a stock based game with the goal to make as much money as possible. The stocks you can buy are all Silicon Valley based company's. Each day the stock opens at 15:30 (Amsterdam Time). The game has a live view where you can see the latest rates.
Live version: https://stockedup.herokuapp.com/
To use the game you have to login using Twitter. The first time you have to setup your account by filling in some information. After loggin in for the first time, you will recieve €100.000,-. You will see an empty portfolio after logging in for the first time. If you want to buy stock, click on the 'Overzicht' button. You will now see all available stocks.
To buy one of the stocks, simply click on the box with the name and logo of the stock you would like to buy. A new page will open with the latest price a.k.a. the price you are going to buy them for. In the input field you can see the max amount of stocks you can buy. After filling in the amount, simply press 'Kopen' to actually buy them. Now you will be redirected to your personal portfolio again.
To sell stocks, simply click the 'verkopen' button next to your portfolio. You can only sell all stocks of a company at once. By clicking 'Verkopen' the stocks will be sold and the money will be added to your saldo again.
To see all users and their saldo, click on the 'Bekijk alle users' button under the portfolio view.
- Login & create an account using Twitter oAuth
- Live view with the latest stock rates, updated every 5 seconds
- Buy and sell stocks to make more money
- Live portfolio view to see the profits or losses you've made
- Overview of other people's saldo
This is the data model of this application. It shows the communication between server, api, web socket and the Twitter oAuth process.
Check if user is logged in This check is fired at each page where you need to be logged in. It check's if there is a user session and, if so redirects you to the desired page.
function checkForSession(req, res, next) {
if (req.session.login) {
res.locals.data = req.session.data;
res.locals.user = req.session.user;
next();
} else {
res.redirect('/account/login');
}
}
oAuth callback This callback checks if the Twitter login was succesfull, if so a session will be created so that the user can visit all secret pages and perform al functionalities.
router.get('/callback', function(req, res) {
const config = {
token: req.session.ReqToken,
secret: req.session.ReqSecret,
verify: req.query.oauth_verifier
}
/* GAIN TWITTER ACCESS
--------------------------------------------------------------- */
consumer.getOAuthAccessToken(config.token, config.secret, config.verify, function(error, token, secret, results) {
if (error) {
console.log(error);
} else {
req.session.oauthAccessToken = token;
req.session.oauthAccessSecret = secret;
req.session.login = true;
res.redirect('/twitter');
}
});
});
Connect to database and update stock information every 5 seconds This function connects to the MongoDB database. Every 5 seconds the latest stock information will be requested using the API. If there is a change on one of the stock values, this will be editted in the database. As well there will be a socket emit so that the live view will update it's actual value & rate.
MongoClient.connect(dbConfig, (err, database) => {
if (err) return console.log(err)
db = database
const collection = db.collection('stock');
/* UPDATE STOCK DATA EVERY 1 MINUTE AND SAVE TO MONGODB
--------------------------------------------------------------- */
setInterval(function(){
/* LOOP TROUGH ALL STOCKS AND COMPARE ACTUAL TO DB
--------------------------------------------------------------- */
allStocks.forEach(function(stock) {
const url = `${process.env.STOCKAPIURL}${process.env.STOCKGLOBAL}symbol=${stock}${process.env.STOCKAPIKEY}`;
/* REQUEST TO API FOR ACTUAL STOCK DATA FOR EACH STOCK
--------------------------------------------------------------- */
request(url, function (error, response, body) {
let requestData = {};
if(JSON.parse(body)) {
requestData = JSON.parse(body)[process.env.MAIN];
} else {
requestData = {
'03. Latest Price': 0,
'07. Close (Previous Trading Day)': 0
}
}
/* SEARCH FOR STOCK IN DATABASE
--------------------------------------------------------------- */
collection.findOne({
ticker: stock
}, function(err, ticker) {
/* CHECK IF API RATE CORRESPONDS TO RATE IN DB
--------------------------------------------------------------- */
if (ticker.actual != requestData[process.env.LATEST]) {
let lastValue = ticker.actual;
const percentageChange = ((requestData[process.env.LATEST] - requestData[process.env.OPEN]) / requestData[process.env.OPEN]) * 100
let dbData = {type: 'stock', ticker: stock, actual: requestData[process.env.LATEST], last: lastValue, open: requestData[process.env.OPEN], difference: percentageChange.toFixed(2)}
/* UPDATE DB WITH NEWEST RATINGS IF SO
--------------------------------------------------------------- */
collection.update({ticker: stock}, dbData, {upsert:true}, function(err, doc) {
io.emit('stock change', dbData)
if (err) return res.send(500, {error: err});
});
}
});
});
});
}, 5000);
});
Latest Portfolio Value's This function gets the latest stock values that are in a users portfolio. It creates an object that can be used in the view & emits a message to the socket so the changes are visible in the live view.
function checkValue() {
const collection = db.collection('stock');
setInterval(function() {
for (var key in portfolio) {
collection.find({
"ticker": portfolio[key].ticker
}, function(err, singleStock) {
singleStock.forEach(function(d) {
/* IF ACTUAL PRICE IS NOT THE SAME AS PORTFOLIO PRICE, UPDATE AND EMIT TO SOCKET
--------------------------------------------------------------- */
if (portfolio[d.ticker].price != d.actual) {
const difference = (((Number(d.actual) - (Number(portfolio[d.ticker].price)))) / Number(portfolio[d.ticker].price) * 100).toFixed(2)
const newPrice = d.actual;
const data = [d.ticker, newPrice, difference];
io.emit('new price', data)
}
})
});
}
}, 5000);
}
This is the overview with all stocks and their values. The percentage is the difference since the stock closed the day before
This is the overview with all stocks the user has. It has a live update function as well, so that you can see the latest rate every 5 seconds
This is the screen you see when you buy or sell stocks
The overview with all users and their actual saldo
The message you get to see as soon as your internet connection is down
This is the list with all used packages needed to run the application. They can be installed using npm install
in the console when in the folder.
-
Body-parser
Middleware for body parsing -
Dotenv
Load enviroment variables from .env files -
EJS
Templating library (Embedded JavaScript templates) -
Express
Web framework for NodeJS (routing) -
Express-session
Middleware for creating sessions -
MongoDB
Official MongoDB library for NodeJS -
Request
Client for HTTP requests -
Socket.io
Enables websockets -
Compression
GZIP compression -
Path
For using paths -
oAuth
oAuth API for NodeJS -
HTTP
Package for HTTP servers
This are the packages for developing, these are not necessary for the application to work.
-
Nodemon
Run your app while restarting on changes in files
- Enable oAuth for logging in with Twitter
- Update all stock data every 5 minutes
- First time profile setup
- Portfolio view with live updates
- Buy and sell stocks
- Overview with all users & their saldo
- Offline error when connection is down
- D3 visualizations with intraday data
- Buy/Sell notifications the user can setup
- Add cryptocurrencies to the stocklist
- Weekly competition, the most earning user wins
git clone https://github.com/camille500/RTW2.git
cd RTW2
npm install
Ask me for the missing variables
CONSUMERKEY={Twitter Consumer Key}
CONSUMERSECRET={Twitter Consumer Secret}
ACCESSTOKEN={Twitter Access Token}
ACCESSTOKENSECRET={Twitter Access Token Secret}
MONGODB_URI={MongoDB URI}
SESSIONSECRET={Session Secret}
STOCKAPIURL=http://www.alphavantage.co/query?
STOCKAPIKEY={Stock API Key}
STOCKGLOBAL=function=GLOBAL_QUOTE&
STOCKINTRA=function=GLOBAL_QUOTE&
MAIN=Realtime Global Securities Quote
LATEST=03. Latest Price
OPEN=07. Close (Previous Trading Day)
npm start
MIT © Camille Sébastien Niessen