投資組合大擂台 Ver. 2
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

109 lines
4.5 KiB

import pandas as pd
import json
import yfinance as yf
import numpy as np
import psycopg2
from psycopg2.extras import execute_values
from tqdm import tqdm
import datetime
import schedule
import time
from config import SQL_CONFIG
#SQL setting
# Quick status: print the latest available dates in DB
def print_last_update():
try:
conn = psycopg2.connect(**SQL_CONFIG)
cursor = conn.cursor()
cursor.execute("SELECT MAX(date) FROM stock_price")
us_last = cursor.fetchone()[0]
cursor.execute("SELECT MAX(date) FROM stock_price_tw")
tw_last = cursor.fetchone()[0]
print(f"Latest US date in DB: {us_last}" if us_last else "Latest US date in DB: None")
print(f"Latest TW date in DB: {tw_last}" if tw_last else "Latest TW date in DB: None")
cursor.close()
conn.close()
except Exception as e:
print(f"Check last update failed: {e}")
def update_data():
# Connect to the database
conn = psycopg2.connect(**SQL_CONFIG)
cursor = conn.cursor()
print("Stock prices US updating")
# Show current latest date in table for quick verification
try:
cursor.execute("SELECT MAX(date) FROM stock_price")
last_overall = cursor.fetchone()[0]
print(f"US table current latest date: {last_overall}")
except Exception:
pass
# Get the list of tickers
cursor.execute("SELECT DISTINCT ticker FROM stock_price")
tickers = [row[0] for row in cursor.fetchall()]
for ticker in tqdm(tickers):
# Get the latest date for this ticker
cursor.execute(f"SELECT MAX(date) FROM stock_price WHERE ticker = '{ticker}'")
latest_date = cursor.fetchone()[0]
# If the latest date is not today, update the data
if latest_date < datetime.date.today():
df = yf.download(ticker, start=latest_date.strftime('%Y-%m-%d'),
end=datetime.date.today().strftime('%Y-%m-%d'), progress=False, threads=False)
if df is None or df.empty:
continue
price_col = 'Close' if 'Close' in df.columns else ('Adj Close' if 'Adj Close' in df.columns else None)
if price_col is None:
continue
value = [(ticker, df.index[i], float(df[price_col].iloc[i])) for i in range(len(df))]
with conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as curs:
sql = "insert into stock_price (ticker, date, price) values %s"
execute_values(curs, sql, value)
print("Stock prices US updated")
def update_data_tw():
# Connect to the database
conn = psycopg2.connect(**SQL_CONFIG)
cursor = conn.cursor()
print("Stock prices US updating")
# Show current latest date in table for quick verification
try:
cursor.execute("SELECT MAX(date) FROM stock_price_tw")
last_overall = cursor.fetchone()[0]
print(f"TW table current latest date: {last_overall}")
except Exception:
pass
# Get the list of tickers
cursor.execute("SELECT DISTINCT ticker FROM stock_price_tw")
tickers = [row[0] for row in cursor.fetchall()]
for ticker in tqdm(tickers):
# Get the latest date for this ticker
cursor.execute(f"SELECT MAX(date) FROM stock_price_tw WHERE ticker = '{ticker}'")
latest_date = cursor.fetchone()[0]
# If the latest date is not today, update the data
if latest_date < datetime.date.today():
df = yf.download(ticker, start=latest_date.strftime('%Y-%m-%d'),
end=datetime.date.today().strftime('%Y-%m-%d'), progress=False, threads=False)
if df is None or df.empty:
continue
price_col = 'Close' if 'Close' in df.columns else ('Adj Close' if 'Adj Close' in df.columns else None)
if price_col is None:
continue
value = [(ticker, row.name.strftime('%Y-%m-%d'), row['Close']) for _, row in df.iterrows()]
with conn:
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as curs:
sql = "insert into stock_price_tw (ticker, date, price) values %s"
execute_values(curs, sql, value)
print("Stock prices TW updated")
# Print once on startup
print_last_update()
# Schedule the task
schedule.every().day.at("17:00").do(update_data)
schedule.every().day.at("18:00").do(update_data_tw)
# Keep the script running
while True:
schedule.run_pending()
time.sleep(1)