Оптимизация возврата корзины акций Python Pandas

Я хочу создать сценарий, который ищет оптимальное время для покупки и продажи корзины акций в течение месяца на основе общей доходности корзины.

Например, предположим, что у акции 1 самая высокая доходность в 8%, если я покупаю во 2 день и продаю в день 12, у акции 2 самая высокая доходность в 4%, если я покупаю в день 9 и продаю в день 15 и акция 3. имеет самую высокую доходность -1%, если я покупаю в день 1 и продаю в день 20. Мой вопрос заключается в том, как написать сценарий, который будет рассматривать все возможности возврата для всех трех акций и выдавать результат, который дает наивысший результат. возврат к общей корзине акций, если бы мне пришлось покупать все три акции в один и тот же день и продавать в один и тот же день.

Например, наивысший доход для всех трех акций может быть при покупке в 4-й день и продаже в 17-й день, когда общая прибыль на вложенный доллар составляет 7% для акции 1, 3,5% для акций 2 и -1,25% для акций. 3. Это основано на том факте, что мы не смогли бы получить наиболее оптимальную доходность для каждой акции, если бы все три акции были куплены и проданы в один и тот же день.

Оптимизация возврата корзины акций Python Pandas

Это проблема с домашним заданием?

bombayquant 06.12.2018 15:42

Нет, я понимаю, что это не прогнозный индикатор / скорее тестирование на истории для конкретной группы акций / анализ сектора.

John 06.12.2018 16:12
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
2
243
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

отсортировать df по дате.

df = df.sort_values(by ='Date', ascending=True)

затем суммируйте все запасы, ежедневно

df['total'] = df[['TSLA Price', 'NVDA Price', 'AAPL Price']].sum(axis=1)

затем используйте следующую функцию

def max_profit(li):
    max_profit, purchase_on, sell_on = 0, 0, 0
    for i, buy in enumerate(li):
        for j, sell in enumerate(li[i+1:]):
            if sell-buy > max_profit:
                max_profit, purchase_on, sell_on = sell-buy, i, i+j+1
    return max_profit, purchase_on, sell_on

max_profit, purchase_on, sell_on = max_profit(df['total'].tolist())

Даты покупки / продажи будут ...

buy_date, sell_date = df['Date'].iloc[purchase_on], df['Date'].iloc[sell_on ]

Чтобы взвесить по-разному, просто умножьте акции на веса, а затем суммируйте.

Прадип! Отлично! Это выглядит фантастически, есть только одна проблема, которую я вижу - после запуска кода он достигает максимальной прибыли между ценами закрытия, однако по какой-то причине он дает дату продажи -1- так, например, в нем точно указано 23 ноября как дата покупки, но указано, что 30 ноября должно быть датой продажи, и похоже, что расчет принимает во внимание 12/3 как дату продажи для максимальной прибыли, но указывает 30 ноября как дату продажи - (правильный расчет с правильной датой, но при печати указана неточная дата продажи)

John 06.12.2018 18:06

Да, sell_on должно быть i + j + 1. Исправлено

Pradeep Pathak 06.12.2018 18:08

Прадип, большое спасибо! Вы очень талантливы, еще раз спасибо за вашу помощь!

John 06.12.2018 18:10

Это похоже на очень старый пост, но я сразу перейду к тому, что у меня есть для вас.

import pandas as pd  
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import scipy.optimize as sco
import datetime as dt
import math
from datetime import datetime, timedelta
from pandas_datareader import data as wb
from sklearn.cluster import KMeans
np.random.seed(777)


start = '2018-06-30'
end = '2020-06-30'
# N = 90
# start = datetime.now() - timedelta(days=N)
# end = dt.datetime.today()



tickers = ['AXP','AAPL','BA','CAT','CSCO','CVX','XOM','GS','HD','IBM','INTC','JNJ','KO','JPM','MCD','MMM','MRK','MSFT','NKE','PFE','PG','TRV','UNH','RTX','VZ','V','WBA','WMT','DIS','DOW']

thelen = len(tickers)

price_data = []
for ticker in tickers:
    prices = wb.DataReader(ticker, start = start, end = end, data_source='yahoo')[['Adj Close']]
    price_data.append(prices.assign(ticker=ticker)[['ticker', 'Adj Close']])

df = pd.concat(price_data)
df.dtypes
df.head()
df.shape

pd.set_option('display.max_columns', 500)

df = df.reset_index()
df = df.set_index('Date')
table = df.pivot(columns='ticker')
# By specifying col[1] in below list comprehension
# You can select the stock names under multi-level column
table.columns = [col[1] for col in table.columns]
table.head()

def portfolio_annualised_performance(weights, mean_returns, cov_matrix):
    returns = np.sum(mean_returns*weights ) *252
    std = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights))) * np.sqrt(252)
    return std, returns
  
