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  }