tradex/lib/tradex/yahoo_finance.ex

94 lines
2.7 KiB
Elixir

defmodule Tradex.YahooFinance do
@moduledoc """
Module to fetch historical stock quotes from Yahoo Finance's v8 API.
"""
@yahoo_finance_url "https://query1.finance.yahoo.com/v8/finance/chart/"
@doc """
Fetches historical stock quotes for a given symbol (ticker) within a date range.
## Parameters
- symbol: The stock symbol (e.g., "ADBE" for Adobe).
- start_date: The start date as a `DateTime`.
- end_date: The end date as a `DateTime`.
## Returns
- {:ok, list_of_quotes} on success.
- {:error, reason} on failure.
"""
def fetch_historical_quotes(symbol, start_date, end_date) do
# Convert dates to Unix timestamps
start_unix = DateTime.to_unix(start_date)
end_unix = DateTime.to_unix(end_date)
# Build the URL with query parameters
url = "#{@yahoo_finance_url}#{symbol}?period1=#{start_unix}&period2=#{end_unix}&interval=1d"
# Make the HTTP GET request
case HTTPoison.get(url) do
{:ok, %HTTPoison.Response{status_code: 200, body: body}} ->
# Parse the JSON response
parse_json(body)
{:ok, %HTTPoison.Response{status_code: status_code}} ->
{:error, "Failed to fetch data. Status code: #{status_code}"}
{:error, reason} ->
{:error, reason}
end
end
@doc """
Parses the JSON response from Yahoo Finance's v8 API into a list of maps.
## Parameters
- json_data: The JSON data as a string.
## Returns
- {:ok, list_of_quotes} if the JSON is valid.
- {:error, reason} if the JSON is invalid or an error occurs.
"""
defp parse_json(json_data) do
case Jason.decode(json_data) do
{:ok,
%{
"chart" => %{
"result" => [
%{
"timestamp" => timestamps,
"indicators" => %{
"quote" => [%{"open" => opens, "high" => highs, "low" => lows, "close" => closes, "volume" => volumes}],
"adjclose" => [%{"adjclose" => adj_closes}]
}
}
]
}
}} ->
# Combine the data into a list of maps
quotes =
[timestamps, opens, highs, lows, closes, adj_closes, volumes]
|> Enum.zip()
|> Enum.map(fn {timestamp, open, high, low, close, adj_close, volume} ->
%{
date: DateTime.from_unix!(timestamp),
open: open,
high: high,
low: low,
close: close,
adj_close: adj_close,
volume: volume
}
end)
{:ok, quotes}
{:ok, _} ->
{:error, "No data found in the response"}
{:error, reason} ->
{:error, "Failed to parse JSON response: #{reason}"}
end
end
end