Skip to content

Instantly share code, notes, and snippets.

@itsKnight847
Created August 24, 2023 23:17
Show Gist options
  • Save itsKnight847/cd4c19da0fc5a54606bbe5a9f45a7ba3 to your computer and use it in GitHub Desktop.
Save itsKnight847/cd4c19da0fc5a54606bbe5a9f45a7ba3 to your computer and use it in GitHub Desktop.
grand exchange investigator
// const item = require('./data/data.json');
const allItems = require('./data/data-hr.json');
const fs = require('fs');
let states = [];
const dir = "./data";
try {
const files = fs.readdirSync(dir);
let filesProcessed = 0;
files.forEach((file) => {
fs.readFile(`${dir}/${file}`, "utf8", (err, data) => {
if (err) {
console.error(`Error reading file ${file}:`, err);
return;
}
let p = JSON.parse(data);
let state = new Map();
state.set('timestamp',p.timestamp);
Object.keys(p.data).map( (val) => {
state.set(parseInt(val), p.data[val]);
});
states.push(state);
filesProcessed++;
if (filesProcessed === files.length) {
//calculate grown for all states
const allItemsGrowth = calculateGrowthAll(states);
console.log(allItemsGrowth)
//calculate for single item
// getItem(states,4151);
}
});
});
} catch (err) {
console.error("Error:", err);
}
function getItem(states, itemId){
//28338,
let itemSnapShots = [];
let stateIndex = 1;
states.map( state => {
const itemSnapshot = state.get(itemId);
if(!itemSnapshot){
console.error(`skip snapshot for item: ${itemId}, state: ${stateIndex}`);
} else {
const timestamp = state.get('timestamp');
const date = new Date(timestamp * 1000); // Convert seconds to milliseconds
itemSnapShots.push({
state: stateIndex,
itemSnapshot,
calculateAverageWeight: calculateAverageWeight(itemSnapshot),
timestamp,
date: date.toISOString()
});
}
stateIndex++
});
let sorted = itemSnapShots.sort( (a,b) => {
return b.timestamp - a.timestamp
});
console.log(itemSnapShots);
}
function calculateGrowthAll(states){
//run all items available
const allItemsIds = [...states[0].keys()];
let allItemsGrowth = {};
allItemsIds.map( itemId => {
let itemSnapShots = [];
let stateIndex = 1;
states.map( state => {
const itemSnapshot = state.get(itemId);
if(!itemSnapshot?.highPriceVolume || !itemSnapshot?.avgLowPrice || !itemSnapshot?.lowPriceVolume){
console.error(`skip item: ${itemId}, state: ${stateIndex}, missing price label. ${JSON.stringify(itemSnapshot)}`);
} else {
itemSnapShots.push(itemSnapshot);
}
stateIndex++
});
if(itemSnapShots.length >= 2){
const growth = calculateGrowthPercentage(itemSnapShots);
allItemsGrowth = Object.assign(allItemsGrowth, {
itemId,
growth
})
} else {
console.error(`not enough dataset for item: ${itemId}`);
}
})
return allItemsGrowth;
}
function calculateAverageWeight(record) {
const totalHighPriceVolume = record.highPriceVolume;
const totalLowPriceVolume = record.lowPriceVolume;
const totalVolume = totalHighPriceVolume + totalLowPriceVolume;
const weightedHighPrice = record.avgHighPrice * totalHighPriceVolume;
const weightedLowPrice = record.avgLowPrice * totalLowPriceVolume;
const averageWeight = (weightedHighPrice + weightedLowPrice) / totalVolume;
return Math.round(averageWeight);
}
function calculateGrowthPercentage(item) {
const latestPriceData = item[item.length - 1];
const earliestPriceData = item[0];
const latestWeightedPrice = (latestPriceData.highPriceVolume * latestPriceData.avgHighPrice +
latestPriceData.lowPriceVolume * latestPriceData.avgLowPrice) /
(latestPriceData.highPriceVolume + latestPriceData.lowPriceVolume);
const earliestWeightedPrice = (earliestPriceData.highPriceVolume * earliestPriceData.avgHighPrice +
earliestPriceData.lowPriceVolume * earliestPriceData.avgLowPrice) /
(earliestPriceData.highPriceVolume + earliestPriceData.lowPriceVolume);
const growthPercentage = ((latestWeightedPrice - earliestWeightedPrice) / earliestWeightedPrice) * 100;
return growthPercentage;
}
// Weighted Moving Average Growth Rate
function calculateWeightedMovingAverageGrowthRate(data, windowSize) {
const prices = data.map(entry => (entry.avgHighPrice + entry.avgLowPrice) / 2);
const movingAverages = [];
for (let i = windowSize - 1; i < prices.length; i++) {
const sum = prices.slice(i - windowSize + 1, i + 1).reduce((acc, price) => acc + price, 0);
movingAverages.push(sum / windowSize);
}
const growthRates = movingAverages.map((avg, i) => ((avg - movingAverages[i - 1]) / movingAverages[i - 1]) * 100);
return growthRates.slice(1); // Exclude the first entry (undefined growth rate)
}
// Relative Strength Index (RSI)
function calculateRSI(data, period) {
const priceChanges = data.map((entry, i) => i > 0 ? (entry.avgHighPrice - data[i - 1].avgHighPrice) : 0);
const positiveChanges = priceChanges.map(change => Math.max(change, 0));
const negativeChanges = priceChanges.map(change => Math.max(-change, 0));
const avgGain = calculateSimpleMovingAverage(positiveChanges, period);
const avgLoss = calculateSimpleMovingAverage(negativeChanges, period);
const rs = avgGain.map((avg, i) => avg / avgLoss[i]);
const rsi = rs.map(rsValue => 100 - (100 / (1 + rsValue)));
return rsi;
}
// Helper function for calculating Simple Moving Average (SMA)
function calculateSimpleMovingAverage(data, period) {
const sma = [];
for (let i = period - 1; i < data.length; i++) {
const sum = data.slice(i - period + 1, i + 1).reduce((acc, value) => acc + value, 0);
sma.push(sum / period);
}
return sma;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment