backend/fastify/sell-stock/server.js
2024-05-26 22:28:08 +02:00

158 lines
5.2 KiB
JavaScript
Executable File

function processHoldingsList(holdings, soldTicker) {
const stockGroups = {};
for (const stock of holdings) {
if (stock.symbol in stockGroups) {
stockGroups[stock.symbol].totalCost -= stock.boughtPrice * stock.numberOfShares;
stockGroups[stock.symbol].totalShares -= stock.numberOfShares;
} else {
stockGroups[stock.symbol] = {
totalCost: stock.boughtPrice * stock.numberOfShares,
totalShares: stock.numberOfShares,
name: stock.name,
assetType: stock.assetType,
currentPrice: stock.currentPrice,
dailyChange: stock.dailyChange,
sinceBoughtChange: stock.sinceBoughtChange,
};
}
if (stock.symbol === soldTicker) {
// Only update dailyChange and sinceBoughtChange for the sold ticker
stockGroups[stock.symbol].dailyChange = stock.dailyChange;
stockGroups[stock.symbol].sinceBoughtChange = stock.sinceBoughtChange;
stockGroups[stock.symbol].currentPrice = stock.currentPrice;
}
}
const updatedHoldings = [];
for (const symbol in stockGroups) {
const { totalCost, totalShares, name, assetType, currentPrice, dailyChange, sinceBoughtChange } = stockGroups[symbol];
let finalBoughtPrice;
if (totalShares !== 0) {
finalBoughtPrice = totalCost / totalShares;
} else {
// If totalShares is 0, set finalBoughtPrice to 0
finalBoughtPrice = 0;
}
const updatedStock = {
symbol,
name,
assetType,
boughtPrice: finalBoughtPrice,
currentPrice,
dailyChange,
sinceBoughtChange: Number(((currentPrice / finalBoughtPrice - 1) * 100)?.toFixed(2)),
numberOfShares: totalShares,
};
updatedHoldings.push(updatedStock);
}
return updatedHoldings;
}
// Declare a route
module.exports = function (fastify, opts, done) {
const pb = opts.pb;
fastify.post('/sell-stock', async (request, reply) => {
const holidays = ['2024-01-01', '2024-01-15','2024-02-19','2024-03-29','2024-05-27','2024-06-19','2024-07-04','2024-09-02','2024-11-28','2024-12-25'];
const currentDate = new Date().toISOString().split('T')[0];
// Get the current time in the ET time zone
const etTimeZone = 'America/New_York';
const currentTime = new Date().toLocaleString('en-US', { timeZone: etTimeZone });
// Determine if the NYSE is currently open or closed
const currentHour = new Date(currentTime).getHours();
const isWeekend = new Date(currentTime).getDay() === 6 || new Date(currentTime).getDay() === 0;
const isBeforeMarketOpen = currentHour < 9 || (currentHour === 9 && new Date(currentTime).getMinutes() < 30);
const isAfterMarketClose = currentHour >= 16;
const isStockMarketOpen = !(isWeekend || isBeforeMarketOpen || isAfterMarketClose || holidays?.includes(currentDate));
let output;
if (isStockMarketOpen === true) {
const data = request.body;
const currentDate = new Date();
const year = currentDate.getFullYear();
const month = String(currentDate.getMonth() + 1).padStart(2, '0'); // Month is zero-based
const day = '01';
const formattedDate = `${year}-${month}-${day}`; // Output: "yyyy-mm-01"
const { userId, symbol, name, numberOfShares, soldPrice } = data;
let currentPortfolio = await pb.collection("portfolios").getList(1, 500, {
filter: `user="${userId}" && created >="${formattedDate}" `,
});
currentPortfolio = currentPortfolio?.items[0];
let holdings = currentPortfolio?.holdings || [];
let tradingHistory = currentPortfolio?.tradingHistory || [];
let availableCash = currentPortfolio?.availableCash || 0;
// Find the stock in the holdings list
const stockIndex = holdings.findIndex((stock) => stock.symbol === symbol);
if(stockIndex !== -1)
{
const soldValue = numberOfShares * soldPrice;
// Reduce the number of shares from the existing holding
holdings[stockIndex].numberOfShares -= numberOfShares;
if (holdings[stockIndex].numberOfShares <= 0) {
// If all shares are sold, remove the stock from the holdings list
holdings.splice(stockIndex, 1);
}
// Add the sold value to the available cash
availableCash += soldValue;
// Recalculate the updated holdings list
const updatedHoldings = processHoldingsList(holdings);
tradingHistory.push({'symbol': symbol,
'name': name,
'assetType': data['assetType'],
'numberOfShares': numberOfShares,
'price': Number(soldPrice),
'type': 'sell',
'date': new Date()});
try {
await pb.collection("portfolios").update(currentPortfolio?.id, {
"holdings": updatedHoldings,
"availableCash": availableCash,
"tradingHistory": tradingHistory,
})
output = 'success';
} catch (err) {
output = 'failure';
}
}
}
else {
output = 'marketClosed'
}
reply.send({ message: output })
})
done();
};