Как я могу минимизировать вывод функции python - PullRequest
0 голосов
/ 23 апреля 2020

У меня есть функция, которая выполняет определенные вычисления и возвращает число, известное как неожиданная потеря портфеля в финансах. У меня есть датафрейм, таблица Excel, известная как портфолио, и функция получает данные из этого портфолио. Теперь мне нужно минимизировать вывод функции, используя определенный столбец в этом кадре данных. Эта функция относится ко многим функциям, поэтому, когда я использую функцию минимизации Сципи, она не решает нужные мне числа.

Ниже я приведу скрипт, который я использую. Я хочу минимизировать конечную функцию под названием «loss_calculator_under_default», получающую массив с именем nominal. Мне нужны числа в этом номинальном массиве, чтобы минимизировать вывод этой функции, при этом ограничение «сумма номинальных» составляет определенную величину Я включу фрагмент из файла моей книги, который вы можете использовать, если хотите помочь. Заранее спасибо всем, кто помог.

Это скрипт

**# First import the necessary libraries for calculation from scipy import integrate import scipy.optimize as so from math import pi, inf, sqrt, exp import numpy as np import pandas as pn from statistics import median import matplotlib.pyplot as plt import scipy.stats from openpyxl import load_workbook import csv import matplotlib.pyplot as plt from openpyxl.chart import BarChart , Reference

# We need transition and other helper matrices yspread = [0.0015,0.003,0.0045,0.006,0.0075,0.009,0.0105,0.013,0.0155,0.018,0.023,0.028,0.033,0.043,0.053,0.063,0.078] tranmat = [[0.8906,0.0616,0.0304,0.0049,0.0074,0.0029,0.0017,0,0,0,0.0004,0,0,0,0,0,0,0.0001], [0.0265,0.792,0.082,0.0686,0.0241,0.0033,0.0005,0.0019,0,0,0.0009,0,0,0,0,0,0,0.0002], [0.0074,0.0305,0.809,0.0882,0.0413,0.0142,0.0061,0.0017,0,0,0,0,0.0005,0.0008,0,0,0,0.0003], [0.0008,0.0064,0.0352,0.8148,0.093,0.0328,0.0089,0.0025,0.0022,0.0017,0,0.0004,0.0009,0,0,0,0,0.0004], [0.0003,0.0011,0.0062,0.0576,0.8088,0.075,0.03,0.0081,0.0028,0.0014,0.0037,0.0026,0.0005,0.0012,0.0001,0,0,0.0006], [0.0005,0.0006,0.003,0.008,0.0557,0.8075,0.0748,0.0299,0.0083,0.0041,0.0029,0.0011,0.0012,0.0003,0.0007,0.0003,0.0003,0.0008], [0.0005,0.0011,0.0005,0.0024,0.0155,0.0868,0.754,0.0703,0.0383,0.015,0.0057,0.002,0.0023,0.0035,0.0005,0.0005,0.0001,0.001], [0.0008,0.0002,0.0014,0.0019,0.0021,0.0284,0.0804,0.7468,0.0773,0.0329,0.0109,0.0048,0.0037,0.0058,0.0009,0.0002,0.0002,0.0013], [0.0007,0.0011,0.0013,0.0018,0.0018,0.0092,0.0387,0.0727,0.7535,0.074,0.0177,0.0055,0.0069,0.0051,0.0047,0.0027,0.0003,0.0023], [0.0003,0,0.0003,0.0008,0.0019,0.0061,0.0069,0.0342,0.0992,0.7129,0.0679,0.0276,0.0202,0.0085,0.0033,0.0036,0.0017,0.0046], [0.0009,0,0,0.0003,0.0024,0.0013,0.0073,0.0082,0.032,0.0836,0.7231,0.05,0.0422,0.0122,0.0138,0.0124,0.0036,0.0067], [0,0,0,0.0003,0.0004,0.0016,0.0014,0.0039,0.0077,0.0253,0.0918,0.7035,0.0682,0.0184,0.0407,0.0207,0.0058,0.0103], [0,0.0002,0,0,0.0004,0.0017,0.0019,0.0019,0.0028,0.0075,0.0294,0.0547,0.7238,0.0525,0.056,0.0334,0.0092,0.0246], [0.0002,0,0,0,0.0006,0.001,0.0016,0.0008,0.0026,0.0032,0.0045,0.0269,0.0609,0.7152,0.0558,0.068,0.019,0.0397], [0,0,0.0006,0.0001,0.0011,0,0.0007,0.0018,0.0012,0.0019,0.003,0.0169,0.0305,0.0595,0.6338,0.117,0.0382,0.0937], [0,0,0.0007,0,0.0002,0.0004,0.0007,0.0012,0.0013,0.0022,0.002,0.0038,0.0128,0.0441,0.0369,0.6814,0.0751,0.1372], [0,0,0,0,0,0,0,0,0.0054,0.0054,0.0071,0,0.0152,0.0206,0.0137,0.032,0.6046,0.296], [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1]]

ztresh = [[-1.229,-1.666,-2.109,-2.239,-2.567,-2.849,-3.28,-3.28,-3.28,-3.28,-3.719,-3.719,-3.719,-3.719,-3.719,-3.719,-3.719,
-1000], [1.936,-0.91,-1.284,-1.867,-2.464,-2.694,-2.746,-3.052,-3.052,-3.052,-3.54,-3.54,-3.54,-3.54,-3.54,-3.54,-3.54, -1000], [2.439,1.776,-1.023,-1.515,-1.984,-2.348,-2.712,-2.935,-2.935,-2.935,-2.935,-2.935,-3.051,-3.432,-3.432,-3.432,-3.432, -1000], [3.143,2.446,1.724,-1.067,-1.646,-2.119,-2.403,-2.534,-2.703,-2.918,-2.918,-3.002,-3.353,-3.353,-3.353,-3.353,-3.353, -1000], [3.421,2.977,2.423,1.512,-1.145,-1.634,-2.031,-2.227,-2.32,-2.373,-2.571,-2.81,-2.886,-3.193,-3.239,-3.239,-3.239,
-1000], [3.279,3.049,2.638,2.251,1.492,-1.152,-1.646,-2.054,-2.269,-2.429,-2.6,-2.686,-2.811,-2.855,-2.983,-3.058,-3.156,
-1000], [3.277,2.953,2.863,2.611,2.052,1.244,-1.084,-1.484,-1.872,-2.154,-2.329,-2.412,-2.535,-2.854,-2.942,-3.06,-3.09,
-1000], [3.142,3.076,2.819,2.628,2.489,1.814,1.199,-1.089,-1.548,-1.914,-2.122,-2.254,-2.39,-2.787,-2.925,-2.966,-3.011,
-1000], [3.179,2.913,2.742,2.586,2.476,2.149,1.603,1.14,-1.179,-1.693,-1.919,-2.014,-2.166,-2.323,-2.552,-2.792,-2.834,
-1000], [3.415,3.415,3.221,2.993,2.717,2.351,2.138,1.64,1.038,-1.092,-1.48,-1.729,-2.019,-2.22,-2.329,-2.495,-2.605,
-1000], [3.131,3.131,3.131,3.036,2.688,2.583,2.251,2.047,1.623,1.099,-1.076,-1.335,-1.658,-1.793,-2.001,-2.316,-2.473,
-1000], [1000,1000,1000,3.406,3.167,2.818,2.665,2.423,2.16,1.743,1.115,-0.978,-1.305,-1.422,-1.789,-2.141,-2.315,
-1000], [1000,3.518,3.518,3.518,3.215,2.822,2.633,2.507,2.37,2.135,1.687,1.278,-0.932,-1.159,-1.497,-1.827,-1.967, -1000], [3.522,3.522,3.522,3.522,3.136,2.908,2.704,2.638,2.471,2.328,2.185,1.735,1.268,-0.906,-1.142,-1.566,-1.754, -1000], [1000,1000,3.229,3.185,2.9,2.9,2.796,2.624,2.537,2.435,2.31,1.922,1.573,1.188,-0.678,-1.117,-1.318,
-1000], [1000,1000,3.212,3.212,3.129,3.007,2.882,2.728,2.612,2.473,2.379,2.241,1.954,1.48,1.246,-0.798,-1.093,
-1000], [1000,1000,1000,1000,1000,1000,1000,1000,2.552,2.301,2.1,2.1,1.838,1.61,1.496,1.285,-0.536,
-1000], [1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,1000,
-1000]]

# Returns expected loss and unexpected loss under default and migration modes as a tuple
# Tuple order: Expected loss default, Expected loss migration, Unex. default, Unex migration def exp_unex_loss_calculator(bond_rating, d, c, mrr, vrr, ne, dirty_price, ld, pd):
    helper1 = tranmat[int(bond_rating)][:17]

    default1 = pd * (dirty_price - mrr)
    default2 = pd * (dirty_price - mrr)**2
    deltay = []
    deltap = []
    delfactor = []
    delfactor2 = []
    for i in range(17):
        deltay.append( -(yspread[int(bond_rating)] - yspread[i]) / yspread[int(bond_rating)]/100)
    for i in range(17):
        deltap.append( dirty_price * d * deltay[i] - 0.5 * dirty_price * c * deltay[i]**2 )
    for i in range(17):
        delfactor.append(helper1[i] * deltap[i])
    for i in range(17):
        delfactor2.append(helper1[i] * deltap[i]**2)

    out1 = sum(delfactor) + default1
    out2 = sum(delfactor2) + default2

    expected_loss = ne * pd * (dirty_price - mrr)
    unexpected_loss = ne * sqrt(pd * vrr**2 + ld**2*pd*(1-pd))
    expected_loss_m = ne * out1
    unexpected_loss_m = ne * sqrt(pd * vrr**2 + out2 - out1**2)
    return int(expected_loss), int(expected_loss_m), int(unexpected_loss), int(unexpected_loss_m)

def upper_limit_finder(bond1_pd, bond2_pd):
    qu = bond1_pd
    qu2 = bond2_pd
    a = qu * sqrt(2 * pi)
    a2 = qu2 * sqrt(2 * pi)

    def integrand(u):
        return exp(-0.5*u**2)
    def func(x):
        return integrate.quad(integrand, -inf, x)[0] - a
    def func1(y):
        return integrate.quad(integrand, -inf, y)[0] - a2

    sol = so.fsolve(func, 0)
    sol2 = so.fsolve(func1, 0)
    return float(sol), float(sol2)



# Default correlation between two obligors def default_correlation_calc(joint_prob_of_default, pd1, pd2):
    return (joint_prob_of_default - pd1 * pd2) / (sqrt(pd1 * (1-pd1) * pd2 * (1-pd2)))

# Loss correlation between two obligors def loss_correlation_calc(ne1, ne2, pd1, pd2, ld1, ld2, rok, ul1, ul2):
    return (ne1 * ne2 * sqrt(pd1 * (1-pd1)) * sqrt(pd2 * (1-pd2)) * rok) / (ul1 * ul2)

low_limits = [] up_limits = [] joint_migration_prob = []
# Finding the integral limits from z treshold tables def limits_calculator(bond_rating1, bond_rating_2):
    x = list(range(0,18))
    for i in x:
        low_limits.append(ztresh[int(bond_rating1)][i])
        up_limits.append(ztresh[int(bond_rating_2)][i])

# Joint probability of default calculator for two obligor pairs def joint_probability_of_def_calc(low_limit1, up_limit1, low_limit2, up_limit2, asset_return_corr):
    def integrand(x, y):
        return np.exp(-(x**2 - 2*asset_return_corr*x*y + y**2)/(2*abs(1 - asset_return_corr**2)))
    coefficient = 1 / (2*pi*sqrt(1 - asset_return_corr**2))
    re = integrate.dblquad(integrand, low_limit1, up_limit1, lambda x: low_limit2, lambda x: up_limit2)
    return re[0] * coefficient

asset_return = 0.3

# Function for calculating the joint migration probabilities. Returns an array of probabilities def finalcalc():
    x = list(range(0,18))
    for u in x:
        for y in x:
            if (u == 0) and (y == 0):
                joint_migration_prob.append(joint_probability_of_def_calc(low_limits[u], inf, up_limits[y], inf, asset_return))
            elif (u == 0):
                joint_migration_prob.append(joint_probability_of_def_calc(low_limits[u], inf, up_limits[y], up_limits[y-1], asset_return))
            elif (y == 0):
                joint_migration_prob.append(joint_probability_of_def_calc(low_limits[u], low_limits[u-1], up_limits[y], inf, asset_return))
            else:
                joint_migration_prob.append(joint_probability_of_def_calc(low_limits[u], low_limits[u-1], up_limits[y], up_limits[y-1], asset_return))
    return joint_migration_prob

# Calculating the delta p from two bonds def delta_p_calc(bond_rating, dirty_price, d, c, mrr, pd):
    deltay = []
    deltap = []
    default1 = pd * (dirty_price - mrr)
    for i in range(0,17):
        deltay.append( -(yspread[bond_rating] - yspread[i]) / yspread[bond_rating]/100)

    for i in range(0,17):
        deltap.append( dirty_price * d * deltay[i] - 0.5 * dirty_price * c * deltay[i]**2 )
    deltap.append(default1)
    return deltap

# Calculating the expected correlation loss def expected_correlation_loss(bond_rating1,dirty_price1, duration1, convexity1, mrr1, pd1,
                            bond_rating2,dirty_price2, duration2, convexity2, mrr2, pd2):
    g = []

    first_pik = delta_p_calc(bond_rating1,dirty_price1, duration1, convexity1, mrr1, pd1)
    second_pik = delta_p_calc(bond_rating2,dirty_price2, duration2, convexity2, mrr2, pd2)
    for i in range(18):
        for u in range(18):
            g.append(first_pik[i] * second_pik[u])

    limits_calculator(bond_rating1, bond_rating2)
    h = finalcalc()

    ell = []
    for i in range(324):
        ell.append(1000000 * 1000000 * h[i] * g[i])
    return -1 * int(sum(ell))

path = r"/Users/faridjafarov/desktop/creditrisk/portfolio_kb.xlsx" portfolio = pn.read_excel(path, sheet_name="Sheet1")



iterable = range(len(portfolio["issuer"])) def unexpected_loss_portfolio(x, y):
    limits = upper_limit_finder(portfolio["pd"][x], portfolio["pd"][y])
    probt = joint_probability_of_def_calc(-inf, limits[0], -inf,  limits[1],asset_return)
    rosigma = default_correlation_calc(probt, portfolio["pd"][x], portfolio["pd"][y])
    unexpected_loss_1 = exp_unex_loss_calculator(portfolio["rating_int"][x], portfolio["duration"][x],
                                                 portfolio["convexity"][x], portfolio["mrr"][x],
                                                 portfolio["vrr"][x], portfolio["nominal"][x], portfolio["dirty_price"][x],
                                                 portfolio["ld"][x], portfolio["pd"][x])[2]
    unexpected_loss_2 = exp_unex_loss_calculator(portfolio["rating_int"][y], portfolio["duration"][y],
                                                 portfolio["convexity"][y], portfolio["mrr"][y],
                                                 portfolio["vrr"][y], portfolio["nominal"][y], portfolio["dirty_price"][1],
                                                 portfolio["ld"][y], portfolio["pd"][y])[2]
    probk = loss_correlation_calc(portfolio["nominal"][x], portfolio["nominal"][y], portfolio["pd"][x], portfolio["pd"][y],
                                  portfolio["ld"][x], portfolio["pd"][y], rosigma, unexpected_loss_1, unexpected_loss_2)

    return probk * unexpected_loss_1 * unexpected_loss_2



# loss_correlation_calc(ne1, ne2, pd1, pd2, ld1, ld2, rok, ul1, ul2) factors = [] un_losses = [] expected_losses = []

def losses_calculator_under_default(nominal):
    for j in iterable:
        for k in iterable:
            un_losses.append(unexpected_loss_portfolio(j, k))

    for j in iterable:
        factors.append(pow(exp_unex_loss_calculator(portfolio["rating_int"][j], portfolio["duration"][j],
                                                    portfolio["convexity"][j], portfolio["mrr"][j],
                                                    portfolio["vrr"][j], nominal[j], portfolio["dirty_price"][j],
                                                    portfolio["ld"][j], portfolio["pd"][j])[2],2))
    for k in iterable:
        expected_losses.append(exp_unex_loss_calculator(portfolio["rating_int"][j], portfolio["duration"][j],
                                                        portfolio["convexity"][j], portfolio["mrr"][j],
                                                        portfolio["vrr"][j], nominal[j], portfolio["dirty_price"][j],
                                                        portfolio["ld"][j], portfolio["pd"][j])[0])
    final_unexpected_loss = sqrt(sum(factors) + sum(un_losses))

    return int(final_unexpected_loss)**

Это фрагмент таблицы Excel

Фрагмент таблицы Excel, некоторые из столбцов там нет, они все числа

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