Inventory Management “Inventory Policies & Simulations”

Dinesh Raju
6 min readMay 8, 2023

--

In the last article we calculated the safety stock and reorder points depending on the variability in demand, lead times, ABC classification & service level requirements. Now based on these parameters we will find the inventory policy to be deployed that will give the optimal replenishment rate and cycle service level.

Inventory policies can either be continuous (event based) or periodic (time based).

Continuous:-

1) s, Q — Min — Q Policy (Q-fixed quantity like EOQ, MOQ, SNP)

In this policy we define Minimum stock level & the Fixed order quantity. Reordering level is set such as the lead times match with the number of days it would take for the reorder quantity Q to be received at the factory. So reorder level will act as a trigger for ordering and will be (μDL + σ DL * k )

Good for B Class items where we do not need to dynamically monitor the stock levels

Also, it is suitable for businesses with constant demand, where the cost of holding and ordering inventory is high.

Get your data with the daily, weekly or monthly sales data of any product say A. We are only going to need the column with the sales quantities.

import pandas as pd
import inventorize as inv
import numpy as np
import array

Sales_data= pd.read_csv('your_data')

### Get the sales data for the product A into a separate df
A= Sales_data [['A']]

### Find the mean sales of A
mean_A= A.mean()

### Find the standard deviation of sales of A
sd_A= A.std()

### Say the variable lead time is 7 days
leadtime=7

### Now lets simulate the discussed inventory policies both in normal and
### poisson distributions

# Min Q inventory policy
### We will use ‘inv.sim_min_Q_normal’ function from the inventorize
### library which has the following arguments in order, demand, mean,
### standard deviation, leadtime, service level, Quantity - ordering quantity,
### Min(default is false and will be calculated as per the (μDL + σ DL * k)
### formula if its set to false or else we can enter any value,
### if we need to consider shortage cost we enter the value of the shortage
### cost for every unit of inventory or the default value is 0,
### similarly for ordering cost and inventory cost.

### We will consider the shortage, ordering and inventory cost as 1,
### to compare the impact of these in different policies.

A_sq=inv.sim_min_Q_normal(A, mean_A, sd_A , leadtime=7,
service_level=0.8, Quantity=100,
shortage_cost=1,ordering_cost=1,
inventory_cost=1)

### Results are in the form of a dictionary:
A_sq [1].to_csv('A_sq.csv')

### We can take this data to excel to look at the daily inventory levels,
### min level, the ordering quantity Q, date on which ordered, date on which
### received, lost orders and the inventory position which is simply the
### current stock plus the orders in transit which will be considered as
### the minimum level over which the ordering will be done

A_sq [0].to_csv(' A_sq.csv')

### Now we can change the service level parameter to 0.9 from 0.8,
### which is bound to increase the inventory costs and at the same time reduce
### the shortage costs.
A_sq1=inv.sim_min_Q_normal(A, mean_A, sd_A , leadtime=7,
service_level=0.9, Quantity=100,
shortage_cost=1, ordering_cost=1,
inventory_cost=1)

### Similarly we can study the impact of changing the ordering quantity, etc.


A_sq2=inv.sim_min_Q_normal(A, mean_A, sd_A , leadtime=7,
service_level=0.9, Quantity=300,
shortage_cost=1, ordering_cost=1,
inventory_cost=1)

### At a later point we will use Machine Learning to fix these parameters as
### per the business opportunities to minimize the impact of constrains.

2) s, S — Min — Max Policy

In this policy we define Minimum stock level, Maximum stock level and the Reordering level. Reordering level is set such as the lead times match with the number of days it would take for the reorder quantity to be received at the factory. So reorder level will act as a trigger for ordering and will be (μDL + σ DL * k ) whereas the min level basically will be the safety stock (σ DL * k), while the max level can be set either based on the storage capacity of the warehouse or the shelf life of the product or depending on the frequency of demand or by trial and error or by consensus.

This policy is more dynamic and resilient to change, so it is most commonly used for A Class items.

