Skip to content

Commit

Permalink
Merge pull request #74 from ivelin/fix/dashboard
Browse files Browse the repository at this point in the history
fix: forecasting around market holidays
  • Loading branch information
ivelin authored Jan 21, 2025
2 parents edd49f2 + 2afb52f commit fa2850b
Show file tree
Hide file tree
Showing 4 changed files with 22 additions and 15 deletions.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = canswim
version = 0.0.15
version = 0.0.20250107
author = Ivelin Ivanov
author_email = [email protected]
description = "Developer toolkit for CANSLIM investment style practitioners"
Expand Down
8 changes: 6 additions & 2 deletions src/canswim/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import signal
import sys
from dotenv import load_dotenv
from importlib import metadata

# load os env vars before loguru import
# otherwise it won't pickup LOGURU_LEVEL
Expand Down Expand Up @@ -84,8 +85,6 @@
help="""Optional argument for the `dashboard` task. Whether to reuse previously created search database (faster start time) or update with new forecast data (slower start time).""",
)

args = parser.parse_args()

logging_dir = os.getenv("logging_dir", "tmp")
logging_path = f"{logging_dir}/canswim.log"
rot = "24 hours"
Expand All @@ -99,6 +98,11 @@
ret=ret,
)

version = metadata.version('canswim')
logger.info(f"canswim version: {version}")

args = parser.parse_args()

logger.info("command line args: {args}", args=args)

hfhub = HFHub()
Expand Down
25 changes: 13 additions & 12 deletions src/canswim/forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,8 @@ def get_forecast(self, forecast_start_date: pd.Timestamp = None):
f"Target {tickers_list[i]} start date, end date, sample count: {ts.start_time()}, {ts.end_time()}, {len(ts)}"
)
# if forecast start date is after the end of the target time series,
# then we can still forecast if the target series ends on the business day before the forecast start date
cutoff_forecast_start_date = ts.end_time() + BDay(n=1)
# then we can still forecast if the target series ends on the open market business day before the forecast start date
cutoff_forecast_start_date = get_next_open_market_day(after_date=ts.end_time())
if forecast_start_date == cutoff_forecast_start_date:
target_sliced = ts
if forecast_start_date < cutoff_forecast_start_date:
Expand All @@ -92,7 +92,7 @@ def get_forecast(self, forecast_start_date: pd.Timestamp = None):
future_cov_list.append(self.canswim_model.future_cov_list[i])
else:
logger.info(
f"Skipping {tickers_list[i]} for forecast start date {forecast_start_date} due to lack of historical data."
f"Skipping {tickers_list[i]} for forecast start date {forecast_start_date} due to lack of historical data. Min {self.canswim_model.min_samples} samples needed. Historical timeseries has {len(ts)} samples and ends on {ts.end_time()}."
)
except ValueError as e:
logger.warning(
Expand Down Expand Up @@ -234,27 +234,28 @@ def _list_to_df(forecasts: dict = None):
def upload_data(self):
self.hfhub.upload_data()



def get_next_open_market_day():
def get_next_open_market_day(after_date=None):
"""Get the date of the next open market day after a given date: after_date when provided or after today otherwise."""
# Get calendar for NYSE
nyse = mcal.get_calendar('NYSE')

# Get today's date
today = datetime.now().date()
if after_date is None:
# Get today's date
today = datetime.now().date()
after_date = today

# Look for the next valid trading day within a reasonably big window of 30 days
valid_days = nyse.valid_days(start_date=today, end_date=today + timedelta(days=30), tz=None)
# Look for the next valid trading day within a reasonably big window of 20 regular business days
valid_days = nyse.valid_days(start_date=after_date+BDay(1), end_date=after_date + BDay(20), tz=None)

next_trading_day = None

if valid_days is not None and len(valid_days) > 0:
next_trading_day = valid_days[0]

if next_trading_day is not None:
logger.info(f"The next open stock market date is: {next_trading_day}")
logger.debug(f"The next open stock market date is: {next_trading_day}")
else:
logger.warning("No open market day found within the next 30 days.")
logger.info("No open market day found within the next 30 days.")

# If we can't find a next valid day within 30 days (which shouldn't happen for NYSE), return None
return next_trading_day
Expand Down
2 changes: 2 additions & 0 deletions src/canswim/hfhub.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import torch
import tarfile
import os.path
from pathlib import Path


class HFHub:
Expand Down Expand Up @@ -155,6 +156,7 @@ def download_data(self, repo_id: str = None, local_dir: str = None):
data_dir = self.data_dir
if repo_id is None:
repo_id = self.repo_id
Path(data_dir).mkdir(parents=True, exist_ok=True)
logger.info(
f"Downloading hf data from {repo_id} to data dir:\n",
os.listdir(data_dir),
Expand Down

0 comments on commit fa2850b

Please sign in to comment.