Big update, compatable with latest version of Conky
This commit is contained in:
parent
8bad18f047
commit
858154b5c4
8 changed files with 890 additions and 577 deletions
193
stocks/get_stocks_finnhub.py
Executable file
193
stocks/get_stocks_finnhub.py
Executable file
|
|
@ -0,0 +1,193 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import requests
|
||||
import argparse
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def fetch_current_stock_data(api_key, symbol):
|
||||
url = "https://finnhub.io/api/v1/quote"
|
||||
params = {
|
||||
'symbol': symbol,
|
||||
'token': api_key
|
||||
}
|
||||
try:
|
||||
response = requests.get(url, params=params, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"current_price": data.get("c"),
|
||||
"open_price": data.get("o")
|
||||
}
|
||||
else:
|
||||
print(f"Error: Failed to fetch current data for {symbol} (HTTP {response.status_code})")
|
||||
return None
|
||||
except requests.RequestException as e:
|
||||
print(f"Error: Failed to get current stock data for {symbol} - {e}")
|
||||
return None
|
||||
|
||||
|
||||
def fetch_current_crypto_data(api_key, symbol):
|
||||
url = "https://finnhub.io/api/v1/crypto/candle"
|
||||
current_time = int(datetime.now().timestamp())
|
||||
params = {
|
||||
'symbol': symbol,
|
||||
'resolution': '1', # 1-minute resolution
|
||||
'from': current_time - 60, # Last minute
|
||||
'to': current_time,
|
||||
'token': api_key
|
||||
}
|
||||
try:
|
||||
response = requests.get(url, params=params, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("s") == "ok" and "c" in data:
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"current_price": data["c"][-1], # Last closing price
|
||||
"open_price": data["o"][-1] # Last opening price
|
||||
}
|
||||
else:
|
||||
print(f"Error: Crypto data not OK for {symbol}")
|
||||
return None
|
||||
else:
|
||||
print(f"Error: Failed to fetch crypto data for {symbol} (HTTP {response.status_code})")
|
||||
return None
|
||||
except requests.RequestException as e:
|
||||
print(f"Error: Failed to get crypto data for {symbol} - {e}")
|
||||
return None
|
||||
|
||||
|
||||
def fetch_historical_data(api_key, symbol, range_in_days):
|
||||
url = "https://finnhub.io/api/v1/stock/candle" if ':' in symbol else "https://finnhub.io/api/v1/crypto/candle"
|
||||
end_time = int(datetime.now().timestamp())
|
||||
start_time = int((datetime.now() - timedelta(days=range_in_days)).timestamp())
|
||||
params = {
|
||||
'symbol': symbol,
|
||||
'resolution': 'D', # Daily candles
|
||||
'from': start_time,
|
||||
'to': end_time,
|
||||
'token': api_key
|
||||
}
|
||||
try:
|
||||
response = requests.get(url, params=params, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get("s") == "ok":
|
||||
return {
|
||||
"symbol": symbol,
|
||||
"timestamps": data["t"],
|
||||
"close_prices": data["c"]
|
||||
}
|
||||
else:
|
||||
print(f"Error: Historical data not ok for {symbol}")
|
||||
return None
|
||||
else:
|
||||
print(f"Error: Failed to fetch historical data for {symbol} (HTTP {response.status_code})")
|
||||
return None
|
||||
except requests.RequestException as e:
|
||||
print(f"Error: Failed to get historical stock data for {symbol} - {e}")
|
||||
return None
|
||||
|
||||
def main():
|
||||
# Parse command-line arguments
|
||||
parser = argparse.ArgumentParser(description="Fetch stock data from FinnHub.")
|
||||
parser.add_argument("--api_key", required=True, help="Your personal FinnHub API key")
|
||||
parser.add_argument("--symbols", required=True, help="Stock symbols (comma separated) to fetch")
|
||||
parser.add_argument("--range_in_days", default=0, type=int, help="Number of days to compare against (optional, default is 0)")
|
||||
parser.add_argument("--price_dec_places", default=0, type=int, help="Number of decimal places for prices (default is 0)")
|
||||
parser.add_argument("--percent_dec_places", default=1, type=int, help="Number of decimal places for percentages (default is 1)")
|
||||
args = parser.parse_args()
|
||||
|
||||
# Split symbols
|
||||
symbols = args.symbols.strip().upper().split(",")
|
||||
|
||||
# Use a list to build the final output string
|
||||
output = []
|
||||
|
||||
# Prepare for printing output
|
||||
color_header = "${color}"
|
||||
color_label = "${color3}"
|
||||
color_value = "${color3}"
|
||||
color_good = "${color6}"
|
||||
color_bad = "${color7}"
|
||||
line_tab1_offset = "${goto 25}"
|
||||
line_tab2_offset = "${goto 90}"
|
||||
line_tab3_offset = "${alignr}" # Could also replace this with goto 120 if you don't like the right alignment
|
||||
historical_data_exists = False
|
||||
|
||||
# Iterate symbols (crypto symbols have a colon in them, i.e. BINANCE:BTCUSDT; COINBASE:BTCUSD)
|
||||
for symbol in symbols:
|
||||
current_data = fetch_current_crypto_data(args.api_key, symbol) if ':' in symbol else fetch_current_stock_data(args.api_key, symbol)
|
||||
if current_data:
|
||||
current_price = current_data['current_price']
|
||||
if args.range_in_days > 0:
|
||||
# Fetch historical data if range_in_days > 0
|
||||
historical_data = fetch_historical_data(args.api_key, symbol, args.range_in_days)
|
||||
if historical_data:
|
||||
historical_data_exists = True
|
||||
# Find the closing price for exactly X days ago
|
||||
target_date = (datetime.now() - timedelta(days=args.range_in_days)).strftime("%Y-%m-%d")
|
||||
timestamps = historical_data["timestamps"]
|
||||
close_prices = historical_data["close_prices"]
|
||||
|
||||
# Convert timestamps to dates and find the target date's index
|
||||
date_to_close_price = {
|
||||
datetime.fromtimestamp(ts).strftime("%Y-%m-%d"): price
|
||||
for ts, price in zip(timestamps, close_prices)
|
||||
}
|
||||
|
||||
historical_closing_price = date_to_close_price.get(target_date, None)
|
||||
if historical_closing_price is not None:
|
||||
# Calculate difference in value from current price to historical close
|
||||
price_difference = current_price - historical_closing_price
|
||||
percent_change = (price_difference / historical_closing_price) * 100
|
||||
color_dynamic = (
|
||||
color_good if round(price_difference, args.price_dec_places) > 0
|
||||
else color_bad if round(price_difference, args.price_dec_places) < 0
|
||||
else color_value
|
||||
)
|
||||
output.append(
|
||||
f"{line_tab1_offset}{color_label}{symbol}: {line_tab2_offset}{color_value}{round(current_price, args.price_dec_places):.{args.price_dec_places}f} "
|
||||
f"{line_tab3_offset}{color_dynamic}{round(price_difference, args.price_dec_places):+.{args.price_dec_places}f} "
|
||||
f"({round(percent_change, args.percent_dec_places):+.{args.percent_dec_places}f}%)"
|
||||
)
|
||||
else:
|
||||
output.append(
|
||||
f"{symbol}: {round(current_price, args.price_dec_places):.{args.price_dec_places}f} "
|
||||
f"| {args.range_in_days} days: No historical data"
|
||||
)
|
||||
else:
|
||||
output.append(f"{symbol}: Error fetching historical data")
|
||||
else:
|
||||
# Only include intraday change if no historical data is requested
|
||||
open_price = current_data['open_price']
|
||||
if open_price is not None and current_price is not None:
|
||||
intraday_change = current_price - open_price
|
||||
intraday_percent_change = (intraday_change / open_price) * 100
|
||||
color_dynamic = (
|
||||
color_good if round(intraday_change, args.price_dec_places) > 0
|
||||
else color_bad if round(intraday_change, args.price_dec_places) < 0
|
||||
else color_value
|
||||
)
|
||||
output.append(
|
||||
f"{line_tab1_offset}{color_label}{symbol}: {line_tab2_offset}{color_value}{round(current_price, args.price_dec_places):.{args.price_dec_places}f} "
|
||||
f"{line_tab3_offset}{color_dynamic}{round(intraday_change, args.price_dec_places):+.{args.price_dec_places}f} "
|
||||
f"({round(intraday_percent_change, args.percent_dec_places):+.{args.percent_dec_places}f}%)"
|
||||
)
|
||||
else:
|
||||
output.append(
|
||||
f"{symbol}: {round(current_price, args.price_dec_places):.{args.price_dec_places}f} | Intraday: N/A"
|
||||
)
|
||||
else:
|
||||
output.append(f"{symbol}: Error fetching current data")
|
||||
|
||||
# Join all parts of the output and print it
|
||||
header_label = f"{args.range_in_days} Day" if historical_data_exists else "Intraday"
|
||||
header_line = f"{line_tab1_offset}{color_header}Ticker{line_tab2_offset}Price ($$){line_tab3_offset}{header_label}{color_label}"
|
||||
return header_line + "\n" + f"{line_tab1_offset}{color_header}${{voffset -5}}${{hr 1}}" + "\n" + "\n".join(output)
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(main())
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue