158 lines
5.2 KiB
JavaScript
158 lines
5.2 KiB
JavaScript
|
|
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();
|
|
};
|
|
|