Home > python > Calcolo Interessi capitale composto

Calcolo Interessi capitale composto

Un piccolo programmino per calcolare il capitale composto.
In sostanza serve a calcolare il valore totale da restituire in caso di prestito,
rivalutando il capitale di anno in anno, del tasso di interesse concordato.

Es.

Capitale iniziale: 30’000
Tasso di interesse: 1.5 %
Anni (tempo esaurimento debito): 5

La formula per il calcolo del capitale da restituire è:

capitale * [( 1 + tasso/100) ^ anni]

Nel nostro caso abbiamo:

30000 * [1.015 ^ 5] = 32’318.52

Il calcolo di ogni rata mensile è ovviamente dato dal totale diviso
il numero di mesi in 5 anni:

32’318.52 / 60 = 538.64

Il codice è semplicissimo e c’è anche disponibile una mini-gui:

# file: capcomp.py
'''Modulo per il calcolo di un capitale con interessi composto:

    cap = valore in entrata es. 10000 (euro)
    tasso = tasso di interesse applicato es. 1.5 (%)
    anni = durata del muto es. 5

 La formula per il calcolo dell'interese composito e':

    val = cap * (1 + tasso/100 ) ^ anni

 esempio con valori suddetti:

    val = 10000 * (1 + 0.015) ^ 5 = 10772.840038843746
'''


class InvalidDataError(Exception):   # pylint: disable=C0111,C0321
    pass


def composto(cap, tasso, anni):
    '''Restituisce il valore del capitale composto con interesse
       a tasso = tasso dopo una durata = anni'''
    try:
        return round(float(cap) * (1 + float(tasso) / 100) ** int(anni), 2)
    except (ValueError, TypeError):
        raise InvalidDataError('Errore dati in ingresso: ripetere')


def mensile(valore, anni):
    '''Restituisce il valore mensile dell'interesse composto
       precedentemente calcolato'''
    try:
        return round(float(valore / (int(anni) * 12)), 2)
    except (ValueError, TypeError):
        raise InvalidDataError('Errore dati in ingresso: ripetere')


def main():
    '''app starter'''
    cap = raw_input('cap iniziale? ')
    tasso = raw_input('tasso di interesse? ')
    anni = raw_input('durata in anni? ')
    i = composto(cap, tasso, anni)
    print "cap composto rivalutato: ", i
    rata = mensile(i, anni)
    print "rata mensile: ", rata

if __name__ == '__main__':
    main()

La gui:

# file: ccgui.py
import wx
import capcomp


class CCAttributeError(Exception):
    pass


class CCValidator(wx.PyValidator):
    def __init__(self, *a, **k):
        wx.PyValidator.__init__(self, *a, **k)

    def Clone(self):
        return CCValidator()

    def Validate(self, w):
        'Return False and set yellow bg to controls if no data'
        ctl = self.GetWindow()
        if not ctl.IsEnabled():
            return True
        val = ctl.GetValue().strip()
        if not val:
            ctl.SetBackgroundColour('yellow')
            ctl.Refresh()
            return False
        else:
            ctl.SetBackgroundColour(wx.SystemSettings_GetColour(
                                                    wx.SYS_COLOUR_WINDOW))
            ctl.Refresh()
            return True


