summaryrefslogtreecommitdiffstats
path: root/filter.go
blob: e9153e4fb4fe0833f51e47c73d6efe787eac1c48 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (c) 2013-2024 by Michael Dvorkin and contributors. All Rights Reserved.
// Use of this source code is governed by a MIT-style license that can
// be found in the LICENSE file.

package mop

import (
	"strings"
	"strconv"
)

// Filter gets called to sort stock quotes by one of the columns. The
// setup is rather lengthy; there should probably be more concise way
// that uses reflection and avoids hardcoding the column names.
type Filter struct {
	profile *Profile // Pointer to where we store sort column and order.
}

// Returns new Filter struct.
func NewFilter(profile *Profile) *Filter {
	return &Filter{
		profile: profile,
	}
}

// Changes money and % notation to a plain float for math, comparisons.
func stringToNumber (numberString string) float64 {
	// If the string "$3.6B" is passed in, the returned float will be 3.6E+09.
	// If 0.03% is passed in, the returned float will be 0.03 (NOT 0.0003!).
	newString := strings.TrimSpace(numberString) // Take off whitespace.
	newString = strings.Replace(newString,"$","",1)      // Remove the $ symbol.
	newString = strings.Replace(newString,"%","",1)      // Remove the $ symbol.
	newString = strings.Replace(newString,"K","E+3",1)   // Thousand (kilo)
	newString = strings.Replace(newString,"M","E+6",1)   // Million
	newString = strings.Replace(newString,"B","E+9",1)   // Billion
	newString = strings.Replace(newString,"T","E+12",1)  // Trillion
	finalValue, _ := strconv.ParseFloat(newString, 64)
	return finalValue
}

// Apply builds a list of sort interface based on current sort
// order, then calls sort.Sort to do the actual job.
func (filter *Filter) Apply(stocks []Stock) []Stock {
	var filteredStocks []Stock

	for _, stock := range stocks {
		var values = make(map[string]interface{})
		// Make conversions from the strings to floats where necessary.
		values["ticker"]        = strings.TrimSpace(stock.Ticker) // Remains string
		values["last"]          = stringToNumber(stock.LastTrade)
		values["change"]        = stringToNumber(stock.Change)
		values["changePercent"] = stringToNumber(stock.ChangePct)
		values["open"]          = stringToNumber(stock.Open)
		values["low"]           = stringToNumber(stock.Low)
		values["high"]          = stringToNumber(stock.High)
		values["low52"]         = stringToNumber(stock.Low52)
		values["high52"]        = stringToNumber(stock.High52)
		values["dividend"]      = stringToNumber(stock.Dividend)
		values["yield"]         = stringToNumber(stock.Yield)
		values["mktCap"]        = stringToNumber(stock.MarketCap)
		values["mktCapX"]       = stringToNumber(stock.MarketCapX)
		values["volume"]        = stringToNumber(stock.Volume)
		values["avgVolume"]     = stringToNumber(stock.AvgVolume)
		values["pe"]            = stringToNumber(stock.PeRatio)
		values["peX"]           = stringToNumber(stock.PeRatioX)
		values["direction"]     = stock.Direction                 // Remains int.

		result, err := filter.profile.filterExpression.Evaluate(values)

		if err != nil {
                        // The filter isn't working, so reset to no filter.
                        filter.profile.Filter = ""
                        // Return an empty list.  The next main loop cycle will
                        // show unfiltered.
                        return filteredStocks
		}

		truthy, ok := result.(bool)

		if !ok {
                        // The filter isn't working, so reset to no filter.
                        filter.profile.Filter = ""
                        // Return an empty list.  The next main loop cycle will
                        // show unfiltered.
                        return filteredStocks
		}

		if truthy {
			filteredStocks = append(filteredStocks, stock)
		}
	}

	return filteredStocks
}