def render_to_response(self, context): qs = context['paginator'].object_list.all( ) # all() to get a fresh queryset instance qs = list(qs.values_list('asx_code', flat=True)) if len(qs) == 0: warning(self.request, "No stocks to report") sentiment_data, df, top10, bottom10, n_stocks = (None, None, None, None, 0) else: sentiment_data, df, top10, bottom10, n_stocks = plot_heatmap( qs, n_top_bottom=self.n_top_bottom) context.update({ 'most_recent_date': self.as_at_date, 'sentiment_heatmap': sentiment_data, 'watched': user_watchlist( self.request.user), # to ensure bookmarks are correct 'n_top_bottom': self.n_top_bottom, 'best_ten': top10, 'worst_ten': bottom10, 'title': 'Find by dividend yield or P/E', 'sentiment_heatmap_title': "Recent sentiment: {} total stocks".format(n_stocks), }) add_messages(self.request, context) return super().render_to_response(context)
def render_to_response(self, context): context.update(self.template_values_dict) context.update({ # NB: we use update() to not destroy page_obj 'watched': user_watchlist(self.request.user), # to highlight top10/bottom10 bookmarks correctly 'title': 'Find by company sector', }) assert context['sector_id'] is not None and isinstance( context['sector_id'], int) context['sentiment_heatmap_title'] = "{}: past {} days".format( context['sector_name'], context['n_days']) add_messages(self.request, context) return super().render_to_response(context)
def show_matching_companies(matching_companies, title, heatmap_title, user_purchases, request, extra_context=None): """ Support function to public-facing views to eliminate code redundancy """ assert len(matching_companies) > 0 assert isinstance(title, str) and isinstance(heatmap_title, str) stocks_queryset, date = latest_quote(matching_companies) stocks_queryset = stocks_queryset.order_by('asx_code') print("Found {} quotes for {} stocks".format(stocks_queryset.count(), len(matching_companies))) # paginate results for 50 stocks per page paginator = Paginator(stocks_queryset, 50) page_number = request.GET.get('page', 1) page_obj = paginator.page(page_number) # add sentiment heatmap amongst watched stocks n_days = 30 n_top_bottom = 20 sentiment_heatmap_data, df, top10, bottom10, n = \ plot_heatmap(matching_companies, all_dates=desired_dates(start_date=n_days), n_top_bottom=n_top_bottom) context = { "most_recent_date": latest_quotation_date('ANZ'), "page_obj": page_obj, "title": title, "watched": user_watchlist(request.user), 'n_top_bottom': n_top_bottom, "best_ten": top10, "worst_ten": bottom10, "virtual_purchases": user_purchases, "sentiment_heatmap": sentiment_heatmap_data, "sentiment_heatmap_title": "{}: past {} days".format(heatmap_title, n_days) } if extra_context: context.update(extra_context) add_messages(request, context) return render(request, 'all_stocks.html', context=context)
def show_companies( matching_companies, # may be QuerySet or iterable of stock codes (str) request, sentiment_timeframe: Timeframe, extra_context=None, template_name="all_stocks.html", ): """ Support function to public-facing views to eliminate code redundancy """ virtual_purchases_by_user = user_purchases(request.user) if isinstance(matching_companies, QuerySet): stocks_queryset = matching_companies # we assume QuerySet is already sorted by desired criteria elif matching_companies is None or len(matching_companies) > 0: stocks_queryset, _ = latest_quote(matching_companies) # FALLTHRU # sort queryset as this will often be requested by the USER sort_by = tuple(request.GET.get("sort_by", "asx_code").split(",")) info(request, "Sorting by {}".format(sort_by)) stocks_queryset = stocks_queryset.order_by(*sort_by) # keep track of stock codes for template convenience asx_codes = [quote.asx_code for quote in stocks_queryset.all()] n_top_bottom = extra_context['n_top_bottom'] if 'n_top_bottom' in extra_context else 20 print("show_companies: found {} stocks".format(len(asx_codes))) # setup context dict for the render context = { # NB: title and heatmap_title are expected to be supplied by caller via extra_context "timeframe": sentiment_timeframe, "title": "Caller must override", "watched": user_watchlist(request.user), "n_stocks": len(asx_codes), "n_top_bottom": n_top_bottom, "virtual_purchases": virtual_purchases_by_user, } # since we sort above, we must setup the pagination also... assert isinstance(stocks_queryset, QuerySet) paginator = Paginator(stocks_queryset, 50) page_number = request.GET.get("page", 1) page_obj = paginator.page(page_number) context['page_obj'] = page_obj context['object_list'] = paginator if len(asx_codes) <= 0: warning(request, "No matching companies found.") else: df = selected_cached_stocks_cip(asx_codes, sentiment_timeframe) sentiment_heatmap_data, top10, bottom10 = plot_heatmap(df, sentiment_timeframe, n_top_bottom=n_top_bottom) sector_breakdown_plot = plot_breakdown(df) context.update({ "best_ten": top10, "worst_ten": bottom10, "sentiment_heatmap": sentiment_heatmap_data, "sentiment_heatmap_title": "{}: {}".format(context['title'], sentiment_timeframe.description), "sector_breakdown_plot": sector_breakdown_plot, }) if extra_context: context.update(extra_context) add_messages(request, context) #print(context) return render(request, template_name, context=context)
def show_companies( matching_companies, # may be QuerySet or iterable of stock codes (str) request, sentiment_timeframe: Timeframe, extra_context=None, template_name="all_stocks.html", ): """ Support function to public-facing views to eliminate code redundancy """ if isinstance(matching_companies, QuerySet): stocks_queryset = matching_companies # we assume QuerySet is already sorted by desired criteria elif matching_companies is None or len(matching_companies) > 0: stocks_queryset, _ = latest_quote(matching_companies) # FALLTHRU else: # no companies to report? warning(request, "No matching companies.") return render(request, template_name, context={"timeframe": sentiment_timeframe}) # prune companies without a latest price, makes no sense to report them stocks_queryset = stocks_queryset.exclude(last_price__isnull=True) # sort queryset as this will often be requested by the USER arg = request.GET.get("sort_by", "asx_code") #info(request, "Sorting by {}".format(arg)) if arg == "sector" or arg == "sector,-eps": ss = { s["asx_code"]: s["sector_name"] for s in stocks_by_sector().to_dict("records") } if arg == "sector": stocks_queryset = sorted(stocks_queryset, key=lambda s: ss.get(s.asx_code, "Z") ) # companies without sector sort last else: eps_dict = { s.asx_code: s.eps if s.eps is not None else 0.0 for s in stocks_queryset } stocks_queryset = sorted( stocks_queryset, key=lambda s: (ss.get(s.asx_code, "Z"), -eps_dict.get(s.asx_code, 0.0)), ) else: sort_by = tuple(arg.split(",")) stocks_queryset = stocks_queryset.order_by(*sort_by) # keep track of stock codes for template convenience asx_codes = [quote.asx_code for quote in stocks_queryset] n_top_bottom = (extra_context["n_top_bottom"] if "n_top_bottom" in extra_context else 20) print("show_companies: found {} stocks".format(len(asx_codes))) # setup context dict for the render context = { # NB: title and heatmap_title are expected to be supplied by caller via extra_context "timeframe": sentiment_timeframe, "title": "Caller must override", "watched": user_watchlist(request.user), "n_stocks": len(asx_codes), "n_top_bottom": n_top_bottom, "virtual_purchases": user_purchases(request.user), } # since we sort above, we must setup the pagination also... # assert isinstance(stocks_queryset, QuerySet) paginator = Paginator(stocks_queryset, 50) page_number = request.GET.get("page", 1) page_obj = paginator.page(page_number) context["page_obj"] = page_obj context["object_list"] = paginator # compute totals across all dates for the specified companies to look at top10/bottom10 in the timeframe ld = LazyDictionary() ld["cip_df"] = lambda ld: selected_cached_stocks_cip( asx_codes, sentiment_timeframe) ld["sum_by_company"] = lambda ld: ld["cip_df"].sum(axis=1, numeric_only=True) ld["top10"] = lambda ld: ld["sum_by_company"].nlargest(n_top_bottom) ld["bottom10"] = lambda ld: ld["sum_by_company"].nsmallest(n_top_bottom) ld["stocks_by_sector"] = lambda ld: stocks_by_sector() if len(asx_codes) <= 0 or len(ld["top10"]) <= 0: warning(request, "No matching companies found.") else: sorted_codes = "-".join(sorted(asx_codes)) sentiment_heatmap_uri = cache_plot( f"{sorted_codes}-{sentiment_timeframe.description}-stocks-sentiment-plot", lambda ld: plot_heatmap(sentiment_timeframe, ld), datasets=ld, ) key = f"{sorted_codes}-{sentiment_timeframe.description}-breakdown-plot" sector_breakdown_uri = cache_plot(key, plot_breakdown, datasets=ld) top10_plot_uri = cache_plot( f"top10-plot-{'-'.join(ld['top10'].index)}", lambda ld: plot_cumulative_returns(ld["top10"].index, ld), datasets=ld, ) bottom10_plot_uri = cache_plot( f"bottom10-plot-{'-'.join(ld['bottom10'].index)}", lambda ld: plot_cumulative_returns(ld["bottom10"].index, ld), datasets=ld, ) context.update({ "best_ten": ld["top10"], "worst_ten": ld["bottom10"], "sentiment_heatmap_uri": sentiment_heatmap_uri, "sentiment_heatmap_title": "{}: {}".format(context["title"], sentiment_timeframe.description), "sector_breakdown_uri": sector_breakdown_uri, "top10_plot_uri": top10_plot_uri, "bottom10_plot_uri": bottom10_plot_uri, "timeframe_end_performance": timeframe_end_performance(ld), }) if extra_context: context.update(extra_context) add_messages(request, context) # print(context) return render(request, template_name, context=context)