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
| class TradingAccount:
"""Basic trading account"""
def __init__(self, owner, cash):
self.owner = owner
self._cash = cash
self._holdings = {} # {ticker: number of shares held}
self._trades = [] # trade history
@property
def cash(self):
return self._cash
@property
def holdings(self):
return dict(self._holdings) # return a copy to prevent direct external modification
def buy(self, symbol, shares, price):
cost = shares * price
if cost > self._cash:
raise ValueError(f"Insufficient cash: need {cost:,}, have {self._cash:,}")
self._cash -= cost
self._holdings[symbol] = self._holdings.get(symbol, 0) + shares
self._trades.append(("Buy", symbol, shares, price))
print(f"Bought {symbol} {shares} shares @ {price}, cash remaining: {self._cash:,.0f}")
def sell(self, symbol, shares, price):
if self._holdings.get(symbol, 0) < shares:
raise ValueError(f"Insufficient {symbol} shares")
self._cash += shares * price
self._holdings[symbol] -= shares
if self._holdings[symbol] == 0:
del self._holdings[symbol]
self._trades.append(("Sell", symbol, shares, price))
print(f"Sold {symbol} {shares} shares @ {price}, cash remaining: {self._cash:,.0f}")
def portfolio(self, current_prices):
total = self._cash
print(f"\n===== {self.owner}'s Portfolio =====")
print(f"Cash: {self._cash:>12,.0f}")
for symbol, shares in self._holdings.items():
price = current_prices.get(symbol, 0)
value = shares * price
total += value
print(f"{symbol}: {shares} shares × {price:,} = {value:>10,.0f}")
print(f"{'─' * 30}")
print(f"Total assets: {total:>10,.0f}")
def __str__(self):
return f"TradingAccount({self.owner}, cash={self._cash:,.0f})"
class MarginAccount(TradingAccount):
"""Margin account (inherits from TradingAccount, supports leverage)"""
def __init__(self, owner, cash, leverage=2):
super().__init__(owner, cash)
self.leverage = leverage # leverage multiplier
@property
def buying_power(self):
"""Buying power = cash × leverage"""
return self._cash * self.leverage
def buy(self, symbol, shares, price):
cost = shares * price
if cost > self.buying_power:
raise ValueError(f"Exceeds buying power limit: {self.buying_power:,}")
# Accessing parent's private attribute must go through methods
# Simplified here: deduct only the actual cash proportion
actual_cost = cost / self.leverage
self._cash -= actual_cost
self._holdings[symbol] = self._holdings.get(symbol, 0) + shares
self._trades.append(("Buy (Margin)", symbol, shares, price))
print(f"Margin buy {symbol} {shares} shares @ {price}, buying power remaining: {self.buying_power:,.0f}")
# Regular account
acc = TradingAccount("Alice", 100_000)
acc.buy("2330", 10, 950)
acc.buy("0050", 20, 150)
acc.sell("2330", 5, 1_000)
current_prices = {"2330": 1_000, "0050": 155}
acc.portfolio(current_prices)
print()
# Margin account
margin = MarginAccount("Bob", 50_000, leverage=2)
print(f"Buying power: {margin.buying_power:,}") # 100,000
margin.buy("2330", 5, 950)
|