71 lines
2.2 KiB
Python
71 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Generate ESC/POS ticker tape output from trade CSV data.
|
|
|
|
Reads a CSV of trades (timestamp, symbol, lots, price) and generates
|
|
ESC/POS commands with 90° rotated text to emulate an old stock ticker tape.
|
|
|
|
Each character gets its own printed row. When the receipt paper is turned
|
|
sideways, symbol characters read across the top and price characters read
|
|
across the bottom — just like a real ticker tape.
|
|
"""
|
|
|
|
import csv
|
|
import sys
|
|
|
|
from escpos.printer import Dummy
|
|
|
|
# TM-T88V with 90° rotation: Font A chars are 24 dots wide (instead of 12),
|
|
# so 512 printable dots / 24 = 21 chars fit across the 80mm paper width.
|
|
LINE_WIDTH = 21
|
|
|
|
|
|
def print_trade(p, symbol, lots, price):
|
|
"""Print a single trade as ticker tape characters, one per row."""
|
|
if lots > 1:
|
|
price_str = f"{lots}s{price:.2f}"
|
|
else:
|
|
price_str = f"{price:.2f}"
|
|
|
|
# Symbol characters at the top (right-aligned)
|
|
for ch in symbol:
|
|
p.text(" " * (LINE_WIDTH - 1) + ch + "\n")
|
|
|
|
# Price characters at the bottom (left-aligned)
|
|
for ch in price_str:
|
|
p.text(ch + "\n")
|
|
|
|
# Blank line separator between trades
|
|
p.text("\n")
|
|
|
|
|
|
def main():
|
|
csv_file = sys.argv[1] if len(sys.argv) > 1 else "trades_sample_sorted.csv"
|
|
output_file = sys.argv[2] if len(sys.argv) > 2 else "ticker_tape.bin"
|
|
|
|
p = Dummy(profile="TM-T88V")
|
|
p.hw("INIT")
|
|
# ESC V 1: 90° clockwise character rotation (not exposed by python-escpos)
|
|
p._raw(b"\x1b\x56\x01")
|
|
# ESC 3 n: set line spacing to n/180 inch. Font A chars are 12 dots wide,
|
|
# so n=12 makes rotated characters sit flush with no gap.
|
|
p._raw(b"\x1b\x33\x0c")
|
|
|
|
with open(csv_file) as f:
|
|
reader = csv.reader(f)
|
|
for row in reader:
|
|
_timestamp, symbol, lots_str, price_str = row
|
|
lots = int(lots_str)
|
|
price = float(price_str)
|
|
print_trade(p, symbol, lots, price)
|
|
|
|
# Feed past the cutter (~20mm above print head, ~12 lines at 12-dot spacing)
|
|
p.text("\n" * 16)
|
|
p.cut()
|
|
|
|
with open(output_file, "wb") as f:
|
|
f.write(p.output)
|
|
print(f"Wrote {len(p.output)} bytes to {output_file}", file=sys.stderr)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|