This program calculates the Average Monthly Balance 
        of an account for sample months transactions.
        and interest is applied (3.5% pa) on the AMB 
        if AMB is less than the stipulated minimum balance then a 
        penalty is applied (@ Rs. 375 with applicable tax of 18%)
        otherwise interest is posted after tax deduction.

        The product is obtained as follows:
        Consider a runbalance, find the number of days the 
        runbalance is valid. For example in the month of july 
        the runbalance of Rs. 500 available from 1s tot 2nd, so the product is 500*1=500 
        The next balance of Rs. 11500 is available from 2nd to 9th i.e. the number of days 
        elapsed is 7 and product is 11500x 7 = 80500 and so on from 27th till end of the month 
        of July, the runbalance is Rs. 8500 and available for 5 days so the 
        product on 31st from 27th is 8500 x 5 = 42500. 
        
/************* Javascript functions init and startme **********/
function init(nm,dt,bal)
{
    account.nm=nm;
    account.dt=dt;
    account.balance=bal;
    account.min=10000;
    account.rate=3.5;
    account.T=[];
    account.R=[];
    account.caldays=31;
    account.closingbal=0;
}

function td(v,ali)
{
    if (ali==undefined) ali='right';
    return "<td align='"+ali+"'>"+v+"</td>";
}
function th(v,ali)
{
    if (ali==undefined) ali='center';
    return "<th align='"+ali+"'>"+v+"</th>";
}

function startme(nm,dt,bal,flag) {
    if (flag==undefined) flag=false;
    if (!flag) $('#out').html('');
    $('#js').show();
    init(nm,dt,0)
    account.caldays=31;
    account.T.splice(0,0,[1,bal])
    account.R.splice(0,0,"opening balance")
    for (var i=0; i<intrans.length;i++)
    {
        account.T[account.T.length]=intrans[i]
        account.R[account.R.length]='';
    }
    i=0;
    runbal=0;
    var s='<table>';
    s+="<tr>";
        s+=th("Date")+th("Remark",'left')+th("DEBIT",'right')+th("CREDIT",'right')+th("Runbalance",'right');
        s+=th("Product",'right');
        s+=th("Cumulative",'right');
        s+="</tr>";
        s+="<tr>";
        s+=td(account.dt)+td(account.nm,'left');
        s+="</tr>";
    
    prod=0;
    cumproduct=0;
    prevdate=1;
    while (i<account.T.length)
    {
        if (prevdate!=account.T[i][0])
        {
            dif=account.T[i][0]-prevdate;
            prod=runbal*dif;
            cumproduct+=prod;
            s+=td(fix2(prod))+td(fix2(cumproduct));
        }
        prevdate=account.T[i][0];
        s+="<tr>";
        runbal+=account.T[i][1];
        if (runbal<0) 
        {
            account.T.splice(i+1,0,[account.T[i][0],-account.T[i][1]]);
            account.R[i]='Min.balance?';
            account.R.splice(i+1,0,"Trans. Reversed")
        }
        s+="</tr>";
        if (account.T[i][1]>=0) 
        {
            var cr=account.T[i][1];
            var db='';
        }
        else
        {
            db=account.T[i][1];
            cr='';
        }
        s+=td(fmtdate(account.dt, account.T[i][0]));
        s+=td(account.R[i],'left')+td(fix2(db))+td(fix2(cr))+td(fix2(runbal));
        
        i++;
    }
    dif=account.caldays+1-prevdate;
    prod=runbal*dif;
    cumproduct+=prod;
    s+=td(fix2(prod))+td(fix2(cumproduct));
    s+="</tr><tr>";
        AMB=cumproduct/account.caldays;
        if (AMB<account.min)
        {
            interest=-375.00
            rem='penalty'
        }
        else
        {
            interest=AMB*account.rate*account.caldays/365/100;
            rem='intt';
        }
        gst=-Math.abs(interest*18/100);
        account.closingbal=runbal+interest+gst;
        s+="<td colspan=7>"+fmtdate(account.dt,account.caldays)+
            " Average Monthly Balance="+fix2(AMB)+" "+rem+"="+fix2(interest)+" tax="+fix2(gst)+" "+fix2(account.closingbal)+"</td>";
    s+="</tr>";
    
    s+="</table>"
    $('#out').append(s);
    if (!flag)
    {
        flag=true;
        startme(nm,'20210801',account.closingbal,flag);
    }
}

/******************** JAVASCRIPT SELECTED FUNCTIONS ENDS HERE *********/            
FULL PROGRAM IN PYTHON:
# This program calculates Average Monthly balance and apply interest
def fmtdate(dt,dd=1):
    return "{:02d}-{:2s}-{:4s}".format(dd,dt[4:6],dt[0:4],)

