def add(code, user): # Get current stock info from Finnhub API code = code.upper() api = Api() messages = {} try: stockinfo = api.search(code) except Exception as e: messages['error'] = str(e) return messages price = stockinfo['c'] timestamp = stockinfo['t'] # cache stock info if this is the first time app has encountered stock stocks = Stock.objects.filter(code=code) if (stocks.count() != 1): Stock.objects.create(name=stockinfo["name"], code=code) stock_to_add_in_wl = Stock.objects.get(code=code) wl = WatchListItem.objects.filter(user_id=user, stock=stock_to_add_in_wl) if (wl.count() != 0): messages['error'] = "Stock {} is already in your watchlist".format( code) return messages WatchListItem.objects.create(user_id=user, stock=stock_to_add_in_wl, timestamp=datetime.utcnow().timestamp()) messages['success'] = "Stock {} added to your watchlist".format(code) return messages
def sell(code, units, user): code = code.upper() api = Api() messages = {} try: tgt = api.search(code) except Exception as e: messages['error'] = str(e) return messages stocks = Stock.objects.filter(code=code) if (stocks.count() != 1): Stock.objects.create(name=tgt["name"], code=code) st = Stock.objects.get(code=code) price = tgt['c'] money = price * units current_units = purchases.get_total_owned_units(user, code) balance = user.profile.balance remaining_sell_units = units if current_units >= units: ps = purchases.get_unsold_purhases(user, code) for p in ps: if (remaining_sell_units == 0): break unsold_purchased_units = p.orignialUnitBought - p.unitSold if (unsold_purchased_units <= remaining_sell_units): remaining_sell_units = remaining_sell_units - unsold_purchased_units p.unitSold = p.orignialUnitBought p.save() else: p.unitSold = p.unitSold + remaining_sell_units p.save() remaining_sell_units = 0 newBalance = balance + decimal.Decimal(float(money)) user.profile.balance = newBalance user.save() messages[ 'success'] = "Successfully sold {} shares of Stock {} costing {}".format( units, code, round(money, 2)) Transaction.objects.create(user_id=user, stock=st, units=units, price=price, action="sell") else: messages[ 'error'] = "Insufficient number of shares in Stock {} to sell {} units".format( code, units) return messages
class test_search(TestCase): def setUp(self): self.api = Api() def test_upper(self): assert self.api.search("AAPL") != {} def test_lower(self): assert self.api.search("aapl") != {} def test_invalid(self): assert self.api.search( "abcd") == "The stock code you searched was invalid" assert self.api.search( "goog") == "The stock code you searched was invalid"
def list_watchlist(user, messages): api = Api() result = WatchListItem.objects.filter(user_id=user) wlist = [] for row in result: wlist_entry = {} code = row.stock.code wlist_entry['code'] = code wlist_entry['name'] = row.stock.name wlist_entry['date'] = row.date wlist_entry['timestamp'] = row.timestamp # Get current stock info from Finnhub API try: stockinfo = api.search(code) wlist_entry['current'] = stockinfo['c'] wlist_entry['change'] = stockinfo['change'] except Exception as e: wlist_entry['current'] = "N/A" wlist_entry['change'] = "N/A" messages['error'] = str(e) wlist.append(wlist_entry) # Get all alerts related to stock stock = Stock.objects.get(code=code) alerts_to_show = WatchListAlert.objects.filter(user_id=user, stock=stock, triggered=True, shown=False) print(len(alerts_to_show)) for alert in alerts_to_show: messages[ f'alert at {alert.dateTriggered} for {alert.stock.code}'] = f"Stock {alert.stock.name} hit {alert.watchprice} at {alert.dateTriggered}" alert.shown = True alert.save() # Column for watch prices not triggered yet alerts_not_triggered_yet = WatchListAlert.objects.filter( user_id=user, stock=stock, triggered=False) wlist_entry['alerts'] = [] for alert in alerts_not_triggered_yet: wlist_entry['alerts'].append(alert) return wlist, messages
class test_search(TestCase): def setUp(self): self.api = Api() def test_upper(self): assert self.api.search("AAPL") != {} def test_lower(self): assert self.api.search("aapl") != {} def test_invalid(self): try: info = self.api.search("abcd") except Exception as e: assert str(e) == "The stock code you searched was invalid" else: assert 1 == 2
def get_user_profit(user_id, cprice_cache): api = Api() purchases = Purchase.objects.filter(user_id=user_id, unitSold__lt=F('orignialUnitBought')) total_worth = 0 for purchase in purchases: orignialUnitBought = purchase.orignialUnitBought unitSold = purchase.unitSold unitsOwned = orignialUnitBought - unitSold if purchase.stock.code not in cprice_cache.keys(): stockinfo = api.search(purchase.stock.code) cprice_cache[purchase.stock.code] = stockinfo['c'] current_price = cprice_cache[purchase.stock.code] purchase_worth = round(unitsOwned * current_price, 2) total_worth = total_worth + purchase_worth return round(total_worth, 2), cprice_cache
def buy(code, units, user): code = code.upper() api = Api() messages = {} try: tgt = api.search(code) except Exception as e: messages['error'] = str(e) return messages stocks = Stock.objects.filter(code=code) if (stocks.count() != 1): Stock.objects.create(name=tgt["name"], code=code) st = Stock.objects.get(code=code) price = tgt['c'] price = decimal.Decimal(float(price)) money = price * units balance = user.profile.balance if balance >= money: newBalance = balance - money user.profile.balance = newBalance user.save() Purchase.objects.create(user_id=user, stock=st, price=price, orignialUnitBought=units, unitSold=0) Transaction.objects.create(user_id=user, stock=st, units=units, price=price, action="buy") messages[ 'success'] = "Successfully bought {} shares of Stock {} costing {}".format( units, code, round(money, 2)) else: messages[ 'error'] = "Insufficient funds in balance for buying {} units of Stock {} for ${}".format( units, code, round(money, 2)) return messages
def get_purchases_info(user_id, include_sold): api = Api() if include_sold: purchases = Purchase.objects.filter( user_id=user_id).order_by('dateBought') else: purchases = Purchase.objects.filter( user_id=user_id, unitSold__lt=F('orignialUnitBought')).order_by('dateBought') cprice_cache = {} purchase_summary = [] messages = {} for purchase in purchases: summary_entry = {} summary_entry['code'] = purchase.stock.code summary_entry['dateBought'] = purchase.dateBought summary_entry['price'] = purchase.price summary_entry['orignialUnitBought'] = purchase.orignialUnitBought summary_entry['unitsSold'] = purchase.unitSold summary_entry[ 'unitsOwned'] = purchase.orignialUnitBought - purchase.unitSold summary_entry[ 'paid'] = summary_entry['unitsOwned'] * summary_entry['price'] if purchase.stock.code not in cprice_cache.keys(): try: stockinfo = api.search(purchase.stock.code) except Exception as e: messages['error'] = str(e) return [], messages # Add api result to cache cprice_cache[purchase.stock.code] = stockinfo['c'] summary_entry['c'] = cprice_cache[purchase.stock.code] summary_entry[ 'worth'] = summary_entry['unitsOwned'] * summary_entry['c'] summary_entry['profit'] = round( float(summary_entry['worth']) - float(summary_entry['paid']), 2) summary_entry['timestamp'] = purchase.dateBought purchase_summary.append(summary_entry) return purchase_summary, messages
def search_view(request): if ("code" in request.GET): messages = {} api = Api() code = request.GET.get('code') try: result = api.search(code) except Exception as e: messages['error'] = str(e) search_info = {'messages': messages} else: search_info = result finally: return render(request, 'simulator/search.html', search_info) return render(request, 'simulator/search.html')
def stock_detail(request, code): stockObj = Stock.objects.get(code=code) api = Api() stockinfo = api.search(code) stock = {} stock['code'] = stockObj.code stock['name'] = stockObj.name stock['current'] = stockinfo['c'] stock['change'] = stockinfo['change'] stock['alerts'] = [] alerts_not_triggered_yet = WatchListAlert.objects.filter(user_id=request.user, stock=stockObj, triggered=False) if alerts_not_triggered_yet.count() == 0: stock['alert'] = "No alerts to display" else: stock['alert'] = "" for alert in alerts_not_triggered_yet: stock['alerts'].append(alert) return render(request, 'simulator/stock_detail.html', {'stock': stock})
def setUp(self): self.api = Api()
def __init__(self): self.api = Api()
class Watchprice: def __init__(self): self.api = Api() ''' Method used to check if a given watch price alert has been trigged. parameters alertId : WatchListAlert model ID field ''' def check(self, alertId): while True: time.sleep(10) try: alert = WatchListAlert.objects.get(id=alertId) if alert.triggered: return code = alert.stock.code action = alert.action current_price = self.api.search(code)['c'] if action == "sell": # current price is greater than or equal to watchprice if current_price >= alert.watchprice: # frontend - add new notification alert.dateTriggered = datetime.now().isoformat( ' ', 'seconds') # db - set flag to true alert.triggered = True alert.save() return elif action == "buy": # current price is less than or equal to watchprice if current_price <= alert.watchprice: # frontend - add new notification alert.dateTriggered = datetime.now().isoformat( ' ', 'seconds') # db - set flag to true alert.triggered = True alert.save() return except: # ID cant be found exception because watch price was deleted. End thread return ''' Method used to set a watchprice of a given stock. Watchprices with a "buy" action are triggered when the current price is below the watch price (buy low), whereas watchprices with a "sell" action are triggered when the current price is above the watch price (sell high). parameters code : string price : float user : User model action : string ("buy" or "sell") returns messages : {string : string} ''' def set(self, code, price, user, action): stock = Stock.objects.get(code=code) alert = WatchListAlert.objects.create(user_id=user, stock=stock, watchprice=price, action=action) messages = {} messages[ 'watchprice_set'] = f"Successfully set trigger to {action} stock {code} at watch price {price}" alertId = alert.pk th = threading.Thread(target=self.check, args=(alertId, )) th.start() print("Returning messages") return messages ''' Starts the threads which will monitor the watchprices by with the check method ''' def start_up(self): alerts = WatchListAlert.objects.filter(triggered=False) for alert in alerts: th = threading.Thread(target=self.check, args=(alert.id, )) th.start() ''' Removes a given watch price parameters user : User model alert : WatchListAlert model returns messages : {string : string} ''' def remove(self, user, alert): alert_obj = WatchListAlert.objects.get(user_id=user, id=alert) code = alert_obj.stock.code price = alert_obj.watchprice messages = {} messages[ 'removed_wp'] = "Watchprice {} of stock {} has been removed from your watchlist".format( price, code) alert_obj.delete() return messages