-
-
Notifications
You must be signed in to change notification settings - Fork 280
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: added support for CoinCap as a data source for crypto price quotes
- Loading branch information
1 parent
fb847bf
commit 987c9c9
Showing
11 changed files
with
221 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package coincap_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/go-resty/resty/v2" | ||
"github.com/jarcoal/httpmock" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
var client = resty.New() | ||
|
||
var _ = BeforeSuite(func() { | ||
httpmock.ActivateNonDefault(client.GetClient()) | ||
}) | ||
|
||
var _ = BeforeEach(func() { | ||
httpmock.Reset() | ||
}) | ||
|
||
var _ = AfterSuite(func() { | ||
httpmock.DeactivateAndReset() | ||
}) | ||
|
||
func TestQuote(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "CoinCap Quote Suite") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
package coincap_test | ||
|
||
import ( | ||
"net/http" | ||
|
||
"github.com/jarcoal/httpmock" | ||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
|
||
c "github.com/achannarasappa/ticker/internal/common" | ||
. "github.com/achannarasappa/ticker/internal/quote/coincap" | ||
g "github.com/onsi/gomega/gstruct" | ||
) | ||
|
||
var _ = Describe("CoinCap Quote", func() { | ||
Describe("GetAssetQuotes", func() { | ||
It("should make a request to get stock quotes and transform the response", func() { | ||
responseFixture := `{ | ||
"data": [ | ||
{ | ||
"id": "bitcoin", | ||
"rank": "1", | ||
"symbol": "BTC", | ||
"name": "Bitcoin", | ||
"supply": "19685775.0000000000000000", | ||
"maxSupply": "21000000.0000000000000000", | ||
"marketCapUsd": "1248489381324.9592799671502700", | ||
"volumeUsd24Hr": "7744198446.5431034815177485", | ||
"priceUsd": "63420.8905326287270868", | ||
"changePercent24Hr": "1.3622077494913284", | ||
"vwap24Hr": "62988.1090433238215198", | ||
"explorer": "https://blockchain.info/" | ||
} | ||
], | ||
"timestamp": 1714453771801 | ||
}` | ||
responseUrl := `=~\/v2\/assets.*ids\=bitcoin.*` | ||
httpmock.RegisterResponder("GET", responseUrl, func(req *http.Request) (*http.Response, error) { | ||
resp := httpmock.NewStringResponse(200, responseFixture) | ||
resp.Header.Set("Content-Type", "application/json") | ||
return resp, nil | ||
}) | ||
|
||
output := GetAssetQuotes(*client, []string{"bitcoin"}) | ||
Expect(output).To(g.MatchAllElementsWithIndex(g.IndexIdentity, g.Elements{ | ||
"0": g.MatchFields(g.IgnoreExtras, g.Fields{ | ||
"QuotePrice": g.MatchFields(g.IgnoreExtras, g.Fields{ | ||
"Price": Equal(63420.89053262873), | ||
"PricePrevClose": Equal(64284.8148182606), | ||
"PriceOpen": Equal(0.0), | ||
"PriceDayHigh": Equal(0.0), | ||
"PriceDayLow": Equal(0.0), | ||
"Change": Equal(863.9242856318742), | ||
"ChangePercent": Equal(1.3622077494913285), | ||
}), | ||
"QuoteSource": Equal(c.QuoteSourceCoinCap), | ||
"Exchange": g.MatchFields(g.IgnoreExtras, g.Fields{ | ||
"IsActive": BeTrue(), | ||
"IsRegularTradingSession": BeTrue(), | ||
}), | ||
}), | ||
})) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package coincap | ||
|
||
import ( | ||
"strconv" | ||
"strings" | ||
|
||
c "github.com/achannarasappa/ticker/internal/common" | ||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
// Quote represents a quote of a single security from the API response | ||
type Quote struct { | ||
ShortName string `json:"name"` | ||
Symbol string `json:"symbol"` | ||
RegularMarketChangePercent string `json:"changePercent24Hr"` | ||
RegularMarketPrice string `json:"priceUsd"` | ||
RegularMarketVolume string `json:"volumeUsd24Hr"` | ||
MarketCap string `json:"marketCapUsd"` | ||
} | ||
|
||
// Response represents the container object from the API response | ||
type Response struct { | ||
Data []Quote `json:"data"` | ||
} | ||
|
||
func transformQuote(responseQuote Quote) c.AssetQuote { | ||
|
||
price, _ := strconv.ParseFloat(responseQuote.RegularMarketPrice, 64) | ||
changePercent, _ := strconv.ParseFloat(responseQuote.RegularMarketChangePercent, 64) | ||
pricePrevClose := (1 + changePercent/100) * price | ||
marketCap, _ := strconv.ParseFloat(responseQuote.MarketCap, 64) | ||
volume, _ := strconv.ParseFloat(responseQuote.RegularMarketVolume, 64) | ||
|
||
assetQuote := c.AssetQuote{ | ||
Name: responseQuote.ShortName, | ||
Symbol: responseQuote.Symbol, | ||
Class: c.AssetClassCryptocurrency, | ||
Currency: c.Currency{ | ||
FromCurrencyCode: "USD", | ||
}, | ||
QuotePrice: c.QuotePrice{ | ||
Price: price, | ||
PricePrevClose: pricePrevClose, | ||
PriceOpen: 0.0, | ||
PriceDayHigh: 0.0, | ||
PriceDayLow: 0.0, | ||
Change: pricePrevClose - price, | ||
ChangePercent: changePercent, | ||
}, | ||
QuoteExtended: c.QuoteExtended{ | ||
FiftyTwoWeekHigh: 0.0, | ||
FiftyTwoWeekLow: 0.0, | ||
MarketCap: marketCap, | ||
Volume: volume, | ||
}, | ||
QuoteSource: c.QuoteSourceCoinCap, | ||
Exchange: c.Exchange{ | ||
Name: "Crypto Aggregate via CoinCap", | ||
Delay: 0, | ||
State: c.ExchangeStateOpen, | ||
IsActive: true, | ||
IsRegularTradingSession: true, | ||
}, | ||
Meta: c.Meta{ | ||
IsVariablePrecision: true, | ||
}, | ||
} | ||
|
||
return assetQuote | ||
|
||
} | ||
|
||
func transformQuotes(responseQuotes []Quote) []c.AssetQuote { | ||
|
||
quotes := make([]c.AssetQuote, 0) | ||
for _, responseQuote := range responseQuotes { | ||
quotes = append(quotes, transformQuote(responseQuote)) | ||
} | ||
|
||
return quotes | ||
|
||
} | ||
|
||
// GetAssetQuotes issues a HTTP request to retrieve quotes from the API and process the response | ||
func GetAssetQuotes(client resty.Client, symbols []string) []c.AssetQuote { | ||
symbolsString := strings.Join(symbols, ",") | ||
|
||
res, _ := client.R(). | ||
SetResult(Response{}). | ||
SetQueryParam("ids", strings.ToLower(symbolsString)). | ||
Get("https://api.coincap.io/v2/assets") | ||
|
||
return transformQuotes((res.Result().(*Response)).Data) //nolint:forcetypeassert | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,10 @@ func getPrecision(f float64) int { | |
return 3 | ||
} | ||
|
||
if v >= 1000 && f < 0 { | ||
return 1 | ||
} | ||
|
||
return 2 | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters