Skip to content

Commit e30ae13

Browse files
refactor: move yahoo price monitor
1 parent c9eed66 commit e30ae13

File tree

13 files changed

+157
-80
lines changed

13 files changed

+157
-80
lines changed

internal/common/common.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,8 @@ type Currency struct {
155155
FromCurrencyCode string
156156
// CodeConverted is the currency code that pricing and values have been converted into
157157
ToCurrencyCode string
158+
// Rate is the conversion rate from the original currency to the converted currency
159+
Rate float64
158160
}
159161

160162
type QuotePrice struct {

internal/monitor/monitor.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99

1010
c "github.com/achannarasappa/ticker/v4/internal/common"
1111
monitorCoinbase "github.com/achannarasappa/ticker/v4/internal/monitor/coinbase"
12-
monitorYahoo "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo"
12+
monitorPriceYahoo "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/monitor-price"
1313
)
1414

1515
// Monitor represents an overall monitor which manages API specific monitors
@@ -28,9 +28,8 @@ type Monitor struct {
2828

2929
// ConfigMonitor represents the configuration for the main monitor
3030
type ConfigMonitor struct {
31-
Reference c.Reference
32-
Config c.Config
33-
ErrorLogger *log.Logger
31+
RefreshInterval int
32+
ErrorLogger *log.Logger
3433
}
3534

3635
// ConfigUpdateFns represents the callback functions for when asset quotes are updated
@@ -56,12 +55,12 @@ func NewMonitor(configMonitor ConfigMonitor) (*Monitor, error) {
5655
ChanUpdateAssetQuote: chanUpdateAssetQuote,
5756
},
5857
monitorCoinbase.WithStreamingURL("wss://ws-feed.exchange.coinbase.com"),
59-
monitorCoinbase.WithRefreshInterval(time.Duration(configMonitor.Config.RefreshInterval)*time.Second),
58+
monitorCoinbase.WithRefreshInterval(time.Duration(configMonitor.RefreshInterval)*time.Second),
6059
)
6160

