def test_short_returns():
    b_data = prep_data.get_data('^GSPC', '2018-05-01', '2019-05-01', 'monthly')
    b_transformed_data, dates = prep_data.transform_yahoo_finance_dict(b_data)
    b_asset_data = prep_data.generate_asset_data_array(b_transformed_data)

    # MSFT is a winner, X is a loser during this period
    data = prep_data.get_data(['MSFT', 'X'], '2018-05-01', '2019-05-01',
                              'monthly')
    transformed_data, dates = prep_data.transform_yahoo_finance_dict(data)
    asset_data = prep_data.generate_asset_data_array(transformed_data)

    msft_start = asset_data[0].price_data[-1]
    msft_end = asset_data[0].price_data[0]
    msft_ret = (msft_end - msft_start) / msft_start
    x_start = asset_data[1].price_data[-1]
    x_end = asset_data[1].price_data[0]
    x_ret = (x_end - x_start) / x_start

    # Calculate long only returns
    long_p_ret = PortfolioReturns(asset_data, np.array([0.5, 0.5]),
                                  b_asset_data[0])
    expected_return = (msft_ret + x_ret) / 2
    assert round(long_p_ret.total_return, 3) == round(expected_return, 3)

    # Calculate long / short returns
    long_short_p_ret = PortfolioReturns(asset_data, np.array([0.5, -0.5]),
                                        b_asset_data[0])
    expected_return = (msft_ret - x_ret) / 2
    assert round(long_short_p_ret.total_return, 3) == round(expected_return, 3)
def do_task_optimize(name,
                     tickers,
                     benchmark_index: str,
                     start_date,
                     end_date,
                     user_id,
                     task_id,
                     interval='weekly'):
    job_start = datetime.now()

    # Get & prepare portfolio data
    data = prep_data.get_data(tickers, start_date, end_date, interval)
    transformed_data, dates = prep_data.transform_yahoo_finance_dict(data)
    asset_data = prep_data.generate_asset_data_array(transformed_data)

    # Get benchmark data
    benchmark_data = prep_data.get_data(benchmark_index, start_date, end_date,
                                        interval)
    benchmark_transformed_data, _ = prep_data.transform_yahoo_finance_dict(
        benchmark_data)
    benchmark_asset_data = prep_data.generate_asset_data_array(
        benchmark_transformed_data)
    benchmark_returns = PortfolioReturns(benchmark_asset_data)

    # Optimize portfolio
    matrices = prep_data.AssetMatrices(asset_data)
    optimizer = optimize.Optimize(matrices, benchmark_asset_data[0])
    results = optimizer.optimize_all()

    job_end = datetime.now()

    job = {
        'job_start': job_start,
        'job_end': job_end,
        'asset_data': [a.as_dict() for a in asset_data],
        'matrices': matrices.as_dict(),
        'price_dates': dates,
        'parameters': {
            'tickers': tickers,
            'start_date': start_date,
            'end_date': end_date,
            'interval': interval
        },
        'benchmark_index': {
            'asset_data': benchmark_asset_data[0].as_dict(),
            'returns': benchmark_returns.as_dict()
        },
        'results': [res.as_dict() for res in results],
        'user_id': user_id,
        'task_id': task_id,
        'published': False,
        'name': name
    }
    return insert_job(job)
def test_short_returns_complex():
    b_data = prep_data.get_data('^GSPC', '2018-05-13', '2019-05-13', 'weekly')
    b_transformed_data, dates = prep_data.transform_yahoo_finance_dict(b_data)
    b_asset_data = prep_data.generate_asset_data_array(b_transformed_data)

    data = prep_data.get_data(['MSFT', 'X', 'AA', 'SPLK'], '2018-05-13',
                              '2019-05-13', 'weekly')
    transformed_data, dates = prep_data.transform_yahoo_finance_dict(data)
    asset_data = prep_data.generate_asset_data_array(transformed_data)

    long_p_ret = PortfolioReturns(asset_data, np.array([1., 0., 0., 0.]),
                                  b_asset_data[0])
    long_short_p_ret = PortfolioReturns(
        asset_data, np.array([1., -0.3847, -0.3808, 0.7655]), b_asset_data[0])
    assert 1 == 1
    def generate_min_std_dev(self, shorting_allowed=False) -> OptimizeOutcome:
        def min_std_dev_fn(weights_vec: np.ndarray):
            return self.calculate_std_dev(
                weights_vec, self.asset_matrices.variance_covariance_matrix)

        bnds = self.short_ok_bnds if shorting_allowed else self.long_only_bnds

        optimize_result: OptimizeResult = minimize(
            min_std_dev_fn,
            self.equal_weights,
            method='SLSQP',
            bounds=bnds,
            constraints=[
                self.weights_equal_1_constraint,
                self.returns_gte_max_constraint
            ])

        pw = self.process_weights(optimize_result.x)
        portfolio_returns = PortfolioReturns(self.asset_matrices.asset_data,
                                             pw['normalized_weights'],
                                             self.benchmark_data)

        return OptimizeOutcome(OptimizeGoal.MIN_STD_DEV, shorting_allowed,
                               pw['normalized_weights'], pw['returns'],
                               pw['std_dev'], pw['sharpe_ratio'],
                               optimize_result, portfolio_returns)
def test_returns_s_and_p_500():
    data = prep_data.get_data('^GSPC', '2018-05-01', '2019-02-01', 'weekly')
    transformed_data, dates = prep_data.transform_yahoo_finance_dict(data)
    asset_data = prep_data.generate_asset_data_array(transformed_data)
    portfolio_returns = PortfolioReturns(asset_data)
    assert len(portfolio_returns.portfolio_returns) == len(
        asset_data[0].returns)
    assert len(portfolio_returns.portfolio_values) == len(
        asset_data[0].price_data)
    def __init__(self, asset_matrices: AssetMatrices,
                 benchmark_data: AssetData):
        self.asset_matrices = asset_matrices
        self.benchmark_data = benchmark_data

        # Bounds for optimizer must match length of data
        self.long_only_bnds = [[0, 1] for x in asset_matrices.asset_data]
        self.short_ok_bnds = [[-1, 1] for x in asset_matrices.asset_data]

        # Generate equal returns data as a baseline
        self.equal_weights = np.array([1 / len(asset_matrices.asset_data)] *
                                      len(asset_matrices.asset_data))
        equal_weights_results = self.process_weights(self.equal_weights)
        equal_weights_returns = PortfolioReturns(
            self.asset_matrices.asset_data, self.equal_weights, benchmark_data)
        self.equal_weights_outcome = OptimizeOutcome(
            OptimizeGoal.EQUAL_WEIGHT, False, self.equal_weights,
            equal_weights_results['returns'], equal_weights_results['std_dev'],
            equal_weights_results['sharpe_ratio'], None, equal_weights_returns)

        self.min_std_dev = np.min(asset_matrices.std_dev_vec)
        # The standard deviation must be <= the lowest standard deviation of any assets
        self.std_dev_lte_min_constraint = {
            'type':
            'ineq',
            'fun':
            lambda arr: self.min_std_dev - self.calculate_std_dev(
                arr, self.asset_matrices.variance_covariance_matrix)
        }

        self.max_returns = np.max(asset_matrices.avg_returns_vec)
        # The rate of return must be greater than the rate of return for any asset
        self.returns_gte_max_constraint = {
            'type':
            'ineq',
            'fun':
            lambda arr: self.calculate_returns(
                arr, self.asset_matrices.avg_returns_vec) - self.max_returns
        }