Created
August 24, 2023 23:17
-
-
Save itsKnight847/cd4c19da0fc5a54606bbe5a9f45a7ba3 to your computer and use it in GitHub Desktop.
grand exchange investigator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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