62-
var yahoo *monitorYahoo.MonitorYahoo
63-
yahoo = monitorYahoo.NewMonitorYahoo(
64-
monitorYahoo.Config{
61+
var yahoo *monitorPriceYahoo.MonitorYahoo
62+
yahoo = monitorPriceYahoo.NewMonitorYahoo(
63+
monitorPriceYahoo.Config{
6564
Ctx: ctx,
6665
UnaryURL: "https://query1.finance.yahoo.com",
6766
SessionRootURL: "https://finance.yahoo.com",
@@ -70,7 +69,7 @@ func NewMonitor(configMonitor ConfigMonitor) (*Monitor, error) {
7069
ChanError: chanError,
7170
ChanUpdateAssetQuote: chanUpdateAssetQuote,
7271
},
73-
monitorYahoo.WithRefreshInterval(time.Duration(configMonitor.Config.RefreshInterval)*time.Second),
72+
monitorPriceYahoo.WithRefreshInterval(time.Duration(configMonitor.RefreshInterval)*time.Second),
7473
)
7574

7675
m := &Monitor{

internal/monitor/yahoo/fixtures_test.go renamed to internal/monitor/yahoo/monitor-price/fixtures_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package monitorYahoo_test
1+
package monitorPriceYahoo_test
22

33
import (
44
"github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/unary"

internal/monitor/yahoo/monitor.go renamed to internal/monitor/yahoo/monitor-price/monitor.go

Lines changed: 74 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package monitorYahoo
1+
package monitorPriceYahoo
22

33
import (
44
"context"
@@ -8,7 +8,7 @@ import (
88
"time"
99

1010
c "github.com/achannarasappa/ticker/v4/internal/common"
11-
poller "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/poller"
11+
poller "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/monitor-price/poller"
1212
unary "github.com/achannarasappa/ticker/v4/internal/monitor/yahoo/unary"
1313
)
1414

@@ -18,24 +18,23 @@ type MonitorYahoo struct {
1818
poller *poller.Poller
1919
unary *unary.UnaryAPI
2020
input input
21-
productIds []string // Yahoo APIs refer to trading pairs as Product IDs which symbols ticker accepts with a -USD suffix
22-
productIdsPolling []string
21+
symbols []string
22+
symbolToCurrency map[string]string // Map of symbols to currency
2323
assetQuotesCache []c.AssetQuote // Asset quotes for all assets retrieved at start or on symbol change
2424
assetQuotesCacheLookup map[string]*c.AssetQuote // Asset quotes for all assets retrieved at least once (symbol change does not remove symbols)
2525
chanPollUpdateAssetQuote chan c.MessageUpdate[c.AssetQuote]
26-
27-
chanError chan error
28-
mu sync.RWMutex
29-
ctx context.Context
30-
cancel context.CancelFunc
31-
isStarted bool
32-
chanUpdateAssetQuote chan c.MessageUpdate[c.AssetQuote]
26+
chanError chan error
27+
mu sync.RWMutex
28+
ctx context.Context
29+
cancel context.CancelFunc
30+
isStarted bool
31+
chanUpdateAssetQuote chan c.MessageUpdate[c.AssetQuote]
3332
}
3433

3534
// input represents user input for the Yahoo monitor with any transformation
3635
type input struct {
37-
productIds []string
38-
productIdsLookup map[string]bool
36+
symbols []string
37+
symbolsLookup map[string]bool
3938
}
4039

4140
// Config contains the required configuration for the Yahoo monitor
@@ -65,6 +64,7 @@ func NewMonitorYahoo(config Config, opts ...Option) *MonitorYahoo {
6564

6665
monitor := &MonitorYahoo{
6766
assetQuotesCacheLookup: make(map[string]*c.AssetQuote),
67+
symbolToCurrency: make(map[string]string),
6868
assetQuotesCache: make([]c.AssetQuote, 0),
6969
chanPollUpdateAssetQuote: make(chan c.MessageUpdate[c.AssetQuote]),
7070
chanError: config.ChanError,
@@ -115,32 +115,38 @@ func (m *MonitorYahoo) GetAssetQuotes(ignoreCache ...bool) ([]c.AssetQuote, erro
115115
}
116116

117117
// SetSymbols sets the symbols to monitor
118-
func (m *MonitorYahoo) SetSymbols(productIds []string, nonce int) error {
118+
func (m *MonitorYahoo) SetSymbols(symbols []string, nonce int) error {
119119

120120
var err error
121121

122122
m.mu.Lock()
123123

124-
// Deduplicate productIds since input may have duplicates
125-
slices.Sort(productIds)
126-
m.productIds = slices.Compact(productIds)
127-
m.productIdsPolling = m.productIds
128-
m.input.productIds = productIds
129-
m.input.productIdsLookup = make(map[string]bool)
130-
for _, productId := range productIds {
131-
m.input.productIdsLookup[productId] = true
124+
// Deduplicate symbols since input may have duplicates
125+
slices.Sort(symbols)
126+
m.symbols = slices.Compact(symbols)
127+
m.input.symbols = symbols
128+
m.input.symbolsLookup = make(map[string]bool)
129+
for _, symbol := range symbols {
130+
m.input.symbolsLookup[symbol] = true
132131
}
133132

134133
m.mu.Unlock()
135134

135+
// Check for symbols which don't have a known currency and retrieve the currency for those symbols
136+
// TODO: conditionally bypass if currency conversion is not enabled
137+
// err = m.getCurrencyForEachSymbolAndUpdateCurrencyMap()
138+
// if err != nil {
139+
// return err
140+
// }
141+
136142
// Since the symbols have changed, make a synchronous call to get price quotes for the new symbols
137143
_, err = m.getAssetQuotesAndReplaceCache()
138144
if err != nil {
139145
return err
140146
}
141147

142148
// Set the symbols to monitor on the poller
143-
m.poller.SetSymbols(m.productIdsPolling, nonce)
149+
m.poller.SetSymbols(m.symbols, nonce)
144150

145151
return nil
146152

@@ -254,7 +260,7 @@ func (m *MonitorYahoo) handleUpdates() {
254260
func (m *MonitorYahoo) getAssetQuotesAndReplaceCache() ([]c.AssetQuote, error) {
255261

256262
// Make a synchronous call to get price quotes
257-
assetQuotes, assetQuotesByProductId, err := m.unaryAPI.GetAssetQuotes(m.productIds)
263+
assetQuotes, assetQuotesByProductId, err := m.unaryAPI.GetAssetQuotes(m.symbols)
258264
if err != nil {
259265
return []c.AssetQuote{}, err
260266
}
@@ -268,3 +274,47 @@ func (m *MonitorYahoo) getAssetQuotesAndReplaceCache() ([]c.AssetQuote, error) {
268274

269275
return m.assetQuotesCache, nil
270276
}
277+
278+
func (m *MonitorYahoo) getCurrencyForEachSymbolAndUpdateCurrencyMap() error {
279+
// No need to process if no symbols are provided
280+
if len(m.symbols) == 0 {
281+
return nil
282+
}
283+
284+
symbolsWithoutCurrency := make([]string, 0)
285+
286+
// Check if symbols already have a currency mapping
287+
for _, symbol := range m.symbols {
288+
if _, exists := m.symbolToCurrency[symbol]; !exists {
289+
symbolsWithoutCurrency = append(symbolsWithoutCurrency, symbol)
290+
}
291+
}
292+
293+
// Get currency information for each symbol
294+
symbolToCurrency, err := m.unaryAPI.GetCurrencyMap(symbolsWithoutCurrency)
295+
if err != nil {
296+
return fmt.Errorf("failed to get currency information: %w", err)
297+
}
298+
299+
m.mu.Lock()
300+
defer m.mu.Unlock()
301+
302+
// Update currency information in the existing asset quotes cache
303+
for symbol, currency := range symbolToCurrency {
304+
m.symbolToCurrency[symbol] = currency.FromCurrency
305+
}
306+
307+
return nil
308+
}
309+
310+
// GetCurrencyRates accepts an array of ISO 4217 currency codes and a target ISO 4217 currency code and returns a conversion rate for each of the input currencies to the target currency
311+
func (m *MonitorYahoo) GetCurrencyRates(inputCurrencies []string, targetCurrency string) (c.CurrencyRates, error) {
312+
313+
// currencyRates, err := m.unaryAPI.GetCurrencyRates(inputCurrencies, targetCurrency)
314+
// if err != nil {
315+
// return nil, fmt.Errorf("failed to get currency rates: %w", err)
316+
// }
317+
318+
// return currencyRates, nil
319+
return nil, nil
320+
}

internal/monitor/yahoo/monitor_suite_test.go renamed to internal/monitor/yahoo/monitor-price/monitor_suite_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package monitorYahoo_test
1+
package monitorPriceYahoo_test
22

33
import (
44
"testing"

0 commit comments

Comments
 (0)