Change table to box-style, supports unicode by default and ASCII as fallback mode
This commit is contained in:
parent
4c70fbd27a
commit
ef75e3e5f0
3 changed files with 103 additions and 8 deletions
|
|
@ -9,6 +9,10 @@ from .formatter import (
|
|||
format_currency_color,
|
||||
format_currency_color_padded,
|
||||
truncate_ticker,
|
||||
format_table_header,
|
||||
format_table_separator,
|
||||
format_table_row,
|
||||
get_box_chars,
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -26,29 +30,45 @@ def main():
|
|||
action="store_true",
|
||||
help="Disable ANSI color output",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--ascii",
|
||||
action="store_true",
|
||||
help="Use ASCII characters instead of Unicode box-drawing",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
no_color = args.no_color
|
||||
ascii_mode = args.ascii
|
||||
|
||||
kalshi = KalshiCSV(args.csv_path)
|
||||
kalshi.parse()
|
||||
|
||||
headers = ["Ticker", "Side", "Qty", "Entry", "Exit", "P&L (No Fees)", "Fees"]
|
||||
widths = [32, 4, 6, 6, 6, 14, 6]
|
||||
|
||||
print()
|
||||
print(
|
||||
f"{'Ticker':<32} | {'Side':<4} | {'Qty':<6} | {'Entry':<6} | {'Exit':<6} | {'P&L (No Fees)':<14} | {'Fees':<6}"
|
||||
)
|
||||
print("-" * 90)
|
||||
print(format_table_separator(widths, ascii_mode, "top"))
|
||||
print(format_table_header(headers, widths, ascii_mode))
|
||||
print(format_table_separator(widths, ascii_mode, "middle"))
|
||||
|
||||
for trade in kalshi.trades:
|
||||
pnl_str = format_currency_color_padded(trade["pnl_no_fees"], 14, no_color)
|
||||
fees = trade["open_fees"] + trade["close_fees"]
|
||||
ticker_display = truncate_ticker(trade["ticker"])
|
||||
print(
|
||||
f"{ticker_display:<32} | {trade['side']:<4} | {trade['qty']:<6.2f} | "
|
||||
f"${trade['entry']:<5.2f} | ${trade['exit']:<5.2f} | {pnl_str} | ${fees:<5.2f}"
|
||||
)
|
||||
|
||||
print("-" * 90)
|
||||
box = get_box_chars(ascii_mode)
|
||||
row = (
|
||||
f" {ticker_display:<32} "
|
||||
f"{box['vertical']} {trade['side']:<4} "
|
||||
f"{box['vertical']} {trade['qty']:<6.2f} "
|
||||
f"{box['vertical']} ${trade['entry']:<5.2f} "
|
||||
f"{box['vertical']} ${trade['exit']:<5.2f} "
|
||||
f"{box['vertical']} {pnl_str} "
|
||||
f"{box['vertical']} ${fees:<5.2f} "
|
||||
)
|
||||
print(box["vertical"] + row + box["vertical"])
|
||||
|
||||
print(format_table_separator(widths, ascii_mode, "bottom"))
|
||||
print(f"Total Transactions Parsed: {kalshi.summary['trade_count']}")
|
||||
print(f"Total Exchange Fees Paid: ${kalshi.summary['total_fees']:.2f}")
|
||||
print(
|
||||
|
|
|
|||
|
|
@ -51,3 +51,64 @@ def truncate_ticker(ticker, max_len=32):
|
|||
if len(ticker) > 29:
|
||||
return ticker[:29] + "..."
|
||||
return ticker
|
||||
|
||||
|
||||
UNICODE_BOX = {
|
||||
"top_left": "┌",
|
||||
"top_right": "┐",
|
||||
"bottom_left": "└",
|
||||
"bottom_right": "┘",
|
||||
"horizontal": "─",
|
||||
"vertical": "│",
|
||||
"top_tee": "┬",
|
||||
"bottom_tee": "┴",
|
||||
"left_tee": "├",
|
||||
"right_tee": "┤",
|
||||
"cross": "┼",
|
||||
}
|
||||
|
||||
ASCII_BOX = {
|
||||
"top_left": "+",
|
||||
"top_right": "+",
|
||||
"bottom_left": "+",
|
||||
"bottom_right": "+",
|
||||
"horizontal": "-",
|
||||
"vertical": "|",
|
||||
"top_tee": "+",
|
||||
"bottom_tee": "+",
|
||||
"left_tee": "+",
|
||||
"right_tee": "+",
|
||||
"cross": "+",
|
||||
}
|
||||
|
||||
|
||||
def get_box_chars(ascii_mode=False):
|
||||
"""Returns the appropriate box-drawing characters."""
|
||||
return ASCII_BOX if ascii_mode else UNICODE_BOX
|
||||
|
||||
|
||||
def format_table_header(headers, widths, ascii_mode=False):
|
||||
"""Formats a table header row with box-drawing characters."""
|
||||
box = get_box_chars(ascii_mode)
|
||||
cells = [f" {h:<{w}} " for h, w in zip(headers, widths)]
|
||||
return box["vertical"] + box["vertical"].join(cells) + box["vertical"]
|
||||
|
||||
|
||||
def format_table_separator(widths, ascii_mode=False, position="middle"):
|
||||
"""Formats a table separator line with box-drawing characters."""
|
||||
box = get_box_chars(ascii_mode)
|
||||
segments = [box["horizontal"] * (w + 2) for w in widths]
|
||||
|
||||
if position == "top":
|
||||
return box["top_left"] + box["top_tee"].join(segments) + box["top_right"]
|
||||
elif position == "bottom":
|
||||
return box["bottom_left"] + box["bottom_tee"].join(segments) + box["bottom_right"]
|
||||
else:
|
||||
return box["left_tee"] + box["cross"].join(segments) + box["right_tee"]
|
||||
|
||||
|
||||
def format_table_row(values, widths, ascii_mode=False):
|
||||
"""Formats a table data row with box-drawing characters."""
|
||||
box = get_box_chars(ascii_mode)
|
||||
cells = [f" {str(v):<{w}} " for v, w in zip(values, widths)]
|
||||
return box["vertical"] + box["vertical"].join(cells) + box["vertical"]
|
||||
|
|
|
|||
|
|
@ -85,3 +85,17 @@ def test_cli_ticker_truncation(tmp_path):
|
|||
assert result.returncode == 0
|
||||
assert "VERYLONGTICKERNAME-THAT-EXCEE..." in result.stdout
|
||||
assert "VERYLONGTICKERNAME-THAT-EXCEEDS-THIRTY-CHARS" not in result.stdout
|
||||
|
||||
|
||||
def test_cli_ascii_flag(sample_csv):
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "kalshi_csv.cli", sample_csv, "--no-color", "--ascii"],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "+" in result.stdout
|
||||
assert "-" in result.stdout
|
||||
assert "|" in result.stdout
|
||||
assert "┌" not in result.stdout
|
||||
assert "│" not in result.stdout
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue