Instructions
Requirements and Specifications
Source Code
import csv
import datetime
import json
import operator
MAIN_MENU = '''\nPlease choose from the options below
1. Load trading data
2. Load current stock prices
3. Manually enter a new trade
4. View trading data
5. View current portfolio
6. Save trading data
7. Quit'''
def main():
trading_data = []
current_prices = {}
print("Welcome to the Trader Assistant")
print("Programmed by <your name here>")
print(MAIN_MENU)
menu_choice = input(">>> ")
while menu_choice != '7':
if menu_choice == '1':
trading_data = load_trading_data()
elif menu_choice == '2':
current_prices = load_prices_data()
elif menu_choice == '3':
enter_new_trade(trading_data)
elif menu_choice == '4':
view_trading_data(trading_data)
elif menu_choice == '5':
view_portfolio(trading_data, current_prices)
elif menu_choice == '6':
save(trading_data)
else:
print("Invalid selection")
print(MAIN_MENU)
menu_choice = input(">>> ")
def load_trading_data():
trading_data = []
loaded = False
# keep asking user until valid loading happened
while not loaded:
filename = input('Enter filename: ').strip()
# checking if input is blank
if len(filename) == 0:
print('Cannot be blank.')
continue
# checking if filename is valid by trying to open such file
# if not - exception is thrown
try:
file_in = open(filename, 'r', newline='')
csv_reader = csv.reader(file_in)
for row in csv_reader:
row[2] = int(row[2]) # convert the quantity into an int
row[3] = float(row[3]) # convert the dollar value into a float
row[4] = datetime.datetime.strptime(row[4], '%Y-%m-%d') # convert the string value into a datetime
trading_data.append(row)
print(f"{len(trading_data)} trades loaded.")
file_in.close()
loaded = True
# processing possible exceptions
except FileNotFoundError:
print('Please enter a valid filename.')
except Exception:
print('Error with file format.')
# returning result
return trading_data
def load_prices_data():
current_prices = {}
# keep asking user until valid loading happened
loaded = False
while not loaded:
filename = input('Enter filename: ').strip()
# checking if input is blank
if len(filename) == 0:
print('Cannot be blank.')
continue
# checking if filename is valid by trying to open such file
# if not - exception is thrown
try:
file_in = open(filename, 'r', newline='')
current_prices = json.load(file_in)
for key in current_prices:
current_prices[key] = float(current_prices[key]) # converting price strings to float
print(f"Loaded {len(current_prices)} stock prices.")
file_in.close()
loaded = True
# processing possible exceptions
except FileNotFoundError:
print('Please enter a valid filename.')
except Exception:
print('Error with file format.')
return current_prices
def enter_new_trade(trading_data):
ticker = ''
# keep asking for ticker until a non blank input
while len(ticker) == 0:
ticker = input('{0:<34}'.format('Ticker:')).strip()
if len(ticker) == 0:
print('Cannot be blank.')
# keep asking for Buy or Sell until b or s is input
flag = ''
while len(flag) == 0:
flag = input('{0:<34}'.format('Buy or sell:')).strip()
if flag != 'b' and flag != 's':
print('Please enter b or s.')
flag = ''
# keep asking for quantity until positive integer is input
qos = 0
while qos <= 0:
try:
qos = int(input('{0:<34}'.format('Quantity of stock:')).strip())
if qos <= 0:
print('Please enter a positive whole number.')
# exception happens on any conversion from string to int error
except Exception:
print('Please enter a positive whole number.')
cost = 0.0
prompt = 'Total proceeds (less brokerage):'
if flag == 'b':
prompt = 'Total cost (including brokerage):'
# keep asking for cost until positive float is input
while cost <= 0.0:
try:
cost = float(input('{0:<34}'.format(prompt)).strip())
if cost <= 0.0:
print('Please enter a positive number.')
# exception happens on any conversion from string to int error
except Exception:
print('Please enter a positive number.')
date = None
# keep asking for quantity until good-formatted date is input
while date is None:
try:
date = datetime.datetime.strptime(input('{0:<34}'.format('Date:')).strip(), '%Y-%m-%d')
break
# exception happens on any date parsing error
except Exception:
print('Please enter a date in yyyy-mm-dd format.')
flag_s = 'SELL'
if flag == 'b':
flag_s = 'BUY'
# making good formatted strings
print('{0} {1:<10} {2:<12}{3:>5} for $ {4:>13.2f}'.format(datetime.datetime.strftime(date, '%Y-%m-%d'), ticker, flag_s, str(qos), cost))
# adding created record to data list
record = [ticker, flag, qos, cost, date]
trading_data.append(record)
print('Trade added to system.')
def view_trading_data(trading_data):
if len(trading_data) > 0:
# trying to read ticker filter
ticker = input('Ticker (leave blank for all): ').strip()
# making filtering of all trades based on ticker
copy = []
for trade in trading_data:
if len(ticker) == 0 or trade[0] == ticker:
copy.append(trade)
# if filter resulted in an empty list, showing message
if len(copy) == 0:
print('No trades found for that ticker symbol.')
return
# asking if sort is needed
sort_needed = input('Sort dates in reverse chronological order? (y/n) ').strip() == 'y'
if sort_needed:
# if sorting is needed, making sorting by date in reverse order
copy.sort(key=lambda x: x[4], reverse=True)
# for each trade in sorted filtered list, outputting result
for trade in copy:
ticker = trade[0]
flag_s = 'SELL'
if trade[1] == 'b':
flag_s = 'BUY'
quantity = trade[2]
dollar_value = trade[3]
date = trade[4]
# making good formatted strings
print('{0} {1:<10} {2:<12}{3:>5} for $ {4:>13.2f}'.format(datetime.datetime.strftime(date, '%Y-%m-%d'), ticker,
flag_s, str(quantity), dollar_value))
else:
print("No trades found.")
def view_portfolio(trading_data, current_prices):
# checking if data list is not empty
if len(trading_data) > 0:
tickers = []
# collecting all existing tickers
for trade in trading_data:
if trade[0] not in tickers:
tickers.append(trade[0])
# for each ticker making calculations
for ticker in tickers:
print(ticker)
total_units = 0
# counting total units
for trade in trading_data:
if trade[0] == ticker:
# if there was BUY, number of units is increased
if trade[1] == 'b':
total_units += trade[2]
else:
# if there was SELL, number of units is decreased
total_units -= trade[2]
# outputting number of units
print('{0:<15} {1:>15}'.format('Total units:', str(total_units)))
# outputting value
value = 0.00
if total_units != 0 and ticker not in current_prices:
# showing unknown message if units is not 0 and there is no such ticker in current_prices
print('Current value unknown.')
else:
if ticker in current_prices:
value = current_prices[ticker] * total_units
print('{0:<15} {1:>18.2f}'.format('Total value: $', value))
else:
print("No trades found.")
def save(trading_data):
saved = False
# keep asking user until valid saving happened
while not saved:
filename = input('Enter filename: ').strip()
# checking if input is blank
if len(filename) == 0:
print('Cannot be blank.')
continue
# checking if filename is valid by trying to open such file
# if not - exception is thrown
try:
file_out = open(filename, 'w', newline='')
for trade in trading_data:
trade_s = [trade[0], trade[1], str(trade[2]), str(trade[3]), datetime.datetime.strftime(trade[4], '%Y-%m-%d')]
print(','.join(trade_s), file=file_out)
print(f"Data saved to {filename}.")
file_out.close()
saved = True
# processing possible exceptions
except Exception:
print('Please enter a valid filename.')
main()