def random_portfolios(num_portfolios, mean_returns, cov_matrix, risk_free_rate):
    results = np.zeros((3,num_portfolios))
    weights_record = []
    for i in range(num_portfolios):
        weights = np.random.random(thelen)
        weights /= np.sum(weights)
        weights_record.append(weights)
        portfolio_std_dev, portfolio_return = portfolio_annualised_performance(weights, mean_returns, cov_matrix)
        results[0,i] = portfolio_std_dev
        results[1,i] = portfolio_return
        results[2,i] = (portfolio_return - risk_free_rate) / portfolio_std_dev
    return results, weights_record


returns = table.pct_change()
mean_returns = returns.mean()
cov_matrix = returns.cov()
num_portfolios = 10000
risk_free_rate = 0.0178



def display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate):
    results, weights = random_portfolios(num_portfolios,mean_returns, cov_matrix, risk_free_rate)
    
    max_sharpe_idx = np.argmax(results[2])
    sdp, rp = results[0,max_sharpe_idx], results[1,max_sharpe_idx]
    max_sharpe_allocation = pd.DataFrame(weights[max_sharpe_idx],index=table.columns,columns=['allocation'])
    max_sharpe_allocation.allocation = [round(i*100,2)for i in max_sharpe_allocation.allocation]
    max_sharpe_allocation = max_sharpe_allocation.T
    
    min_vol_idx = np.argmin(results[0])
    sdp_min, rp_min = results[0,min_vol_idx], results[1,min_vol_idx]
    min_vol_allocation = pd.DataFrame(weights[min_vol_idx],index=table.columns,columns=['allocation'])
    min_vol_allocation.allocation = [round(i*100,2)for i in min_vol_allocation.allocation]
    min_vol_allocation = min_vol_allocation.T
    
    print("-")
    print("Maximum Sharpe Ratio Portfolio Allocation\n")
    print("Annualised Return:", round(rp,2))
    print("Annualised Volatility:", round(sdp,2))
    print("\n")
    print(max_sharpe_allocation)
    print("-")
    print("Minimum Volatility Portfolio Allocation\n")
    print("Annualised Return:", round(rp_min,2))
    print("Annualised Volatility:", round(sdp_min,2))
    print("\n")
    print(min_vol_allocation)
    
    plt.figure(figsize=(10, 7))
    plt.scatter(results[0,:],results[1,:],c=results[2,:],cmap='YlGnBu', marker='o', s=10, alpha=0.3)
    plt.colorbar()
    plt.scatter(sdp,rp,marker='*',color='r',s=500, label='Maximum Sharpe ratio')
    plt.scatter(sdp_min,rp_min,marker='*',color='g',s=500, label='Minimum volatility')
    plt.title('Simulated Portfolio Optimization based on Efficient Frontier')
    plt.xlabel('annualised volatility')
    plt.ylabel('annualised returns')
    plt.legend(labelspacing=0.8)
    

display_simulated_ef_with_random(mean_returns, cov_matrix, num_portfolios, risk_free_rate)

Результат:

Maximum Sharpe Ratio Portfolio Allocation

Annualised Return: 0.16
Annualised Volatility: 0.25


            AAPL   AXP    BA   CAT  CSCO   CVX   DIS   DOW    GS    HD   IBM  \
allocation  4.76  1.63  1.03  0.26  1.22  0.05  6.86  0.43  1.02  6.42  0.88   

            INTC   JNJ   JPM    KO   MCD   MMM   MRK  MSFT   NKE   PFE    PG  \
allocation  2.56  0.64  4.92  0.27  6.64  4.13  6.99  5.49  4.52  2.35  6.36   

            RTX   TRV   UNH    V    VZ   WBA   WMT  XOM  
allocation  5.3  1.79  0.39  6.8  7.06  0.67  5.98  2.6  
-
Minimum Volatility Portfolio Allocation

Annualised Return: 0.13
Annualised Volatility: 0.24


            AAPL   AXP    BA   CAT  CSCO   CVX   DIS   DOW    GS    HD   IBM  \
allocation  4.43  0.59  0.59  1.01  1.69  0.56  1.04  0.81  0.64  1.44  1.72   

            INTC   JNJ  JPM    KO   MCD   MMM   MRK  MSFT  NKE   PFE    PG  \
allocation  3.43  3.47  2.9  5.43  7.61  4.99  7.78  4.72  2.2  7.13  6.72   

             RTX   TRV   UNH     V    VZ   WBA   WMT   XOM  
allocation  0.47  4.56  2.95  0.47  6.84  7.81  4.76  1.23 

Ну наконец то:

Вы можете попробовать и другие вещи. Перейдите по ссылке ниже, чтобы узнать все подробности.

https://github.com/ASH-WICUS/Notebooks/blob/master/Portfolio%20Optimization.ipynb

Другие вопросы по теме