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  }