diff --git a/Aux-AddOn.toc b/Aux-AddOn.toc index 034878b..715a232 100644 --- a/Aux-AddOn.toc +++ b/Aux-AddOn.toc @@ -15,7 +15,6 @@ stack.lua post.lua sheet.lua history.lua -stat_histogram.lua info.xml completion.xml diff --git a/core.lua b/core.lua index ccf8786..5376ece 100644 --- a/core.lua +++ b/core.lua @@ -1,4 +1,4 @@ -AuxVersion = '2.2.13' +AuxVersion = '2.2.14' AuxAuthors = 'shirsig; Zerf; Zirco (Auctionator); Nimeral (Auctionator backport)' local lastRightClickAction = GetTime() @@ -36,7 +36,7 @@ function Aux_OnLoad() local item_id, suffix_id = EnhTooltip.BreakLink(link) local item_key = (item_id or 0)..':'..(suffix_id or 0) - local auction_count, day_count, TDA, EMA5, EMA30 = Aux.history.get_price_data(item_key) + local auction_count, day_count, TDA, EMA7, trend, variance = Aux.history.price_data(item_key) if auction_count == 0 then EnhTooltip.AddLine('Never seen at auction', nil, true) @@ -45,21 +45,30 @@ function Aux_OnLoad() EnhTooltip.AddLine('Seen '..auction_count..' '..Aux_PluralizeIf('time', auction_count)..' at auction', nil, true) EnhTooltip.LineColor(0.5, 0.8, 0.1) - local market_value = Aux.history.get_market_value(item_key) + local market_value = Aux.history.market_value(item_key) + local trend_percentage = ceil((1 - trend) * 100) + local market_value_line if count == 1 then - EnhTooltip.AddLine('Market Value: '..Aux.util.money_string(market_value), nil, true) + market_value_line = 'Market Value: '..Aux.util.money_string(market_value) else - EnhTooltip.AddLine('Market Value: '..Aux.util.money_string(market_value * count)..' / '..Aux.util.money_string(market_value), nil, true) + market_value_line = 'Market Value: '..Aux.util.money_string(market_value * count)..' / '..Aux.util.money_string(market_value) + if trend_percentage > 0 then + market_value_line = market_value_line..' ('..GREEN_FONT_COLOR_CODE..'+'..trend_percentage..'%'..GREEN_COLOR_CODE_CLOSE..')' + elseif trend_percentage < 0 then + market_value_line = market_value_line..' ('..RED_FONT_COLOR_CODE..trend_percentage..'%'..FONT_COLOR_CODE_CLOSE..')' + end end + EnhTooltip.AddLine(market_value_line, nil, true) EnhTooltip.LineColor(0.1,0.8,0.5) -- EnhTooltip.AddLine('TDA: '..(TDA > 0 and Aux.util.money_string(TDA) or RED_FONT_COLOR_CODE..'n/a'..FONT_COLOR_CODE_CLOSE), nil, true) -- EnhTooltip.LineColor(0.1,0.8,0.5) --- EnhTooltip.AddLine('EMA5: '..(EMA5 > 0 and Aux.util.money_string(EMA5) or RED_FONT_COLOR_CODE..'n/a'..FONT_COLOR_CODE_CLOSE), nil, true) +-- EnhTooltip.AddLine('EMA7: '..(EMA7 > 0 and Aux.util.money_string(EMA7) or RED_FONT_COLOR_CODE..'n/a'..FONT_COLOR_CODE_CLOSE), nil, true) -- EnhTooltip.LineColor(0.1,0.8,0.5) --- EnhTooltip.AddLine('EMA30: '..(EMA30 > 0 and Aux.util.money_string(EMA30) or RED_FONT_COLOR_CODE..'n/a'..FONT_COLOR_CODE_CLOSE), nil, true) +-- EnhTooltip.AddLine('Trend: '..trend_percentage..'%', nil, true) +-- EnhTooltip.LineColor(0.1,0.8,0.5) +-- EnhTooltip.AddLine('SD: '..sqrt(variance), nil, true) -- EnhTooltip.LineColor(0.1,0.8,0.5) - end end) end diff --git a/filter_search_frame.lua b/filter_search_frame.lua index 37729fc..436795d 100644 --- a/filter_search_frame.lua +++ b/filter_search_frame.lua @@ -134,15 +134,15 @@ public.views = { title = 'Pct', width = 40, comparator = function(group1, group2) - local market_price1 = Aux.history.get_market_value(group1[1].item_key) - local market_price2 = Aux.history.get_market_value(group2[1].item_key) + local market_price1 = Aux.history.market_value(group1[1].item_key) + local market_price2 = Aux.history.market_value(group2[1].item_key) local factor1 = market_price1 > 0 and group1[1].buyout_price_per_unit / market_price1 local factor2 = market_price2 > 0 and group2[1].buyout_price_per_unit / market_price2 return Aux.util.compare(factor1, factor2, Aux.util.GT) end, cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), cell_setter = function(cell, group) - local market_price = Aux.history.get_market_value(group[1].item_key) + local market_price = Aux.history.market_value(group[1].item_key) local pct = market_price > 0 and ceil(100 / market_price * group[1].buyout_price_per_unit) if not pct then @@ -487,15 +487,15 @@ public.views = { title = 'Pct', width = 40, comparator = function(row1, row2) - local market_price1 = Aux.history.get_market_value(row1.item_key) - local market_price2 = Aux.history.get_market_value(row2.item_key) + local market_price1 = Aux.history.market_value(row1.item_key) + local market_price2 = Aux.history.market_value(row2.item_key) local factor1 = market_price1 > 0 and row1.buyout_price_per_unit and row1.buyout_price_per_unit / market_price1 local factor2 = market_price2 > 0 and row2.buyout_price_per_unit and row2.buyout_price_per_unit / market_price2 return Aux.util.compare(factor1, factor2, Aux.util.GT) end, cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), cell_setter = function(cell, datum) - local market_price = Aux.history.get_market_value(datum.item_key) + local market_price = Aux.history.market_value(datum.item_key) local pct = market_price > 0 and datum.buyout_price_per_unit and ceil(100 / market_price * datum.buyout_price_per_unit) if not pct then diff --git a/history.lua b/history.lua index 7aa82a0..df00e81 100644 --- a/history.lua +++ b/history.lua @@ -2,7 +2,7 @@ local private, public = {}, {} Aux.history = public private.PUSH_INTERVAL = 57600 -private.NEW_RECORD = '0#0#0#0#' +private.NEW_RECORD = '0#0#0#1#0#' function private.load_data() local dataset = Aux.persistence.load_dataset() @@ -10,15 +10,16 @@ function private.load_data() return dataset.history end -function public.read_record(item_key) +function private.read_record(item_key) local data = private.load_data() local record = Aux.persistence.deserialize(data.item_data[item_key] or private.NEW_RECORD, '#') return { auction_count = tonumber(record[1]), day_count = tonumber(record[2]), - EMA5 = tonumber(record[3]), - EMA30 = tonumber(record[4]), - histogram = Aux.util.map(Aux.persistence.deserialize(record[5], ';', 'x'), function(value) + EMA7 = tonumber(record[3]), + trend = tonumber(record[4]), + variance = tonumber(record[5]), + histogram = Aux.util.map(Aux.persistence.deserialize(record[6], ';', 'x'), function(value) return tonumber(value) end), } @@ -29,8 +30,9 @@ function private.write_record(item_key, record) data.item_data[item_key] = Aux.persistence.serialize({ record.auction_count, record.day_count, - record.EMA5, - record.EMA30, + record.EMA7, + record.trend, + record.variance, Aux.persistence.serialize(record.histogram, ';', 'x'), },'#') end @@ -49,7 +51,7 @@ function public.process_auction(auction_info) local buyout = auction_info.buyout_price / auction_info.aux_quantity - local item_record = public.read_record(auction_info.item_key) + local item_record = private.read_record(auction_info.item_key) item_record.auction_count = item_record.auction_count + 1 @@ -64,18 +66,18 @@ function public.process_auction(auction_info) private.write_record(auction_info.item_key, item_record) end -function public.get_price_data(item_key) - local item_record = public.read_record(item_key) - return item_record.auction_count, item_record.day_count, private.daily_market_value(item_record.histogram), item_record.EMA5, item_record.EMA30 +function public.price_data(item_key) + local item_record = private.read_record(item_key) + return item_record.auction_count, item_record.day_count, private.daily_market_value(item_record.histogram), item_record.EMA7, item_record.trend, item_record.variance end -function public.get_market_value(item_key) - local auction_count, day_count, daily_market_value, EMA5, EMA30 = public.get_price_data(item_key) +function public.market_value(item_key) + local auction_count, day_count, daily_market_value, EMA7, trend, variance = public.price_data(item_key) if day_count == 0 then return daily_market_value else - return EMA5 + return EMA7 * trend end end @@ -110,18 +112,23 @@ function private.push_data() for item_key, _ in pairs(item_data) do - local item_record = public.read_record(item_key) + local item_record = private.read_record(item_key) if getn(item_record.histogram) ~= 0 then local daily_market_value = private.daily_market_value(item_record.histogram) if item_record.day_count == 0 then - item_record.EMA5 = daily_market_value - item_record.EMA30 = daily_market_value + item_record.EMA7 = daily_market_value + item_record.trend = 1 + item_record.variance = 0 else - item_record.EMA5 = 2/3 * item_record.EMA5 + 1/3 * daily_market_value - item_record.EMA30 = 13/14 * item_record.EMA30 + 1/14 * daily_market_value + local new_trend = daily_market_value / item_record.EMA7 + local new_variance = (daily_market_value - item_record.EMA7) ^ 2 + + item_record.EMA7 = 3/4 * item_record.EMA7 + 1/4 * daily_market_value + item_record.trend = 3/4 * item_record.trend + 1/4 * new_trend + item_record.variance = 3/4 * item_record.variance + 1/4 * new_variance end item_record.day_count = item_record.day_count + 1 @@ -134,7 +141,7 @@ function private.push_data() data.next_push = time() + private.PUSH_INTERVAL end ---function private.max_heap(array) +--function private.max_heap(array) -- might use a max heap to keep track of the n smallest values of the day instead of the histogram calculation -- local self = {} -- -- local ROOT = 1 @@ -160,7 +167,6 @@ end -- end -- -- function self.extract(signature) --- return data[signature] ~= nil and data[signature] >= time() -- end -- -- return self diff --git a/item_search_frame.lua b/item_search_frame.lua index 607c58b..6899d6e 100644 --- a/item_search_frame.lua +++ b/item_search_frame.lua @@ -147,15 +147,15 @@ public.views = { title = 'Pct', width = 40, comparator = function(group1, group2) - local market_price1 = Aux.history.get_market_value(group1[1].item_key) - local market_price2 = Aux.history.get_market_value(group2[1].item_key) + local market_price1 = Aux.history.market_value(group1[1].item_key) + local market_price2 = Aux.history.market_value(group2[1].item_key) local factor1 = market_price1 > 0 and group1[1].buyout_price_per_unit / market_price1 local factor2 = market_price2 > 0 and group2[1].buyout_price_per_unit / market_price2 return Aux.util.compare(factor1, factor2, Aux.util.GT) end, cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), cell_setter = function(cell, group) - local market_price = Aux.history.get_market_value(group[1].item_key) + local market_price = Aux.history.market_value(group[1].item_key) local pct = market_price > 0 and ceil(100 / market_price * group[1].buyout_price_per_unit) if not pct then @@ -426,15 +426,15 @@ public.views = { title = 'Pct', width = 40, comparator = function(row1, row2) - local market_price1 = Aux.history.get_market_value(row1.item_key) - local market_price2 = Aux.history.get_market_value(row2.item_key) + local market_price1 = Aux.history.market_value(row1.item_key) + local market_price2 = Aux.history.market_value(row2.item_key) local factor1 = market_price1 > 0 and row1.buyout_price_per_unit and row1.buyout_price_per_unit / market_price1 local factor2 = market_price2 > 0 and row2.buyout_price_per_unit and row2.buyout_price_per_unit / market_price2 return Aux.util.compare(factor1, factor2, Aux.util.GT) end, cell_initializer = Aux.sheet.default_cell_initializer('RIGHT'), cell_setter = function(cell, datum) - local market_price = Aux.history.get_market_value(datum.item_key) + local market_price = Aux.history.market_value(datum.item_key) local pct = market_price > 0 and datum.buyout_price_per_unit and ceil(100 / market_price * datum.buyout_price_per_unit) if not pct then diff --git a/scan.lua b/scan.lua index 494df50..9f2dd6b 100644 --- a/scan.lua +++ b/scan.lua @@ -151,7 +151,6 @@ function scan_auctions_helper(i, n, k) if not snapshot.contains(auction_info.signature) then snapshot.add(auction_info.signature, auction_info.duration) Aux.history.process_auction(auction_info) --- Aux.stat_histogram.process_auction(auction_info) end else recurse() diff --git a/slash.lua b/slash.lua index d859d9e..e07e0a2 100644 --- a/slash.lua +++ b/slash.lua @@ -6,11 +6,8 @@ function SlashCmdList.AUX(parameter) Aux.persistence.load_dataset().snapshot = {} Aux.log('Snapshot cleared.') elseif parameter == 'clear history' then - Aux.persistence.load_dataset().stat_average_data = {} + Aux.persistence.load_dataset().history = {} Aux.log('History cleared.') - elseif parameter == 'clear histogram' then - Aux.persistence.load_dataset().stat_histogram_data = {} - Aux.log('Histogram data cleared.') elseif parameter == 'clear' then aux_database = {} Aux.log('Database cleared.') diff --git a/stat_histogram.lua b/stat_histogram.lua deleted file mode 100644 index 82b659c..0000000 --- a/stat_histogram.lua +++ /dev/null @@ -1,180 +0,0 @@ -local private, public = {}, {} -Aux.stat_histogram = public - -private.NEW_RECORD = '0:0:0:0:' - -function private.load_data() - local dataset = Aux.persistence.load_dataset() - dataset.stat_histogram_data = dataset.stat_histogram_data or { item_data = {} } - return dataset.stat_histogram_data -end - -function private.read_current_record(item_key) - if private.current_item_key ~= item_key then - local data = private.load_data() - local record = Aux.persistence.deserialize(data.item_data[item_key] or private.NEW_RECORD, ':') - private.current_record = { - min = tonumber(record[1]), - max = tonumber(record[2]), - step = tonumber(record[3]), - count = tonumber(record[4]), - } - private.current_record.values = {} - for i=5, getn(record) do - private.current_record.values[private.current_record.min - 5 + i] = tonumber(record[i]) - end - private.current_item_key = item_key - end -end - -function private.write_current_record() - local data = private.load_data() - - local values = {} - for i=private.current_record.min,private.current_record.max do - tinsert(values, private.current_record.values[i]) - end - - data.item_data[private.current_item_key] = Aux.persistence.serialize({ - private.current_record.min, - private.current_record.max, - private.current_record.step, - private.current_record.count, - Aux.persistence.serialize(values, ':'), - }, ':') -end - -function public.get_price_data(item_key) - private.read_current_record(item_key) - - local median = 0 - local Q1 = 0 - local Q3 = 0 - local percent40 = 0 - local percent30 = 0 - local recount = 0 - - if private.current_record.min == private.current_record.max then - median = private.current_record.min * private.current_record.step - else - for i = private.current_record.min, private.current_record.max do - recount = recount + private.current_record.values[i] - if Q1 == 0 and private.current_record.count > 4 then -- Q1 is meaningless with very little data - if recount >= private.current_record.count / 4 then - Q1 = i * private.current_record.step - end - end - if percent30 == 0 then - if recount >= private.current_record.count * 0.3 then - percent30 = i * private.current_record.step - end - end - if percent40 == 0 then - if recount >= private.current_record.count * 0.4 then - percent40 = i * private.current_record.step - end - end - if median == 0 then - if recount >= private.current_record.count / 2 then - median = i * private.current_record.step - end - end - if Q3 == 0 and private.current_record.count > 4 then -- Q3 is meaningless with very little data - if recount >= private.current_record.count * 3 / 4 then - Q3 = i * private.current_record.step - end - end - end - end - - return median, Q1, Q3, percent30, percent40, private.current_record.count, private.current_record.step -end - -function public.process_auction(auction_info) - - if auction_info.buyout_price == 0 then - return - end - - private.read_current_record(auction_info.item_key) - - local buyout = auction_info.buyout_price / auction_info.aux_quantity - - if private.current_record.count == 0 then - private.current_record.step = ceil(buyout / 100) - end - - local index = ceil(buyout / private.current_record.step) - - if private.current_record.count <= 20 and index > 100 then - private.refactor(buyout, 100) - index = 100 - end - - if private.current_record.count <= 20 or index <= 300 then - - if private.current_record.min == 0 then - private.current_record.min = index - private.current_record.max = index - private.current_record.values[index] = 0 - elseif private.current_record.min > index then - for i = index, private.current_record.min - 1 do - private.current_record.values[i] = 0 - end - private.current_record.min = index - elseif private.current_record.max < index then - for i = private.current_record.max + 1, index do - private.current_record.values[i] = 0 - end - private.current_record.max = index - end - - private.current_record.values[index] = private.current_record.values[index] + 1 - private.current_record.count = private.current_record.count + 1 - - local median = public.get_price_data(auction_info.item_key) - - local step_too_small = private.current_record.step < median / 115 - local step_too_large = private.current_record.step > median / 85 and private.current_record.step > 1 - if private.current_record.count > 20 and (step_too_small or step_too_large) then - private.refactor(median, 100) - end - - private.write_current_record() - end -end - -function private.refactor(pmax, precision) - - local new_step = ceil(pmax / precision) - - if private.current_record.min == 0 then - return - end - - local conversion = private.current_record.step / new_step - local new_min = ceil(conversion * private.current_record.min) - local new_max = ceil(conversion * private.current_record.max) - local new_values = {} - - if new_max > 300 then - --we need to crop off the top end - new_max = 300 - private.current_record.max = floor(300 / conversion) - end - for i = new_min, new_max do - new_values[i] = 0 - end - local new_count = 0 - for i = private.current_record.min, private.current_record.max do - local j = ceil(conversion * i) - new_values[j] = new_values[j] + private.current_record.values[i] - new_count = new_count + private.current_record.values[i] - end - - private.current_record.min = new_min - private.current_record.max = new_max - private.current_record.step = new_step - private.current_record.count = new_count - private.current_record.values = new_values -end \ No newline at end of file