<jupyter_start><jupyter_text>importação do arquivo bruto de históricos diários de cotações da B3 do ano de 2019 e tratamento dos dados<jupyter_code>#importação do arquivo bruto de históricos diários de cotações da B3 do ano de 2019
arquivo_excel = 'COTAHIST_A2019completo.xlsx'

df = pd.read_excel(arquivo_excel, names=['zeroum','ano','mes','dia','momento','id','tipo0','nome','tipo1','tipo2','tipo3','moeda','var0','var1','var2','var3','var4','var5','var6','carac','fim']).astype(str)
df
# Criação de coluna de data para definição da série temporal

df['data'] = df[['dia','mes','ano']].agg('/'.join, axis=1)
df['data'] = pd.to_datetime(df['data'])<jupyter_output><empty_output><jupyter_text>^https://stackoverflow.com/questions/15891038/change-data-type-of-columns-in-pandashttps://stackoverflow.com/questions/17134716/convert-dataframe-column-type-from-string-to-datetime-dd-mm-yyyy-format<jupyter_code>#convertendo strings para valores numericos
cols = ['var0','var1','var2','var3','var4','var5','var6']
df[cols] = df[cols].apply(pd.to_numeric, errors='coerce')<jupyter_output><empty_output><jupyter_text>^https://stackoverflow.com/questions/36814100/pandas-to-numeric-for-multiple-columns<jupyter_code>#Correção das casas decimais
dfcalc = df[cols].apply(lambda x : x/100)
#Criando coluna apenas com o valor de fechamento
df['close'] = dfcalc.replace(0,np.nan).ffill(axis=1).iloc[:,-1].astype(np.float64)<jupyter_output><empty_output><jupyter_text>^https://stackoverflow.com/questions/53133183/pandas-dataframe-get-value-of-last-nonzero-column  Filtrando apenas ações do tipo preferenciais e lote padrão para evitar duplicidade de empresas no portfólio<jupyter_code>#Criando novo dataframe apenas com os valores necessários para 
colunascsv = ['id','data','tipo0','tipo1','close']
df[colunascsv].loc[lambda df : df['tipo1'] == 'PN',:].to_csv(r'fechamento.csv')
b3_2019 = df[colunascsv].loc[lambda df : df['tipo1'] == 'PN',:]
b3_2019 = b3_2019.loc[lambda b3_2019 : b3_2019['tipo0'] == '10']
#b3_2019 = b3_2019.drop(b3_2019[b3_2019.tipo0 != 20]).index
b3_2019<jupyter_output><empty_output><jupyter_text>agrupando tabela por dia versus empresa e calculando as variações diárias<jupyter_code>b3diff = b3_2019.sort_values(['id','data'])
b3diff.loc[b3diff['id'] == b3diff['id'].shift(), 'logret'] = \
    np.log(b3diff['close']) - np.log(b3diff['close'].shift())


b3agr = b3diff.groupby(['data','id'])['logret'].last().unstack().fillna(0)
b3agr<jupyter_output><empty_output><jupyter_text>Cálculo do índice de sharpe. O ativo livre de risco considerado foi o Tesouro Prefixado 2019 que previsa retorno anual de 6,54% (0,0251% ao dia)<jupyter_code>#novo dataframe com o indice de sharpe calculado
dfsort_std = b3agr.clip(upper=0)
dfsort_std

dfratios = b3agr

dfratios.loc['mean'] = b3agr.mean()
dfratios.loc['std'] = b3agr.std()
dfratios.loc['std_sort'] = dfsort_std.std()
dfratios.loc['sharpe'] = (lambda x,y : math.sqrt(252)*((x - (0.000251421742025526)) / y))(dfratios.loc['mean',:],dfratios.loc['std',:])
dfratios.loc['sortino'] = (lambda x,y : math.sqrt(252)*((x - (0.000251421742025526)) / y))(dfratios.loc['mean',:],dfratios.loc['std_sort',:])
dfratios.to_csv(r'indices.csv')
dfratios<jupyter_output><empty_output><jupyter_text>Cálculo da otimização utilizando Sortino - cálculo dos pesos de cada ativo em um portfólio dos 20 melhores índicesRestrições aplicadas aos pesos1 - Deve ser maior que 0,01;2 - Deve ser menor que 0,15;3 - Deve somar 1;<jupyter_code>import cvxpy as cp
from cplex import *
from operator import mul
w = cp.Variable(10)
assets_sortino = dfratios.loc['sortino',:].nlargest(10).reset_index()

