42Cummer's picture
Upload 15 files
2f560eb verified
import pandas as pd
import numpy as np
import os
import time
from datetime import datetime, timedelta
# --- CONFIGURATION ---
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
data_dir = os.path.join(project_root, "data")
if not os.path.exists(data_dir):
os.makedirs(data_dir)
TICKER = "VFV.TO"
CACHE_FILE = os.path.join(data_dir, "vfv_market_data.csv")
CACHE_DURATION_SECONDS = 900 # 15 minutes default
def sync_market_clock():
"""
Blocks execution until the start of the next minute + buffer.
Ensures we pull data right after the candle closes.
"""
now = datetime.now()
# Calculate seconds until the next minute mark (xx:xx:00)
# We add 2 seconds buffer to allow Yahoo's API to propagate the close
sleep_seconds = 60 - now.second + 2
if sleep_seconds < 5:
# If we are too close to the boundary (e.g., xx:xx:59), wait an extra minute
sleep_seconds += 60
next_pull = now + timedelta(seconds=sleep_seconds)
print(f" [SYNC] Waiting {sleep_seconds}s for candle close ({next_pull.strftime('%H:%M:%S')})...")
time.sleep(sleep_seconds)
def get_vfv_data(force_refresh=False):
"""
Fetches VFV.TO market data.
Args:
force_refresh (bool): If True, ignores cache timer and forces API pull.
"""
# 1. Check if cache exists and is fresh (unless forced)
if os.path.exists(CACHE_FILE) and not force_refresh:
last_modified = os.path.getmtime(CACHE_FILE)
age_seconds = time.time() - last_modified
if age_seconds < CACHE_DURATION_SECONDS:
print(f"--- [CACHE HIT] Loading data from {CACHE_FILE} ---")
return pd.read_csv(CACHE_FILE, index_col=0, parse_dates=True)
# 2. Fetch fresh data
print(f"--- [{'FORCE' if force_refresh else 'STALE'}] Fetching fresh data for {TICKER}... ---")
try:
# Import here so the monitor can still run off the existing CSV cache
# even if `yfinance` isn't installed in the current environment.
import yfinance as yf # type: ignore
# Fetching 5 days to ensure continuity
data = yf.download(TICKER, period="5d", interval="1m", progress=False)
if data.empty:
print("Warning: No data returned from API.")
return None
# Save to cache (Your existing logic)
data.to_csv(CACHE_FILE)
print("--- [SUCCESS] Cache updated with fresh data ---")
return data
except ModuleNotFoundError as e:
print(f"An error occurred while fetching data: {e}")
# If yfinance isn't available, fall back to whatever is on disk.
if os.path.exists(CACHE_FILE):
print("--- [FALLBACK] yfinance missing; using existing cache ---")
return pd.read_csv(CACHE_FILE, index_col=0, parse_dates=True)
return None
except Exception as e:
print(f"An error occurred while fetching data: {e}")
# Fallback to cache if API fails
if os.path.exists(CACHE_FILE):
print("--- [FALLBACK] Returning stale cache data ---")
return pd.read_csv(CACHE_FILE, index_col=0, parse_dates=True)
return None
if __name__ == "__main__":
# Test the sync and force logic
# sync_market_clock()
df = get_vfv_data(force_refresh=True)
if df is not None:
print(f"Latest Close: {df['Close'].iloc[-1]}")