94 lines
2.7 KiB
Elixir
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
|