From eddb01f774a84281e2958c2e62866eeb907ee26b Mon Sep 17 00:00:00 2001 From: Giulio De Pasquale Date: Sat, 11 Oct 2025 11:32:01 +0100 Subject: [PATCH] mbleh --- __init__.py | 3 ++ paperone.py | 127 +++++++++++++++++++++++++++++++------------------ poetry.lock | 21 +++++++- pyproject.toml | 3 +- 4 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 __init__.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..a1655f6 --- /dev/null +++ b/__init__.py @@ -0,0 +1,3 @@ +from beartype.claw import beartype_this_package + +beartype_this_package() diff --git a/paperone.py b/paperone.py index 8d5fc9e..231fabb 100755 --- a/paperone.py +++ b/paperone.py @@ -2,41 +2,85 @@ import requests import math +from sys import exit from datetime import datetime from dotenv import load_dotenv +from typing import NoReturn from os import environ +from enum import Enum load_dotenv() -API_KEY = environ.get("API_KEY") +API_KEY: str | None = environ.get("API_KEY") +BASE_URL: str = "https://api.taapi.io" -def is_trading_day(date): +class Indicator(Enum): + rsi = "rsi" + + +class Interval(Enum): + OneMinute = 60 + FiveMinutes = 300 + FifteenMinutes = 900 + ThirtyMinutes = 1800 + OneHour = 3600 + TwoHours = 7200 + FourHours = 14400 + TwelveHours = 43200 + OneDay = 86400 + OneWeek = 604800 + + +def query_indicator( + ticker: str, indicator: Indicator, target_date: datetime +) -> requests.Response: + interval: str = "1d" + candles: int = calculate_candles_to_target_date(target_date, interval) + target_url = f"{BASE_URL}/{indicator}" + + params: dict[str, str | int | bool] = { + "secret": API_KEY, + "symbol": ticker, + "interval": interval, + "type": "stocks", + "gaps": "false", + "addResultTimestamp": "true", + "backtrack": candles, + "results": "14", + } + + response: requests.Response = requests.get(target_url, params=params) + + return response + + +def is_trading_day(date: datetime) -> bool: return date.weekday() not in [5, 6] -def calculate_candles_to_target_date(target_date, interval="1h", current_time=None): - """ - Calculate the number of candles needed to go back from now to the target date. - """ +def parse_date_yyyymmdd(date_str: str) -> datetime: + return datetime.strptime(date_str, "%Y%m%d") - # Parse target_date if it's a string - if isinstance(target_date, str): - try: - target_date = datetime.strptime(target_date, "%Y-%m-%d %H:%M:%S") - except ValueError: - target_date = datetime.strptime(target_date, "%Y-%m-%d") - # Set current_time to now if not provided +def format_date_readable(date: datetime) -> str: + return date.strftime("%B %d, %Y") + + +def calculate_candles_to_target_date( + target_date: datetime, + interval: str = "1h", + current_time: datetime | None = None, +) -> int: if current_time is None: current_time = datetime.now() # Calculate time difference - time_diff = current_time - target_date - time_diff_seconds = time_diff.total_seconds() + time_diff: datetime = current_time - target_date + time_diff_seconds: float = time_diff.total_seconds() # Parse interval to get candle duration in seconds - interval_map = { + interval_map: dict[str, int] = { "1m": 60, "5m": 300, "15m": 900, @@ -49,45 +93,38 @@ def calculate_candles_to_target_date(target_date, interval="1h", current_time=No "1w": 604800, } - candle_duration_seconds = interval_map[interval] + candle_duration_seconds: int = interval_map[interval] # Calculate number of candles (round up) - num_candles = math.ceil(time_diff_seconds / candle_duration_seconds) + num_candles: int = math.ceil(time_diff_seconds / candle_duration_seconds) return num_candles -url = "https://api.taapi.io/rsi" +def main() -> NoReturn: + date = parse_date_yyyymmdd("20250821") + indicator = Indicator.rsi + ticker = "AAPL" + response = query_indicator(ticker, indicator.value, date) -target_date = "2025-08-11 14:30:00" -interval = "1d" -candles = calculate_candles_to_target_date(target_date, interval) + if response.status_code == 200: + data: dict[str, list[float] | list[int]] = response.json() -params = { - "secret": API_KEY, - "symbol": "AAPL", - "interval": interval, - "type": "stocks", - "gaps": "false", - "addResultTimestamp": "true", - "backtrack": candles, - "results": "14", -} + print(f"{indicator.value} values for {ticker} on {format_date_readable(date)}:") -response = requests.get(url, params=params) + for rsi_val, ts in zip(data["value"], data["timestamp"]): + dt: datetime = datetime.fromtimestamp(ts) -if response.status_code == 200: - data = response.json() + if not is_trading_day(dt): + continue - print("RSI Values for AAPL on August 11, 2025 (Hourly):") + print(f"{dt.strftime('%Y-%m-%d %H:%M:%S')} | RSI: {rsi_val:.2f}") + else: + print(f"Error: {response.status_code}") + print(response.text) - for rsi_val, ts in zip(data["value"], data["timestamp"]): - dt = datetime.fromtimestamp(ts) + exit(0) - if not is_trading_day(dt): - continue - - print(f"{dt.strftime('%Y-%m-%d %H:%M:%S')} | RSI: {rsi_val:.2f}") -else: - print(f"Error: {response.status_code}") - print(response.text) + +if __name__ == "__main__": + main() diff --git a/poetry.lock b/poetry.lock index 2d16d35..e1eed4b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,5 +1,24 @@ # This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +[[package]] +name = "beartype" +version = "0.22.2" +description = "Unbearably fast near-real-time hybrid runtime-static type-checking in pure Python." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "beartype-0.22.2-py3-none-any.whl", hash = "sha256:12077afe3528eba5c5b801f816712f7ff06f6da5509994c79561e29b48bcedb8"}, + {file = "beartype-0.22.2.tar.gz", hash = "sha256:ff3a7df26af8d15fa87f97934f0f6d41bbdadca971c410819104998dd26013d2"}, +] + +[package.extras] +dev = ["autoapi (>=0.9.0)", "celery", "click", "coverage (>=5.5)", "equinox ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "fastmcp ; python_version > \"3.9.0\" and python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "polars ; python_version < \"3.14.0\"", "pydata-sphinx-theme (<=0.7.2)", "pygments", "pyright (>=1.1.370)", "pytest (>=4.0.0)", "rich-click", "setuptools", "sphinx", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.14.0\""] +doc-rtd = ["autoapi (>=0.9.0)", "pydata-sphinx-theme (<=0.7.2)", "setuptools", "sphinx (>=4.2.0,<6.0.0)", "sphinxext-opengraph (>=0.7.5)"] +test = ["celery", "click", "coverage (>=5.5)", "equinox ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "fastmcp ; python_version > \"3.9.0\" and python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=4.0.0)", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "tox (>=3.20.1)", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.14.0\""] +test-tox = ["celery", "click", "equinox ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "fastmcp ; python_version > \"3.9.0\" and python_version < \"3.14.0\"", "jax[cpu] ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "jaxtyping ; sys_platform == \"linux\"", "langchain ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "mypy (>=0.800) ; platform_python_implementation != \"PyPy\"", "nuitka (>=1.2.6) ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "numba ; python_version < \"3.14.0\"", "numpy ; python_version < \"3.14.0\" and sys_platform != \"darwin\" and platform_python_implementation != \"PyPy\"", "pandera (>=0.26.0) ; python_version < \"3.14.0\"", "polars ; python_version < \"3.14.0\"", "pygments", "pyright (>=1.1.370)", "pytest (>=4.0.0)", "rich-click", "sphinx", "sqlalchemy", "torch ; sys_platform == \"linux\" and python_version < \"3.14.0\"", "typer", "typing-extensions (>=3.10.0.0)", "xarray ; python_version < \"3.14.0\""] +test-tox-coverage = ["coverage (>=5.5)"] + [[package]] name = "certifi" version = "2025.10.5" @@ -174,4 +193,4 @@ zstd = ["zstandard (>=0.18.0)"] [metadata] lock-version = "2.1" python-versions = ">=3.13" -content-hash = "bcb786a9953b63169bdbd028399b76d053f04ef56d967cd750f3f9cca3f67627" +content-hash = "3f5fbe1c67324920f0a88200610bdf594bd4839fa97e478499b1e200f939a0a0" diff --git a/pyproject.toml b/pyproject.toml index aafc8a2..7c9e05a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,8 @@ readme = "README.md" requires-python = ">=3.13" dependencies = [ "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)" ]