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  }