function [DataCleaned, Spot, VolumesClustered] = DataCleaning(r, T, i, tail_filter, underlying)
% Reading of the dataset and initial filtering to preserve liquid options
str = strcat('Data',underlying,'\Data',num2str(i),'.xlsx');
Data = rmmissing(readtable(str));
Data = Data(Data.Bid ~= 0,:);
Data = Data(Data.Ask./Data.Bid<=10,:);

% Composition of Call and Put datasets, sorted by ascending strike
mid_price = (Data.Bid+Data.Ask)/2;
Strikes = Data.Strike;
Volumes = Data.Volume;
index_Call = strcmp(Data.Type,'CALL');
Call = [mid_price(index_Call), Strikes(index_Call), Volumes(index_Call)];
Call = sortrows(Call,2);
Put = [mid_price(~index_Call), Strikes(~index_Call), Volumes(~index_Call)];
Put = sortrows(Put,2);

% Computation of the spot price with Put-Call parity
CommonK = intersect(Call(:,2),Put(:,2));
iCall = ismember(Call(:,2),CommonK);
iPut = ismember(Put(:,2),CommonK);
SpotVec = Call(iCall,1)-Put(iPut,1)+CommonK*exp(-r*T);
Spot = median(SpotVec);

% Moneyness computation
Fwd = Spot*exp(r*T);
[~,index_IVatm] = min(abs(Fwd-Call(:,2)));
IV_atm = IV_BS(Call(index_IVatm,1:2),Spot,r,T,1);
m_Call = log(Call(:,2)/Fwd)./(sqrt(T).*IV_atm);
Call = [Call, m_Call];
m_Put = log(Put(:,2)/Fwd)./(sqrt(T).*IV_atm);
Put = [Put, m_Put];

% Only Out-of-the-money Calls (positive m) and Puts (negative m) are employed
% A range of moneyness between -8 and 5 is selected
Call = Call(m_Call>=0 & m_Call<=5,:);
Put = Put(m_Put>=-8 & m_Put<0,:);

% Market implied volatilities, flag = 1 for calls, flag = -1 for puts
IV_Call = IV_BS(Call(:,1:2),Spot,r,T,1);
IV_Put = IV_BS(Put(:,1:2),Spot,r,T,-1);
Call = [Call, IV_Call];
Put = [Put, IV_Put];

% Cleaning procedure on the tails
if tail_filter == 1
    check = false;
else 
    check = true;
end

while ~check
    enter = false;

    % check on the monotonicity of the prices
    i=1;
    while Put(i,1)>=Put(i+1,1)
        Put(i,:)=[];
        enter = true;
    end
    
    i=length(Call(:,1));
    while Call(i,1)>=Call(i-1,1)
        Call(i,:)=[];
        i=i-1;
        enter = true;
    end
    
    % check on the monotonicity of the IV
    i=1;
    while Put(i,5)<=Put(i+1,5)
        Put(i,:)=[];
        enter = true;
    end
    
    if min(Call(:,5))~=Call(end,5)
        i=length(Call(:,1));
        while Call(i,5)<=Call(i-1,5)
            Call(i,:)=[];
            i=i-1;
            enter = true;
        end
    end

    if ~enter
        check = true;
    end
end

DataCleaned = [Put; Call];

% Clustering the volumes according to the moneyness level
VolumesClustered = zeros(14,1);
xx = -8:5;
for i = 1:length(VolumesClustered)
    VolumesClustered(i) = sum(DataCleaned(round(DataCleaned(:,4))==xx(i),3));
end

end