github.com/diadata-org/diadata@v1.4.593/internal/pkg/filtersBlockService/FilterVWAPIR.go (about) 1 package filters 2 3 import ( 4 "math" 5 "strconv" 6 "time" 7 8 "github.com/diadata-org/diadata/pkg/dia" 9 models "github.com/diadata-org/diadata/pkg/model" 10 log "github.com/sirupsen/logrus" 11 ) 12 13 // FilterVWAP ... 14 type FilterVWAPIR struct { 15 exchange string 16 currentTime time.Time 17 prices []float64 18 volumes []float64 19 lastTrade dia.Trade 20 param int 21 value float64 22 modified bool 23 filterName string 24 asset dia.Asset 25 nativeDenomination bool 26 } 27 28 func NewFilterVWAPIR(asset dia.Asset, exchange string, currentTime time.Time, param int, nativeDenomination bool) *FilterVWAPIR { 29 s := &FilterVWAPIR{ 30 asset: asset, 31 exchange: exchange, 32 prices: []float64{}, 33 volumes: []float64{}, 34 currentTime: currentTime, 35 param: param, 36 filterName: "VWAPIR" + strconv.Itoa(param), 37 nativeDenomination: nativeDenomination, 38 } 39 return s 40 } 41 42 func (s *FilterVWAPIR) Compute(trade dia.Trade) { 43 s.compute(trade) 44 } 45 46 func (filter *FilterVWAPIR) compute(trade dia.Trade) { 47 filter.modified = true 48 if filter.lastTrade != (dia.Trade{}) { 49 if trade.Time.Before(filter.currentTime) { 50 log.Errorln("FilterVWAPIR: Ignoring Trade out of order ", filter.currentTime, trade.Time) 51 return 52 } 53 } 54 filter.fill(trade) 55 filter.lastTrade = trade 56 } 57 58 // fill just adds a trade to the prices and volumes slices. 59 func (filter *FilterVWAPIR) fill(trade dia.Trade) { 60 // filter.currentTime is the timestamp of the last filled trade. 61 filter.processDataPoint(trade) 62 filter.currentTime = trade.Time 63 } 64 65 func (filter *FilterVWAPIR) processDataPoint(trade dia.Trade) { 66 if !filter.nativeDenomination { 67 filter.prices = append([]float64{trade.EstimatedUSDPrice}, filter.prices...) 68 } else { 69 filter.prices = append([]float64{trade.Price}, filter.prices...) 70 } 71 filter.volumes = append([]float64{trade.Volume}, filter.volumes...) 72 } 73 74 func (s *FilterVWAPIR) FinalCompute(t time.Time) float64 { 75 log.Info("final compute of time ", t) 76 return s.finalCompute(t) 77 } 78 79 func (s *FilterVWAPIR) finalCompute(t time.Time) float64 { 80 if s.lastTrade == (dia.Trade{}) { 81 return 0.0 82 } 83 84 if len(s.prices) == 0 { 85 return 0.0 86 } 87 88 if len(s.prices) < 2 { 89 s.value = s.prices[0] 90 return s.prices[0] 91 } 92 cleanPrices, bounds := removeOutliers(s.prices) 93 if len(bounds) < 2 { 94 return 0.0 95 } 96 97 cleanedVolumes := s.volumes[bounds[0]:bounds[1]] 98 99 priceVolume := []float64{} 100 for index, price := range cleanPrices { 101 priceVolume = append(priceVolume, price*math.Abs(cleanedVolumes[index])) 102 } 103 104 var total float64 = 0 105 var totalVolume float64 = 0 106 107 for _, v := range cleanedVolumes { 108 totalVolume += math.Abs(v) 109 } 110 111 for _, v := range priceVolume { 112 total += v 113 } 114 115 s.value = total / totalVolume 116 117 // Reset filters 118 s.prices = []float64{} 119 s.volumes = []float64{} 120 121 return s.value 122 } 123 124 func (s *FilterVWAPIR) FilterPointForBlock() *dia.FilterPoint { 125 return s.filterPointForBlock() 126 } 127 128 func (s *FilterVWAPIR) filterPointForBlock() *dia.FilterPoint { 129 if s.exchange != "" { 130 return &dia.FilterPoint{ 131 Value: s.value, 132 Name: s.filterName, 133 Time: s.currentTime, 134 Asset: s.asset, 135 } 136 } else { 137 return &dia.FilterPoint{ 138 Value: s.value, 139 Name: s.filterName, 140 Time: s.currentTime, 141 Asset: s.asset, 142 } 143 } 144 } 145 146 func (filter *FilterVWAPIR) save(ds models.Datastore) error { 147 if filter.modified { 148 filter.modified = false 149 err := ds.SetFilter(filter.filterName, filter.asset, filter.exchange, filter.value, filter.currentTime) 150 if err != nil { 151 log.Errorln("FilterVWAPIR: Error:", err) 152 } 153 return err 154 } else { 155 return nil 156 } 157 }