github.com/diadata-org/diadata@v1.4.593/internal/pkg/filtersBlockService/FilterMEDIR.go (about) 1 package filters 2 3 import ( 4 "strconv" 5 "time" 6 7 "github.com/diadata-org/diadata/pkg/dia" 8 models "github.com/diadata-org/diadata/pkg/model" 9 log "github.com/sirupsen/logrus" 10 ) 11 12 // FilterMEDIR contains the configuration parameters of the filter. 13 // It implements a trimmed median. Outliers are eliminated using interquartile range 14 // see: https://en.wikipedia.org/wiki/Interquartile_range 15 type FilterMEDIR struct { 16 asset dia.Asset 17 exchange string 18 currentTime time.Time 19 prices []float64 20 lastTrade dia.Trade 21 memory int 22 value float64 23 filterName string 24 modified bool 25 nativeDenomination bool 26 } 27 28 // NewFilterMEDIR creates a FilterMEDIR 29 func NewFilterMEDIR(asset dia.Asset, exchange string, currentTime time.Time, memory int, nativeDenomination bool) *FilterMEDIR { 30 filter := &FilterMEDIR{ 31 asset: asset, 32 exchange: exchange, 33 prices: []float64{}, 34 currentTime: currentTime, 35 memory: memory, 36 filterName: "MEDIR" + strconv.Itoa(memory), 37 nativeDenomination: nativeDenomination, 38 } 39 return filter 40 } 41 42 func (filter *FilterMEDIR) compute(trade dia.Trade) { 43 filter.modified = true 44 if filter.lastTrade != (dia.Trade{}) { 45 if trade.Time.Before(filter.currentTime) { 46 log.Errorln("FilterMEDIR: Ignoring Trade out of order ", filter.currentTime, trade.Time) 47 return 48 } 49 } 50 filter.processDataPoint(trade) 51 filter.lastTrade = trade 52 filter.currentTime = trade.Time 53 } 54 55 func (filter *FilterMEDIR) Compute(trade dia.Trade) { 56 filter.compute(trade) 57 } 58 func (filter *FilterMEDIR) FinalCompute(t time.Time) { 59 filter.finalCompute(t) 60 } 61 62 func (filter *FilterMEDIR) processDataPoint(trade dia.Trade) { 63 /// first remove extra value from buffer if already full 64 if len(filter.prices) >= filter.memory { 65 filter.prices = filter.prices[0 : filter.memory-1] 66 } 67 if !filter.nativeDenomination { 68 filter.prices = append([]float64{trade.EstimatedUSDPrice}, filter.prices...) 69 } else { 70 filter.prices = append([]float64{trade.Price}, filter.prices...) 71 } 72 } 73 74 func (filter *FilterMEDIR) finalCompute(t time.Time) float64 { 75 if filter.lastTrade == (dia.Trade{}) { 76 log.Info("last trade emtpy") 77 return 0.0 78 } 79 cleanPrices, _ := removeOutliers(filter.prices) 80 filter.value = computeMedian(cleanPrices) 81 filter.prices = []float64{filter.lastTrade.EstimatedUSDPrice} 82 return filter.value 83 } 84 85 func (filter *FilterMEDIR) filterPointForBlock() *dia.FilterPoint { 86 if filter.exchange != "" || filter.filterName != dia.FilterKing { 87 return nil 88 } 89 return &dia.FilterPoint{ 90 Asset: filter.asset, 91 Value: filter.value, 92 Name: filter.filterName, 93 Time: filter.currentTime, 94 } 95 } 96 97 func (filter *FilterMEDIR) FilterPointForBlock() *dia.FilterPoint { 98 return &dia.FilterPoint{ 99 Asset: filter.asset, 100 Value: filter.value, 101 Name: filter.filterName, 102 Time: filter.currentTime, 103 } 104 } 105 func (filter *FilterMEDIR) save(ds models.Datastore) error { 106 if filter.modified { 107 filter.modified = false 108 err := ds.SetFilter(filter.filterName, filter.asset, filter.exchange, filter.value, filter.currentTime) 109 if err != nil { 110 log.Errorln("FilterMEDIR: Error:", err) 111 } 112 return err 113 } else { 114 return nil 115 } 116 }