Skip to content

Commit

Permalink
[#11] Add Support For Fetching CryptoCurrency Prices
Browse files Browse the repository at this point in the history
Add a getDailyCryptoPrices function to the AlphaVantage module for
fetching prices for a cryptocurrency.

Have the fetchPrices function take a list of cryptocurrencies in
addition to the CommoditySymbols from a ledger file. It will split the
commodities into equities & cryptos and hit the appropriate AlphaVantage
route to get the prices.

Add a `cryptocurrencies` configuration option and `-c`/`--crypto` flags
to the exe, allowing users to specify the cryptocurrencies to fetch
prices for.

Eventually, we should ditch manual specification & use AlphaVantage's
supported Digital Currency list:
https://www.alphavantage.co/digital_currency_list/

Refs #11
  • Loading branch information
prikhi committed May 29, 2021
1 parent 116f476 commit b04550b
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 77 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## master

* Add support for fetching cryptocurrency prices with the `-c` flag and
`cryptocurrencies` config option.
* Add support for config file at `$XDG_CONFIG_HOME/hstockquotes/config.yaml`
with `api-key`, `exclude`, & `rate-limit` options.

Expand Down
20 changes: 18 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,19 @@ NOTE: hledger defines an `AUTO` commodity if you use the default commodity
directive(`D`).


### Cryptocurrencies

You can specify a list of cryptocurrencies that you wish to pull prices for
with the `-c` or `--crypto` flag. You can pass a comma-separated list of
currencies or pass the flag multiple times. We will split the commodities from
your journal file into a list of equities & cryptocurrencies and hit the
appropriate AlphaVantage route for each.

```sh
hledger-stockquotes -a MY_API_KEY -c BTC,ETH --crypto XMR -c BNB
```


### API Limits

AlphaVantage has an API request limit of 5 requests per minute.
Expand All @@ -75,15 +88,18 @@ ranges that would be queried instead of making requests to AlphaVantage.
`$XDG_CONFIG_HOME/hledger-stockquotes/config.yaml`(`$XDG_CONFIG_HOME` is
usually `~/.config/`).

You can set the `api-key`, `rate-limit`, & `exclude` options via this file:
You can set the `api-key`, `rate-limit`, `cryptocurrencies`, & `exclude`
options via this file:

```yaml
rate-limit: false
api-key: DeAdBeEf9001
crypto-currencies:
- BTC
- XMR
exclude:
- USD
- AUTO
- BTC
```
CLI flags & environmental variables will override config file settings.
Expand Down
71 changes: 54 additions & 17 deletions app/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Data.Aeson ( (.:?)
, FromJSON(..)
, withObject
)
import Data.List ( partition )
import Data.Maybe ( fromMaybe )
import Data.Time ( Day
, defaultTimeLocale
Expand Down Expand Up @@ -49,7 +50,7 @@ import System.IO ( hPutStrLn

import Hledger.StockQuotes
import Paths_hledger_stockquotes ( version )
import Web.AlphaVantage ( Config(..) )
import Web.AlphaVantage

import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as T
Expand All @@ -66,7 +67,12 @@ main = do
journalFile
if not dryRun
then do
prices <- fetchPrices cfg commodities start end rateLimit
prices <- fetchPrices cfg
commodities
cryptoCurrencies
start
end
rateLimit
if null prices
then logError "No price directives were able to be fetched."
else LBS.writeFile outputFile $ makePriceDirectives prices
Expand All @@ -76,9 +82,12 @@ main = do
<> showDate start
<> " to "
<> showDate end
putStrLn "Querying Commodities:"
forM_ commodities
$ \commodity -> putStrLn $ "\t" <> T.unpack commodity
let (stocks, cryptos) =
partition (`notElem` cryptoCurrencies) commodities
putStrLn "Querying Stocks:"
forM_ stocks $ \commodity -> putStrLn $ "\t" <> T.unpack commodity
putStrLn "Querying CryptoCurrencies:"
forM_ cryptos $ \commodity -> putStrLn $ "\t" <> T.unpack commodity
where
showDate :: Day -> String
showDate = formatTime defaultTimeLocale "%Y-%m-%d"
Expand All @@ -97,6 +106,7 @@ data AppConfig = AppConfig
, journalFile :: FilePath
, outputFile :: FilePath
, excludedCurrencies :: [String]
, cryptoCurrencies :: [T.Text]
, dryRun :: Bool
}
deriving (Show, Eq)
Expand Down Expand Up @@ -127,6 +137,9 @@ mergeArgsEnvCfg ConfigFile {..} Args {..} = do
if argExcludedCurrencies == defaultExcludedCurrencies
then fromMaybe defaultExcludedCurrencies cfgExcludedCurrencies
else argExcludedCurrencies
cryptoCurrencies = if null argCryptoCurrencies
then maybe [] (map T.pack) cfgCryptoCurrencies
else concatMap (T.splitOn "," . T.pack) argCryptoCurrencies
outputFile = argOutputFile
dryRun = argDryRun
return AppConfig { .. }
Expand All @@ -136,6 +149,7 @@ data ConfigFile = ConfigFile
{ cfgApiKey :: Maybe String
, cfgRateLimit :: Maybe Bool
, cfgExcludedCurrencies :: Maybe [String]
, cfgCryptoCurrencies :: Maybe [String]
}
deriving (Show, Eq)

Expand All @@ -144,6 +158,7 @@ instance FromJSON ConfigFile where
cfgApiKey <- o .:? "api-key"
cfgRateLimit <- o .:? "rate-limit"
cfgExcludedCurrencies <- o .:? "exclude"
cfgCryptoCurrencies <- o .:? "cryptocurrencies"
return ConfigFile { .. }

loadConfigFile :: IO ConfigFile
Expand All @@ -160,7 +175,7 @@ loadConfigFile = do
else return defaultConfig
where
defaultConfig :: ConfigFile
defaultConfig = ConfigFile Nothing Nothing Nothing
defaultConfig = ConfigFile Nothing Nothing Nothing Nothing



Expand All @@ -170,6 +185,7 @@ data Args = Args
, argJournalFile :: Maybe FilePath
, argOutputFile :: FilePath
, argExcludedCurrencies :: [String]
, argCryptoCurrencies :: [String]
, argDryRun :: Bool
}
deriving (Data, Typeable, Show, Eq)
Expand Down Expand Up @@ -215,6 +231,14 @@ argSpec =
&= name "output-file"
&= name "o"
&= typ "FILE"
, argCryptoCurrencies =
[]
&= help
"Cryptocurrencies to fetch prices for. Flag can be passed multiple times."
&= explicit
&= name "c"
&= name "crypto"
&= typ "TICKER,..."
, argExcludedCurrencies = defaultExcludedCurrencies &= args &= typ
"EXCLUDED_CURRENCY ..."
, argDryRun =
Expand All @@ -240,14 +264,23 @@ argSpec =
, "By default, we find all non-USD commodities in your "
, "journal file and query AlphaVantage for their stock prices "
, "over the date range used in the journal file. Currently, we "
, "only support public U.S. equities & do not call out to AlphaVantage's"
, "FOREX or Crypto API routes. If you have commodities that are "
, "not supported by AlphaVantage, hledger-stockquotes will output "
, "an error when attempting to processing them. To avoid processing "
, "of unsupported currencies, you can pass in any commodities to "
, "exclude as arguments. If you use the default commodity directive "
, "in your journal file, hledger will include an `AUTO` commodity "
, "when parsing your journal."
, "only support public U.S. equities & cryptocurrencies & do "
, "not call out to AlphaVantage's FOREX API routes. "
, "If you have commodities that are not supported by AlphaVantage, "
, "hledger-stockquotes will output an error when attempting to "
, "processing them. To avoid processing of unsupported currencies, "
, "you can pass in any commodities to exclude as arguments."
, "If you use the default commodity directive in your journal file, "
, "hledger will include an `AUTO` commodity when parsing your journal."
, ""
, ""
, "CRYPTOCURRENCIES"
, ""
, "Use the `-c` flag to specify which commodities are cryptocurrencies. "
, "You can pass the flag multiple times or specify them as a "
, "comma-separated list. For the listed cryptocurrencies, we will "
, "hit AlphaVantage's Daily Crypto Prices API route instead of the "
, "normal Stock Prices route."
, ""
, ""
, "API LIMITS"
Expand Down Expand Up @@ -288,9 +321,10 @@ argSpec =
, "to parse a configuration file in $XDG_CONFIG_HOME/hledger-stockquotes/config.yaml. "
, "It currently supports the following top-level keys: "
, ""
, "- `api-key`: (string) Your AlphaVantage API Key"
, "- `exclude`: (list of strings) Currencies to Exclude"
, "- `rate-limit`: (bool) Obey AlphaVantage's Rate Limit"
, "- `api-key`: (string) Your AlphaVantage API Key"
, "- `cryptocurrencies`: (list of string) Cryptocurrencies to Fetch"
, "- `exclude`: (list of strings) Currencies to Exclude"
, "- `rate-limit`: (bool) Obey AlphaVantage's Rate Limit"
, ""
, "Environmental variables will overide any config file options, "
, "and CLI flags will override both environmental variables & "
Expand All @@ -305,6 +339,9 @@ argSpec =
, "Output prices into a custom journal file:"
, " hledger-stockquotes -a <your-api-key> -o prices/2021.journal"
, ""
, "Fetch prices for all commodities, including Bitcoin:"
, " hledger-stockquotes -a <your-api-key> -c BTC"
, ""
, "Ignore the default, foreign, & crypto commodities:"
, " hledger-stockquotes -a <your-api-key> AUTO BTC ETH EUR"
]
Loading

0 comments on commit b04550b

Please sign in to comment.