class CCPanel(wx.Panel):
    def __init__(self, *a, **k):
        wx.Panel.__init__(self, *a, **k)

        # controlli ----------------------------------------------------------
        self.cap = wx.TextCtrl(self, validator=CCValidator())
        self.tasso = wx.TextCtrl(self, validator=CCValidator())
        self.anni = wx.ComboBox(self, style=wx.CB_DROPDOWN | wx.CB_READONLY,
                                validator=CCValidator())

        calcola = wx.Button(self, -1, 'CALCOLA')
        reset = wx.Button(self, -1, 'reset')
        self.ricap = wx.TextCtrl(self)
        self.rata = wx.TextCtrl(self)

        # setting -------------------------------------------------------------
        self.SetFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL,
                             wx.FONTSTYLE_NORMAL))
        for ctl in (self.ricap, self.rata):
            ctl.SetFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.FONTSTYLE_NORMAL,
                                wx.FONTSTYLE_NORMAL))
        self.ricap.SetEditable(False)
        calcola.SetDefault()
        self.anni.SetItems([''] + [str(num) for num in range(1, 31)])

        # binding -------------------------------------------------------------
        for ctl, evt in ((calcola, self.on_calc), (reset, self.on_reset)):
            ctl.Bind(wx.EVT_BUTTON, evt)

        # layout -------------------------------------------------------------
        g = wx.FlexGridSizer(7, 2, 5, 5)
        g.AddGrowableCol(1)
        for lab, ctl, flag in (
                ('capitale iniziale', self.cap, wx.EXPAND),
                ('tasso di interesse', self.tasso, wx.EXPAND),
                ('durata (anni)', self.anni, wx.EXPAND),):
            g.Add(wx.StaticText(self, -1, lab), 0, wx.ALIGN_CENTER_VERTICAL)
            g.Add(ctl, 0, flag)

        s_btn = wx.BoxSizer()
        s_btn.Add(calcola, 2, wx.EXPAND | wx.ALL, 5)
        s_btn.Add(reset, 1, wx.EXPAND | wx.ALL, 5)

        s_res = wx.BoxSizer()
        s_res.Add(self.ricap, 2, wx.EXPAND | wx.ALL, 5)
        s_res.Add(self.rata, 1, wx.EXPAND | wx.ALL, 5)

        s_stx = wx.BoxSizer()
        s_stx.Add(wx.StaticText(self, -1, 'Capitale riv'), 2,
               wx.EXPAND | wx.ALL, 5)
        s_stx.Add(wx.StaticText(self, -1, 'Rata mensile'), 1,
               wx.EXPAND | wx.ALL, 5)

        s = wx.BoxSizer(wx.VERTICAL)
        s.Add(g, 0, wx.EXPAND | wx.ALL, 5)
        s.Add((5, 5))
        s.Add(s_stx, 0, wx.EXPAND)
        s.Add((5, 5))
        s.Add(s_res, 0, wx.EXPAND)
        s.Add((5, 5))
        s.Add(s_btn, 0, wx.EXPAND)
        self.SetSizer(s)
        self.Fit()

    def on_reset(self, evt):
        for ctl in (self.cap, self.tasso, self.ricap, self.rata):
            ctl.SetValue('')
        self.anni.SetValue('')

    def on_calc(self, evt):
        self.ricap.SetValue('')
        if not self.Validate():
            wx.MessageBox('Dati non validi o mancanti.', 'Errore',
                          wx.ICON_ERROR)
            return False
        try:
            ricap = capcomp.composto(self.cap.GetValue().strip(),
                                     self.tasso.GetValue().strip(),
                                     self.anni.GetValue())
            rata = capcomp.mensile(ricap, self.anni.GetValue())
            self.ricap.SetValue(unicode(ricap))
            self.rata.SetValue(unicode(rata))
        except CCAttributeError:
            wx.MessageBox('Controlla i dati inseriti', 'Errore', wx.ICON_ERROR)
            return False


class MainFrame(wx.Frame):
    def __init__(self, *a, **k):
        wx.Frame.__init__(self, *a, **k)
        CCPanel(self)
        self.Fit()
        self.SetTitle('Capitale Composto')


def main():
    '''app starter'''
    app = wx.PySimpleApp()
    fr = MainFrame(None)
    fr.Show()
    app.MainLoop()


if __name__ == '__main__':
    main()

Volendo anche il codice di test (quasi inutile vista la complessità del codice):

# file: capcomptest.py
import unittest
from capcomp import composto, mensile, InvalidDataError


class CalcolaTest(unittest.TestCase):
    def setUp(self):
        self.capitale = 10000
        self.tasso = 1.5
        self.anni = 5
        self.recap = composto(self.capitale, self.tasso, self.anni)
        self.rata = mensile(10772.84, self.anni)

    def test_risultato_esatto(self):
        '''testa che il valore del capitale composto sia quello atteso'''
        self.assertEqual(self.recap, 10772.84,
                         'Errore: valore non corretto')

    def test_rata(self):
        '''testa che la rata mensile, sia quello attesa'''
        self.assertEqual(self.rata, 179.55,
                         'Errore: valore non corretto')


class BadInputRecapTest(unittest.TestCase):
    def test_bad_input_composto_capitale(self):
        '''Solleva un'eccezione in caso di comp-input diverso da <float>'''
        self.assertRaises(InvalidDataError, composto, 'b', 1.5, 5)

    def test_bad_input_composto_tasso(self):
        '''Solleva un'eccezione in caso di comp-input diverso da <float>'''
        self.assertRaises(InvalidDataError, composto, 10000, 'b', 5)

    def test_bad_input_composto_anni(self):
        '''Solleva un'eccezione in caso di comp-input diverso da <int>'''
        self.assertRaises(InvalidDataError, composto, 10000, 1.5, 'b')


class BadInputMensileTest(unittest.TestCase):
    def test_bad_input_mensile_cap(self):
        '''Solleva un'eccezione in caso di mens-input diverso da <float>'''
        self.assertRaises(InvalidDataError, mensile, 'b', 5)

    def test_bad_input_mensile_anni(self):
        '''Solleva un'eccezione in caso di mens-input diverso da <int>'''
        self.assertRaises(InvalidDataError, mensile, 10000, 'b')


def testit():
    calcola_suite = unittest.TestLoader().loadTestsFromTestCase(CalcolaTest)
    bad_composto_suite = unittest.TestLoader().loadTestsFromTestCase(
                                                    BadInputRecapTest)
    bad_mensile_suite = unittest.TestLoader().loadTestsFromTestCase(
                                                    BadInputMensileTest)
    all_tests = unittest.TestSuite([calcola_suite, bad_composto_suite,
                                    bad_mensile_suite])
    unittest.TextTestRunner(verbosity=2).run(all_tests)

if __name__ == '__main__':
    testit()

Eccolo al lavoro:

banco@banco-laptop:~$ python ccgui.py

Categorie:python
  1. Non c'è ancora nessun commento.
  1. No trackbacks yet.

Lascia un commento

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

%d blogger cliccano Mi Piace per questo: