Esempio n. 1
0
    def test_recommend_risk_fully_answered_bad_questions(self):
        # Fully populate the answers, but no range in the available question responses, we should get 0.5
        goal = Fixture1.goal1()
        settings = Fixture1.settings1()
        account = settings.goal.account
        Fixture1.populate_risk_profile_questions()  # Also populates all possible answers.
        Fixture1.populate_risk_profile_responses()

        Fixture1.risk_profile_question3()  # Add a question we don't have an answer for
        self.assertEqual(recommend_risk(settings), MINIMUM_RISK)

        # Now answer the question, we shouldn't get MINIMUM_RISK
        account.primary_owner.risk_profile_responses.add(Fixture1.risk_profile_answer3a())
        self.assertNotEqual(recommend_risk(settings), MINIMUM_RISK)
Esempio n. 2
0
 def test_recommend_risk_fully_answered(self):
     # Fully populate the answers, we should get 0.5
     goal = Fixture1.goal1()
     settings = Fixture1.settings1()
     Fixture1.populate_risk_profile_questions()  # Also populates all possible answers.
     Fixture1.populate_risk_profile_responses()
     self.assertEqual(recommend_risk(settings), 1.0)
Esempio n. 3
0
 def test_recommend_risk_fully_unanswered(self):
     # Populate the questions, we should still get 0.5
     goal = Fixture1.goal1()
     settings = Fixture1.settings1()
     account = settings.goal.account
     Fixture1.populate_risk_profile_questions()
     self.assertEqual(recommend_risk(settings), MINIMUM_RISK)
Esempio n. 4
0
    def test_max_risk(self):
        goal = Fixture1.goal1()
        settings = Fixture1.settings1()
        client = goal.account.primary_owner
        # Add the weights for the risk factors
        Fixture1.populate_risk_profile_questions()  # Also populates all possible answers.
        Fixture1.populate_risk_profile_responses()

        # we haven't set a net worth or a target, so worth_score isn't a factor

        # An all-9s account will have a max_risk of 1
        self.assertEqual(max_risk(settings), 1.0)

        # and if they are low risk behavior, high Ability + Sophistication
        # the max risk is still 1
        client.risk_profile_responses.clear()
        client.risk_profile_responses.add(Fixture1.risk_profile_answer1c())
        client.risk_profile_responses.add(Fixture1.risk_profile_answer2c())
        self.assertEqual(max_risk(settings), 1.0)

        # but if they are risky, new and unskilled, recommend no risk
        client.risk_profile_responses.clear()
        client.risk_profile_responses.add(Fixture1.risk_profile_answer1d())
        client.risk_profile_responses.add(Fixture1.risk_profile_answer2d())
        self.assertAlmostEqual(recommend_risk(settings), 0.1, 1)
        self.assertAlmostEqual(max_risk(settings), 0.1, 1)
Esempio n. 5
0
    def test_recommend_risk(self):
        goal = Fixture1.goal1()
        settings = Fixture1.settings1()
        client = goal.account.primary_owner
        # Add the weights for the risk factors
        Fixture1.populate_risk_profile_questions()  # Also populates all possible answers.
        Fixture1.populate_risk_profile_responses()

        # First lets start with the test_client, who scored 9 for all B,A,S

        # A goal of 80% of the value on a all-9s account is a bad idea
        # It's the lowest possible score
        settings.goal.account.primary_owner.net_worth = 100
        settings.goal.cash_balance = 80
        self.assertAlmostEqual(recommend_risk(settings), 0.10, 2)

        # A goal of 50% of the value is just as bad
        settings.goal.account.primary_owner.net_worth = 100
        settings.goal.cash_balance = 50
        self.assertAlmostEqual(recommend_risk(settings), 0.10, 2)

        # A goal of 10% of the value on a all-9s account is 1.0
        # meaning this is the safest possible bet
        settings.goal.account.primary_owner.net_worth = 100
        settings.goal.cash_balance = 10
        self.assertAlmostEqual(recommend_risk(settings), 1.0, 2)

        # A goal of 33% of the value on a all-9s account is about 0.5
        # Even if you are risky, sophisticated and rich, 30% is a lot
        settings.goal.account.primary_owner.net_worth = 100
        settings.goal.cash_balance = 33
        self.assertAlmostEqual(recommend_risk(settings), 0.5, 1)

        # For a new investor, the best possible suggestion is 10% or less
        settings.goal.account.primary_owner.net_worth = 100
        settings.goal.cash_balance = 10
        client.risk_profile_responses.clear()
        client.risk_profile_responses.add(Fixture1.risk_profile_answer1b())
        client.risk_profile_responses.add(Fixture1.risk_profile_answer2b())
        self.assertAlmostEqual(recommend_risk(settings), 0.2, 1)
Esempio n. 6
0
 def test_fully_answered_zero_max(self):
     goal = Fixture1.goal1()
     setting = Fixture1.settings1()
     risk_metric = setting.metric_group.metrics.get(type=GoalMetric.METRIC_TYPE_RISK_SCORE)
     q = RiskProfileQuestionFactory.create(group=goal.account.primary_owner.risk_profile_group)
     a = RiskProfileAnswerFactory.create(b_score=0, a_score=0, s_score=0, question=q)
     client = goal.account.primary_owner
     client.risk_profile_responses.add(a)
     self.assertGreater(risk_metric.configured_val, 0.01)
     with self.assertRaises(ValidationError) as ex:
         validate_risk_score(setting)
     risk_metric.configured_val = 0
     risk_metric.save()
     self.assertEqual(validate_risk_score(setting), None)  # Should now complete OK.
     self.assertEqual(max_risk(setting), 0.0)
     self.assertEqual(recommend_risk(setting), 0.0)
Esempio n. 7
0
    def create(self, validated_data):
        """
        Override the default create because we need to generate a portfolio.
        :param validated_data:
        :return: The created Goal
        """
        account = validated_data['account']

        with transaction.atomic():
            metric_group = GoalMetricGroup.objects.create(
                type=GoalMetricGroup.TYPE_CUSTOM)
            settings = GoalSetting.objects.create(
                target=validated_data['target'],
                completion=validated_data['completion'],
                hedge_fx=False,
                metric_group=metric_group,
            )

            portfolio_set = validated_data[
                'portfolio_set'] if 'portfolio_set' in validated_data else account.default_portfolio_set

            goal = Goal.objects.create(
                account=account,
                name=validated_data['name'],
                type=validated_data['type'],
                portfolio_set=portfolio_set,
                selected_settings=settings,
            )
            # Based on the risk profile, and whether an ethical profile was specified on creation, set up Metrics.
            recommended_risk = recommend_risk(settings)
            GoalMetric.objects.create(
                group=metric_group,
                type=GoalMetric.METRIC_TYPE_RISK_SCORE,
                comparison=GoalMetric.METRIC_COMPARISON_EXACTLY,
                rebalance_type=GoalMetric.REBALANCE_TYPE_ABSOLUTE,
                rebalance_thr=0.05,
                configured_val=recommended_risk)
            if validated_data['ethical']:
                GoalMetric.objects.create(
                    group=metric_group,
                    type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX,
                    feature=AssetFeatureValue.Standard.SRI_OTHER.get_object(),
                    comparison=GoalMetric.METRIC_COMPARISON_EXACTLY,
                    rebalance_type=GoalMetric.REBALANCE_TYPE_ABSOLUTE,
                    rebalance_thr=0.05,
                    configured_val=1  # Start with 100% ethical.
                )

            # Make sure the risk score assigned is appropriate for the goal.
            firm_config = account.primary_owner.firm.config
            unlimited = firm_config.risk_score_unlimited
            try:
                validate_risk_score(settings, unlimited)
            except CVE as verr:
                raise ValidationError(verr.message)

            # Add the initial deposit if specified.
            initial_dep = validated_data.pop('initial_deposit', None)
            if initial_dep is not None:
                Transaction.objects.create(reason=Transaction.REASON_DEPOSIT,
                                           to_goal=goal,
                                           amount=initial_dep)

            # Calculate the optimised portfolio
            goal.calculate_portfolio_for_selected()

        return goal
Esempio n. 8
0
 def test_recommend_risk_no_weights(self):
     goal = Fixture1.goal1()
     settings = Fixture1.settings1()
     self.assertEqual(recommend_risk(settings), MINIMUM_RISK)
Esempio n. 9
0
 def test_recommend_risk_no_questions(self):
     goal = Fixture1.goal1()
     settings = Fixture1.settings1()
     account = settings.goal.account
     self.assertEqual(recommend_risk(settings), MINIMUM_RISK)
Esempio n. 10
0
    def create(self, validated_data):
        """
        Override the default create because we need to generate a portfolio.
        :param validated_data:
        :return: The created Goal
        """
        account = validated_data['account']

        data_provider = DataProviderDjango()
        execution_provider = ExecutionProviderDjango()
        idata = get_instruments(data_provider)

        with transaction.atomic():
            metric_group = GoalMetricGroup.objects.create(
                type=GoalMetricGroup.TYPE_CUSTOM)
            settings = GoalSetting.objects.create(
                target=validated_data['target'],
                completion=validated_data['completion'],
                hedge_fx=False,
                metric_group=metric_group,
            )

            portfolio_provider_id = validated_data[
                'portfolio_provider'] if 'portfolio_provider' in validated_data else get_default_provider_id(
                )

            portfolio_set_id = ''
            portfolio_providers = PortfolioProvider.objects.all()
            portfolio_provider = get_default_provider()
            for pp in portfolio_providers:
                if pp.id == portfolio_provider_id:
                    portfolio_provider = pp

            if portfolio_provider.type == constants.PORTFOLIO_PROVIDER_TYPE_KRANE:
                portfolio_set_type = constants.PORTFOLIO_SET_TYPE_KRANE
            elif portfolio_provider.type == constants.PORTFOLIO_PROVIDER_TYPE_AON:
                portfolio_set_type = constants.PORTFOLIO_SET_TYPE_AON
            elif portfolio_provider.type == constants.PORTFOLIO_PROVIDER_TYPE_LEE:
                portfolio_set_type = constants.PORTFOLIO_SET_TYPE_LEE
            else:
                raise Exception('unhandled portfolio_provider_id')

            portfolio_sets = PortfolioSet.objects.all()
            portfolio_set = account.default_portfolio_set
            for ps in portfolio_sets:
                if ps.type == portfolio_set_type:
                    portfolio_set = ps

            goal = Goal.objects.create(
                account=account,
                name=validated_data['name'],
                type=validated_data['type'],
                portfolio_set=portfolio_set,
                portfolio_provider=portfolio_provider,
                selected_settings=settings,
            )
            # Based on the risk profile, and whether an ethical profile was specified on creation, set up Metrics.
            recommended_risk = recommend_risk(settings)
            GoalMetric.objects.create(
                group=metric_group,
                type=GoalMetric.METRIC_TYPE_RISK_SCORE,
                comparison=GoalMetric.METRIC_COMPARISON_EXACTLY,
                rebalance_type=GoalMetric.REBALANCE_TYPE_ABSOLUTE,
                rebalance_thr=0.05,
                configured_val=recommended_risk)
            if validated_data['ethical']:
                GoalMetric.objects.create(
                    group=metric_group,
                    type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX,
                    feature=AssetFeatureValue.Standard.SRI_OTHER.get_object(),
                    comparison=GoalMetric.METRIC_COMPARISON_EXACTLY,
                    rebalance_type=GoalMetric.REBALANCE_TYPE_ABSOLUTE,
                    rebalance_thr=0.05,
                    configured_val=1  # Start with 100% ethical.
                )

            # Make sure the risk score assigned is appropriate for the goal.
            try:
                validate_risk_score(settings)
            except CVE as verr:
                raise ValidationError(verr.message)

            # Add the initial deposit if specified.
            initial_dep = validated_data.pop('initial_deposit', None)
            if initial_dep is not None:
                Transaction.objects.create(reason=Transaction.REASON_DEPOSIT,
                                           to_goal=goal,
                                           amount=initial_dep)

            # Calculate the optimised portfolio
            try:
                weights, er, stdev = calculate_portfolio(
                    settings, data_provider, execution_provider, True, idata)
                portfolio = Portfolio.objects.create(
                    setting=settings,
                    stdev=stdev,
                    er=er,
                )
                items = [
                    PortfolioItem(portfolio=portfolio,
                                  asset=Ticker.objects.get(id=tid),
                                  weight=weight,
                                  volatility=idata[0].loc[tid, tid])
                    for tid, weight in weights.iteritems()
                ]
                PortfolioItem.objects.bulk_create(items)
            except Unsatisfiable:
                # We detect when loading a goal in the allocation screen if there has been no portfolio created
                # and return a message to the user. It it perfectly reasonable for a goal to be created without a
                # portfolio.
                logger.exception(
                    "No suitable portfolio could be found. Leaving empty.")

        return goal