github.com/diadata-org/diadata@v1.4.593/pkg/utils/statistics.go (about) 1 package utils 2 3 import ( 4 "errors" 5 "math" 6 "sort" 7 ) 8 9 // DiscardOutliers discards every data point from @prices and @volumes that deviates from 10 // the price median by more than @basispoints basis points. 11 func DiscardOutliers(prices []float64, volumes []float64, basispoints float64) (newPrices []float64, newVolumes []float64, discarded []int, err error) { 12 if len(prices) != len(volumes) { 13 err = errors.New("number of prices does not equal number of volumes ") 14 return 15 } 16 median := ComputeMedian(prices) 17 threshold := basispoints * float64(0.0001) * median 18 for i := 0; i < len(prices); i++ { 19 if math.Abs(prices[i]-median) < threshold { 20 newPrices = append(newPrices, prices[i]) 21 newVolumes = append(newVolumes, volumes[i]) 22 } else { 23 discarded = append(discarded, i) 24 } 25 } 26 return 27 } 28 29 // ComputeMedian returns the median of @samples. 30 func ComputeMedian(samples []float64) (median float64) { 31 var length = len(samples) 32 if length > 0 { 33 sort.Float64s(samples) 34 if length%2 == 0 { 35 median = (samples[length/2-1] + samples[length/2]) / 2 36 } else { 37 median = samples[(length+1)/2-1] 38 } 39 } 40 return 41 } 42 43 // vwap returns the volume weighted average price for the slices @prices and @volumes. 44 func Vwap(prices []float64, volumes []float64) (float64, error) { 45 //log.Info("prices, volumes: ", prices, volumes) 46 if len(prices) != len(volumes) { 47 return 0, errors.New("number of prices does not equal number of volumes ") 48 } 49 avg := float64(0) 50 totalVolume := float64(0) 51 for i := 0; i < len(prices); i++ { 52 avg += prices[i] * math.Abs(volumes[i]) 53 totalVolume += math.Abs(volumes[i]) 54 } 55 if totalVolume > 0 { 56 return avg / totalVolume, nil 57 } else { 58 return 0, nil 59 } 60 }