You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
6.5 KiB
225 lines
6.5 KiB
|
4 years ago
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
-- TradeSkillMaster_AuctionDB --
|
||
|
|
-- http://www.curse.com/addons/wow/tradeskillmaster_auctiondb --
|
||
|
|
-- --
|
||
|
|
-- A TradeSkillMaster Addon (http://tradeskillmaster.com) --
|
||
|
|
-- All Rights Reserved* - Detailed license information included with addon. --
|
||
|
|
-- ------------------------------------------------------------------------------ --
|
||
|
|
|
||
|
|
-- load the parent file (TSM) into a local variable and register this file as a module
|
||
|
|
local TSM = select(2, ...)
|
||
|
|
local Data = TSM:NewModule("Data")
|
||
|
|
|
||
|
|
-- weight for the market value from X days ago (where X is the index of the table)
|
||
|
|
local WEIGHTS = {[0] = 132, [1] = 125, [2] = 100, [3] = 75, [4] = 45, [5] = 34, [6] = 33,
|
||
|
|
[7] = 38, [8] = 28, [9] = 21, [10] = 15, [11] = 10, [12] = 7, [13] = 5, [14] = 4}
|
||
|
|
local MIN_PERCENTILE = 0.15 -- consider at least the lowest 15% of auctions
|
||
|
|
local MAX_PERCENTILE = 0.30 -- consider at most the lowest 30% of auctions
|
||
|
|
local MAX_JUMP = 1.2 -- between the min and max percentiles, any increase in price over 120% will trigger a discard of remaining auctions
|
||
|
|
|
||
|
|
function Data:ConvertScansToAvg(scans)
|
||
|
|
if not scans then return end
|
||
|
|
-- do a sanity check
|
||
|
|
if type(scans) == "number" then
|
||
|
|
scans = {scans}
|
||
|
|
end
|
||
|
|
if not scans.avg then
|
||
|
|
local total, num = 0, 0
|
||
|
|
for _, value in ipairs(scans) do
|
||
|
|
total = total + value
|
||
|
|
num = num + 1
|
||
|
|
end
|
||
|
|
scans.avg = floor(total/num+0.5)
|
||
|
|
scans.count = num
|
||
|
|
end
|
||
|
|
return scans
|
||
|
|
end
|
||
|
|
|
||
|
|
function Data:GetDay(t)
|
||
|
|
t = t or time()
|
||
|
|
return floor(t / (60*60*24))
|
||
|
|
end
|
||
|
|
|
||
|
|
-- Updates all the market values
|
||
|
|
function Data:UpdateMarketValue(itemData)
|
||
|
|
local day = Data:GetDay()
|
||
|
|
|
||
|
|
local scans = CopyTable(itemData.scans)
|
||
|
|
itemData.scans = {}
|
||
|
|
for i=0, 14 do
|
||
|
|
if i <= TSM.MAX_AVG_DAY then
|
||
|
|
if type(scans[day-i]) == "number" then
|
||
|
|
scans[day-i] = {avg=scans[day-i], count=1}
|
||
|
|
end
|
||
|
|
itemData.scans[day-i] = scans[day-i] and CopyTable(scans[day-i])
|
||
|
|
else
|
||
|
|
local dayScans = scans[day-i]
|
||
|
|
if type(dayScans) == "table" then
|
||
|
|
if dayScans.avg then
|
||
|
|
itemData.scans[day-i] = dayScans.avg
|
||
|
|
else
|
||
|
|
-- old method
|
||
|
|
itemData.scans[day-i] = Data:GetAverage(dayScans)
|
||
|
|
end
|
||
|
|
elseif dayScans then
|
||
|
|
itemData.scans[day-i] = dayScans
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
itemData.marketValue = Data:GetMarketValue(itemData.scans)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- gets the average of a list of numbers
|
||
|
|
-- DEPRECATED
|
||
|
|
function Data:GetAverage(data)
|
||
|
|
local total, num = 0, 0
|
||
|
|
for _, marketValue in ipairs(data) do
|
||
|
|
total = total + marketValue
|
||
|
|
num = num + 1
|
||
|
|
end
|
||
|
|
|
||
|
|
return num > 0 and floor((total / num) + 0.5)
|
||
|
|
end
|
||
|
|
|
||
|
|
-- gets the market value given a set of scans
|
||
|
|
function Data:GetMarketValue(scans)
|
||
|
|
local day = Data:GetDay()
|
||
|
|
local totalAmount, totalWeight = 0, 0
|
||
|
|
|
||
|
|
for i=0, 14 do
|
||
|
|
local dayScans = scans[day-i]
|
||
|
|
if dayScans then
|
||
|
|
local dayMarketValue
|
||
|
|
if type(dayScans) == "table" then
|
||
|
|
if dayScans.avg then
|
||
|
|
dayMarketValue = dayScans.avg
|
||
|
|
else
|
||
|
|
-- old method
|
||
|
|
dayMarketValue = Data:GetAverage(scans)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
dayMarketValue = dayScans
|
||
|
|
end
|
||
|
|
if dayMarketValue then
|
||
|
|
totalAmount = totalAmount + (WEIGHTS[i] * dayMarketValue)
|
||
|
|
totalWeight = totalWeight + WEIGHTS[i]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
for i in ipairs(scans) do
|
||
|
|
if i < day - 14 then
|
||
|
|
scans[i] = nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return totalWeight > 0 and floor(totalAmount / totalWeight + 0.5) or 0
|
||
|
|
end
|
||
|
|
|
||
|
|
function Data:ProcessData(scanData, groupItems)
|
||
|
|
if TSM.processingData then return TSMAPI:CreateTimeDelay(0.2, function() Data:ProcessData(scanData, groupItems) end) end
|
||
|
|
|
||
|
|
|
||
|
|
-- wipe all the minBuyout data
|
||
|
|
if groupItems then
|
||
|
|
for itemString in pairs(groupItems) do
|
||
|
|
local itemID = TSMAPI:GetItemID(itemString)
|
||
|
|
if TSM.data[itemID] then
|
||
|
|
TSM:DecodeItemData(itemID)
|
||
|
|
TSM.data[itemID].minBuyout = nil
|
||
|
|
TSM:EncodeItemData(itemID)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
else
|
||
|
|
for itemID, data in pairs(TSM.data) do
|
||
|
|
TSM:DecodeItemData(itemID)
|
||
|
|
data.minBuyout = nil
|
||
|
|
TSM:EncodeItemData(itemID)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local scanDataList = {}
|
||
|
|
for itemID, data in pairs(scanData) do
|
||
|
|
tinsert(scanDataList, {itemID, data})
|
||
|
|
end
|
||
|
|
|
||
|
|
-- go through each item and figure out the market value / update the data table
|
||
|
|
local index = 1
|
||
|
|
local day = Data:GetDay()
|
||
|
|
local function DoDataProcessing()
|
||
|
|
for i = 1, 500 do
|
||
|
|
if index > #scanDataList then
|
||
|
|
TSMAPI:CancelFrame("adbProcessDelay")
|
||
|
|
TSM.processingData = nil
|
||
|
|
break
|
||
|
|
end
|
||
|
|
|
||
|
|
local itemID, data = unpack(scanDataList[index])
|
||
|
|
TSM:DecodeItemData(itemID)
|
||
|
|
TSM.data[itemID] = TSM.data[itemID] or {scans={}, lastScan = 0}
|
||
|
|
local marketValue = Data:CalculateMarketValue(data.records)
|
||
|
|
|
||
|
|
local scanData = TSM.data[itemID].scans
|
||
|
|
scanData[day] = scanData[day] or {avg=0, count=0}
|
||
|
|
if type(scanData[day]) == "number" then
|
||
|
|
-- this should never happen...
|
||
|
|
scanData[day] = {scanData[day]}
|
||
|
|
end
|
||
|
|
scanData[day].avg = scanData[day].avg or 0
|
||
|
|
scanData[day].count = scanData[day].count or 0
|
||
|
|
if #scanData[day] > 0 then
|
||
|
|
scanData[day] = Data:ConvertScansToAvg(scanData[day])
|
||
|
|
end
|
||
|
|
scanData[day].avg = floor((scanData[day].avg * scanData[day].count + marketValue) / (scanData[day].count + 1) + 0.5)
|
||
|
|
scanData[day].count = scanData[day].count + 1
|
||
|
|
|
||
|
|
TSM.data[itemID].lastScan = TSM.db.factionrealm.lastCompleteScan
|
||
|
|
TSM.data[itemID].minBuyout = data.minBuyout > 0 and data.minBuyout or nil
|
||
|
|
TSM.data[itemID].quantity = data.quantity
|
||
|
|
Data:UpdateMarketValue(TSM.data[itemID])
|
||
|
|
TSM:EncodeItemData(itemID)
|
||
|
|
|
||
|
|
index = index + 1
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
TSM.processingData = true
|
||
|
|
TSMAPI:CreateTimeDelay("adbProcessDelay", 0, DoDataProcessing, 0.1)
|
||
|
|
end
|
||
|
|
|
||
|
|
function Data:CalculateMarketValue(records)
|
||
|
|
local totalNum, totalBuyout = 0, 0
|
||
|
|
local numRecords = #records
|
||
|
|
|
||
|
|
for i=1, numRecords do
|
||
|
|
totalNum = i - 1
|
||
|
|
if i ~= 1 and i > numRecords*MIN_PERCENTILE and (i > numRecords*MAX_PERCENTILE or records[i] >= MAX_JUMP*records[i-1]) then
|
||
|
|
break
|
||
|
|
end
|
||
|
|
|
||
|
|
totalBuyout = totalBuyout + records[i]
|
||
|
|
if i == numRecords then
|
||
|
|
totalNum = i
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local uncorrectedMean = totalBuyout / totalNum
|
||
|
|
local varience = 0
|
||
|
|
|
||
|
|
for i=1, totalNum do
|
||
|
|
varience = varience + (records[i]-uncorrectedMean)^2
|
||
|
|
end
|
||
|
|
|
||
|
|
local stdDev = sqrt(varience/totalNum)
|
||
|
|
local correctedTotalNum, correctedTotalBuyout = 1, uncorrectedMean
|
||
|
|
|
||
|
|
for i=1, totalNum do
|
||
|
|
if abs(uncorrectedMean - records[i]) < 1.5*stdDev then
|
||
|
|
correctedTotalNum = correctedTotalNum + 1
|
||
|
|
correctedTotalBuyout = correctedTotalBuyout + records[i]
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local correctedMean = floor(correctedTotalBuyout / correctedTotalNum + 0.5)
|
||
|
|
|
||
|
|
return correctedMean
|
||
|
|
end
|