def test_get_asset_weights_held_less_than1y_without_new_postions(self): fund = TickerFactory.create(unit_price=2.1) goal = GoalFactory.create() today = datetime.date(2016, 1, 1) # Create a 6 month old execution, transaction and a distribution that caused the transaction Fixture1.create_execution_details(goal, fund, 10, 2, datetime.date(2014, 6, 1)) ep = ExecutionProviderDjango() vals = ep.get_asset_weights_held_less_than1y(goal, today) self.assertEqual(len(vals), 0)
def test_get_asset_weights_without_tax_winners(self): fund = TickerFactory.create(unit_price=3) goal = GoalFactory.create() today = datetime.date(2016, 1, 1) # Create a 6 month old execution, transaction and a distribution that caused the transaction Fixture1.create_execution_details(goal, fund, 10, 2, datetime.date(2014, 6, 1)) Fixture1.create_execution_details(goal, fund, 10, 4, datetime.date(2015, 6, 1)) ep = ExecutionProviderDjango() vals = ep.get_asset_weights_without_tax_winners(goal=goal) self.assertAlmostEqual(vals[fund.id], (10*3) / goal.available_balance)
def calculate_portfolio_for_selected(self): from portfolios.providers.data.django import DataProviderDjango from portfolios.providers.execution.django import ExecutionProviderDjango from portfolios.calculation import Unsatisfiable, calculate_portfolio, get_instruments data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() idata = get_instruments(data_provider) try: weights, er, stdev = calculate_portfolio(self.selected_settings, data_provider, execution_provider, True, idata) portfolio = Portfolio.objects.create( setting=self.selected_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.")
def handle(self, *args, **options): from portfolios.providers.execution.django import ExecutionProviderDjango data_provider = DataProviderDjango(timezone.now().date()) execution_provider = ExecutionProviderDjango() idata = get_instruments(data_provider) for gs in GoalSetting.objects.all(): if gs.can_rebalance: logger.info('Rebalancing goal %s' % gs.goal) rebalance(gs.goal, idata, data_provider, execution_provider)
def __init__(self): self._covars = self._samples = self._instruments = self._masks = None self.data_provider = DataProviderBacktest(sliding_window_length=250 * 5, dir='/backtesting/') self.execution_provider = ExecutionProviderDjango() MarkowitzScaleFactory.create() self.data_provider.get_goals() self.goal = None
def handle_noargs(self, **options): ''' runs process(data_provider, execution_provider, delay) in betasmartz / execution / end_of_day.py ''' from datetime import datetime from execution.end_of_day import process from portfolios.providers.execution.django import ExecutionProviderDjango from portfolios.providers.data.django import DataProviderDjango data_provider = DataProviderDjango(datetime.now().date()) execution_provider = ExecutionProviderDjango() process(data_provider, execution_provider, 5)
def setUp(self): self.t1 = TickerFactory.create(symbol='SPY', unit_price=5) self.t2 = TickerFactory.create(symbol='VEA', unit_price=5) self.t3 = TickerFactory.create(symbol='TIP', unit_price=100) self.t4 = TickerFactory.create(symbol='IEV', unit_price=100) self.t5 = TickerFactory.create(symbol='IEV2', unit_price=100, asset_class=self.t4.asset_class) self.equity = AssetFeatureValueFactory.create( name='equity', assets=[self.t1, self.t2]) self.bond = AssetFeatureValueFactory.create(name='bond', assets=[self.t3, self.t4]) self.goal_settings = GoalSettingFactory.create() asset_classes = [ self.t1.asset_class, self.t2.asset_class, self.t3.asset_class, self.t4.asset_class ] portfolio_set = PortfolioSetFactory.create(name='set', risk_free_rate=0.01, asset_classes=asset_classes) self.goal = GoalFactory.create(approved_settings=self.goal_settings, active_settings=self.goal_settings, cash_balance=100, portfolio_set=portfolio_set) self.tickers = [self.t1, self.t2, self.t3, self.t4, self.t4] self.prices = [4, 4, 90, 90, 95] self.quantities = [5, 5, 5, 5, 5] self.executed = [ date(2015, 1, 1), date(2016, 1, 1), date(2015, 1, 1), date(2016, 1, 1), date(2016, 1, 1) ] self.execution_details = [] for i in range(5): execution = Fixture1.create_execution_details( self.goal, self.tickers[i], self.quantities[i], self.prices[i], self.executed[i]) self.execution_details.append(execution) self.data_provider = DataProviderDjango(mocked_now.date()) self.execution_provider = ExecutionProviderDjango() MarkowitzScaleFactory.create() self.setup_performance_history() self.idata = get_instruments(self.data_provider) self.portfolio = PortfolioFactory.create(setting=self.goal_settings) self.current_weights = get_held_weights(self.goal)
def handle(self, *args, **options): # calculate portfolios data_provider = DataProviderDjango() exec_provider = ExecutionProviderDjango() for goal in Goal.objects.all(): if goal.selected_settings is not None: try: calculate_portfolios(setting=goal.selected_settings, data_provider=data_provider, execution_provider=exec_provider) except Unsatisfiable as e: logger.warn(e)
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 process(modeladmin, request, queryset): from datetime import datetime from execution.end_of_day import process from portfolios.providers.execution.django import ExecutionProviderDjango from portfolios.providers.data.django import DataProviderDjango data_provider = DataProviderDjango(datetime.now().date()) execution_provider = ExecutionProviderDjango() try: process(data_provider, execution_provider, 5, queryset) modeladmin.message_user( request, "Selected Goals has been processed successfully.") except Exception as e: modeladmin.message_user(request, "Error! Can't process.", level=messages.ERROR)
def test_calculate_portfolio_old(self): fund0 = TickerFactory.create(symbol='IAGG') fund1 = TickerFactory.create(symbol='ITOT') fund5 = TickerFactory.create(symbol='GRFXX') fund2 = TickerFactory.create(symbol='VEA') fund0 = TickerFactory.create(symbol='IPO') fund3 = TickerFactory.create(symbol='EEM') fund4 = TickerFactory.create(symbol='AGG') AssetFeatureValueFactory.create( assets=[fund1, fund2, fund3, fund4, fund5]) ps1 = PortfolioSetFactory \ .create(asset_classes=[fund1.asset_class, fund2.asset_class, fund3.asset_class, fund4.asset_class, fund5.asset_class]) # Create a settings object with a metric for a feature with no instruments in the current portfolio set. feature = AssetFeatureValueFactory.create() settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create(group=settings.metric_group) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MAXIMUM, configured_val=.3) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # The below fund has the desired feature, but is not in the goal's portfolio set. feature.assets.add(fund1) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the prediction # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() idata = build_instruments(data_provider) result = calculate_portfolio_old(settings=settings, data_provider=data_provider, execution_provider=execution_provider, idata=idata) self.assertTrue(True)
def test_calculate_portfolio(self): # TODO # constraints -> limit them -> maximum minimum value of 5%, maximum max value of 95% asset_class1 = AssetClassFactory.create(name='US_TOTAL_BOND_MARKET') asset_class2 = AssetClassFactory.create(name='HEDGE_FUNDS') fund0 = TickerFactory.create(symbol='IAGG', asset_class=asset_class1) fund0 = TickerFactory.create(symbol='GRFXX', asset_class=asset_class1) fund1 = TickerFactory.create(symbol='ITOT', asset_class=asset_class2) fund0 = TickerFactory.create(symbol='IPO') fund0 = TickerFactory.create(symbol='AGG', asset_class=asset_class1) fund6 = TickerFactory.create(symbol='rest') ps1 = PortfolioSetFactory \ .create(asset_classes=[asset_class1, asset_class2, fund6.asset_class]) feature = AssetFeatureValueFactory.create() feature.assets.add(fund6) settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_RISK_SCORE) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MINIMUM, configured_val=0.5) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() execution_provider = ExecutionProviderDjango() idata = build_instruments(data_provider) result = calculate_portfolio(settings=settings, data_provider=data_provider, execution_provider=execution_provider, idata=idata) self.assertTrue(True)
def setUp(self): self.t1 = TickerFactory.create(symbol='SPY', unit_price=5) self.t2 = TickerFactory.create(symbol='VEA', unit_price=5) self.t3 = TickerFactory.create(symbol='TIP', unit_price=100) self.t4 = TickerFactory.create(symbol='IEV', unit_price=100) self.equity = AssetFeatureValueFactory.create( name='equity', assets=[self.t1, self.t2]) self.bond = AssetFeatureValueFactory.create(name='bond', assets=[self.t3, self.t4]) self.goal_settings = GoalSettingFactory.create() asset_classes = [ self.t1.asset_class, self.t2.asset_class, self.t3.asset_class, self.t4.asset_class ] portfolio_set = PortfolioSetFactory.create(name='set', risk_free_rate=0.01, asset_classes=asset_classes) self.goal = GoalFactory.create(approved_settings=self.goal_settings, cash_balance=100, portfolio_set=portfolio_set) Fixture1.create_execution_details(self.goal, self.t1, 5, 4, date(2016, 1, 1)) Fixture1.create_execution_details(self.goal, self.t2, 5, 4, date(2016, 1, 1)) Fixture1.create_execution_details(self.goal, self.t3, 5, 90, date(2016, 1, 1)) Fixture1.create_execution_details(self.goal, self.t4, 5, 90, date(2016, 1, 1)) Fixture1.create_execution_details(self.goal, self.t4, 5, 90, date(2016, 1, 1)) self.data_provider = DataProviderDjango() self.execution_provider = ExecutionProviderDjango() MarkowitzScaleFactory.create() self.setup_performance_history() self.idata = get_instruments(self.data_provider)
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, Goal.State.INACTIVE]) 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 create_settings(plan): """ Creates some settings that can be used to create a real retirement goal if desired. :param plan: The retirement plan to create settings for. :return: A GoalSetting object that has been saved in the database. The caller needs to destroy it if it is no longer required :raises Unsatisfiable if no suitable portfolio could be found for the plan. """ metric_group = GoalMetricGroup.objects.create(type=GoalMetricGroup.TYPE_CUSTOM) settings = GoalSetting.objects.create( target=0, completion=timezone.now().date(), hedge_fx=False, metric_group=metric_group, ) risk_metric = 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=plan.desired_risk) # Create a mock goal so we can call calculate_portfolio class MockGoal(object): portfolio_set = plan.client.advisor.default_portfolio_set id = 0 available_balance = 100000 current_balance = 100000 def __str__(self): return "Retiresmartz calculation Goal for plan: {}".format(plan) # Create a dummy settings object for the calculation. # We need to do this because we are using a fake goal, as we don't have a real goal yet. settings_data = GoalSettingSerializer(instance=settings).data calc_settings = GoalSettingStatelessSerializer.create_stateless(settings_data, MockGoal()) data_provider = DataProviderDjango() idata = get_instruments(data_provider) weights, er, stdev = calculate_portfolio( settings=calc_settings, idata=idata, data_provider=data_provider, execution_provider=ExecutionProviderDjango() ) 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.items()] PortfolioItem.objects.bulk_create(items) return settings
def setUp(self): Region.objects.create(name="AU") Region.objects.create(name="UK") Region.objects.create(name="US") AssetClass.objects.create(name="US_BONDS", investment_type=InvestmentType.Standard.BONDS.get(), display_order=1) AssetClass.objects.create(name="AU_STOCKS", investment_type=InvestmentType.Standard.STOCKS.get(), display_order=2) AssetClass.objects.create(name="AU_STOCK_MUTUALS", investment_type=InvestmentType.Standard.STOCKS.get(), display_order=3) index = MarketIndex.objects.create(id=1, display_name='ASSIndex', region=Region.objects.get(name="AU"), currency='AUD', data_api='bloomberg', data_api_param='MI1') ass = Ticker.objects.create(symbol="ASS", display_name='AU Stock 1', ethical=False, region=Region.objects.get(name="AU"), asset_class=AssetClass.objects.get(name='AU_STOCKS'), ordering=1, description='some stock', benchmark=index, data_api='portfolios.api.bloomberg', data_api_param='ASS') ubs = Ticker.objects.create(symbol="USB", display_name='US Bond 1', ethical=True, region=Region.objects.get(name="US"), asset_class=AssetClass.objects.get(name='US_BONDS'), ordering=1, description='some stock', benchmark=index, data_api='portfolios.api.bloomberg', data_api_param='USB') usb1 = Ticker.objects.create(symbol="USB1", display_name='US Bond 2', ethical=False, region=Region.objects.get(name="US"), asset_class=AssetClass.objects.get(name='US_BONDS'), ordering=1, description='some stock', benchmark=index, data_api='portfolios.api.bloomberg', data_api_param='USB1') aums = Ticker.objects.create(symbol="AUMS", display_name='AU Mutual Stocks 1', ethical=True, region=Region.objects.get(name="AU"), asset_class=AssetClass.objects.get(name='AU_STOCK_MUTUALS'), etf=False, ordering=1, description='some stock', benchmark=index, data_api='portfolios.api.bloomberg', data_api_param='AUMS') self._data_provider = DataProviderDjango() self._execution_provider = ExecutionProviderDjango() self._covars, self._samples, self._instruments, self._masks = build_instruments(self._data_provider) MarkowitzScale.objects.create(date=self._data_provider.get_current_date(), min=-1, max=1, a=1, b=2, c=3)
def test_calc_opt_inputs_no_assets_for_constraint(self): """ Makes sure when we have no assets filling a constraint, we behave appropriately. """ # This fund has a different feature to the one in the mix metric, but it is in the correct portfolio set. fund1 = TickerFactory.create() AssetFeatureValueFactory.create(assets=[fund1]) ps1 = PortfolioSetFactory.create(asset_classes=[fund1.asset_class]) # Create a settings object with a metric for a feature with no instruments in the current portfolio set. feature = AssetFeatureValueFactory.create() settings = GoalSettingFactory.create() risk_metric = GoalMetricFactory.create(group=settings.metric_group) mix_metric = GoalMetricFactory.create( group=settings.metric_group, type=GoalMetric.METRIC_TYPE_PORTFOLIO_MIX, feature=feature, comparison=GoalMetric.METRIC_COMPARISON_MAXIMUM, configured_val=.3) goal = GoalFactory.create(selected_settings=settings, portfolio_set=ps1) # The below fund has the desired feature, but is not in the goal's portfolio set. fund2 = TickerFactory.create() feature.assets.add(fund2) # Create some instrument data for the two assets self.m_scale = MarkowitzScaleFactory.create() # populate the data needed for the prediction # We need at least 500 days as the cycles go up to 70 days and we need at least 7 cycles. populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) data_provider = DataProviderDjango() idata = build_instruments(data_provider) execution_provider = ExecutionProviderDjango() # Get the opt inputs, there should be no constraint for the max for the feature with no funds. result = calc_opt_inputs(settings=settings, idata=idata, data_provider=data_provider, execution_provider=execution_provider) xs, lam, constraints, settings_instruments, settings_symbol_ixs, lcovars = result self.assertEqual(len(constraints), 3) # All positive, and sum to 1 # Then create a fund in the portfolio I want. We should get a constraint for the maximum for the feature. fund3 = TickerFactory.create(asset_class=fund1.asset_class) feature.assets.add(fund3) delete_data() populate_prices(500, asof=mocked_now.date()) populate_cycle_obs(500, asof=mocked_now.date()) populate_cycle_prediction(asof=mocked_now.date()) idata = build_instruments(data_provider) result = calc_opt_inputs(settings=settings, idata=idata, data_provider=data_provider, execution_provider=execution_provider) xs, lam, constraints, settings_instruments, settings_symbol_ixs, lcovars = result self.assertEqual(len(constraints), 4) # All positive, sum to 1, and the max constraint
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