diff --git a/.Jules/palette.md b/.Jules/palette.md index 96bd45d..aaee479 100644 --- a/.Jules/palette.md +++ b/.Jules/palette.md @@ -5,3 +5,7 @@ ## 2025-02-28 - Structured CLI Reports **Learning:** Dense numerical data in CLI output is hard to parse. Using ASCII box-drawing characters and alignment to create a "dashboard" or "invoice" style summary significantly improves readability and perceived quality. **Action:** When summarizing simulation or batch job results, always format the final report as a structured table or box rather than a list of print statements. + +## 2025-03-01 - Dynamic Progress Bars in Quiet Mode +**Learning:** For long-running CLI processes that suppress verbose logging (e.g., `--quiet`), users can feel lost or assume the process has hung. +**Action:** Implement a dynamic progress bar using `\r` and `flush=True` conditional on `sys.stdout.isatty()` to provide system status visibility without polluting standard output logs. diff --git a/bitcoin_trading_simulation.py b/bitcoin_trading_simulation.py index cb07d20..cfb29ec 100644 --- a/bitcoin_trading_simulation.py +++ b/bitcoin_trading_simulation.py @@ -84,7 +84,7 @@ def simulate_trading(signals, initial_cash=10000, quiet=False): if not quiet: print(f"\n{Colors.HEADER}{Colors.BOLD}------ Daily Trading Ledger ------{Colors.ENDC}") - for i, row in signals.iterrows(): + for idx, (i, row) in enumerate(signals.iterrows()): if i > 0: portfolio.loc[i, 'cash'] = portfolio.loc[i-1, 'cash'] portfolio.loc[i, 'btc'] = portfolio.loc[i-1, 'btc'] @@ -94,14 +94,16 @@ def simulate_trading(signals, initial_cash=10000, quiet=False): btc_to_buy = portfolio.loc[i, 'cash'] / row['price'] portfolio.loc[i, 'btc'] += btc_to_buy portfolio.loc[i, 'cash'] -= btc_to_buy * row['price'] - print(f"{Colors.GREEN}🟢 Day {i}: Buy {btc_to_buy:.4f} BTC at ${row['price']:.2f}{Colors.ENDC}") + if not quiet: + print(f"{Colors.GREEN}🟢 Day {i}: Buy {btc_to_buy:.4f} BTC at ${row['price']:.2f}{Colors.ENDC}") # Sell signal elif row['positions'] == -2.0: if portfolio.loc[i, 'btc'] > 0: cash_received = portfolio.loc[i, 'btc'] * row['price'] portfolio.loc[i, 'cash'] += cash_received - print(f"{Colors.FAIL}🔴 Day {i}: Sell {portfolio.loc[i, 'btc']:.4f} BTC at ${row['price']:.2f}{Colors.ENDC}") + if not quiet: + print(f"{Colors.FAIL}🔴 Day {i}: Sell {portfolio.loc[i, 'btc']:.4f} BTC at ${row['price']:.2f}{Colors.ENDC}") portfolio.loc[i, 'btc'] = 0 portfolio.loc[i, 'total_value'] = portfolio.loc[i, 'cash'] + portfolio.loc[i, 'btc'] * row['price'] @@ -109,6 +111,13 @@ def simulate_trading(signals, initial_cash=10000, quiet=False): if not quiet: print(f"Day {i}: Portfolio Value: ${portfolio.loc[i, 'total_value']:.2f}, " f"Cash: ${portfolio.loc[i, 'cash']:.2f}, BTC: {portfolio.loc[i, 'btc']:.4f}") + elif sys.stdout.isatty(): + # Dynamic progress bar for quiet mode + progress = int((idx + 1) / len(signals) * 100) + print(f"\r{Colors.CYAN}Running simulation: {progress}%{Colors.ENDC}", end="", flush=True) + + if quiet and sys.stdout.isatty(): + print() return portfolio diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..41e0572 --- /dev/null +++ b/main.tf @@ -0,0 +1 @@ +terraform {} \ No newline at end of file diff --git a/test_isatty.py b/test_isatty.py new file mode 100644 index 0000000..1882575 --- /dev/null +++ b/test_isatty.py @@ -0,0 +1,3 @@ +def test_isatty(capsys): + import sys + print("isatty:", sys.stdout.isatty()) diff --git a/test_progress.py b/test_progress.py new file mode 100644 index 0000000..d2b6312 --- /dev/null +++ b/test_progress.py @@ -0,0 +1,12 @@ +import sys +import pandas as pd +from bitcoin_trading_simulation import simulate_trading, Colors + +# mock isatty +sys.stdout.isatty = lambda: True + +signals = pd.DataFrame(index=range(10)) +signals['price'] = [100.0] * 10 +signals['positions'] = [0.0] * 10 + +simulate_trading(signals, quiet=True) diff --git a/test_quiet.py b/test_quiet.py new file mode 100644 index 0000000..53da94e --- /dev/null +++ b/test_quiet.py @@ -0,0 +1,7 @@ +import sys +from bitcoin_trading_simulation import simulate_bitcoin_prices, calculate_moving_averages, generate_trading_signals, simulate_trading + +prices = simulate_bitcoin_prices(days=60, initial_price=50000, volatility=0.02) +signals = calculate_moving_averages(prices) +signals = generate_trading_signals(signals) +simulate_trading(signals, quiet=True) diff --git a/test_quiet_buy_sell.py b/test_quiet_buy_sell.py new file mode 100644 index 0000000..c61725d --- /dev/null +++ b/test_quiet_buy_sell.py @@ -0,0 +1,21 @@ +import pandas as pd +from bitcoin_trading_simulation import simulate_trading + +def test_quiet_suppresses_buys_sells(): + signals = pd.DataFrame(index=range(3)) + signals['price'] = [100.0, 101.0, 102.0] + signals['positions'] = [2.0, -2.0, 0.0] + + import io + import sys + + old_stdout = sys.stdout + sys.stdout = io.StringIO() + simulate_trading(signals, initial_cash=1000, quiet=True) + out = sys.stdout.getvalue() + sys.stdout = old_stdout + + assert out == "" + +test_quiet_suppresses_buys_sells() +print("Passed")