some scan/manage work

This commit is contained in:
Manuel Simon Hirsig
2015-10-29 00:42:51 +01:00
parent e89481f3b2
commit 1928799df6
11 changed files with 135 additions and 400 deletions
+21 -192
View File
@@ -7,7 +7,7 @@ Aux.history = {}
local process_auction, balanced_list, update_snapshot
local get_market_price, get_usable_median, get_historical_median, get_median, get_percentile
local price_cache
local auction_cache
function Aux.history.on_close()
@@ -26,7 +26,7 @@ function Aux.history.start_scan()
AuxHistoryScanButton:Hide()
AuxHistoryStopButton:Show()
price_cache = {}
auction_cache = {}
Aux.log('Scanning auctions ...')
Aux.scan.start{
@@ -39,12 +39,14 @@ function Aux.history.start_scan()
process_auction(i)
end,
on_complete = function()
process_scanned_prices()
process_scanned_auctions()
AuxHistoryStopButton:Hide()
AuxHistoryScanButton:Show()
end,
on_abort = function()
process_scanned_auctions()
AuxHistoryStopButton:Hide()
AuxHistoryScanButton:Show()
end,
@@ -59,8 +61,20 @@ function Aux.history.start_scan()
}
end
function process_scanned_prices()
for item_key, item_data in price_cache do
function process_scanned_auctions()
local time = time()
for item_key, auctions in pairs(auction_cache) do
local min_price, accumulated_price
for _, auction in ipairs(auctions) do
min_price = min_price and min(min_price, auction.price) or auction.price
accumulated_price = (accumulated_price or 0) + auction.price
end
Aux.persistence.store_scan_record(item_key, {
time = time,
count = getn(auctions),
min_price = min_price,
accumulated_price = accumulated_price,
})
end
end
@@ -76,192 +90,7 @@ function process_auction(index)
local price = ceil(buyout_price / aux_quantity)
local item_key = auction_info.item_signature
local signature = Aux.info.auction_signature(index)
scanned_signatures.add(signature)
local snapshot = Aux.persistence.get_snapshot()
if not snapshot.contains(signature) then
snapshot.add(signature)
local item_record = Aux.persistence.load_item_record(item_key)
item_record = item_record or {
count = 0,
accumulated_price = 0,
median_list = {},
}
local median_list = balanced_list(MAX_HISTORY_SIZE)
median_list.add_all(item_record.median_list)
median_list.add(price)
Aux.persistence.store_item_record(item_key, {
count = item_record.count + 1,
accumulated_price = item_record.accumulated_price + price,
median_list = median_list.values(),
})
end
auction_cache[item_key] = auction_cache[item_key] or {}
tinsert(auction_cache[item_key], { price=price })
end
end
function Aux.history.get_market_price(item_key)
local market_price
local item_record = Aux.persistence.load_item_record(item_key)
if item_record then
local median = get_usable_median(item_record.median_list)
if median then
market_price = median
elseif item_record.count > 0 then
market_price = item_record.accumulated_price / item_record.count
end
end
return market_price
end
function get_usable_median(values)
local median, count = get_median(values)
if count >= MIN_SEEN then
return median, count
end
end
function get_median(values)
return get_percentile(values, 0.5)
end
-- Return weighted average percentile such that returned value
-- is larger than or equal to (100*pct)% of the table values
-- 0 <= pct <= 1
function get_percentile(values, pct)
local _percentile = function(sorted_values, pct, first, last)
local f = (last - first) * pct + first
local i1, i2 = floor(f), ceil(f)
f = f - i1
return sorted_values[i1] * (1 - f) + sorted_values[i2] * f
end
local n = getn(values)
if n == 0 then
return 0, 0 -- if there is an empty table, returns median = 0, count = 0
elseif n == 1 then
return tonumber(values[1]), 1
end
-- The following calculations require a sorted table
table.sort(values)
-- Skip IQR calculations if table is too small to have outliers
if n <= 4 then
return _percentile(values, pct, 1, n), n
end
-- REWORK by Karavirs to use IQR*1.5 to ignore outliers
-- q1 is median 1st quartile q2 is median of set q3 is median of 3rd quartile iqr is q3 - q1
local q1 = _percentile(values, 0.25, 1, n)
local q3 = _percentile(values, 0.75, 1, n)
local iqr = (q3 - q1) * 1.5
local iqlow, iqhigh = q1 - iqr, q3 + iqr
-- Find first and last index to include in median calculation
local first, last = 1, n
-- Skip low outliers
while values[first] < iqlow do
first = first + 1
end
-- Skip high outliers
while values[last] > iqhigh do
last = last - 1
end
return _percentile(values, pct, first, last), last - first + 1
end
function balanced_list(max_size, cmp)
local self = {}
local values = {}
cmp = cmp or Aux.util.compare
function self.add(value)
local left = 1
local right = getn(values)
local middle_value
local middle
local destination
while left <= right do
middle = floor((right - left) / 2) + left
middle_value = values[middle]
if cmp(value, middle_value) == Aux.util.LT then
right = middle - 1
elseif cmp(value, middle_value) == Aux.util.GT then
left = middle + 1
else
destination = middle
break
end
end
destination = destination or left
tinsert(values, destination, value)
if max_size and getn(values) > max_size then
if destination <= floor(max_size / 2) + 1 then
tremove(values)
else
tremove(values, 1)
end
end
end
function self.add_all(array)
self.clear()
for _, value in ipairs(array) do
self.add(value)
end
end
function self.clear()
values = {}
end
function self.values()
local result = {}
for _, value in ipairs(values) do
tinsert(result, value)
end
return result
end
function self.size()
return getn(values)
end
function self.get(index)
return values[index]
end
function self.max_size()
return max_size
end
return self
end
function Aux.history.get_price_suggestion(key, quantity)
local market_price = Aux.history.get_market_price(key)
return market_price and market_price * quantity * UNDERCUT_FACTOR or 0
end