Akshay Raje
Akshay Raje

Reputation: 892

How to make percentage distribution with least rounding error

I am dealing with a problem when I have to assign a specific portfolio budget to buy stocks. The stock price and percentage of budget allotted to each stock is known and lets assume that the budget is $100,000. Given below is a generic percentage calculation that I am currently using:

data = [
  {stock: 'INFY', price: 1122.9, percent: 0.304},
  {stock: 'SUNPHARMA', price: 890.95, percent: 0.177},
  {stock: 'TCS', price: 2597.7, percent: 0.123},
  {stock: 'HCLTECH', price: 856, percent: 0.117},
  {stock: 'LUPIN', price: 2019, percent: 0.112},
  {stock: 'DIVISLAB', price: 1097, percent: 0.085}, 
  {stock: 'CADILAHC', price: 409.4, percent: 0.082}   
];
  
var budget = 100000;
var actual = 0;

for ( var i = 0; i < data.length; i++ in data ) {
  shares = Math.floor((budget * data[i].percent) / data[i].price);
  document.write( data[i].stock + ': ' );
  document.write( shares );
  document.write( '<br />' );
  spent = shares * data[i].price;
  actual += spent;  
}

document.write( '<hr />' );

document.write( 'Budget: ' + budget );
document.write( '<br />' );
document.write( 'Actual spent: ' + actual );

What should be the approach / algorithm / code to find the optimal way to use the budget such that:

To meet the above two conditions it is ok to deviate from the percentage of budget allotted to each stock but the deviation should be least possible

Upvotes: 0

Views: 193

Answers (1)

charlietfl
charlietfl

Reputation: 171669

Add one more important variable minPrice .

Once initial allotment is done based on the percentages you can create an additional while loop that keeps adding shares while the remainder is greater than or equal to the minimum price.

var budget = 100000;
var actual = 0;
var minPrice = Infinity;

for ( var i = 0; i < data.length; i++ in data ) {
  data[i].shares = Math.floor((budget * data[i].percent) / data[i].price);    
  actual +=  data[i].shares * data[i].price;
  minPrice  = data[i].price < minPrice ? data[i].price : minPrice;    
}


var remain = budget - actual;
// attempts to add 1 share each iteration until not enough left to buy any shares
while( remain >= minPrice){
    for(var i =0; i < data.length; i++){
        if(data[i].price <= minPrice){
            data[i].shares +=1;
            remain -= data[i].price;
            actual += data[i].price
        }
    }    
}

Since initial data is sorted by highest portfolio percentage, higher priority would automatically get more shares first if their price is less than remainder of budget

Upvotes: 1

Related Questions