Spaces:
Sleeping
Sleeping
File size: 2,559 Bytes
f2e9588 533ab64 dbff4bd 533ab64 dbff4bd 1670a39 dbff4bd 533ab64 f2e9588 533ab64 f2e9588 1670a39 d926132 1670a39 533ab64 4f627a5 533ab64 4f627a5 dbff4bd 533ab64 ac73d75 5dabbc5 dbff4bd 5dabbc5 dbff4bd 533ab64 dbff4bd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
import re
from collections.abc import Sequence
from datetime import timedelta
from typing import Any
import numpy as np
import pandas as pd
from dateutil import parser # type: ignore
def normalize_ticker_symbol(ticker_input: str) -> str:
"""Remove all non-alphanumeric characters from ticker input, return uppercase."""
return re.sub(r"[^A-Z0-9]", "", ticker_input.upper())
def get_available_tickers() -> list[str]:
"""This list is too limited, I opted for any input + validation in the app."""
nasdaq_url = "https://www.nasdaqtrader.com/dynamic/SymDir/nasdaqlisted.txt"
nyse_url = "https://www.nasdaqtrader.com/dynamic/SymDir/otherlisted.txt"
nasdaq_tickers = pd.read_csv(nasdaq_url, sep="|")["Symbol"].dropna().tolist()[:-1]
nyse_tickers = pd.read_csv(nyse_url, sep="|")["ACT Symbol"].dropna().tolist()[:-1]
all_tickers = sorted(set(nasdaq_tickers + nyse_tickers)) # type: ignore
return all_tickers
def date_to_idx_range(timestamps: pd.DatetimeIndex, date_range: Sequence[Any]) -> tuple[int, int]:
if all(date_range):
idx0, idx1 = timestamps.get_indexer(date_range, method="nearest")
return (idx0, idx1)
else:
return (0, -1)
def get_date_range(figure_layout: dict[str, Any]) -> Sequence[str | None]:
date_range: Sequence[str | None] = [None, None]
# check xaxis2 first
if "xaxis2" in figure_layout and figure_layout["xaxis2"].get("range"):
date_range = figure_layout["xaxis2"]["range"]
# if not found, check xaxis1
elif "xaxis1" in figure_layout and figure_layout["xaxis1"].get("range"):
date_range = figure_layout["xaxis1"]["range"]
# else:
# print(figure_layout)
return date_range
def adjust_date_range(
timestamps: pd.DatetimeIndex,
offset_days: int,
triggered_id: str = "btn-1y",
date_range: Sequence[str | None] | None = None,
) -> Sequence[str]:
if not date_range or triggered_id == "btn-ytd":
start_date = timestamps[0].strftime("%Y-%m-%d")
end_date = timestamps[-1].strftime("%Y-%m-%d")
else:
start_date, end_date = date_range
start_date = max(
parser.parse(end_date) - timedelta(days=offset_days),
timestamps[0],
).strftime("%Y-%m-%d")
return [start_date, end_date]
def normalize_prices(prices: pd.DataFrame, date_range: Sequence[Any]) -> pd.DataFrame:
date0, date1 = date_range
prices_normalized = np.nan * prices
prices_normalized.loc[date0:date1] = prices[date0:date1] / prices.loc[date0] - 1
return prices_normalized
|