class account:
    min=10000
    rate=3.5
    caldays=31
    closingbal=0
    def __init__(self,name='ABC', balance=0):
        self.dt='20210801'
        self.balance=balance
        self.name=name
        self.T=[]   ## Transactions dt,amt 
        self.R=[]   ## Remark
    def trans(self,*argtup):
        for (d,amt) in argtup:
            self.R.append('')
            self.T.append(detail(d,amt))
    def disp(self):
        print(self.dt, self.name)
        for i in range(len(self.T)):
            self.T[i].disp()
            print( self.R[i])

    def validate(self):
        runbal=self.balance
        prod=0 # runbal*(self.caldays+1-1)
        ob=detail(1,runbal)
        runbal=0
        prevdate=1
        self.T.insert(0,ob)
        self.R.insert(0,"opening balance")
        print(f"{'date':^8s} {'Remark':15s} {'DEBIT':>10s} {'CREDIT':>10s} {'RUNBALANCE':10s}       Product cumulative")
        i=0
        cumulativeprod=0
        prevtrans=''
        while i < len(self.T):
            if self.T[i].dt != prevdate :
                prod=runbal*(self.T[i].dt-prevdate)
                cumulativeprod+=prod
                print(f"{prevtrans} {prod:>10.0f} {cumulativeprod:>10.0f}")
            elif i>0:
                print(prevtrans)
            runbal+=self.T[i].amt
            if runbal < 0 :
                ob=detail(self.T[i].dt,-(self.T[i].amt))
                self.T.insert(i+1,ob)
                self.R[i]="min_balance?"
                self.R.insert(i+1,"Trans. Reversed")
            if self.T[i].amt >= 0 :
                cr=self.T[i].amt
                db=''
                fmt="{:10s} {:15s} {:10s} {:10.2f} {:10.2f} "
            else:
                db=-self.T[i].amt
                cr=''
                fmt="{:10s} {:15s} {:10.2f} {:10s} {:10.2f} "
            prevtrans=fmt.format(fmtdate(self.dt[:6],self.T[i].dt),self.R[i],db,cr,runbal)
            prevdate=self.T[i].dt
            i+=1
        prod=runbal*(self.caldays+1-prevdate)
        cumulativeprod+=prod
        account.closingbal=runbal
        print(f"{prevtrans} {prod:>10.0f} {cumulativeprod:>10.0f}")
        AMB=cumulativeprod/self.caldays
        interest=AMB*self.caldays/365*account.rate/100
        rem='intt'
        if AMB < account.min:
            interest=-375.00
            rem='penaty'
        tax=-abs(interest)*18/100
        print(f"Average Monthly Balance={AMB:10.2f} {rem}={interest:10.2f} GST={tax:10.2f}")
        net=(runbal + interest + tax)
        account.closingbal=net
        print(f"closing balance = {net:10.2f}")



class detail:
    def __init__(self,dt,amt):
        self.dt=dt
        self.amt=amt
    def disp(self):
        print (self.dt,self.amt,end=' ')

ob=account("ShriRam",500)
ob.dt='20210701'
ob.caldays=31
ob.disp()
ob.trans((2,5000),(2,6000),(9,-4000),(10,1000),(27,-11500))
ob.validate()
ob=account("ShriRam",ob.closingbal)
ob.dt='20210801'
ob.caldays=31
ob.disp()
ob.trans((2,5000),(2,6000),(9,-4000),(10,1000),(27,-11500))
ob.validate()
#### SAMPLE OUTPUT
# 16:19 public_html/bnvenkat.com/apy2> python3 AverageMB.py
# 20210701 ShriRam
#   date   Remark               DEBIT     CREDIT RUNBALANCE       Product cumulative
# 01-07-2021 opening balance                500.00     500.00         500        500
# 02-07-2021                               5000.00    5500.00 
# 02-07-2021                               6000.00   11500.00       80500      81000
# 09-07-2021                    4000.00               7500.00        7500      88500
# 10-07-2021                               1000.00    8500.00      144500     233000
# 27-07-2021 min_balance?      11500.00              -3000.00 
# 27-07-2021 Trans. Reversed              11500.00    8500.00       42500     275500
# Average Monthly Balance=   8887.10 penaty=   -375.00 GST=    -67.50
# closing balance =    8057.50
# 20210801 ShriRam
#   date   Remark               DEBIT     CREDIT RUNBALANCE       Product cumulative
# 01-08-2021 opening balance               8057.50    8057.50        8058       8058
# 02-08-2021                               5000.00   13057.50 
# 02-08-2021                               6000.00   19057.50      133402     141460
# 09-08-2021                    4000.00              15057.50       15058     156518
# 10-08-2021                               1000.00   16057.50      272978     429495
# 27-08-2021                   11500.00               4557.50       22788     452282
# Average Monthly Balance=  14589.76 intt=     43.37 GST=     -7.81
# closing balance =    4593.06
# 16:52 public_html/bnvenkat.com/apy2>