Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change handling of outliers in price server #38

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions price-server/src/lib/statistics.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BigNumber } from 'bignumber.js'
import { num } from './num'

export function average(array: BigNumber[]): BigNumber {
export function average(array: BigNumber[], removeOutliers = false, threshold = 0.1): BigNumber {
if (!array || !array.length) {
throw new Error('empty array')
}
Expand All @@ -10,6 +10,27 @@ export function average(array: BigNumber[]): BigNumber {
return array[0]
}

if (removeOutliers === true && array.length >= 3) {
// remove outliers only if we have enough entries
// i.e. remove values that are 10% or more different from the median
const sortedArray = array.sort((a, b) => a.minus(b).toNumber())
const median = sortedArray[Math.floor(sortedArray.length / 2)]
const filteredArray = sortedArray.filter((x) => {
const dist = num(1.0).minus(x.dividedBy(median)).abs()

// 10% threshold
if (dist.isLessThanOrEqualTo(threshold)) {
return true
} else {
console.error(
`Skipping outlier ${x.toString()} with distance ${dist.toString()} from median ${median.toString()}`
)
return false
}
})
array = filteredArray
}

return array.reduce((a, b) => a.plus(b)).dividedBy(num(array.length))
}

Expand Down Expand Up @@ -62,6 +83,7 @@ export function hasOutliers(nums: BigNumber[], threshold = 0.1): boolean {
return false
}

let outliers = 0
const values = nums.slice().sort((a, b) => a.minus(b).toNumber())

for (let i = 0; i < values.length; i += 1) {
Expand All @@ -71,9 +93,13 @@ export function hasOutliers(nums: BigNumber[], threshold = 0.1): boolean {

// 3% threshold
if (dist.isGreaterThanOrEqualTo(threshold)) {
return true
outliers += 1
}
}

if (outliers > nums.length / 3) {
return true
}

return false
}
2 changes: 1 addition & 1 deletion price-server/src/provider/PricesProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export default class PricesProvider {
return {}
} else {
// ... return a unique object with the average
return { [key]: average(prices) }
return { [key]: average(prices, true) }
}
})
// Transform the array of objects to a single object
Expand Down