feat: Add trading app with position calculator and portfolio management
This commit is contained in:
parent
8302d796e0
commit
b7d3b8bc6d
87
src/trading/main.py
Normal file
87
src/trading/main.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from datetime import datetime
|
||||||
|
from position_calculator import PositionCalculator
|
||||||
|
from portfolio import Portfolio, Position
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Initialize portfolio and position calculator
|
||||||
|
portfolio = Portfolio()
|
||||||
|
calculator = PositionCalculator(account_size=100000) # $100k account
|
||||||
|
|
||||||
|
while True:
|
||||||
|
print("\nTrading Management System")
|
||||||
|
print("1. Calculate Position Size")
|
||||||
|
print("2. Add Position")
|
||||||
|
print("3. View Portfolio")
|
||||||
|
print("4. Remove Position")
|
||||||
|
print("5. Exit")
|
||||||
|
|
||||||
|
choice = input("\nSelect an option (1-5): ")
|
||||||
|
|
||||||
|
if choice == "1":
|
||||||
|
try:
|
||||||
|
entry_price = float(input("Enter entry price: "))
|
||||||
|
stop_loss = float(input("Enter stop loss price: "))
|
||||||
|
|
||||||
|
position = calculator.calculate_position_size(entry_price, stop_loss)
|
||||||
|
|
||||||
|
print("\nPosition Details:")
|
||||||
|
print(f"Shares: {position['shares']}")
|
||||||
|
print(f"Position Value: ${position['position_value']:.2f}")
|
||||||
|
print(f"Risk Amount: ${position['risk_amount']:.2f}")
|
||||||
|
print(f"Risk Per Share: ${position['risk_per_share']:.2f}")
|
||||||
|
|
||||||
|
except ValueError as e:
|
||||||
|
print(f"Error: {e}")
|
||||||
|
|
||||||
|
elif choice == "2":
|
||||||
|
try:
|
||||||
|
symbol = input("Enter symbol: ")
|
||||||
|
entry_price = float(input("Enter entry price: "))
|
||||||
|
shares = int(input("Enter number of shares: "))
|
||||||
|
stop_loss = float(input("Enter stop loss: "))
|
||||||
|
target_price = float(input("Enter target price: "))
|
||||||
|
|
||||||
|
position = Position(
|
||||||
|
symbol=symbol,
|
||||||
|
entry_date=datetime.now(),
|
||||||
|
entry_price=entry_price,
|
||||||
|
shares=shares,
|
||||||
|
stop_loss=stop_loss,
|
||||||
|
target_price=target_price
|
||||||
|
)
|
||||||
|
|
||||||
|
portfolio.add_position(position)
|
||||||
|
print(f"\nAdded position: {symbol}")
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
print("Invalid input. Please try again.")
|
||||||
|
|
||||||
|
elif choice == "3":
|
||||||
|
positions = portfolio.get_position_summary()
|
||||||
|
if not positions:
|
||||||
|
print("\nNo positions in portfolio")
|
||||||
|
else:
|
||||||
|
print("\nCurrent Portfolio:")
|
||||||
|
for pos in positions:
|
||||||
|
print(f"\nSymbol: {pos['symbol']}")
|
||||||
|
print(f"Entry Date: {pos['entry_date']}")
|
||||||
|
print(f"Entry Price: ${pos['entry_price']:.2f}")
|
||||||
|
print(f"Shares: {pos['shares']}")
|
||||||
|
print(f"Current Value: ${pos['current_value']:.2f}")
|
||||||
|
print(f"Stop Loss: ${pos['stop_loss']:.2f}")
|
||||||
|
print(f"Target: ${pos['target_price']:.2f}")
|
||||||
|
|
||||||
|
elif choice == "4":
|
||||||
|
symbol = input("Enter symbol to remove: ")
|
||||||
|
portfolio.remove_position(symbol)
|
||||||
|
print(f"\nRemoved position: {symbol}")
|
||||||
|
|
||||||
|
elif choice == "5":
|
||||||
|
print("\nExiting Trading Management System")
|
||||||
|
break
|
||||||
|
|
||||||
|
else:
|
||||||
|
print("\nInvalid choice. Please try again.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
44
src/trading/portfolio.py
Normal file
44
src/trading/portfolio.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
from typing import List, Dict
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Position:
|
||||||
|
symbol: str
|
||||||
|
entry_date: datetime
|
||||||
|
entry_price: float
|
||||||
|
shares: int
|
||||||
|
stop_loss: float
|
||||||
|
target_price: float
|
||||||
|
|
||||||
|
@property
|
||||||
|
def current_value(self) -> float:
|
||||||
|
# TODO: Implement real-time price fetching
|
||||||
|
return self.shares * self.entry_price
|
||||||
|
|
||||||
|
class Portfolio:
|
||||||
|
def __init__(self):
|
||||||
|
self.positions: List[Position] = []
|
||||||
|
|
||||||
|
def add_position(self, position: Position):
|
||||||
|
"""Add a new position to the portfolio"""
|
||||||
|
self.positions.append(position)
|
||||||
|
|
||||||
|
def remove_position(self, symbol: str):
|
||||||
|
"""Remove a position from the portfolio by symbol"""
|
||||||
|
self.positions = [p for p in self.positions if p.symbol != symbol]
|
||||||
|
|
||||||
|
def get_position_summary(self) -> List[Dict]:
|
||||||
|
"""Get summary of all positions"""
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"symbol": p.symbol,
|
||||||
|
"entry_date": p.entry_date,
|
||||||
|
"entry_price": p.entry_price,
|
||||||
|
"shares": p.shares,
|
||||||
|
"current_value": p.current_value,
|
||||||
|
"stop_loss": p.stop_loss,
|
||||||
|
"target_price": p.target_price
|
||||||
|
}
|
||||||
|
for p in self.positions
|
||||||
|
]
|
||||||
44
src/trading/position_calculator.py
Normal file
44
src/trading/position_calculator.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
class PositionCalculator:
|
||||||
|
def __init__(self, account_size: float, risk_percentage: float = 1.0):
|
||||||
|
"""
|
||||||
|
Initialize position calculator with account size and risk percentage
|
||||||
|
|
||||||
|
Args:
|
||||||
|
account_size (float): Total trading account value
|
||||||
|
risk_percentage (float): Maximum risk per trade as percentage (default 1%)
|
||||||
|
"""
|
||||||
|
self.account_size = account_size
|
||||||
|
self.risk_percentage = risk_percentage / 100.0 # Convert to decimal
|
||||||
|
|
||||||
|
def calculate_position_size(self, entry_price: float, stop_loss: float) -> dict:
|
||||||
|
"""
|
||||||
|
Calculate position size based on risk parameters
|
||||||
|
|
||||||
|
Args:
|
||||||
|
entry_price (float): Planned entry price
|
||||||
|
stop_loss (float): Stop loss price
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Position details including shares and dollar amounts
|
||||||
|
"""
|
||||||
|
# Calculate risk amount in dollars
|
||||||
|
risk_amount = self.account_size * self.risk_percentage
|
||||||
|
|
||||||
|
# Calculate per-share risk
|
||||||
|
risk_per_share = abs(entry_price - stop_loss)
|
||||||
|
|
||||||
|
if risk_per_share == 0:
|
||||||
|
raise ValueError("Entry price cannot equal stop loss price")
|
||||||
|
|
||||||
|
# Calculate number of shares
|
||||||
|
shares = int(risk_amount / risk_per_share)
|
||||||
|
|
||||||
|
# Calculate total position value
|
||||||
|
position_value = shares * entry_price
|
||||||
|
|
||||||
|
return {
|
||||||
|
"shares": shares,
|
||||||
|
"position_value": position_value,
|
||||||
|
"risk_amount": risk_amount,
|
||||||
|
"risk_per_share": risk_per_share
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user