prettify
This commit is contained in:
parent
7909484044
commit
6452802124
148
paperone.py
148
paperone.py
@ -3,7 +3,7 @@
|
||||
import requests
|
||||
import math
|
||||
from sys import exit
|
||||
from datetime import datetime
|
||||
from datetime import datetime, timedelta
|
||||
from dotenv import load_dotenv
|
||||
from typing import NoReturn, List
|
||||
from os import environ
|
||||
@ -11,6 +11,7 @@ from enum import Enum
|
||||
from dataclasses import dataclass
|
||||
from requests.adapters import HTTPAdapter
|
||||
from urllib3.util.retry import Retry
|
||||
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@ -20,6 +21,7 @@ class Indicator:
|
||||
endpoint: str
|
||||
params: dict[str, int]
|
||||
|
||||
|
||||
@dataclass
|
||||
class QueryResult:
|
||||
datetime: datetime
|
||||
@ -51,19 +53,6 @@ class IndicatorEnum(Enum):
|
||||
VOLUME = Indicator(endpoint="volume", params={})
|
||||
|
||||
|
||||
class Interval(Enum):
|
||||
OneMinute = 60
|
||||
FiveMinutes = 300
|
||||
FifteenMinutes = 900
|
||||
ThirtyMinutes = 1800
|
||||
OneHour = 3600
|
||||
TwoHours = 7200
|
||||
FourHours = 14400
|
||||
TwelveHours = 43200
|
||||
OneDay = 86400
|
||||
OneWeek = 604800
|
||||
|
||||
|
||||
class TaapiClient:
|
||||
def __init__(self, api_key: str) -> None:
|
||||
self._api_key: str = api_key
|
||||
@ -222,6 +211,24 @@ def parse_date_yyyymmdd(date_str: str) -> datetime:
|
||||
return datetime.strptime(date_str, "%Y%m%d")
|
||||
|
||||
|
||||
def days_range_from(date: datetime, n: int) -> List[datetime]:
|
||||
"""
|
||||
Generate a list of dates going back n days from the given date (inclusive).
|
||||
|
||||
Example: date=Jan 3, n=2 → [Jan 1, Jan 2, Jan 3]
|
||||
|
||||
Args:
|
||||
date: The target date
|
||||
n: Number of days to backtrack
|
||||
|
||||
Returns:
|
||||
List of datetime objects from (date - n) to date (inclusive)
|
||||
"""
|
||||
start_date = date - timedelta(days=n)
|
||||
|
||||
return [start_date + timedelta(days=i) for i in range(n + 1)]
|
||||
|
||||
|
||||
def format_date_readable(date: datetime) -> str:
|
||||
return date.strftime("%B %d, %Y")
|
||||
|
||||
@ -231,41 +238,96 @@ def main() -> NoReturn:
|
||||
|
||||
if not api_key:
|
||||
print("API_KEY not set")
|
||||
|
||||
exit(0)
|
||||
|
||||
date = parse_date_yyyymmdd("20250821")
|
||||
days_range = 14
|
||||
dates_range = days_range_from(date, days_range)
|
||||
tickers = ["AAPL", "NVDA", "AMD", "META", "MSFT", "GOOG"]
|
||||
indicators = list(IndicatorEnum)
|
||||
|
||||
with TaapiClient(api_key) as client:
|
||||
# for t in ["AAPL", "NVDA", "AMD", "META", "MSFT", "GOOG"]:
|
||||
for t in ["AAPL"]:
|
||||
print(f"TICKER: {t}\n")
|
||||
for i in IndicatorEnum:
|
||||
try:
|
||||
indicator_results = client.query_indicator(t, i.value, date)
|
||||
except Exception as e:
|
||||
# print(f"Could not retrieve data: {e}")
|
||||
|
||||
continue
|
||||
|
||||
if not indicator_results:
|
||||
# print("Could not retrieve data")
|
||||
|
||||
continue
|
||||
|
||||
print(f"Indicator: {i}")
|
||||
|
||||
trading_day_values = [
|
||||
x for x in indicator_results if is_trading_day(x.datetime)
|
||||
]
|
||||
|
||||
for r in trading_day_values:
|
||||
price = client.query_price_on_day(t, r.datetime)
|
||||
print(
|
||||
f"{format_date_readable(r.datetime)} (${price.value:.2f}) - {i.name}: {r.value:.2f}"
|
||||
with Progress(
|
||||
SpinnerColumn(),
|
||||
TextColumn("[progress.description]{task.description}"),
|
||||
BarColumn(),
|
||||
TaskProgressColumn(),
|
||||
TimeRemainingColumn(),
|
||||
) as progress:
|
||||
|
||||
# Overall ticker progress
|
||||
ticker_task = progress.add_task(
|
||||
"[cyan]Processing tickers...", total=len(tickers)
|
||||
)
|
||||
|
||||
with TaapiClient(api_key) as client:
|
||||
for ticker in tickers:
|
||||
# Update ticker task
|
||||
progress.update(
|
||||
ticker_task,
|
||||
description=f"[cyan]Processing {ticker}..."
|
||||
)
|
||||
|
||||
# Price loading subtask
|
||||
price_task = progress.add_task(
|
||||
f"[green] └─ Loading prices for {ticker}...",
|
||||
total=len(dates_range)
|
||||
)
|
||||
|
||||
prices = {}
|
||||
for d in dates_range:
|
||||
progress.update(
|
||||
price_task,
|
||||
description=f"[green] └─ Loading {ticker} price for {format_date_readable(d)}...",
|
||||
advance=1
|
||||
)
|
||||
result = client.query_price_on_day(ticker, d)
|
||||
if result:
|
||||
prices[d.day] = result.value
|
||||
|
||||
# Remove price task when done
|
||||
progress.remove_task(price_task)
|
||||
|
||||
# Indicator loading subtask
|
||||
indicator_task = progress.add_task(
|
||||
f"[yellow] └─ Loading indicators for {ticker}...",
|
||||
total=len(indicators)
|
||||
)
|
||||
|
||||
for indicator_enum in indicators:
|
||||
progress.update(
|
||||
indicator_task,
|
||||
description=f"[yellow] └─ Loading {ticker} indicator: {indicator_enum.name}...",
|
||||
advance=1
|
||||
)
|
||||
|
||||
try:
|
||||
indicator_results = client.query_indicator(
|
||||
ticker, indicator_enum.value, date, results=days_range
|
||||
)
|
||||
except Exception as e:
|
||||
progress.console.print(f"[red]Error retrieving {indicator_enum.name}: {e}")
|
||||
continue
|
||||
|
||||
print("---------------")
|
||||
if not indicator_results:
|
||||
continue
|
||||
|
||||
progress.console.print(f"\n[bold]{ticker} - {indicator_enum.name}:[/bold]")
|
||||
|
||||
trading_day_values = [
|
||||
x for x in indicator_results if is_trading_day(x.datetime)
|
||||
]
|
||||
|
||||
for r in trading_day_values:
|
||||
price_str = f"${prices[r.datetime.day]:.2f}" if r.datetime.day in prices else "N/A"
|
||||
progress.console.print(
|
||||
f" {format_date_readable(r.datetime)} ({price_str}) - {indicator_enum.name}: {r.value:.2f}"
|
||||
)
|
||||
|
||||
# Remove indicator task when done
|
||||
progress.remove_task(indicator_task)
|
||||
|
||||
# Advance overall ticker progress
|
||||
progress.advance(ticker_task)
|
||||
|
||||
exit(0)
|
||||
|
||||
|
142
poetry.lock
generated
142
poetry.lock
generated
@ -120,6 +120,34 @@ files = [
|
||||
{file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "click"
|
||||
version = "8.3.0"
|
||||
description = "Composable command line interface toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"},
|
||||
{file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
description = "Cross-platform colored terminal text."
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
||||
groups = ["main"]
|
||||
markers = "platform_system == \"Windows\""
|
||||
files = [
|
||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "3.10"
|
||||
@ -135,6 +163,57 @@ files = [
|
||||
[package.extras]
|
||||
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "markdown-it-py"
|
||||
version = "4.0.0"
|
||||
description = "Python port of markdown-it. Markdown parsing, done right!"
|
||||
optional = false
|
||||
python-versions = ">=3.10"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"},
|
||||
{file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mdurl = ">=0.1,<1.0"
|
||||
|
||||
[package.extras]
|
||||
benchmarking = ["psutil", "pytest", "pytest-benchmark"]
|
||||
compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"]
|
||||
linkify = ["linkify-it-py (>=1,<3)"]
|
||||
plugins = ["mdit-py-plugins (>=0.5.0)"]
|
||||
profiling = ["gprof2dot"]
|
||||
rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"]
|
||||
testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"]
|
||||
|
||||
[[package]]
|
||||
name = "mdurl"
|
||||
version = "0.1.2"
|
||||
description = "Markdown URL utilities"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
|
||||
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.19.2"
|
||||
description = "Pygments is a syntax highlighting package written in Python."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"},
|
||||
{file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
windows-terminal = ["colorama (>=0.4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.1.1"
|
||||
@ -172,6 +251,67 @@ urllib3 = ">=1.21.1,<3"
|
||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "14.2.0"
|
||||
description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
optional = false
|
||||
python-versions = ">=3.8.0"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "rich-14.2.0-py3-none-any.whl", hash = "sha256:76bc51fe2e57d2b1be1f96c524b890b816e334ab4c1e45888799bfaab0021edd"},
|
||||
{file = "rich-14.2.0.tar.gz", hash = "sha256:73ff50c7c0c1c77c8243079283f4edb376f0f6442433aecb8ce7e6d0b92d1fe4"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
markdown-it-py = ">=2.2.0"
|
||||
pygments = ">=2.13.0,<3.0.0"
|
||||
|
||||
[package.extras]
|
||||
jupyter = ["ipywidgets (>=7.5.1,<9)"]
|
||||
|
||||
[[package]]
|
||||
name = "shellingham"
|
||||
version = "1.5.4"
|
||||
description = "Tool to Detect Surrounding Shell"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
|
||||
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typer"
|
||||
version = "0.19.2"
|
||||
description = "Typer, build great CLIs. Easy to code. Based on Python type hints."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "typer-0.19.2-py3-none-any.whl", hash = "sha256:755e7e19670ffad8283db353267cb81ef252f595aa6834a0d1ca9312d9326cb9"},
|
||||
{file = "typer-0.19.2.tar.gz", hash = "sha256:9ad824308ded0ad06cc716434705f691d4ee0bfd0fb081839d2e426860e7fdca"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
click = ">=8.0.0"
|
||||
rich = ">=10.11.0"
|
||||
shellingham = ">=1.3.0"
|
||||
typing-extensions = ">=3.7.4.3"
|
||||
|
||||
[[package]]
|
||||
name = "typing-extensions"
|
||||
version = "4.15.0"
|
||||
description = "Backported and Experimental Type Hints for Python 3.9+"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"},
|
||||
{file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.5.0"
|
||||
@ -193,4 +333,4 @@ zstd = ["zstandard (>=0.18.0)"]
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.13"
|
||||
content-hash = "3f5fbe1c67324920f0a88200610bdf594bd4839fa97e478499b1e200f939a0a0"
|
||||
content-hash = "0e7245f4fa895043c8681791b01a961b7a5fa94bc3ff72cf63331fcc4e7de7c1"
|
||||
|
@ -10,7 +10,8 @@ requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
"requests (>=2.32.5,<3.0.0)",
|
||||
"python-dotenv (>=1.1.1,<2.0.0)",
|
||||
"beartype (>=0.22.2,<0.23.0)"
|
||||
"beartype (>=0.22.2,<0.23.0)",
|
||||
"typer (>=0.19.2,<0.20.0)"
|
||||
]
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user