forked from vycdev/thermal-printer-scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcrypto_print.py
More file actions
98 lines (81 loc) · 3.93 KB
/
Copy pathcrypto_print.py
File metadata and controls
98 lines (81 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#!/usr/bin/env python3
"""Print a cryptocurrency ticker with a 7-day chart on the S01 printer.
Pulls live price, 24h/7d change, and a week of price history from CoinGecko, and
draws the history as a line chart above the stats.
Examples:
python crypto_print.py # Bitcoin
python crypto_print.py --coin ethereum
python crypto_print.py --coin sol # symbol aliases work too
python crypto_print.py --no-print
"""
from __future__ import annotations
import argparse
from datetime import datetime
from pathlib import Path
from PIL import Image, ImageDraw
from print_common import ROOT, Card, font, get_json
API = "https://api.coingecko.com/api/v3"
ALIASES = {"btc": "bitcoin", "eth": "ethereum", "sol": "solana", "doge": "dogecoin",
"ada": "cardano", "xrp": "ripple", "bnb": "binancecoin", "ltc": "litecoin"}
def fmt_price(p: float) -> str:
if p >= 100:
return f"${p:,.0f}"
if p >= 1:
return f"${p:,.2f}"
return f"${p:.6f}".rstrip("0")
def draw_chart(prices: list[float], w: int, h: int = 150) -> Image.Image:
img = Image.new("L", (w, h), 255)
d = ImageDraw.Draw(img)
lo, hi = min(prices), max(prices)
span = (hi - lo) or 1
n = len(prices)
pad = 4
pts = [(pad + i / (n - 1) * (w - 2 * pad), pad + (1 - (p - lo) / span) * (h - 2 * pad))
for i, p in enumerate(prices)]
d.line(pts, fill=0, width=2, joint="curve")
# baseline at the starting price (dotted) to show net move
y0 = pad + (1 - (prices[0] - lo) / span) * (h - 2 * pad)
for x in range(0, w, 6):
d.point((x, y0), fill=0)
# mark the latest point
lx, ly = pts[-1]
d.ellipse((lx - 3, ly - 3, lx + 3, ly + 3), fill=0)
tiny = font(False, 11)
d.text((pad, pad), fmt_price(hi), fill=0, font=tiny)
d.text((pad, h - 16), fmt_price(lo), fill=0, font=tiny)
return img
def main() -> int:
parser = argparse.ArgumentParser(description="Print a crypto ticker with a 7-day chart on the S01 printer.")
parser.add_argument("--coin", default="bitcoin", help="CoinGecko id or common symbol (default: bitcoin).")
parser.add_argument("--out", type=Path, default=ROOT / "crypto.png")
parser.add_argument("--darkness", type=int, choices=range(1, 6), default=3)
parser.add_argument("--bottom-feed", type=int, default=24)
parser.add_argument("--no-print", action="store_true")
args = parser.parse_args()
coin = ALIASES.get(args.coin.lower(), args.coin.lower())
print(f"Fetching {coin} ...")
markets = get_json(f"{API}/coins/markets?vs_currency=usd&ids={coin}&price_change_percentage=24h,7d")
if not markets:
raise SystemExit(f"No coin '{coin}' on CoinGecko (try the full id, e.g. 'ethereum')")
c = markets[0]
prices = [p[1] for p in get_json(f"{API}/coins/{coin}/market_chart?vs_currency=usd&days=7")["prices"]]
ch24 = c.get("price_change_percentage_24h") or 0
ch7 = c.get("price_change_percentage_7d_in_currency") or 0
sign = lambda v: f"+{v:.1f}%" if v >= 0 else f"{v:.1f}%" # noqa: E731
print(f" {c['name']} {fmt_price(c['current_price'])} 24h {sign(ch24)}")
card = Card()
card.title(f"{c['name'].upper()} {c['symbol'].upper()}")
card.heading(fmt_price(c["current_price"]), size=30)
card.line(f"24h {sign(ch24)} 7d {sign(ch7)}", size=14, bold=True, center=True)
card.gap(4).image(draw_chart(prices, card.inner_w), border=True)
card.line("7-day price", size=11, bold=False, center=True)
card.gap(2).divider()
card.kv("Rank", f"#{c.get('market_cap_rank', '?')}")
card.kv("24h High", fmt_price(c["high_24h"]))
card.kv("24h Low", fmt_price(c["low_24h"]))
card.kv("All-time high", fmt_price(c["ath"]))
card.kv("Market cap", f"${c['market_cap'] / 1e9:.1f}B")
card.footer("coingecko.com", datetime.now().strftime("%Y-%m-%d %H:%M"))
return card.finish(args.out, args.bottom_feed, args.darkness, do_print=not args.no_print)
if __name__ == "__main__":
raise SystemExit(main())