Skip to content
Open
7 changes: 7 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## 2024-05-22 - Visual Hierarchy in CLI Output
**Learning:** Adding color-coded indicators (Green/Red) and emojis (💰, 📉) in CLI tools significantly reduces cognitive load when parsing financial data streams. It transforms a wall of text into a scannable narrative.
**Action:** For data-heavy CLI applications, always implement a semantic color system and visual anchors (icons/emojis) for key events.

## 2024-10-24 - CLI Accessibility and Configuration
**Learning:** Hardcoded values and mandatory color codes limit CLI usability and accessibility. `--no-color` supports monochrome terminals/parsing, and `argparse` empowers users.
**Action:** Always wrap CLI entry points with argument parsing and provide flags to disable purely visual features like color.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,7 @@

# debug information files
*.dwo

# Python
__pycache__/
*.pyc
37 changes: 35 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,35 @@
# code
Programming with C++ code
# Bitcoin Trading Simulation

A Python-based CLI tool that simulates Bitcoin trading using a 'Golden Cross' moving average strategy. It generates synthetic price data using Geometric Brownian Motion, executes trades based on technical indicators, and provides a daily ledger with a final performance summary.

## Features

- **Price Simulation:** Uses Geometric Brownian Motion to simulate 60 days of Bitcoin prices.
- **Trading Strategy:** Implements a Golden Cross strategy (Short MA > Long MA = Buy, Short MA < Long MA = Sell).
- **Rich CLI Output:** features color-coded logs (Green for Buy/Profit, Red for Sell/Loss) and emojis for better readability.
- **Performance metrics:** Compares the strategy's performance against a "Buy and Hold" approach.

## Installation

1. Clone the repository.
2. Install the required dependencies:

```bash
pip install -r requirements.txt
```

## Usage

Run the simulation script:

```bash
python bitcoin_trading_simulation.py
```

## Tests

Run the test suite:

```bash
python test.py
```
91 changes: 70 additions & 21 deletions bitcoin_trading_simulation.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import argparse
import numpy as np
import pandas as pd


class Colors:
HEADER = '\033[95m'
BLUE = '\033[94m'
GREEN = '\033[92m'
RED = '\033[91m'
ENDC = '\033[0m'
BOLD = '\033[1m'


def simulate_bitcoin_prices(days=60, initial_price=50000, volatility=0.02):
"""
Simulates Bitcoin prices for a given number of days using Geometric Brownian Motion.
Expand All @@ -15,6 +26,7 @@ def simulate_bitcoin_prices(days=60, initial_price=50000, volatility=0.02):
prices.append(prices[-1] + price_change)
return pd.Series(prices, name='Price')


def calculate_moving_averages(prices, short_window=7, long_window=30):
"""
Calculates short and long moving averages for a given price series.
Expand All @@ -25,6 +37,7 @@ def calculate_moving_averages(prices, short_window=7, long_window=30):
signals['long_mavg'] = prices.rolling(window=long_window, min_periods=1, center=False).mean()
return signals


