def selected_settings(self, request, pk=None, **kwargs): goal = self.get_object() if request.method == 'GET': serializer = serializers.GoalSettingSerializer( goal.selected_settings) return Response(serializer.data) with transaction.atomic(): # So both the log and change get committed. sr_id = SupportRequest.get_current(request) if request.method == 'POST': check_state(Goal.State(goal.state), Goal.State.ACTIVE) serializer = serializers.GoalSettingWritableSerializer( data=request.data) serializer.is_valid(raise_exception=True) event = Event.SET_SELECTED_SETTINGS.log( '{} {}'.format(self.request.method, self.request.path), request.data, user=request.user, obj=goal, support_request_id=sr_id) # Write any event memo for the event. All the details are wrapped by the serializer. serializer.write_memo(event) settings = serializer.save(goal=goal) # We use the read-only serializer to send the settings object, not the update serializer. serializer = serializers.GoalSettingSerializer(settings) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) elif request.method == 'PUT': check_state(Goal.State(goal.state), Goal.State.ACTIVE) settings = goal.selected_settings event = Event.UPDATE_SELECTED_SETTINGS.log( '{} {}'.format(self.request.method, self.request.path), request.data, user=request.user, obj=goal, support_request_id=sr_id) serializer = serializers.GoalSettingWritableSerializer( settings, data=request.data, partial=True) serializer.is_valid(raise_exception=True) # Write any event memo for the event. All the details are wrapped by the serializer. serializer.write_memo(event) settings = serializer.save(goal=goal) # We use the read-only serializer to send the settings object, not the update serializer. serializer = serializers.GoalSettingSerializer(settings) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_200_OK, headers=headers)
def get_context_data(self, *args, **kwargs): goal_pk = kwargs.get("goal_pk", None) ctx = super(PortfolioAssetClasses, self).get_context_data(*args, **kwargs) if goal_pk: goal = get_object_or_404(Goal, pk=goal_pk) ctx["portfolio_set"] = goal.portfolio_set else: ctx["portfolio_set"] = Goal().portfolio_set return ctx
def archive(self, request, pk=None, **kwargs): """ Override this method as we don't want to actually delete the goal, just disable it. :param instance: The goal to disable :return: None """ goal = self.get_object() # If I'm an advisor or the goal is unsupervised, # archive the goal immediately. sr = SupportRequest.get_current(request, as_obj=True) # check helped user instead if support request is active user, sr_id = (sr.user, sr.id) if sr else (request.user, None) if not goal.account.supervised or user.is_advisor: check_state(Goal.State(goal.state), [Goal.State.ACTIVE, Goal.State.ARCHIVE_REQUESTED]) Event.ARCHIVE_GOAL.log('{} {}'.format(request.method, request.path), user=request.user, obj=goal, support_request_id=sr_id) # Set the state to archive requested, # as the call to archive() requires it. goal.state = Goal.State.ARCHIVE_REQUESTED.value goal.archive() else: # I'm a client with a supervised goal, just change the status to # ARCHIVE_REQUESTED, and add a notification check_state(Goal.State(goal.state), Goal.State.ACTIVE) Event.ARCHIVE_GOAL_REQUESTED.log('{} {}'.format( request.method, request.path), user=request.user, obj=goal, support_request_id=sr_id) # Flag the goal as archive requested. goal.state = Goal.State.ARCHIVE_REQUESTED.value # TODO: Add a notification to the advisor that the goal is archive requested. goal.save() return Response(serializers.GoalSerializer(goal).data)
def calculate_all_portfolios(self, request, pk=None, **kwargs): """ Called to calculate all the portfolio objects for 100 different risk scores for the supplied settings. """ goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) setting_str = request.query_params.get('setting', None) if not setting_str: logger.debug( 'setting parameter missing from calculate_all_portfolios query' ) raise ValidationError( "Query parameter 'setting' must be specified and a valid JSON string" ) try: setting = ujson.loads(setting_str) except ValueError: logger.debug( 'setting parameter for calculate_all_portfolios query not valid json' ) raise ValidationError( "Query parameter 'setting' must be a valid json string") # Create the settings from the dict serializer = serializers.GoalSettingStatelessSerializer(data=setting) serializer.is_valid(raise_exception=True) settings = serializer.create_stateless(serializer.validated_data, goal) # Calculate the portfolio try: data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() data = [ self.build_portfolio_data(item[1], item[0]) for item in calculate_portfolios(setting=settings, data_provider=data_provider, execution_provider=execution_provider) ] return Response(data) except Unsatisfiable as e: rdata = {'reason': "No portfolio could be found: {}".format(e)} if e.req_funds is not None: rdata['req_funds'] = e.req_funds return Response({'error': rdata}, status=status.HTTP_400_BAD_REQUEST)
def get(self, request, *args, **kwargs): portfolio_set = Goal().portfolio_set goal_pk = kwargs.get("goal_pk", None) if goal_pk: try: goal = Goal.objects.get(pk=goal_pk, account__primary_owner=self.client) except ObjectDoesNotExist: goal = None if goal: if goal.is_custom_size: if goal.portfolios in [None, "{}", "[]", ""]: try: portfolios = calculate_portfolios(goal) goal.portfolios = ujson.dumps(portfolios, double_precision=2) goal.save() except OptimizationException: goal.custom_regions = None goal.save() portfolios = ujson.loads(goal.portfolio_set.portfolios) else: portfolios = ujson.loads(goal.portfolios) else: portfolios = ujson.loads(goal.portfolio_set.portfolios) ret = [] for k in portfolios: new_pr = { "risk": int(100 * portfolios[k]["risk"]) / 100, "expectedReturn": portfolios[k]["expectedReturn"], "volatility": portfolios[k]["volatility"], 'allocations': portfolios[k]["allocations"] } ret.append(new_pr) return HttpResponse(ujson.dumps(ret), content_type="application/json") ret = [] portfolios = ujson.loads(portfolio_set.portfolios) for k in portfolios: new_pr = { "risk": int(100 * portfolios[k]["risk"]) / 100, "expectedReturn": portfolios[k]["expectedReturn"], "volatility": portfolios[k]["volatility"], 'allocations': portfolios[k]["allocations"] } ret.append(new_pr) return HttpResponse(ujson.dumps(ret), content_type="application/json")
def deposit(self, request, pk=None, **kwargs): goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) sr_id = SupportRequest.get_current(request) Event.GOAL_DEPOSIT.log('{} {}'.format(request.method, request.path), request.data, user=request.user, obj=goal, support_request_id=sr_id) serializer = serializers.TransactionCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) serializer.save(to_goal=goal, reason=Transaction.REASON_DEPOSIT) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def revert_selected(self, request, pk=None, **kwargs): """ Called to revert the current selected-settings to the approved-settings Returns a validation error if there is no approved-settings. """ goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) if not goal.approved_settings: raise ValidationError("No settings have yet been approved for " "this Goal, cannot revert to last approved.") sr_id = SupportRequest.get_current(request) Event.REVERT_SELECTED_SETTINGS.log('{} {}'.format( request.method, request.path), user=request.user, obj=goal, support_request_id=sr_id) goal.revert_selected() serializer = serializers.GoalSettingSerializer(goal.selected_settings) return Response(serializer.data)
def calculate_portfolios(): # calculate default portfolio yahoo_api = get_api("YAHOO") for ps in PortfolioSet.objects.all(): goal = Goal() goal.custom_portfolio_set = ps ps.portfolios = json.dumps( calculate_portfolios_for_goal(goal, api=yahoo_api)) ps.save() # calculate portfolios for goal in Goal.objects.all(): if goal.is_custom_size: goal.portfolios = json.dumps( calculate_portfolios_for_goal(goal, api=yahoo_api)) goal.save()
def calculate_portfolio(self, request, pk=None, **kwargs): """ Called to calculate a portfolio object for a set of supplied settings. """ goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) setting_str = request.query_params.get('setting', None) if not setting_str: raise ValidationError( "Query parameter 'setting' must be specified and a valid JSON string" ) try: setting = ujson.loads(setting_str) except ValueError: raise ValidationError( "Query parameter 'setting' must be a valid json string") # Create the settings object from the dict serializer = serializers.GoalSettingStatelessSerializer(data=setting) serializer.is_valid(raise_exception=True) settings = serializer.create_stateless(serializer.validated_data, goal) try: data = self.build_portfolio_data( calculate_portfolio( settings=settings, data_provider=DataProviderDjango(), execution_provider=ExecutionProviderDjango())) return Response(data) except Unsatisfiable as e: rdata = {'reason': "No portfolio could be found: {}".format(e)} if e.req_funds is not None: rdata['req_funds'] = e.req_funds return Response({'error': rdata}, status=status.HTTP_400_BAD_REQUEST)
def approve_selected(self, request, pk=None, **kwargs): """ Called to make the currently selected settings approved by the advisor, ready to be activated next time the account is processed (rebalance). """ sr = SupportRequest.get_current(request, as_obj=True) # check helped user instead if support request is active user, sr_id = (sr.user, sr.id) if sr else (request.user, None) if not user.is_advisor: raise PermissionDenied('Only an advisor can approve selections.') goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) Event.APPROVE_SELECTED_SETTINGS.log('{} {}'.format( request.method, request.path), user=request.user, obj=goal, support_request_id=sr_id) goal.approve_selected() serializer = serializers.GoalSettingSerializer(goal.approved_settings) return Response(serializer.data)
def withdraw(self, request, pk=None, **kwargs): goal = self.get_object() check_state(Goal.State(goal.state), Goal.State.ACTIVE) sr_id = SupportRequest.get_current(request) Event.GOAL_WITHDRAWAL.log('{} {}'.format(request.method, request.path), request.data, user=request.user, obj=goal, support_request_id=sr_id) serializer = serializers.TransactionCreateSerializer(data=request.data) serializer.is_valid(raise_exception=True) # Make sure the total amount for the goal is larger than the pending withdrawal amount. if goal.current_balance + 0.0000001 < serializer.validated_data[ 'amount']: emsg = "Goal's current balance: {} is less than the desired withdrawal amount: {}" raise SystemConstraintError( emsg.format(goal.current_balance, serializer.validated_data['amount'])) serializer.save(from_goal=goal, reason=Transaction.REASON_WITHDRAWAL) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def post(self, requests, *args, **kwargs): if "HTTP_X_HTTP_METHOD_OVERRIDE" in requests.META: if requests.META["HTTP_X_HTTP_METHOD_OVERRIDE"] == "DELETE": return self.delete(requests, *args, **kwargs) model = ujson.loads(requests.POST.get("model", '{}')) goal = Goal() goal.account = self.client.accounts.first() goal.name = model.get("name") goal.type = model.get("goalType") if "ETHICAL" in goal.type: goal.custom_portfolio_set = PortfolioSet.objects.get(name="Ethical") goal.account_type = model.get("accountType") goal.completion_date = datetime.strptime( model.get("goalCompletionDate"), '%Y%m%d%H%M%S') goal.allocation = model.get("allocation") goal.target = model.get("goalAmount", None) if goal.target is None: goal.target = 0 goal.income = model.get("income", False) goal.save() return HttpResponse(ujson.dumps({"id": goal.pk}), content_type='application/json')