In general it is suitable for businesses with variable demand and lead time, where the storage capacity is limited and hence helps prevent overstocking.

Now lets do the calculations for this policy considering Poisson distribution.


import pandas as pd
import inventorize as inv
import numpy as np
import array

Sales_data= pd.read_csv('your_data')

### Get the sales data for the product A into a separate df
A= Sales_data[['A']]

### Find the mean sales of A, this will be equal to lambda
mean_A= A.mean()

### In case of Poisson distributions there is no need to find std
### Considering max level of 30 units
A_min_max= inv.sim_min_max_pois(A, mean_A, leadtime=7, service_level=0.8,
Max= 30, shortage_cost=1,ordering_cost=1,
inventory_cost=1)

A_min_max[0].to_csv('A_min_max.csv')

Periodic:-

3) R, S — R (Review Period), S (Max)

We fix a review period like weekly, fortnightly or monthly and irrespective of the stock levels we order upto max.

Here the max level will be the addition of the demand lead time and the demand during the review period. So if the lead time is 10 days and the review period is 15 days, then the max level will the demand for 25 days.

It is suitable when we are buying a lot of items from a single supplier. So instead of implementing different inventory policies for different items being bought from the same supplier, we can save on transportation costs & administrative costs. But at the same time this policy has a lot of holding costs as we need to hold of lot of inventory as a trade off saving the transporation and administrative costs.

import pandas as pd
import inventorize as inv
import numpy as np
import array

Sales_data= pd.read_csv('your_data')

### Get the sales data for the product A into a separate df
A= Sales_data[['A']]

### Find the mean sales of A, this will be equal to lambda
mean_A= A.mean()

### Consdering review period of 3 days
A_periodic_s= inv.Periodic_review_pois(A, mean_A,leadtime=7, service_level=0.9,
Review_period=3,ordering_cost=1,
inventory_cost=1,shortage_cost=1)

A_Periodic_s[0].to_csv('A_Periodic_s.csv')

4) R, s, S — R (Review Period), s (Min), S (Max)

Also known as the hybrid policy, we fix both review period and min, and reorder upto max whenever the stock level reaches min or whenever it reaches the review period, whichever occurs first.

This policy is more dynamic than the Min-Max policy as we will be actively managing the inventory not only on a continuous basis but also on a periodic basis.

import pandas as pd
import inventorize as inv
import numpy as np
import array

Sales_data= pd.read_csv('your_data')

### Get the sales data for the product A into a separate df
A= Sales_data[['A']]

### Find the mean sales of A, this will be equal to lambda
mean_A= A.mean()

A_hybrid= inv.Hibrid_pois(A, mean_A,leadtime=7,service_level=0.9,
Review_period=3,inventory_cost=1,shortage_cost=1,
Min=120, ordering_cost=1)

A_hybrid[0].to_csv('A_hybrid.csv')

5) Base Stock Policy

This is also a periodic review policy, wherein we decide a predefined stock level and during the time of review we will replenish the stock to reach exactly to the predefined stock level. i.e. if in R, S policy if the review period is 1, then it becomes the base stock policy.

For eg. Say the base stock level is 1000 units and the review period is every month. Suppose we sold 500 units during the month, then we will order exactly 500 units to replenish it back to the base stock level.

This policy is very useful for items with low shelf life or for closely monitoring the inventory of items by deploying milk runs.

import pandas as pd
import inventorize as inv
import numpy as np
import array

Sales_data= pd.read_csv('your_data')

### Get the sales data for the product A into a separate df
A= Sales_data[['A']]

### Find the mean sales of A, this will be equal to lambda
mean_A= A.mean()

### Find the standard deviation of sales of A
sd_A= A.std()

A_base= inv.sim_base_normal(A, mean_A, sd_A, leadtime=7,
service_level=0.8,shortage_cost=1,
ordering_cost=1,inventory_cost=1)

A_base[0].to_csv('A_base.csv')

--

--