def generate_trading_signals(signals):
"""
Generates trading signals based on the Golden Cross strategy.
Expand All @@ -36,22 +49,25 @@ def generate_trading_signals(signals):
signals.loc[signals['short_mavg'] > signals['long_mavg'], 'signal'] = 1.0
# A Death Cross (sell signal)
signals.loc[signals['short_mavg'] < signals['long_mavg'], 'signal'] = -1.0

# We create 'positions' to represent the trading action: 1 for buy, -1 for sell, 0 for hold
signals['positions'] = signals['signal'].diff().shift(1)
return signals

def simulate_trading(signals, initial_cash=10000):

def simulate_trading(signals, initial_cash=10000, quiet=False):
"""
Simulates trading based on signals and prints a daily ledger.
"""
portfolio = pd.DataFrame(index=signals.index).fillna(0.0)
portfolio['price'] = signals['price']
portfolio['cash'] = initial_cash
portfolio['cash'] = float(initial_cash)
portfolio['btc'] = 0.0
portfolio['total_value'] = portfolio['cash']
portfolio['total_value'] = float(initial_cash)

if not quiet:
print(f"{Colors.HEADER}{Colors.BOLD}------ Daily Trading Ledger ------{Colors.ENDC}")

print("------ Daily Trading Ledger ------")
for i, row in signals.iterrows():
if i > 0:
portfolio.loc[i, 'cash'] = portfolio.loc[i-1, 'cash']
Expand All @@ -62,46 +78,79 @@ def simulate_trading(signals, initial_cash=10000):
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"Day {i}: Buy {btc_to_buy:.4f} BTC at ${row['price']:.2f}")
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"Day {i}: Sell {portfolio.loc[i, 'btc']:.4f} BTC at ${row['price']:.2f}")
if not quiet:
print(f"{Colors.RED}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']
print(f"Day {i}: Portfolio Value: ${portfolio.loc[i, 'total_value']:.2f}, Cash: ${portfolio.loc[i, 'cash']:.2f}, BTC: {portfolio.loc[i, 'btc']:.4f}")


if not quiet:
msg = (f"Day {i}: Portfolio Value: ${portfolio.loc[i, 'total_value']:.2f}, "
f"Cash: ${portfolio.loc[i, 'cash']:.2f}, BTC: {portfolio.loc[i, 'btc']:.4f}")
print(msg)

return portfolio


def parse_arguments():
parser = argparse.ArgumentParser(description='Bitcoin Trading Simulation')
parser.add_argument('--days', type=int, default=60, help='Number of days to simulate')
parser.add_argument('--initial-cash', type=float, default=10000, help='Initial cash amount')
parser.add_argument('--initial-price', type=float, default=50000, help='Initial Bitcoin price')
parser.add_argument('--volatility', type=float, default=0.02, help='Volatility factor')
parser.add_argument('--quiet', '-q', action='store_true', help='Suppress daily ledger output')
parser.add_argument('--no-color', action='store_true', help='Disable colored output')
return parser.parse_args()


if __name__ == "__main__":
args = parse_arguments()

if args.no_color:
Colors.HEADER = ''
Colors.BLUE = ''
Colors.GREEN = ''
Colors.RED = ''
Colors.ENDC = ''
Colors.BOLD = ''

# Simulate prices
prices = simulate_bitcoin_prices()
prices = simulate_bitcoin_prices(days=args.days, initial_price=args.initial_price, volatility=args.volatility)

# Calculate moving averages
signals = calculate_moving_averages(prices)

# Generate trading signals
signals = generate_trading_signals(signals)

# Simulate trading
portfolio = simulate_trading(signals)
portfolio = simulate_trading(signals, initial_cash=args.initial_cash, quiet=args.quiet)

# Final portfolio performance
final_value = portfolio['total_value'].iloc[-1]
initial_cash = 10000
initial_cash = args.initial_cash
profit = final_value - initial_cash

# Compare with buy and hold strategy
buy_and_hold_btc = initial_cash / prices.iloc[0]
buy_and_hold_value = buy_and_hold_btc * prices.iloc[-1]
print("\n------ Final Portfolio Performance ------")

print(f"\n{Colors.HEADER}{Colors.BOLD}------ Final Portfolio Performance ------{Colors.ENDC}")
print(f"Initial Cash: ${initial_cash:.2f}")
print(f"Final Portfolio Value: ${final_value:.2f}")
print(f"Profit/Loss: ${profit:.2f}")

if profit >= 0:
print(f"Profit/Loss: {Colors.GREEN}📈 ${profit:.2f}{Colors.ENDC}")
else:
print(f"Profit/Loss: {Colors.RED}📉 ${profit:.2f}{Colors.ENDC}")

print(f"Buy and Hold Strategy Value: ${buy_and_hold_value:.2f}")
print("-----------------------------------------")
print(f"{Colors.HEADER}-----------------------------------------{Colors.ENDC}")
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
numpy
pandas
File renamed without changes.