print(assets_sortino)

risk = assets_sortino['sortino'].fillna(0).to_numpy()

restricoes = [
    w >= 0.03,
    w <= 0.25,
    cp.sum(w) == 1
]

objetivo = cp.Maximize(
        cp.sum(
            cp.multiply(risk,w)))

prob = cp.Problem(objetivo,restricoes)

prob.solve(cp.CPLEX, verbose = True)

print (w.value)

retornosort = dfratios[assets_sortino['id']].loc[['mean','std_sort','sortino'],:]
retornosort<jupyter_output>id   sortino
0  PINE10  2.983979
1   EEEL4  1.071178
2   BMGB4  0.843404
3   TASA4  0.835528
4   CSAB4  0.800110
5  BPAN10  0.770751
6   EMAE4  0.766643
7   MSPA4  0.713280
8   EKTR4  0.549469
9   WHRL4  0.502384
Version identifier: 172.16.58.3 | 2019-11-26 | 843d4de2ae
CPXPARAM_Read_DataCheck                          1
CPXPARAM_Preprocessing_QCPDuals                  2
Tried aggregator 1 time.
LP Presolve eliminated 20 rows and 0 columns.
Reduced LP has 1 rows, 10 columns, and 10 nonzeros.
Presolve time = 0.02 sec. (0.01 ticks)
Initializing dual steep norms . . .
[0.25 0.25 0.25 0.07 0.03 0.03 0.03 0.03 0.03 0.03]<jupyter_text>Cálculo da otimização utilizando Sharpe - cálculo dos pesos de cada ativo em um portfólio dos 20 melhores índicesRestrições aplicadas aos pesos1 - Deve ser maior que 0,01;2 - Deve ser menor que 0,15;3 - Deve somar 1;<jupyter_code>z = cp.Variable(10)
assets_sharpe = dfratios.loc['sharpe',:].nlargest(10).reset_index()

print(assets_sharpe)

risk = assets_sharpe['sharpe'].fillna(0).to_numpy()

restricoes = [
    z >= 0.03,
    z <= 0.25,
    cp.sum(z) == 1
]

objetivo = cp.Maximize(
        cp.sum(
            cp.multiply(risk,z)))

prob = cp.Problem(objetivo,restricoes)

prob.solve(cp.CPLEX, verbose = True)

print (z.value)

retornosharpe = dfratios[assets_sharpe['id']].loc[['mean','std','sharpe'],:]
retornosharpe<jupyter_output>id    sharpe
0  PINE10  0.862355
1   EEEL4  0.677476
2   EMAE4  0.545916
3  BPAN10  0.506616
4   TASA4  0.490866
5   BMGB4  0.446363
6   CSAB4  0.426279
7   MSPA4  0.380685
8   EKTR4  0.354975
9   WHRL4  0.345117
Version identifier: 172.16.58.3 | 2019-11-26 | 843d4de2ae
CPXPARAM_Read_DataCheck                          1
CPXPARAM_Preprocessing_QCPDuals                  2
Tried aggregator 1 time.
LP Presolve eliminated 20 rows and 0 columns.
Reduced LP has 1 rows, 10 columns, and 10 nonzeros.
Presolve time = 0.00 sec. (0.01 ticks)
Initializing dual steep norms . . .
[0.25 0.25 0.25 0.07 0.03 0.03 0.03 0.03 0.03 0.03]<jupyter_text>Retornos anualizados dos dois portfólios<jupyter_code>print("O retorno anual do portfólio calculado por Sortino é: ", math.exp(sum(map(mul, retornosort.loc['mean',:], w.value))*252)-1)
print("O retorno anual do portfólio calculado por Sharpe é:", math.exp(sum(map(mul, retornosharpe.loc['mean',:], z.value))*252)-1)<jupyter_output>O retorno anual do portfólio calculado por Sortino é:  0.4132859084809497
O retorno anual do portfólio calculado por Sharpe é: 0.5780661081338336
{'fraction_non_alphanumeric': 0.14504518302956043, 'fraction_numerical': 0.09480778067085312, 'mean_word_length': 4.930971843778384, 'pattern_counts': {'":': 0, '<': 36, '<?xml version=': 0, '>': 36, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 2, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '367337', 'license': 'MIT', 'n_tokens_mistral': 3046, 'n_tokens_neox': 2675, 'n_words': 540, 'path': 'Indices de Risco_e_Otimizacao Convexa.ipynb', 'repo_name': 'ifgdias/notebooks', 'size': '6525'}