prettify
This commit is contained in:
parent
7909484044
commit
6452802124
148
paperone.py
148
paperone.py
@ -3,7 +3,7 @@
|
|||||||
import requests
|
import requests
|
||||||
import math
|
import math
|
||||||
from sys import exit
|
from sys import exit
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from typing import NoReturn, List
|
from typing import NoReturn, List
|
||||||
from os import environ
|
from os import environ
|
||||||
@ -11,6 +11,7 @@ from enum import Enum
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from requests.adapters import HTTPAdapter
|
from requests.adapters import HTTPAdapter
|
||||||
from urllib3.util.retry import Retry
|
from urllib3.util.retry import Retry
|
||||||
|
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TaskProgressColumn, TimeRemainingColumn
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@ -20,6 +21,7 @@ class Indicator:
|
|||||||
endpoint: str
|
endpoint: str
|
||||||
params: dict[str, int]
|
params: dict[str, int]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class QueryResult:
|
class QueryResult:
|
||||||
datetime: datetime
|
datetime: datetime
|
||||||
@ -51,19 +53,6 @@ class IndicatorEnum(Enum):
|
|||||||
VOLUME = Indicator(endpoint="volume", params={})
|
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:
|
class TaapiClient:
|
||||||
def __init__(self, api_key: str) -> None:
|
def __init__(self, api_key: str) -> None:
|
||||||
self._api_key: str = api_key
|
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")
|
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:
|
def format_date_readable(date: datetime) -> str:
|
||||||
return date.strftime("%B %d, %Y")
|
return date.strftime("%B %d, %Y")
|
||||||
|
|
||||||
@ -231,41 +238,96 @@ def main() -> NoReturn:
|
|||||||
|
|
||||||
if not api_key:
|
if not api_key:
|
||||||
print("API_KEY not set")
|
print("API_KEY not set")
|
||||||
|
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
date = parse_date_yyyymmdd("20250821")
|
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:
|
with Progress(
|
||||||
# for t in ["AAPL", "NVDA", "AMD", "META", "MSFT", "GOOG"]:
|
SpinnerColumn(),
|
||||||
for t in ["AAPL"]:
|
TextColumn("[progress.description]{task.description}"),
|
||||||
print(f"TICKER: {t}\n")
|
BarColumn(),
|
||||||
for i in IndicatorEnum:
|
TaskProgressColumn(),
|
||||||
try:
|
TimeRemainingColumn(),
|
||||||
indicator_results = client.query_indicator(t, i.value, date)
|
) as progress:
|
||||||
except Exception as e:
|
|
||||||
# print(f"Could not retrieve data: {e}")
|
# Overall ticker progress
|
||||||
|
ticker_task = progress.add_task(
|
||||||
continue
|
"[cyan]Processing tickers...", total=len(tickers)
|
||||||
|
)
|
||||||
if not indicator_results:
|
|
||||||
# print("Could not retrieve data")
|
with TaapiClient(api_key) as client:
|
||||||
|
for ticker in tickers:
|
||||||
continue
|
# Update ticker task
|
||||||
|
progress.update(
|
||||||
print(f"Indicator: {i}")
|
ticker_task,
|
||||||
|
description=f"[cyan]Processing {ticker}..."
|
||||||
trading_day_values = [
|
)
|
||||||
x for x in indicator_results if is_trading_day(x.datetime)
|
|
||||||
]
|
# Price loading subtask
|
||||||
|
price_task = progress.add_task(
|
||||||
for r in trading_day_values:
|
f"[green] └─ Loading prices for {ticker}...",
|
||||||
price = client.query_price_on_day(t, r.datetime)
|
total=len(dates_range)
|
||||||
print(
|
)
|
||||||
f"{format_date_readable(r.datetime)} (${price.value:.2f}) - {i.name}: {r.value:.2f}"
|
|
||||||
|
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)
|
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"},
|
{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]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "3.10"
|
version = "3.10"
|
||||||
@ -135,6 +163,57 @@ files = [
|
|||||||
[package.extras]
|
[package.extras]
|
||||||
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
|
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]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
@ -172,6 +251,67 @@ urllib3 = ">=1.21.1,<3"
|
|||||||
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
|
||||||
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
|
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]]
|
[[package]]
|
||||||
name = "urllib3"
|
name = "urllib3"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
@ -193,4 +333,4 @@ zstd = ["zstandard (>=0.18.0)"]
|
|||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.13"
|
python-versions = ">=3.13"
|
||||||
content-hash = "3f5fbe1c67324920f0a88200610bdf594bd4839fa97e478499b1e200f939a0a0"
|
content-hash = "0e7245f4fa895043c8681791b01a961b7a5fa94bc3ff72cf63331fcc4e7de7c1"
|
||||||
|
@ -10,7 +10,8 @@ requires-python = ">=3.13"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"requests (>=2.32.5,<3.0.0)",
|
"requests (>=2.32.5,<3.0.0)",
|
||||||
"python-dotenv (>=1.1.1,<2.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